I am plotting 27 maps, or 9 rows and 3 columns. I am using plt.subplots to plot them, but I am struggling to bring the plots closer together? I tried both:
plt.tight_layout()
fig.tight_layout()
But I keep getting this error anytime I add that in:
ValueError: zero-size array to reduction operation minimum which has no identity
This is my code so far with the plt.subplot and mapping, it appears to be working but the map layout is not very readable:
fig, axes = plt.subplots(nrows=9, ncols=3, figsize=(60,44), subplot_kw=dict(projection=ccrs.PlateCarree()))
for i,t,ax in zip(range(27),time_years, axes.ravel()):
ax.set_extent([-90, 10, 5, 85], crs=ccrs.PlateCarree())
x = ax.contourf(longitude,latitude,yearly_means[i],10, extend='both')
ax.add_feature(cfeature.LAND, zorder=100, edgecolor='k')
ax.coastlines()
gridlines = ax.gridlines(draw_labels=True)
gridlines.xlabels_top = False
gridlines.ylabels_right = False
ax.text(.5,-.11, 'Longitude' , va='bottom' , ha='center', rotation='horizontal', rotation_mode= 'anchor',transform=ax.transAxes)
ax.text(-.15, .5, 'Latitude' , va='bottom' , ha='center', rotation='vertical', rotation_mode= 'anchor',transform=ax.transAxes)
ax.set_title('extremes for %d' %t)
cbar = fig.colorbar(x, orientation='horizontal', ax = axes,fraction=.046, pad=0.04)
cbar.set_label('psu', labelpad=15, y=.5, rotation=0)
#plt.tight_layout()
plt.subplots_adjust(wspace=None, hspace=None) # THIS DOES NOT WORK, no change
plt.show()
I tried adding: plt.subplots_adjust to make the width between plots smaller, but there is no difference when I add that line.
How do I bring these plots closer together and make the figures bigger? Also the colorbar overlaps on the image, why might be that happening?
plt.tight_layoutdoesn't remove the padding between the plots automatically but rather fixes overlapping issues.
you can try the pad options described in plt.tight_layout documentation
what will probably work better/best is to use fig, ax = plt.subplots(9,3, figsize=(9,6), layout="compressed")
with emphasis on layout="compressed" which should help in your case of maps/ images layout=compressed
The first thing to try is plt.tight_layout() - it will automatically adjust paddings around subplots. Another thing to play with is figsize and its aspect ratio to make it consistent with your subplots alignment. In your case, the canvas is too wide for the subplots.
Related
I'm attempting to plot two bar charts using matplotlib.pyplot.subplots. I've created subplots within a function, but when I output the subplots they are too long in height and not long enough in width.
Here's the function that I wrote:
def corr_bar(data1, data2, method='pearson'):
# Basic configuration.
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(7, 7))
ax1, ax2 = axes
corr_matrix1 = data1.corr(method=method)
corr_matrix2 = data2.corr(method=method)
cmap = cm.get_cmap('coolwarm')
major_ticks = np.arange(0, 1.1, 0.1)
minor_ticks = np.arange(0, 1.1, 0.05)
# Values for plotting.
x1 = corr_matrix1['price'].sort_values(ascending=False).index
x2 = corr_matrix2['price'].sort_values(ascending=False).index
values1 = corr_matrix1['price'].sort_values(ascending=False).values
values2 = corr_matrix2['price'].sort_values(ascending=False).values
im1 = ax1.bar(x1, values1, color=cmap(values1))
im2 = ax2.bar(x2, values2, color=cmap(values2))
# Formatting for plot 1.
ax1.set_yticks(major_ticks)
ax1.set_yticks(minor_ticks, minor=True)
plt.setp(ax1.get_xticklabels(), rotation=45, ha='right', rotation_mode='anchor')
ax1.grid(which='both')
ax1.grid(which='minor', alpha=0.4)
ax1.grid(which='major', alpha=0.7)
ax1.xaxis.grid(False)
# Formatting for plot 2.
ax2.set_yticks(major_ticks)
ax2.set_yticks(minor_ticks, minor=True)
plt.setp(ax2.get_xticklabels(), rotation=45, ha='right', rotation_mode='anchor')
ax2.grid(which='both')
ax2.grid(which='minor', alpha=0.4)
ax2.grid(which='major', alpha=0.7)
ax2.xaxis.grid(False)
fig.tight_layout()
plt.show()
This function (when run with two Pandas DataFrames) outputs an image like the following:
I purposely captured the blank right side of the image as well in an attempt to better depict my predicament. What I want is for the bar charts to be appropriately sized in height and width as to take up the entire space, rather than be elongated and pushed to the left.
I've tried to use the ax.set(aspect='equal') method but it "scrunches up" the bar chart. Would anybody happen to know what I could do to solve this issue?
Thank you.
When you define figsize=(7,7) you are setting the size of the entire figure and not the subplots. So your entire figure must be a square in this case. You should change it to figsize=(14,7) or use a number larger than 14 to get a little bit of extra space.
I want to plot a list of images. However, the plots are too small, so I cannot see them well. I tried to increase the size but the output is not really what i wanted.
I know there are lot of examples out there, but they are mostly contain mostly overkill solutions.
plt.figure(figsize=(30, 100))
for img in images:
plt.subplots(n_img, 1, figsize=(8,10))
plt.imshow(im, 'gray')
plt.axis('off')
plt.tight_layout()
plt.show()
Thanks
Hard to say if this will help, but to avoid potential confusion with setting figsize twice, I wouldn't call subplots inside your loop. Instead I'd set up the figure and axes first, then plot to each axis in turn:
fig, axs = plt.subplots(n_img, 1, figsize=(8,10))
for img, ax in zip(images, axs):
ax.imshow(img, 'gray')
ax.axis('off')
plt.tight_layout()
plt.show()
I am after an extreme form of matplotlib's tight layout.
I would like the data points to fill the figure from edge to edge without
leaving any borders and without titles, axes, ticks, labels or any other decorations.
I want to do something like what figimage does, but for plots instead of raw images.
How do I do that in matplotlib?
While a solution may be found taking the bits and pieces from an answer to this question it may not be obvious at first sight.
The main idea to have no padding around the axes, is to make the axes the same size as the figure.
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
Alternatively, one can set the outer spacings to 0.
fig, ax = plt.subplots()
plt.subplots_adjust(left=0, right=1, bottom=0, top=1)
Then, in order to remove the axis decorations one can use
ax.set_axis_off()
or
ax.axis("off")
This may now still leave some space between the plotted line and the edge. This can be removed by setting the limits appropriately using ax.set_xlim() and ax.set_ylim(). Or, by using ax.margins(0)
A complete example may thus look like
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
ax.axis("off")
ax.plot([2,3,1])
ax.margins(0)
plt.show()
The answer to this question suggests that I play around with the set_ylim/get_ylim in order to align two twin axes. However, this does not seem to be working out for me.
Code snippet:
fig, ax1 = plt.subplots()
yLim = [minY, maxY]
xLim = [0, 0.01]
for x in analysisNumbers:
ax1.plot(getData(x), vCoords, **getStyle(x))
ax1.set_yticks(vCoords)
ax1.grid(True, which='major')
ax2 = ax1.twinx()
ax2.set_yticks(ax1.get_yticks())
ax2.set_ylim(ax1.get_ylim())
ax2.set_ylim(ax1.get_ylim())
plt.xlim(xLim[0], xLim[1])
plt.ylim(yLim[0], yLim[1])
plt.minorticks_on()
plt.show()
Graph output (open image in a new window):
The twin axes should be the same, but they are not. Their labels are the same, but their alignment is not (see that the zeroes do not line up). What's wrong?
As tcaswell points out in a comment, plt.ylim() only affects one of the axes. If you replace these lines:
ax2.set_ylim(ax1.get_ylim())
ax2.set_ylim(ax1.get_ylim())
plt.xlim(xLim[0], xLim[1])
plt.ylim(yLim[0], yLim[1])
with this:
ax1.set_ylim(yLim[0], yLim[1])
ax2.set_ylim(ax1.get_ylim())
plt.xlim(xLim[0], xLim[1])
It'll work as I'm guessing you intended.
I want to draw a plot with matplotlib with axis on both sides of the plot, similar to this plot (the color is irrelevant to this question):
How can I do this with matplotlib?
Note: contrary to what is shown in the example graph, I want the two axis to be exactly the same, and want to show only one graph. Adding the two axis is only to make reading the graph easier.
You can use tick_params() (this I did in Jupyter notebook):
import matplotlib.pyplot as plt
bar(range(10), range(10))
tick_params(labeltop=True, labelright=True)
Generates this image:
UPD: added a simple example for subplots. You should use tick_params() with axis object.
This code sets to display only top labels for the top subplot and bottom labels for the bottom subplot (with corresponding ticks):
import matplotlib.pyplot as plt
f, axarr = plt.subplots(2)
axarr[0].bar(range(10), range(10))
axarr[0].tick_params(labelbottom=False, labeltop=True, labelleft=False, labelright=False,
bottom=False, top=True, left=False, right=False)
axarr[1].bar(range(10), range(10, 0, -1))
axarr[1].tick_params(labelbottom=True, labeltop=False, labelleft=False, labelright=False,
bottom=True, top=False, left=False, right=False)
Looks like this:
There are a couple of relevant examples in the online documentation:
Two Scales (seems to do exactly what you're asking for)
Dual Fahrenheit and Celsius
I've done this previously using the following:
# Create figure and initial axis
fig, ax0 = plt.subplots()
# Create a duplicate of the original xaxis, giving you an additional axis object
ax1 = ax.twinx()
# Set the limits of the new axis from the original axis limits
ax1.set_ylim(ax0.get_ylim())
This will exactly duplicate the original y-axis.
Eg:
ax = plt.gca()
plt.bar(range(3), range(1, 4))
plt.axhline(1.75, color="gray", ls=":")
twin_ax = ax.twinx()
twin_ax.set_yticks([1.75])
twin_ax.set_ylim(ax.get_ylim())