mayavi mlab get current axes - python

Is there a way of a procedure similar to plt.gca() to get a handle to the current axes. I first do a=mlab.surf(x, y, u2,warp_scale='auto')
and then
b=mlab.plot3d(yy, yy, (yy-40)**2 ,tube_radius=20.0)
but the origin of a and b are different and the plot looks incorrect. So I want to put b into the axes of a
In short, what would be the best way in mayavi to draw a surface and a line on same axes?

What you are expecting to be able to do from your matplotlib experience is not how mayavi axes work. In matplotlib the visualization is a child of the axes and the axes determines its coordinates. In mayavi or vtk, visualization sources consist of points in space. Axes are objects that surround a source and provide tick markings of the coordinate extent of those objects, that are not necessary for the visualizations, and where they exist they are children of sources.

You should remove the argument warp_scale='auto'
a=mlab.surf(x, y, u2)
and it will work.

Related

inset_axes polar projection in a polar plot in matplotlib

I would like to create a polar plot with a polar zoom.
This is what I have done do far:
fig = plt.figure(figsize=(30, 15))
G = gridspec.GridSpec(1, 2)
axes_1 = plt.subplot(G[0],projection='polar')
axes_1.inset_axes(bounds=[0.0,0.0,0.1,0.1],projection='polar')
axes_2 = plt.subplot(G[1])
and here the error that I get:
'Axes' object has no property 'projection'
This is quite strange, because in the manual of inset_axes I have found the option projection (here).
There are some attempts here, but for me is totally unclear, or here, but this last it is not what I what. It is just another plot.
Thanks
From version 3.6, matplotlib.axes.Axes.inset_axes accepts "polar" and "projection" parameters. If you use a older version, there is also a workaround using mpl_toolkits.axes_grid1.inset_locator.inset_axes() (see this answer).
Creating a rectangular zoom of a polar plot is not as straightforward, but this answer may help you.

How do I draw borders around a matplotlib plot using object-oriented code?

I would like generate a plot with the coordinate axes in the middle of the plot area. Using matplotlib, I've managed to get as far as is shown in this sample code:
import matplotlib.pyplot as plt
xvalues = [-3,-2,-1,1,2,3]
yvalues = [2,4,-2,-4,1,-1]
fig, ax = plt.subplots()
ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')
ax.scatter(xvalues, yvalues)
The problem with using set_position() to move the spines into the middle of the plot area is that this removes them as elements of the plot's border. I'm looking for a way to restore the border lines using object-oriented operations on the Figure and Axes instances fig and ax, respectively.
Please note that I'm interested in manifestly object-oriented code only: operations on fig and ax. This constraint is a part of the question.
I won't accept an answer given in terms of plt or equivalent. I already know how to do that. I'll accept an answer demonstrating that it isn't possible to draw these border lines using only manifestly object-oriented code before I accept an answer using plt.

Save colorbar for scatter plot separately

I've got scatter plot with colorbar which I save as PNG image. I need the plot to be of a certain figsize but adding colorbar scales original plot.
import pylab as plt
plt.figure(figsize=FIGSIZE)
plt.scatter(X, Y, c=Z, s=marker_size, norm=LogNorm(), vmin=VMIN, vmax=VMAX, cmap=CMAP,rasterized=True,lw=0,)
CB = plt.colorbar(ticks=TICKS, format=FORMAT)
How could I save original plot (with figsize set as above) and colorbar as two separate images?
The obvious answer is "plot your colorbar separately". You need to create a new figure window and plot your colorbar there, in order to prevent your first figure from being distorted. Small example:
import matplotlib.pyplot as plt
import numpy as np # only for dummy data
X,Y = np.mgrid[-2:3,-2:3]
Z = np.random.rand(*X.shape)
FIGSIZE = (2,3)
plt.figure(figsize=FIGSIZE)
mpb = plt.pcolormesh(X,Y,Z,cmap='viridis')
# plot the original without a colorbar
plt.savefig('plot_nocbar.png')
# plot a colorbar into the original to see distortion
plt.colorbar()
plt.savefig('plot_withcbar.png')
# draw a new figure and replot the colorbar there
fig,ax = plt.subplots(figsize=FIGSIZE)
plt.colorbar(mpb,ax=ax)
ax.remove()
plt.savefig('plot_onlycbar.png')
# save the same figure with some approximate autocropping
plt.savefig('plot_onlycbar_tight.png',bbox_inches='tight')
Consider the following four figures that were produced (click to view properly):
The first is a saved version of the figure without a call to colormap. This is fine, this is what you want to preserve. The second figure shows what happens if we call colorbar without any extra fuss: it takes some space from the original figure, and this is what you want to prevent.
You have to open a new figure (and axes) using plt.subplots, with the size of your original figure. This way you can be sure that the produced colorbar will be the same size as if it was drawn in your original figure. In the above setup I let matplotlib determine the size of the colorbar itself; but then afterward we need to delete the auxiliary axes that would pollute the resulting plot. (The other option would be to create a single axes in the new figure manually, with the expected size of the colorbar. I suspect this is not a feasible course of action.)
Now, as you can see in the third plot, the empty space left after the deleted axes is clearly visible in the resulting plot (but the size of the colorbar is perfect, correspondingly). You can either cut this white space off manually in post-production, or use something that autocrops your colorbar image.
I also included a version of the plot wherein matplotlib itself crops most of the figure: the bbox_inches='tight' keyword argument to savefig does exactly this. The upside is that the resulting image file only contains the colorbar (as seen above in the fourth image), but the size of the resulting colorbar will be slightly different from your original. Depending on your specific needs, you'll need to experiment with the available methods to come up with a solution that's most convenient for you.

