CTKlein
CTKlein

Reputation: 309

Matplotlib heatmap with changing y-values

I'm trying to plot some data for a measurement taken from between two surfaces. The z-direction in the system is defined as normal to the surfaces. The problem is that along the x-axis of my plot I'm varying the separation distance between the two surfaces which means that for every slice, the min/max of the y-axis change. I've sort circumvented this by presenting a normalized y-axis where z_min is the bottom surface and z_max is the top surface: enter image description here

However, this representation somewhat distorts the data. Ideally I would like to show the actual distance to the wall on the y-axis and just leave the areas outside of the system bounds white. I (poorly) sketched what I'm envisioning here (the actual distribution on the heatmap should look different, of course): enter image description here

I can pretty easily plot what I want as a 3D scatter plot like so: enter image description here

But how do I get the data into a plot-able form for a heatmap?

I'm guessing I would have to blow up the MxN array and fill in missing values through interpolation or simply mark them as NAN? But then I'm also not quite sure how to add a hard cutoff to my color scheme to make everything outside of the system white.

Upvotes: 3

Views: 20945

Answers (3)

GBy
GBy

Reputation: 1779

Below an implementation with triangular mesh contouring, based on CT Zhu example.

If your domain is not convex, you will need to provide your own triangles to the triangulation, as default Delaunay triangulation meshes the convex hull from your points.

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as mtri


y = np.array([np.linspace(-i, i, 51) for i in (
              np.linspace(5, 10))[::-1]])
x = (np.zeros((50, 51)) +
     np.linspace(1, 6, 50)[..., np.newaxis])
z = (np.zeros((50, 51)) -
     np.linspace(-5, 5, 51)**2 + 10)  # make up some z data

x = x.flatten()
y = y.flatten()
z = z.flatten()

print "x shape: ", x.shape

triang = mtri.Triangulation(x, y)
plt.tricontourf(triang, z)
plt.colorbar()
plt.show()

enter image description here

Upvotes: 2

CT Zhu
CT Zhu

Reputation: 54330

I guess, maybe 2d interpolation by using griddata will be what you want?

from matplotlib.mlab import griddata
xi=linspace(1,5,100)
yi=linspace(-10.5, 10.5, 100)
y=array([linspace(-i, i, 51) for i in (linspace(5,10))[::-1]]) #make up some y vectors with different range
x=zeros((50,51))+linspace(1,6, 50)[...,newaxis]
z=zeros((50,51))-linspace(-5, 5,51)**2+10 #make up some z data
x=x.flatten()
y=y.flatten()
z=z.flatten()
zi=griddata(x, y, z, xi, yi)
plt.contourf(xi, yi, zi, levels=-linspace(-5, 5,51)**2+10)

enter image description here

Upvotes: 1

tacaswell
tacaswell

Reputation: 87376

You can do this with pcolormesh which takes the corners of quadrilaterals as the arguements

X, Y = np.meshgrid(np.linspace(0, 10, 100), np.linspace(0, 2*np.pi, 150),)
h = np.sin(Y)
Y *= np.linspace(.5, 1, 100)

fig, ax = plt.subplots(1, 1)
ax.pcolormesh(X, Y, h)

enter image description here

Upvotes: 2

Related Questions