4 plots with different sizes on one figure [duplicate] - python

This question already has answers here:
How to make an axes occupy multiple subplots with pyplot
(7 answers)
Closed 24 days ago.
I need to create 4 plots, where there are two large ones and two stacked smaller ones to the right (the sum is the same as the large plots). Picture attached.
So far I managed only to create two separate figures:
fig, axs = plt.subplots(1, 3, figsize=(12, 4))
#plotting
fig, axs_right = plt.subplots(2, 1, figsize=(4, 8))
#plotting
The difficulty is that I need to plot with seaborn and have control over axes to change the way they look.

This is a relatively simple layout you can achieve with plt.subplot2grid():
grid = (2, 3)
fig = plt.figure(figsize=(8, 6)) # or whatever
ax = plt.subplot2grid(grid, (0, 0), rowspan=2) # left column plot
...
ax = plt.subplot2grid(grid, (0, 1), rowspan=2) # middle column plot
...
ax = plt.subplot2grid(grid, (0, 2)) # right column upper plot
...
ax = plt.subplot2grid(grid, (1, 2)) # right column lower plot
...
Result:

There are multiple ways of achieving that, it is described in the "Arranging multiple Axes in a Figure" part of the matplotlib documentation.
Below is a basic recopy for your case:
import matplotlib.pyplot as plt
figsize = (7, 4)
# Method 1
fig, axd = plt.subplot_mosaic(
[
["1", "2", "3"],
["1", "2", "4"],
],
figsize=figsize,
layout="constrained",
)
# Method 2
fig = plt.figure(figsize=figsize, layout="constrained")
spec = fig.add_gridspec(ncols=3, nrows=2)
ax1 = fig.add_subplot(spec[:, 0])
ax2 = fig.add_subplot(spec[:, 1])
ax3 = fig.add_subplot(spec[0, 2])
ax4 = fig.add_subplot(spec[1, 2])
# Method 3
fig = plt.figure(figsize=figsize, layout="constrained")
spec0 = fig.add_gridspec(ncols=2, nrows=1, width_ratios=[2, 1])
spec01 = spec0[0].subgridspec(ncols=2, nrows=1)
spec02 = spec0[1].subgridspec(ncols=1, nrows=2)
ax1 = fig.add_subplot(spec01[0])
ax2 = fig.add_subplot(spec01[1])
ax3 = fig.add_subplot(spec02[0])
ax4 = fig.add_subplot(spec02[1])
plt.show()

Related

Is there a matplotlib function in Python for forcing all subplots inside different figures to have the same x and y axis length?

I'm testing out different way of displaying figures. I have one figure which is made up of 12 subplots split into two columns. Something like...
fig, ax = plt.subplots(6, 2, figsize= (20,26))
I have another code which splits the 12 subplots into 3 different figures based on categorical data. Something like
figA, ax = plt.subplots(5, 1, figsize= (10,23))
figB, ax = plt.subplots(3, 1, figsize= (10,17))
fig2, ax = plt.subplots(4, 1, figsize= (10,20))
Is there a way to ensure all the subplots in every figure have the same x and y axis length?
Answer turns out to be simple. Use a variable that can be scaled by the number of plots in the figure. So, a figure with more plots will have a higher figsize yet equal plot sizes. Something like...
ps = 5 #indicates plot size
figA, ax = plt.subplots(5, 1, figsize= (10, 5*ps))
figB, ax = plt.subplots(3, 1, figsize= (10, 3*ps))
fig2, ax = plt.subplots(4, 1, figsize= (10, 4*ps))

How to center plots in matplotlib and put a photo in it?

I've two frames as you can see on the picture. I want to automatically center this two figures and put in a photo. But I failed in the first part. My code is:
fig, ((ax1,ax2),(ax3,ax4)) = plt.subplots(nrows = 2, ncols = 2)
# Axes 1
ax1 = plt.subplot2grid((3, 3), (0, 0))
#ax1.set_title[['[0,0]']
# Axes 2
ax2 = plt.subplot2grid((3, 3), (0, 2))
I've two other plots, but they don't have to be considered. How to I center this according the whole fig? I couldn't find anything on the matplot site.
Thanks.
Assuming that you don't want the ratio of the displayed length of x- and y-axes of the subplots in the first row of the figure to change, we can use plt.subplot to get the expected result by creating a finer resolution of row by having more columns accessible to plot a particular subplot:
import matplotlib.pyplot as plt
fig, ((ax1,ax2),(ax3,ax4)) = plt.subplots(nrows = 2, ncols = 2)
# Creates a 3 * 13 grid on the figure
ax1 = plt.subplot(3, 13, (4, 6))
ax2 = plt.subplot(3, 13, (8, 10))
plt.show()
This gives:

Creating a 2x2 subplot from one dataset as different graphs

