Adjust whitespace margins on animated Axes3D scatter plot (matplotlib) - python

I am using matplotlib 1.2.1 and am limited to that version for now. The problem I run into is the crowding of the axis labels and ticks in the bottom of the frame with this rotated plot. I have tried plt.adjust_subplots, I've tried tight_layout, changing the figure size, ax.dist and more but nothing seems to change the appearance as shown in the example image below. This is just one frame but often as the plot rotates, it goes out of frame at the bottom (especially when ticks and labels are bigger). Perhaps my problem is where I place the ax.dist argument?
How can I add a little more whitespace at the bottom of this animated plot? As a bonus, how can I get rid of the confusing double grid lines at the edges? Thank you.
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.rcParams['animation.ffmpeg_path']='C:/FFMPEG/bin/ffmpeg.exe'
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
def format_3d_ax(ax):
ax.w_xaxis.set_pane_color((1.0,1.0,1.0,1.0))
ax.w_yaxis.set_pane_color((1.0,1.0,1.0,1.0))
ax.w_zaxis.set_pane_color((1.0,1.0,1.0,1.0))
ax.w_xaxis._axinfo['grid'].update({'linewidth':0.25,'color':'black'})
ax.w_yaxis._axinfo['grid'].update({'linewidth':0.25,'color':'black'})
ax.w_zaxis._axinfo['grid'].update({'linewidth':0.25,'color':'black'})
def rotate(i,ax, angles, elev):
ax.view_init(elev,angles[i])
plt.draw()
return ax
def rotate_3d(fig,ax,angles,elev):
frames=len(angles)
ani=animation.FuncAnimation(fig,rotate, fargs=(ax,angles, elev),blit=True,
frames=frames, interval=200)
return ani
fig=plt.figure(figsize=(12,7.6))
ax=Axes3D(fig)
ax.view_init(elev=25, azim=0)
format_3d_ax(ax)
ax.set_xlabel('Reasonably sized x label')
ax.set_ylabel('Reasonably sized y label')
ax.set_zlabel('z label')
ax.scatter([1],[1],[1], marker='.', s=80)
ani=rotate_3d(fig,ax,range(0,45),25)
Writer=animation.writers['ffmpeg']
writer=Writer(fps=30, bitrate=2000)
ani.save('C:/Temp/test.mp4', writer=writer, dpi=300)
print ('Done') #helps to know when the writer is done.

Related

matplotlib last tick label still visible [duplicate]

I have a semilogx plot and I would like to remove the xticks. I tried:
plt.gca().set_xticks([])
plt.xticks([])
ax.set_xticks([])
The grid disappears (ok), but small ticks (at the place of the main ticks) remain. How to remove them?
The plt.tick_params method is very useful for stuff like this. This code turns off major and minor ticks and removes the labels from the x-axis.
Note that there is also ax.tick_params for matplotlib.axes.Axes objects.
from matplotlib import pyplot as plt
plt.plot(range(10))
plt.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
plt.show()
plt.savefig('plot')
plt.clf()
Not exactly what the OP was asking for, but a simple way to disable all axes lines, ticks and labels is to simply call:
plt.axis('off')
Alternatively, you can pass an empty tick position and label as
# for matplotlib.pyplot
# ---------------------
plt.xticks([], [])
# for axis object
# ---------------
# from Anakhand May 5 at 13:08
# for major ticks
ax.set_xticks([])
# for minor ticks
ax.set_xticks([], minor=True)
Here is an alternative solution that I found on the matplotlib mailing list:
import matplotlib.pylab as plt
x = range(1000)
ax = plt.axes()
ax.semilogx(x, x)
ax.xaxis.set_ticks_position('none')
There is a better, and simpler, solution than the one given by John Vinyard. Use NullLocator:
import matplotlib.pyplot as plt
plt.plot(range(10))
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.show()
plt.savefig('plot')
Try this to remove the labels (but not the ticks):
import matplotlib.pyplot as plt
plt.setp( ax.get_xticklabels(), visible=False)
example
This snippet might help in removing the xticks only.
from matplotlib import pyplot as plt
plt.xticks([])
This snippet might help in removing the xticks and yticks both.
from matplotlib import pyplot as plt
plt.xticks([]),plt.yticks([])
Those of you looking for a short command to switch off all ticks and labels should be fine with
plt.tick_params(top=False, bottom=False, left=False, right=False,
labelleft=False, labelbottom=False)
which allows type bool for respective parameters since version matplotlib>=2.1.1
For custom tick settings, the docs are helpful:
https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.tick_params.html
# remove all the ticks (both axes), and tick labels on the Y axis
plt.tick_params(top='off', bottom='off', left='off', right='off', labelleft='off', labelbottom='on')
Modify the following rc parameters by adding the commands to the script:
plt.rcParams['xtick.bottom'] = False
plt.rcParams['xtick.labelbottom'] = False
A sample matplotlibrc file is depicted in this section of the matplotlib documentation, which lists many other parameters like changing figure size, color of figure, animation settings, etc.
A simple solution to this problem is to set the color of the xticks to White or to whatever the background color is. This will hide the text of the xticks but not the xticks itself.
import matplotlib.pyplot as plt
plt.plot()
plt.xticks(color='white')
plt.show()
Result

