I want to code a function that generates an axes with a plot in it to be able to add it to a larger plot.
It should have the following structure:
def createAxes(data):
# create Axes object and plot data in it
return axes
# somewhere else
fig, axs = plt.subplots(ncols=2, nrows=1, figsize=(10, 5))
axs[0] = createAxes(data1)
axs[0].set_title('data 1')
axs[1] = createAxes(data2)
axs[1].set_title('data 2');
I have already tried to use plt.axes(), for example:
def createAxes(data):
plot = plt.axes()
plot.plot(1,1, color="black")
return plot
For this I get overlaying plots.
Related
I haven't been able to find a solution to this.. Say I define some plotting function so that I don't have to copy-paste tons of code every time I make similar plots...
What I'd like to do is use this function to create a few different plots individually and then put them together as subplots into one figure. Is this even possible? I've tried the following but it just returns blanks:
import numpy as np
import matplotlib.pyplot as plt
# function to make boxplots
def make_boxplots(box_data):
fig, ax = plt.subplots()
box = ax.boxplot(box_data)
#plt.show()
return ax
# make some data:
data_1 = np.random.normal(0,1,500)
data_2 = np.random.normal(0,1.1,500)
# plot it
box1 = make_boxplots(box_data=data_1)
box2 = make_boxplots(box_data=data_2)
plt.close('all')
fig, ax = plt.subplots(2)
ax[0] = box1
ax[1] = box2
plt.show()
I tend to use the following template
def plot_something(data, ax=None, **kwargs):
ax = ax or plt.gca()
# Do some cool data transformations...
return ax.boxplot(data, **kwargs)
Then you can experiment with your plotting function by simply calling plot_something(my_data) and you can specify which axes to use like so.
fig, (ax1, ax2) = plt.subplots(2)
plot_something(data1, ax1, color='blue')
plot_something(data2, ax2, color='red')
plt.show() # This should NOT be called inside plot_something()
Adding the kwargs allows you to pass in arbitrary parameters to the plotting function such as labels, line styles, or colours.
The line ax = ax or plt.gca() uses the axes you have specified or gets the current axes from matplotlib (which may be new axes if you haven't created any yet).
def plot_XAI2(img, model):
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
ax.imshow(img)
ax.imshow(explain_image_lime(img, model))
ax.set_title("Grad-CAM")
ax.set_title("LIME")
plt.show()
img = path_to_image('Lung_cancer (1).jpg')
plot_XAI2(img, model)
predict_image_class(img, model)
The output was empty dimensions without any images, what is the problem?
As #cheersmate says in the comments, you'll want to plot onto axes not ax (which is not defined in your code). axes will be a list containing two Axes objects, so you could instead do:
def plot_XAI2(img, model):
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].imshow(img) # plot in first subplot
axes[1].imshow(explain_image_lime(img, model)) # plot in second subplot
axes[0].set_title("Grad-CAM")
axes[1].set_title("LIME")
plt.show()
I have a contour plot, as shown on the right, the axes of which are returned by a function, and separately a series of six matplotlib subplots displayed as shown on the left.
Sample code (with formatting and unnecessary code removed):
def contour_plot(df):
df = DataFrame(contour_list, columns = ['N0','DI'])
f, ax = plt.subplots(figsize=(7, 7))
sns.kdeplot(data = df, ax=ax, x='N0', y='DI', levels=10)
return f, ax
fig, ax = contour_plot(df)
for i in range(6):
plt.subplot(3,2,i+1)
plt.scatter(x=X, y=Y c=C, s=0.1)
plt.colorbar()
fig = plt.gcf()
fig.set_size_inches(12, 16)
fig.tight_layout()
I want to be able to overlay the contour over each of the other plots, but I'm not sure how to do this? I would hopefully also like to keep the colorbar of the subplot images. Can this be done?
This question already has answers here:
Save a subplot in matplotlib
(2 answers)
Closed 5 years ago.
Suppose I have the following code (modified version of matplotlib gridspec tutorial)
import matplotlib.pyplot as plt
def make_ticklabels_invisible(fig):
for i, ax in enumerate(fig.axes):
ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center")
for tl in ax.get_xticklabels() + ax.get_yticklabels():
tl.set_visible(False)
plt.figure(0)
ax1 = plt.subplot2grid((3,3), (0,0), colspan=3)
ax2 = plt.subplot2grid((3,3), (1,0), colspan=2)
ax3 = plt.subplot2grid((3,3), (1, 2), rowspan=2)
ax4 = plt.subplot2grid((3,3), (2, 0))
plt.subplot2grid((3,3), (2, 1)) # OOPS! Forgot to store axes object
plt.suptitle("subplot2grid")
make_ticklabels_invisible(plt.gcf())
plt.show()
which results in
How can I 'extract' ax5 and plot it 'full screen' in a separate figure without having to recreate the plot?
I can't find anything in official documentation to back up what I'm saying, but my understanding is that it is impossible to "clone" an existing axes onto a new figure. In fact, no artist (line, text, legend) defined in one axes may be added to another axes. This discussion on Github may explain it to some degree.
For example, attempting to add a line from an axes defined on fig1 to an axes on a different figure fig2 raises an error:
import matplotlib.pyplot as plt
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
line, = ax1.plot([0,1])
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
ax2.add_line(line)
>>>RuntimeError: Can not put single artist in more than one figure`
And attempting to add a line that was drawn in ax1 to a second axes ax2 on the same figure raises an error:
fig1 = plt.figure()
ax1 = fig1.add_subplot(121)
line, = ax1.plot([0,1])
ax12 = fig1.add_subplot(122)
ax12.add_line(line)
>>>ValueError: Can not reset the axes. You are probably trying to re-use an artist in more than one Axes which is not supported
The best recommendation I can make is extract the data from the axes you want to copy, and manually plot that into a new axes object that is sized to your liking. Something like below demonstrates this. Note that this works for Line2D objects plotted via ax.plot. If the data was plotted using ax.scatter, then you need to change things just a little bit and I refer you here for instructions on how to extract data from a scatter.
import matplotlib.pyplot as plt
import numpy as np
def rd(n=5):
# Make random data
return np.sort(np.random.rand(n))
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
# Plot three lines on one axes
ax1.plot(rd(), rd(), rd(), rd(), rd(), rd())
xdata = []
ydata = []
# Iterate thru lines and extract x and y data
for line in ax1.get_lines():
xdata.append( line.get_xdata() )
ydata.append( line.get_ydata() )
# New figure and plot the extracted data
fig2 = plt.figure()
ax2 = fig2.add_subplot(111)
for X,Y in zip(xdata,ydata):
ax2.plot(X,Y)
Hope it helps.
Using Matplotlib in an IPython Notebook, I would like to create a figure with subplots which are returned from a function:
import matplotlib.pyplot as plt
%matplotlib inline
def create_subplot(data):
more_data = do_something_on_data()
bp = plt.boxplot(more_data)
# return boxplot?
return bp
# make figure with subplots
f, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(10,5))
ax1 -> how can I get the plot from create_subplot() and put it on ax1?
ax1 -> how can I get the plot from create_subplot() and put it on ax2?
I know that I can directly add a plot to an axis:
ax1.boxplot(data)
But how can I return a plot from a function and use it as a subplot?
Typically, you'd do something like this:
def create_subplot(data, ax=None):
if ax is None:
ax = plt.gca()
more_data = do_something_on_data()
bp = ax.boxplot(more_data)
return bp
# make figure with subplots
f, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(10,5))
create_subplot(data, ax1)
You don't "return a plot from a function and use it as a subplot". Instead you need to plot the boxplot on the axes in the subplot.
The if ax is None portion is just there so that passing in an explicit axes is optional (if not, the current pyplot axes will be used, identical to calling plt.boxplot.). If you'd prefer, you can leave it out and require that a specific axes be specified.