I have a large census dataset I am working with and am taking different data from it and representing it as a singular .png in the end. I have created the graphs individually, but when I try to add them to the subplots they get distorted or axis get messed up.
Current code:
fig = plt.figure()
ax1 = fig.add_subplot(2, 2, 1)
ax2 = fig.add_subplot(2, 2, 2)
ax3 = fig.add_subplot(2, 2, 3)
ax4 = fig.add_subplot(2, 2, 4)
ax1.pie(df.data.valuecounts(normalize=True),labels=None,startangle-240)
ax1.legend(['a','b','c','d','e'])
ax1.axis('equal')
data2=df[['A']].dropna().values
kde=df.A.plot.kde()
binss = np.logspace(0.01,7.0)
ax2=plt.hist(hincp, normed=True, bins=binss)
ax2=plt.xscale('log')
ax3 = df.replace(np.nan,0)
ax3 = (df.groupby(['G'])['R'].sum()/1000)
ax3.plot.bar(width=0.9, color='red',title='Gs').set_ylabel('Rs')
ax3.set_ylabel('Rs')
ax3.set_xlabel('# G')
t = df[['p','o','s','y']]
ax4=plt.scatter(t.o,t.p,s=t.s,c=t.y, marker = 'o', alpha = 0.2)
plt.ylim(0, 10000)
plt.xlim(0,1200000)
cbar=plt.colorbar()
plt.title("this vs that", loc = 'center')
plt.xlabel('this')
plt.ylabel('that')
All four types of graphs should be displayed and not overlap.
You create Axes for each subplot but then you don't use them.
ax1.pie(...) looks correct but later you don't use ax2,ax3,ax4.
If you are going to to use the DataFrame plotting methods, just call plt.subplot before each new plot. Like this.
df = pd.DataFrame(np.random.random((6,3)))
plt.subplot(3,1,1)
df.loc[:,0].plot()
plt.subplot(3,1,2)
df.loc[:,1].plot()
plt.subplot(3,1,3)
df.loc[:,2].plot()
plt.show()
plt.close()
Or use the Axes that you create.
df = pd.DataFrame(np.random.random((6,3)))
fig = plt.figure()
ax1 = fig.add_subplot(3,1,1)
ax2 = fig.add_subplot(3,1,2)
ax3 = fig.add_subplot(3,1,3)
ax1.plot(df.loc[:,0])
ax2.plot(df.loc[:,1])
ax3.plot(df.loc[:,2])
plt.show()
plt.close()

Specify the height of a subplot in a multiple subplot matplotlib in Jupyter [duplicate]

I need to add two subplots to a figure. One subplot needs to be about three times as wide as the second (same height). I accomplished this using GridSpec and the colspan argument but I would like to do this using figure so I can save to PDF. I can adjust the first figure using the figsize argument in the constructor, but how do I change the size of the second plot?
As of matplotlib 3.6.0, width_ratios and height_ratios can now be passed directly as keyword arguments to plt.subplots and subplot_mosaic, as per What's new in Matplotlib 3.6.0 (Sep 15, 2022).
f, (a0, a1) = plt.subplots(1, 2, width_ratios=[3, 1])
f, (a0, a1, a2) = plt.subplots(3, 1, height_ratios=[1, 1, 3])
Another way is to use the subplots function and pass the width ratio with gridspec_kw
matplotlib Tutorial: Customizing Figure Layouts Using GridSpec and Other Functions
matplotlib.gridspec.GridSpec has available gridspect_kw options
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
f, (a0, a1) = plt.subplots(1, 2, gridspec_kw={'width_ratios': [3, 1]})
a0.plot(x, y)
a1.plot(y, x)
f.tight_layout()
f.savefig('grid_figure.pdf')
Because the question is canonical, here is an example with vertical subplots.
# plot it
f, (a0, a1, a2) = plt.subplots(3, 1, gridspec_kw={'height_ratios': [1, 1, 3]})
a0.plot(x, y)
a1.plot(x, y)
a2.plot(x, y)
f.tight_layout()
You can use gridspec and figure:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
gs = gridspec.GridSpec(1, 2, width_ratios=[3, 1])
ax0 = plt.subplot(gs[0])
ax0.plot(x, y)
ax1 = plt.subplot(gs[1])
ax1.plot(y, x)
plt.tight_layout()
plt.savefig('grid_figure.pdf')
I used pyplot's axes object to manually adjust the sizes without using GridSpec:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# definitions for the axes
left, width = 0.07, 0.65
bottom, height = 0.1, .8
bottom_h = left_h = left+width+0.02
rect_cones = [left, bottom, width, height]
rect_box = [left_h, bottom, 0.17, height]
fig = plt.figure()
cones = plt.axes(rect_cones)
box = plt.axes(rect_box)
cones.plot(x, y)
box.plot(y, x)
plt.show()
Probably the simplest way is using subplot2grid, described in Customizing Location of Subplot Using GridSpec.
ax = plt.subplot2grid((2, 2), (0, 0))
is equal to
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 2)
ax = plt.subplot(gs[0, 0])
so bmu's example becomes:
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
ax0 = plt.subplot2grid((1, 3), (0, 0), colspan=2)
ax0.plot(x, y)
ax1 = plt.subplot2grid((1, 3), (0, 2))
ax1.plot(y, x)
plt.tight_layout()
plt.savefig('grid_figure.pdf')
In a simple way, different size sub plotting can also be done without gridspec:
plt.figure(figsize=(12, 6))
ax1 = plt.subplot(2,3,1)
ax2 = plt.subplot(2,3,2)
ax3 = plt.subplot(2,3,3)
ax4 = plt.subplot(2,1,2)
axes = [ax1, ax2, ax3, ax4]
A nice way of doing this was added in matplotlib 3.3.0, subplot_mosaic.
You can make a nice layout using an "ASCII art" style.
For example
fig, axes = plt.subplot_mosaic("ABC;DDD")
will give you three axes on the top row and one spanning the full width on the bottom row like below
A nice thing about this method is that the axes returned from the function is a dictionary with the names you define, making it easier to keep track of what is what e.g.
axes["A"].plot([1, 2, 3], [1, 2, 3])
You can also pass a list of lists to subplot_mosaic if you want to use longer names
fig, axes = plt.subplot_mosaic(
[["top left", "top centre", "top right"],
["bottom row", "bottom row", "bottom row"]]
)
axes["top left"].plot([1, 2, 3], [1, 2, 3])
will produce the same figure