Cartopy coastlines hidden by inset_axes use of Axes.pie

I am producing a map of the world with pie charts in individual model grid boxes. I make the map and coastlines using cartopy. The pie charts I produce using inset_axes. Unfortunately the pie charts hide the coastlines and I'd like to see them clearly.
Minimum working example:
import cartopy.crs as ccrs
import numpy as np
import cartopy.feature as feature
import matplotlib.pyplot as plt
def plot_pie_inset(dataframe_pie,ilat_pie,ilon_pie,axis_main,width_local,alpha_local):
ax_sub= inset_axes(axis_main, width=width_local, height=width_local, loc=3, bbox_to_anchor=(ilat_pie, ilon_pie),bbox_transform=axis_main.figure.transFigure, borderpad=0.0)
wedges,texts= ax_sub.pie(dataframe_pie,colors=colors_dual)
for w in wedges:
w.set_linewidth(0.02)
w.set_alpha(alpha_local)
w.set_zorder(1)
plt.axis('equal')
colors_dual=['RosyBrown','LightBlue']
lat_list= np.arange(0.2,0.7,0.05)
fig= plt.figure()
ax_main= plt.subplot(1,1,1,projection=ccrs.PlateCarree())
ax_main.coastlines(zorder=3)
for ilat in np.arange(len(lat_list)):
plot_pie_inset([75,25],lat_list[ilat],0.72,ax_main,0.2,0.9)
plt.show()
I can see the coastlines by making the pie charts partially transparent by reducing the alpha value. However, this makes the colors somewhat muted. My aim is to have the coastlines as the topmost layer.
I have attempted to use 'zorder' to force the coastlines to the top layer. However, 'zorder' cannot be passed to inset_axes, nor to ax.pie so I've made the patches of color in pie charts translucent. This fails because the ax_main.coastlines does not have its own 'zorder'. The coastline zorder seems to be tied to that of ax_main. There is no benefit in increasing the zorder of ax_main.
Any suggestions greatly welcomed.
The problem is that each axes either lies on top or below another axes. So changing the zorder of artists within axes, does not help here. In principle, one could set the zorder of the axes themselves, putting the inset axes behind the main axes.
ax_sub.set_zorder(axis_main.get_zorder()-1)
Cartopy's GeoAxes uses its own background patch. This would then need to be set to invisble.
ax_main.background_patch.set_visible(False)
Complete example:
import cartopy.crs as ccrs
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
def plot_pie_inset(dataframe_pie,ilat_pie,ilon_pie,axis_main,width_local,alpha_local):
ax_sub= inset_axes(axis_main, width=width_local, height=width_local, loc=3,
bbox_to_anchor=(ilat_pie, ilon_pie),
bbox_transform=axis_main.transAxes,
borderpad=0.0)
wedges,texts= ax_sub.pie(dataframe_pie,colors=colors_dual)
for w in wedges:
w.set_linewidth(0.02)
w.set_alpha(alpha_local)
w.set_zorder(1)
plt.axis('equal')
# Put insets behind main axes
ax_sub.set_zorder(axis_main.get_zorder()-1)
colors_dual=['RosyBrown','LightBlue']
lat_list= np.arange(0.2,0.7,0.05)
fig= plt.figure()
ax_main= plt.subplot(1,1,1,projection=ccrs.PlateCarree())
ax_main.coastlines()
# set background patch invisible, such that axes becomes transparent
# since the GeoAxes from cartopy uses a different patch as background
# the following does not work
# ax_main.patch.set_visible(False)
# so we need to set the GeoAxes' background_patch invisible
ax_main.background_patch.set_visible(False)
for ilat in np.arange(len(lat_list)):
plot_pie_inset([75,25],lat_list[ilat],0.72,ax_main,0.2,0.9)
plt.show()
An alternative solution suggest by a colleague neglects to use the inset_axes but achieves a similar result. The main difference is that the coordinate system in this solution is in the original latitude/longitude coordinates rather than figure coordinates.
def plot_pie_direct(dataframe_pie,ilat_pie,ilon_pie,axis_main,width_local,alpha_local):
wedges,texts= ax_main.pie(dataframe_pie,colors=colors_aer_atm,radius=width_local)
for w in wedges:
w.set_linewidth(0.02) ## Reduce linewidth to near-zero
w.set_center((ilat_pie,ilon_pie))
w.set_zorder(0)
fig= plt.figure()
ax_main= plt.axes(projection=ccrs.PlateCarree())
ax_main.coastlines(zorder=3)
ax_main.set_global()
lim_x= ax_main.get_xlim()
lim_y= ax_main.get_ylim()
for ilat in np.arange(len(lat_list_trim)):
plot_pie_direct(frac_aer_atm_reshape_trim[:,ilat,ilon],x_val_pies[ilon],y_val_pies[ilat],ax_main,lat_list_diff_trim,0.9)
ax_main.coastlines(zorder=3)
ax_main.set_xlim(lim_x)
ax_main.set_ylim(lim_y)
plt.show()

