Remove separation between subplots in horizontal direction - python

I have four 2D arrays I want to plot in four subplots using imshow. I want the separation between these subplots to be removed, making the subplots touch each other, similar to the Matplotlib Documentation (second to last example). My attempt is
fig, axs = plt.subplots(2, 2, sharex='col', sharey='row', gridspec_kw={'hspace': 0, 'wspace': 0})
(ax1, ax2), (ax3, ax4) = axs
ax1.imshow(im1)
ax2.imshow(im2)
ax3.imshow(im3)
ax4.imshow(im4)
for ax in fig.get_axes():
ax.label_outer()
plt.show()
This produces
The separation in the vertical direction seems to be correctly removed, but I still have a separation in the horizontal direction. Does anyone know how I can get rid of that as well here?

You can try something along the lines of this answer of ImportanceOfBeingErnest. I have prepared the following pseudo code based on it for your question. You can try it and see if it works for you.
from matplotlib import gridspec
nrow, ncol = 2, 2
fig = plt.figure(figsize=(6,6))
gs = gridspec.GridSpec(nrow, ncol,
wspace=0.0, hspace=0.0,
top=1.-0.5/(nrow+1), bottom=0.5/(nrow+1),
left=0.5/(ncol+1), right=1-0.5/(ncol+1))
ims = [im1, im2, im3, im4]
c = 0 # Counter for the ims array
for i in range(nrow):
for j in range(ncol):
ax= plt.subplot(gs[i,j])
ax.imshow(ims[c])
ax.set_xticklabels([])
ax.set_yticklabels([])
c += 1
for ax in fig.get_axes():
ax.label_outer()

Related

tight_layout() reserves ylabel and yticklabels space even when disabled