Breaking a plot into subplots [duplicate]

I need to add two subplots to a figure. One subplot needs to be about three times as wide as the second (same height). I accomplished this using GridSpec and the colspan argument but I would like to do this using figure so I can save to PDF. I can adjust the first figure using the figsize argument in the constructor, but how do I change the size of the second plot?
As of matplotlib 3.6.0, width_ratios and height_ratios can now be passed directly as keyword arguments to plt.subplots and subplot_mosaic, as per What's new in Matplotlib 3.6.0 (Sep 15, 2022).
f, (a0, a1) = plt.subplots(1, 2, width_ratios=[3, 1])
f, (a0, a1, a2) = plt.subplots(3, 1, height_ratios=[1, 1, 3])
Another way is to use the subplots function and pass the width ratio with gridspec_kw
matplotlib Tutorial: Customizing Figure Layouts Using GridSpec and Other Functions
matplotlib.gridspec.GridSpec has available gridspect_kw options
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
f, (a0, a1) = plt.subplots(1, 2, gridspec_kw={'width_ratios': [3, 1]})
a0.plot(x, y)
a1.plot(y, x)
f.tight_layout()
f.savefig('grid_figure.pdf')
Because the question is canonical, here is an example with vertical subplots.
# plot it
f, (a0, a1, a2) = plt.subplots(3, 1, gridspec_kw={'height_ratios': [1, 1, 3]})
a0.plot(x, y)
a1.plot(x, y)
a2.plot(x, y)
f.tight_layout()
You can use gridspec and figure:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
gs = gridspec.GridSpec(1, 2, width_ratios=[3, 1])
ax0 = plt.subplot(gs[0])
ax0.plot(x, y)
ax1 = plt.subplot(gs[1])
ax1.plot(y, x)
plt.tight_layout()
plt.savefig('grid_figure.pdf')
I used pyplot's axes object to manually adjust the sizes without using GridSpec:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# definitions for the axes
left, width = 0.07, 0.65
bottom, height = 0.1, .8
bottom_h = left_h = left+width+0.02
rect_cones = [left, bottom, width, height]
rect_box = [left_h, bottom, 0.17, height]
fig = plt.figure()
cones = plt.axes(rect_cones)
box = plt.axes(rect_box)
cones.plot(x, y)
box.plot(y, x)
plt.show()
Probably the simplest way is using subplot2grid, described in Customizing Location of Subplot Using GridSpec.
ax = plt.subplot2grid((2, 2), (0, 0))
is equal to
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 2)
ax = plt.subplot(gs[0, 0])
so bmu's example becomes:
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
ax0 = plt.subplot2grid((1, 3), (0, 0), colspan=2)
ax0.plot(x, y)
ax1 = plt.subplot2grid((1, 3), (0, 2))
ax1.plot(y, x)
plt.tight_layout()
plt.savefig('grid_figure.pdf')
In a simple way, different size sub plotting can also be done without gridspec:
plt.figure(figsize=(12, 6))
ax1 = plt.subplot(2,3,1)
ax2 = plt.subplot(2,3,2)
ax3 = plt.subplot(2,3,3)
ax4 = plt.subplot(2,1,2)
axes = [ax1, ax2, ax3, ax4]
A nice way of doing this was added in matplotlib 3.3.0, subplot_mosaic.
You can make a nice layout using an "ASCII art" style.
For example
fig, axes = plt.subplot_mosaic("ABC;DDD")
will give you three axes on the top row and one spanning the full width on the bottom row like below
A nice thing about this method is that the axes returned from the function is a dictionary with the names you define, making it easier to keep track of what is what e.g.
axes["A"].plot([1, 2, 3], [1, 2, 3])
You can also pass a list of lists to subplot_mosaic if you want to use longer names
fig, axes = plt.subplot_mosaic(
[["top left", "top centre", "top right"],
["bottom row", "bottom row", "bottom row"]]
)
axes["top left"].plot([1, 2, 3], [1, 2, 3])
will produce the same figure

Categories