问题
Is there a way to copy an axis (subplot) to a new figure? This is straightforward in other languages, but I understand that not even a deep copy would work with python's matplotlib. E.g. if I have a figure with 6 subplots, how can I copy 2 of those subplots to a new figure, with all the settings? Labels, tickmarks, legend, grid, etc.
I have found this answer , which is actually 2 in 1: the first no longer works (deprecated syntax), while I couldn't get the second to work in my case.
I manage to recreate a new figure and to remove the subplots I don't want, but I am left with a 3x2 grid of subplots, in which 2 are drawn and 4 are empty. Any suggestions?
I have put together a toy example below; my charts are, of course, way more complex with way more settings.
Note I used seaborn but it should be irrelevant - I believe this is a matplotlib question and the answer is going to be the same regardless of whether seaborn is used.
UPDATE: Following the tips from @Earnest, I can change the geometry of the new figure so that it only has two subplots, doing:
axes.change_geometry(1,2,2)
What I don't know how to do is to move the subplots around. To recap:
- I start with 6 subplots in a 3x2 grid.
- I pickle to memory, then unpickle to a new figure.
- In the new figure, I keep only subplots 1 and 2, i.e. those identified by [rows, columns] [0,1] and [1,0]; the other 4 subplots are now blank spaces.
- I want a [1x2] grid layout; if I do
axes.change_geometry(1,2,2)
then I get that layout, but one of my two subplots disappears.
Any suggestions?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns
import pickle
import io
sns.set(style='darkgrid')
n=int(100)
x=np.arange(0,n)
fig, ax = plt.subplots(3,2)
for i,a in enumerate(ax.flatten() ):
y= np.random.rand(n)
sns.lineplot( x, y , ax =a )
a.set_title('Chart # ' + str(i+1))
a.set_xlabel('my x')
a.set_ylabel('my y')
fig2, ax2 = plt.subplots(1,2)
buf = io.BytesIO()
pickle.dump(fig, buf)
buf.seek(0)
fig2=pickle.load(buf)
tokeep=[1,2]
# note that i == 1correponds to a[0,1]
for i,a in enumerate(fig2.axes):
if not i in(tokeep):
fig2.delaxes(a)
else:
axes=a
回答1:
This is really @Ernest's answer; he pointed me in the right direction. I am typing this here as an answer for future reference, in the hope it can be useful to others. Basically I had to use change_geometry after deleting the subplots I didn't need. I think ggplot in the R universe has a cleaner implementation, but, overall, this seems OK - not too cumbersome. I have commented the code below - hope it's clear enough:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pickle
import io
sns.set(style='darkgrid')
#create the subplots
n=int(100)
x=np.arange(0,n)
fig, ax = plt.subplots(3,2)
for i,a in enumerate(ax.flatten() ):
y= np.random.rand(n)
sns.lineplot( x, y , ax =a )
a.set_title('Chart # ' + str(i+1))
a.set_xlabel('my x')
a.set_ylabel('my y')
# pickle the figure, then unpickle it to a new figure
buf = io.BytesIO()
pickle.dump(fig, buf)
buf.seek(0)
fig2=pickle.load(buf)
# sets which subplots to keep
# note that i == 1correponds to a[0,1]
tokeep=[1,2]
axestokeep=[]
for i,a in enumerate(fig2.axes):
if not i in(tokeep):
fig2.delaxes(a)
else:
axestokeep.extend([a])
axestokeep[0].change_geometry(1,2,1)
axestokeep[1].change_geometry(1,2,2)
来源:https://stackoverflow.com/questions/55419931/can-you-copy-only-some-subplots-to-a-new-figure