I have a 2*4 subplots figure, with half of the ylabel and yticklabels disabled. Unfortunately, tight_layout() does not remove the extra white space which corresponds to the area where the ylabel and yticklabels would appear if they were not disabled. The ylabel and yticklabels are removed because I would like to have 4 pairs of comparison subplots. The plot looks something like this.
I am looking for an efficient way to remove the extra white space. In fact, I would like each pair of plots to be next to each other with no space at all. Here is an working example.
import matplotlib.pyplot as plt
fig, ((ax0, ax1, ax2, ax3), (ax4, ax5, ax6, ax7)) = plt.subplots(2, 4, figsize=(8, 4))
axs = [ax0, ax1, ax2, ax3, ax4, ax5, ax6, ax7]
for i in range(4):
axs[2*i].set_ylabel('parameter '+str(i))
axs[2*i+1].set_yticklabels([])
plt.tight_layout()
plt.show()
The code should yield the above plot. Any tips would be appreciated. Many thanks!
You can do it by having two subgrids and forcing a null distance between the axis (I followed this tutorial). The wspace parameter is described here.
import matplotlib.pyplot as plt
fig = plt.figure(constrained_layout=False) # you must disable automatic spacing
gs = fig.add_gridspec(1, 2, figure=fig)
gs0 = gs[0].subgridspec(2, 2, wspace=0.0)
gs1 = gs[1].subgridspec(2, 2, wspace=0.0)
axs = [[],[]]
for i in range(2):
for j in range(2):
axs[0].append(fig.add_subplot(gs0[i, j]))
axs[1].append(fig.add_subplot(gs1[i, j]))
axs = [*axs[0],*axs[1]]
for i in range(4):
axs[2*i].set_ylabel('parameter ' + str(i))
axs[2*i+1].set_yticklabels([])
Since the automatic spacing is disabled, you may have to play with axis and figure properties to adapt the position of the axis, labels, etc.
A partial (distance won't be null, but may be interesting for other users), more elegant solution is to use constrained_layout when creating the figure. More info in matplotlib's documentation.
import matplotlib.pyplot as plt
fig, axs = plt.subplots(
2, 4,
figsize=(8, 4),
constrained_layout=True,
)
axs = axs.reshape([8])
for i in range(4):
axs[2*i].set_ylabel('parameter '+str(i))
axs[2*i+1].set_yticklabels([])
# plt.tight_layout() # not necessary
plt.show()

Customising Matplotlib Subplots

I've always found matplotlib subplots confusing, and so I was wondering whether somebody could show how to generate the following arrangement of subplots:
Subplot Image
Thanks in advance.
You can use plt.GridSpec to easily create differently sized subplots.
cols = 5 #number of columns in the grid
s = 2 #width of top right subplot in #cells
w = 1 #spacing between subplot columns
fig = plt.figure()
gs = plt.GridSpec(2, cols, figure=fig, wspace=w)
ax1 = fig.add_subplot(gs[0, :-s])
ax2 = fig.add_subplot(gs[0, -s:])
ax3 = fig.add_subplot(gs[1, :-s])
#Marc 's answer is fine, but perhaps easier and more flexible is:
fig, axs = plt.subplots(2, 2, gridspec_kw={'width_ratios':[2, 1]})
# if you really don't want 4 axes:
fig.delaxes(axs[1, 1])

How can axes be despined in Matplotlib?

I am trying to make the below grid of plots a little bit cleaner. I don't want the tick marks on the left side and the bottom to overlap. I have tried to despine the axes by trying the below code, but it doesn't seem to work. Anyone have any suggestions?
fig, ax = plt.subplots(figsize=(15,10))
cols = ['x6', 'x7', 'x16', 'x17']
subset = df[cols]
normed_df = (subset-subset.min())/(subset.max()-subset.min())
style.use('seaborn-darkgrid')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
for sp in range(4):
ax = fig.add_subplot(2,2, sp+1)
ax.hist(normed_df[cols[sp]], density=True)
normed_df[cols[sp]].plot.kde(ax=ax)
ax.tick_params(bottom="off", top="off", left="off", right="off")
After running the above code, I am getting the following plots, however, the ticks are still overlapping.
either do what #Arne suggested:
fig, ax = plt.subplots(rows, cols) #makes a grid of subplots
or make your first two lines this:
fig, ax = plt.subplots(figsize=(15,10))
ax.axis('off')
this will remove the axis around the entire subplot before adding your additional subplots
When you call plt.subplots() without specifying a grid, it creates those axes across the whole figure whose tick marks and labels interfere with your subplot tick labels in the final plot. So change your first line of code to this:
fig, ax = plt.subplots(2, 2, figsize=(15,10))

Python Numpy add hspace between 3D plot and 2D plot with shared axes

Attached is an image showing the current plot. I am setting fig.subplots_adjust(hspace=0) for the 2D plots to share a common x-axis. I would like to add space between the 3D and 2d plots but am not quite sure how to accomplish this as hspace is set to 0.
fig.subplots_adjust(hspace=0)
for ax in [px_t, py_t, pz_t]:
plt.setp(ax.get_xticklabels(), visible=False)
In this case, it's best to use two separate GridSpec instances. That way you can have two separate hspace parameters. Alternatively, you can manually place the top axes.
As an example of the first option:
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
fig = plt.figure(figsize=(8, 10))
gs1 = plt.GridSpec(2, 1, hspace=0.2)
gs2 = plt.GridSpec(8, 1, hspace=0)
ax1 = fig.add_subplot(gs1[0], projection='3d')
ax1.plot(range(10), range(10), range(10))
ax = fig.add_subplot(gs2[4])
lower_axes = [ax]
for i in range(4, 8):
if i > 4:
ax = fig.add_subplot(gs2[i], sharex=lower_axes[0])
ax.plot(range(10))
ax.locator_params(axis='y', nbins=5, prune='both')
lower_axes.append(ax)
for ax in lower_axes:
ax.label_outer()
plt.show()

Issues with python matplotlib and subplot sizes

I am trying to create a figure with 6 sub-plots in python but I am having a problem. Here is a simplified version of my code:
import matplotlib.pyplot as plt
import numpy
g_width = 200
g_height = 200
data = numpy.zeros(g_width*g_height).reshape(g_height,g_width)
ax1 = plt.subplot(231)
im1 = ax1.imshow(data)
ax2 = plt.subplot(232)
im2 = ax2.imshow(data)
ax3 = plt.subplot(233)
im3 = ax3.imshow(data)
ax0 = plt.subplot(234)
im0 = ax0.imshow(data)
ax4 = plt.subplot(235)
im4 = ax4.imshow(data)
ax5 = plt.subplot(236)
ax5.plot([1,2], [1,2])
plt.show()
The above figure has 5 "imshow-based" sub-plots and one simple-data-based sub-plot. Can someone explain to me why the box of the last sub-plot does not have the same size with the other sub-plots? If I replace the last sub-plot with an "imshow-based" sub-plot the problem disappears. Why is this happening? How can I fix it?
The aspect ratio is set to "equal" for the 5imshow()calls (check by callingax1.get_aspect()) while forax5it is set toautowhich gives you the non-square shape you observe. I'm guessingimshow()` defaults to equal while plot does not.
To fix this set all the axis aspect ratios manually e.g when creating the plot ax5 = plt.subplot(236, aspect="equal")
On a side node if your creating many axis like this you may find this useful:
fig, ax = plt.subplots(ncols=3, nrows=2, subplot_kw={'aspect':'equal'})
Then ax is a tuple (in this case ax = ((ax1, ax2, ax3), (ax4, ax5, ax6))) so to plot in the i, j plot just call
ax[i,j].plot(..)

Categories

Resources