Colorbars close to subplots

How can I put colorbars beside each colormap that is in a subplot? A simplified version of my real code is here that shows my problem. As you can see all the colorbars are at the bottom right and also are making the last plot smaller.
from matplotlib import pyplot as plt
import numpy as np
def plots():
fig,ax=plt.subplots(2,2)
for i in range(2):
rho_mat,C_mat=np.random.uniform(size=(50,50)),np.random.uniform(size=(50,50))
ax[0,i].set_title(r"$\rho_{X,Y}$")
p=ax[0,i].imshow(np.fliplr(rho_mat).T,extent=[0.,1,0.,1],vmin=0,vmax=1, interpolation='none')
ax[0,i].set_xlabel(r'$\epsilon_1$')
ax[0,i].set_ylabel(r'$\epsilon_2$')
fig.colorbar(p, shrink=0.5)
ax[1,i].set_title(r"$C_{X,Y}$")
p2=ax[1,i].imshow(np.fliplr(C_mat).T,extent=[0.,1,0.,1],vmin=0,vmax=1, interpolation='none')
ax[1,i].set_xlabel(r'$\epsilon_1$')
ax[1,i].set_ylabel(r'$\epsilon_2$')
fig.colorbar(p2, shrink=0.5)
plt.tight_layout()
plt.show()
plots()
The colorbar method has an optional keyword argument that allows you to specify the axes it is associated with.
In your code you could change the call to colorbar to something like this:
fig.colorbar(p, ax=ax[0,i], shrink=0.5)
fig.colorbar(p2, ax=ax[1,i], shrink=0.5)

Updating Matplotlib 3D with new data and ticker values

When I use axes.cla() on my 3D.plot to remove all the lines, modify the axis' and then call draw() on that figure again, the axis labels and lines become thicker. And it is only on the axis that are modified with ticker. My guess is i have to delete the old axis labels somehow, how can I do that?
Here is a minimal example code of what I am talking about. I linked the redraw to mouse click on the canvas. Code is ment for Python 3. (I already tried a workaround with clf() and redraw the whole figure, but in 3D mode it does not work.)
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.ticker as ticker
def onclick(event):
event.inaxes.cla()
event.inaxes.w_xaxis.set_major_locator(ticker.LinearLocator())
event.inaxes.w_xaxis.set_major_locator(ticker.LinearLocator())
event.canvas.draw()
fig = plt.figure()
axes = fig.add_subplot(111, projection='3d')
fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
I got a workaround by not using cla(). I only removed my plot data in axes.lines and axes.collections.

Add an extra information in a python plot?

Suppose we have a figure with three plots in it for three different parameters. But for the all three plots We have same temperature T=4K . Then how can I add this information in the figure?
I am not interested to write it in the Caption. I want it on the figure itself.
figtext would work well.
The advantage of figtext over text and annotate is that figtext defaults to using the figure coordinates, whereas the others default to using the coordinates of the axes (and therefore "T=4K" would move around if your axes are different between the different plots).
import matplotlib.pyplot as plt
plt.figure()
plt.xlim(-10, 10)
plt.ylim(0, .01)
plt.figtext(.8, .8, "T = 4K")
plt.show()
Here's a demonstration of using annotate. Check out this example for different styles of annotation.
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
fig, ax = plt.subplots()
x = np.linspace(0,4,100)
plt.plot(x,2*x)
plt.plot(x,x**2)
plt.plot(x,np.sqrt(8*x))
ax.annotate('T = 4K', xy=(2,4), xycoords='data',
xytext=(-100,60), textcoords='offset points',
arrowprops=dict(arrowstyle='fancy',fc='0.6',
connectionstyle="angle3,angleA=0,angleB=-90"))
plt.show()
raw_input()
figtext can make annotations at the bootom of multiple subplots figure like a comment independent of figures so you can make additional comments or remarks all in one picture. I was looking for this too. Thank you guys! :-)
import matplotlib.pyplot as plt
plt.figure(1)
plt.suptitle("SOME TITLE HERE")
#FIRST SUBPLOT
plt.subplot(311)
plt.ylabel(r"$a [m/s^2]$") # YOU CAN USE LaTeX TYPESETTING IN PYPLOT STRINGS!
plt.xlabel("time [s]")
plt.grid(True)
plt.plot(some_data)
# SECOND SUBPLOT
plt.subplot(312)
...
# THIRD SUBPLOT
plt.subplot(313)
...
# BOTTOM LABEL
plt.figtext(0.5, 0, "SOME LABEL BELOW ALL SUBPLOTS", ha="center", fontsize=7, bbox={"facecolor":"orange", "alpha":0.5, "pad":5})
# DRAW THE PLOT
plt.show()
Notre ha=center will center the string if x=0.5. You can also use fontsize and bbox parameters to change appearance of the string and its area.
Well, I'm not sure what you mean, but you can add text to the plot with the text() method.
Plot text in matplotlib pyplot
I suggest a grey horizontal zone around the T=4K zone
If you look at axhspan(ymin, ymax, xmin=0, xmax=1, **kwargs) in the matplotlib documentation for axes, you can make things like that:

Categories

Resources