Changing center of rotation in a Matplotlib 3D plot

I have a 3D line plot in matplotlib, created using the following code:
def view(self):
from mpl_toolkits.mplot3d import Axes3D #noqa
import matplotlib.pyplot as plt
ax = plt.figure().gca(projection='3d')
history = np.array(self.position_history)
x, y ,z = history[:, 0], history[:, 1], history[:, 2]
ax.plot(x, y, z)
plt.show()
Here history is an Mx3 array of points. This works fine and pops up a plot as expected. I am able to click and drag to modify the azimuth and elevation interactively. I am able to zoom by right-clicking and dragging.
However I am wondering if it is possible to modify the center point of the pan and zoom? I would like to zoom into the top-right, and then pan around with the top right as my center of rotation. If you have ever used solidworks or another CAD program, this is the behavior I am after. Is this doable? If not interactively, can I do it programmatically?
And finally, if none of this is possible in matplotlib, is there another library that can accomplish what I want?
I have also run into trouble in the past in terms of customizing mplot3d, rather unsuccessfully..
And finally, if none of this is possible in matplotlib, is there another library that can accomplish what I want?
you can do this with mayavi
here is a relevant stackoverflow answer for customizing how you interact with your plot
there are also various useful tips and tricks for animating in general and for using mayavi
(apologies if this isn't useful)
Not sure this will do what you need but you can define the center when you first plot. Here, "c_x" is the center of rotation on the x axis and the -/+ 200 defines the axis to be 200 units in both direction. Likewise for y and z.
If you had the user choose the center before plotting, that could work as a crude work around.
http://matplotlib.org/api/axes_api.html?highlight=set_xbound#matplotlib.axes.Axes.set_xbound
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.autoscale(enable=False,axis='both') #you will need this line to change the Z-axis
ax.set_xbound(c_x-200, c_x+200)
ax.set_ybound(c_y-200, c_y+200)
ax.set_zbound(c_z-200, c_z+200)

Matplotlib - multiple surface plots, wrong overlapping

I am currently plotting two completely different datasets into one 3D surface plot. When I am plotting each one independently, everything works fine. However, as soon as I plot them in one, the visualization is strange. I do the plotting the following way:
fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X,Y,Z, color=color, antialiased=True)
(get new X,Y, Z values)
ax.plot_surface(X,Y,Z, color=color, antialiased=True)
ax.view_init(30, 360)
The output is the following:
As you can see, the blue data is correct, but the green one is somehow in the backside and not correctly visualized. If I plot the green one alone, it works perfectly.
Changing the order of plotting (or playing around with zorder) does not change anything.
Hope someone can help!
Matplotlib is just a 2d plotting library. 3d plots are achieved by projecting the 3d surface onto the image plane.
If you have multiple 3d surfaces, it will turn each into a 2d shape, and then calculate a single height for each shape, and show then in that order.
As far as I'm aware, the zorder option doesn't work, and all it would is change the order of the surfaces anyway.
If you're really unlucky, the grey boxes that make up the axis grids can get plotted above your surface too. That's even more annoying.
Of you must use matplotlib, then i guess you could split up your surface into lots of smaller ones, but you're going to encounter a pretty big performance bit doing this, and you'll to override the values in the legend too.

Categories