Matplotlib: Intelligent figure scale / legend location - python

Some code gives me the following matplotlib figure:
Unfortunately, the figure size is fixed and hence on the top right, the legend and the lines overlap. Is there any way to have the legend not stack on top of the lines?
I am aware that legend allows ax2.legend(loc=0), where 0 will put it into the "best" location. However, with two y axis as here, this will stack both legends on top of each other - not really the best allocation.
My next best try would be to "scale up" the figure, as manually done with an interactive graph, where I have only scaled up both axis:
Doing this with the "real" figure scale requires iterated "trying numbers and checking how far it goes" procedure - which may need to be redone if the graph changes. Is there any way of having matplotlib compute the scale "intelligently"?

If the best location plt.legend(loc='best') fails, try putting the legend outside of the plot:
plt.legend(loc='upper left', bbox_to_anchor=(1.02, 1), borderaxespad=0)
You can scale only legend, not the whole plot. Link here
More on legends here and also here.

Related

How to adjust subplots borders in matplotlib automatically?

When plotting multiple plots using plt.subplots, most of the time the spacing between subplots is not ideal so the the xtick labels of the top plot would overlap with the title of the bottom plots. There is a way to fix this manually by calling say plt.subplots_adjust(hspace=0.5) and changing the parameters interactively to obtain a decent looking plot. Is there a way to calculate the subplot_adjust parameter automatically? Meaning finding the minimum hspace and wspace so that there is not overlap between texts of the plots.
You can use tight_layout https://matplotlib.org/stable/tutorials/intermediate/tight_layout_guide.html or constrained_layout https://matplotlib.org/stable/tutorials/intermediate/constrainedlayout_guide.html
I'm pretty certain that the closest your going to find to an inbuilt calculation method is:
plt.tight_layout()
or
figure.Figure.tight_layout() #if you are using the object version of the code

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.

uneven axis when using pl.imshow

I am having trouble when plotting an image using pylabs imshow. Well there is no problem while plotting but my data is uneven (approx. 32*850) so when I plot it, the y axis is very short compared to the x-axis and you can see an example here example image. I just want the image to be stretched out in the y-axis so it is easier to see.
The code I started with(excluded labels and so on) is:
pl.figure()
pl.imshow(fom_data, interpolation='nearest')
pl.show()
And after googling it I tried changing to
pl.figure(figsize=(6,10))
Which only made the white parts around it larger. I then tried to write it with pyplot instead since it was easier to find people discussing the same thing:
fig, ax = plt.imshow(fom_data,extent=[0,850,0,32],aspect='auto')
plt.show()
As I found in this example: Imshow: extent and aspect but then get the following error message : 'AxesImage' object is not iterable
I am obiusly no pro, but if you know where my brain is going wrong please explain.
Using pyplot:
plt.figure()
plt.imshow(my_image)
plt.axes().set_aspect(aspect="auto") # grab the current axes to set their aspect

Matplotlib: how to make tight_layout independent of ticklabels

Here is part of my code, which exports figures with tight layout.
...
fig.set_size_inches(8,6.8)
fig.tight_layout(rect=(0, 0, 1, 0.9))
# fig.savefig(path,bbox_inches='tight',dpi=100)
fig.savefig(path,dpi=100)
plt.gcf().clear()
plt.close(fig)
...
Unfortunately when I looping over different frames and y axis labels are changing, there are frames when ticklabels getting very close to the edge and then entire plot is shrinked as shown in figures between red and green lines.
https://dl.dropboxusercontent.com/u/248943005/Montage.png
I tried several cases, but this effect is always coming up in one or another way. It seems like it would be good to make tight layout somehow independent of ticklabels. Is that possible? If no, are there alternatives?

matplotlib: enlarge axis-scale label

Is there a way to enlarge the axis-scale label in matplotlib (circled in red in the enlarged plot below)?
I've used ax.tick_params() to successfully edit the tick labels, but I haven't been able to find anything about this specific piece of the plot.
Worse comes to worst, I could go with a manual text() insertion, but I'd like something more direct if possible.
Add a line like this
ax.xaxis.get_children()[1].set_size(15)
To change your major tick scale label (I guess we can call it so) to 15 points, if you plot the plot on ax.
If you plot using the pyplot API, add a line of ax=plt.gca() as well.

Categories