plot irregular data with matplotlib - matplotlib

I have function data within a LinearNDInterpolator that I can evaluate using a meshgrid, and it looks pretty decent aside from some rendering glitches unique to the input data.
X, Y = np.meshgrid(x, y)
Z = interp(X, Y)
fig = plt.figure()
ax = plt.axes(projection="3d")
ax.plot_surface(X, Y, Z, cmap="viridis")
To work around the glitches I need to render the surface at a resolution that exceeds my resources. Also, the glitches are ameliorated when using triangular meshes. So I was hoping to plot the sparse data contained within the convex-hull without interpolating to a regular grid, which would waste memory. Unfortunately the resulting surface is a jumble of skinny triangles; a forest of broken glass. I was under the impression that LinearNDInterpolator simply interpolated the triangles without changing the mesh, so I'm wondering why the result is so poor.
qhull = interp.tri
mptri = mpl.tri.Triangulation\
( x = qhull.points[:, 0]
, y = qhull.points[:, 1]
, triangles = qhull.vertices
)
fig = plt.figure()
ax = plt.axes(projection="3d")
ax.plot_trisurf(mptri, interp.values, cmap="viridis")

Related

How to entend the area/boudaries that shows the data from a Axes3D with matplolib when using the set_box_aspect zoom

I'm trying to zoom in a 3D plot. I'm using the ax.set_box_aspect() fonction. When doing so, the axis are zoomed in, they appear bigger, but the area where the data can be seen stay at the same size as before (the plot are not using the total available space).
The aim in the end is to have two axis, the first one 3d, the other one 2d. I would have wanted the first plot to take all the space available at the top half of the figure.
Here is the code before the Zoom
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
#---- generate data
nn = 100
X = np.random.randn(nn)*20 + 0
Y = np.random.randn(nn)*50 + 30
Z = np.random.randn(nn)*10 + -5
#---- check aspect ratio
asx, asy, asz = np.ptp(X), np.ptp(Y), np.ptp(Z)
fig = plt.figure(figsize=(15,15))
ax = fig.add_subplot(211, projection='3d')
#---- set box aspect ratio
ax.set_box_aspect((asx,asy,asz))
scat = ax.scatter(X, Y, Z, c=X+Y+Z, s=500, alpha=0.8)
ax.set_xlabel('X-axis'); ax.set_ylabel('Y-axis'); ax.set_zlabel('Z-axis')
ax = fig.add_subplot(212)
plt.show()
Before using the zoom
And now when I zoom in, the scatter is limitted in a square frame :
ax.set_box_aspect((asx,asy,asz), zoom = 2 )
After using the zoom
(The data used for the plot doesn't matter here, it is just to showcase my issue.)
I tried changing the axis limit with set_xlim3d or set_xlim, but in either case, the result is the same.
It seems like the showing area (I can't find the right word for it) stays a square no matter what.
I didn't find any usefull information on that matter online, (maybe from the lack of vocabulary to describe my problem).

Need help displaying 4D data in matplotlib 3D scatterplot properly

Hey so I'm an undergraduate working in an imaging lab and I have a 3D numpy array that has values from 0-9 to indicate concentration in a 3D space. I'm trying to plot these values in a scatterplot with a colormap to indicate the value between 0-9. The array is 256 x 256 x 48, so I feel like the size of it is making it difficult for me to plot the array in a meaningful way.
I've attached a picture of what it looks like right now. As you can see the concentration looks very "faded" even for very high values and I'm not entirely sure why. Here is the code I'm using to generate the plot:
current heatmap
fig = plt.figure()
x, y, z = np.meshgrid(range(256), range(256), range(48))
col = sum_array.flatten()
ax = fig.add_subplot(111, projection = '3d')
sc = ax.scatter(x, y, z, c = col, cmap='Reds',
linewidths=.01, s=.03, vmin=0, vmax=9,
marker='.', alpha=1)
plt.colorbar(sc)
plt.show()
If anyone can help me display the colors in a more bright/concentrated manner so the heat map is visually useful, I'd really appreciate it. Thank you!

Is it possible to break x and y axis at the same time on lineplot?

I am working on drawing lineplots with matplotlib.
I checked several posts and could understand how the line break works on matplotlib (Break // in x axis of matplotlib)
However, I was wondering is it possible to break x and y axis all together at the same time.
My current drawing looks like below.
As shown on the graph, x-axis [2000,5000] waste spaces a lot.
Because I have more data that need to be drawn after 7000, I want to save more space.
Is it possible to split x-axis together with y-axis?
Or is there another convenient way to not to show specific region on lineplot?
If there is another library enabling this, I am willing to drop matplotlib and adopt others...
Maybe splitting the axis isn't your best choice. I would perhaps try inserting another smaller figure into the open space of your large figure using add_axes(). Here is a small example.
t = np.linspace(0, 5000, 1000) # create 1000 time stamps
data = 5*t*np.exp(-t/100) # and some fake data
fig, ax = plt.subplots()
ax.plot(t, data)
box = ax.get_position()
width = box.width*0.6
height = box.height*0.6
x = 0.35
y = 0.35
subax = fig.add_axes([x,y,width,height])
subax.plot(t, data)
subax.axis([0, np.max(t)/10, 0, np.max(data)*1.1])
plt.show()

Annotate a data point with a graph

For the lack of better term, is there a way to annotate a data point with a graph? I include an example of what I am for below
Big black data point with a graph corresponding to it. Note that graph is rotated so its "x" axis (not shown) is perpendicular to the "y" axis of the scatter plot
annotation_box http://matplotlib.org/examples/pylab_examples/demo_annotation_box.html is the closest thing I can find at the moment, but even knowing the proper term for what I want to do, would make my life easier.
If I understood the problem correctly, what you need are floating axes that you can place as annotations over your plot. Unfortunately, this is not easily possible in matplotlib, as far I know.
An easy solution would be to just plot the points and graphs in the same axis, with the graphs scaled down and shifted close to the points.
import numpy as np
import scipy.stats as sps
import matplotlib.pyplot as plt
xp = [5, 1, 3]
yp = [2, 1, 4]
# just generate some curves
curves_x = np.array([np.linspace(0, 10, 100)] * 3)
curves_y = sps.gamma.pdf(curves_x[0], [[2], [5], [7]], 1)
plt.scatter(xp, yp, s=50)
for x, y, cx, cy in zip(xp, yp, curves_x, curves_y):
plt.plot(x + cy / np.max(cy) + 0.1 , y + cx / np.max(cx) - 0.5)
plt.show()
This is a very simplistic example. The numbers will have to be tuned to look nice with varying scale of the data.

Pyplot polar surface plot

I am new in pyplot.
I have a Cartesian surface plot:
# offset and omega are arrays
Z = my_function(omega,offset) # my_function give and arrays of omega.size*offset.size
fig, ax = plt.subplots(1)
p = ax.pcolor(offset,omega,Z.T,cmap=cm.jet,vmin=abs(Z).min(),vmax=abs(Z).max())
cb = fig.colorbar(p,ax=ax)
Maybe there is a more simple way to plot a surface but that the way I've found on the internet.
Well, now I want to plot my_function as a surface using polar coordinate, I've tried this:
ax2 = plt.subplot(111, polar=True)
p2 = ax2.pcolor(offset,omega,Z.T,cmap=cm.jet,vmin=abs(Z).min(),vmax=abs(Z).max())
It kind of work, I have a surface plot but it does not take into account the limits of Y.
For example if Y is defined between -15 and 15° I only want my function to be plotted and shown between those angles and not 0 to 360° as my example is doing.
How can I do that ?
I thank you in advance for any answer.