I would like to create a small function for my own work. However I would like to create something like porting existing plots into figures. Which goes like this:
import matplotlib.pyplot as PLT
ax1 = PLT.plot(array1)
ax2 ...
def multi_ax(array_of_ax ):
fig = PLT.figure()
for n in range(some_number):
ax = fig.add_subplot(x,y,n+1)
ax.replacing(array_of_ax[n], postions_of_array)
Is there way to fit this way? Thanks in advance.
It isn't possible to move an axes from one figure to another; the axes is linked to the figure upon creation.
Instead, you'll have to first generate the figure, and then the axeses within that figure.
Related
What i want
I want to combine two matplotlib figures in one new subplot.
The two figures are returned from visualization functions of libraries i don't want to or can't change myself(rebuild from source etc.). Also it should be not a hack-around but rather be a nice generic matplotlib solution.
The pseudo code looks like the following.
Pseudo code
import matplotlib.pyplot as plt
from library1 import magic_visualization_1
from library2 import magic_visualization_2
# Data of type some_crazy_data_type_of_the_library e.g. no simple x,y coords
data = ...
fig1 = magic_visualization_1(data) # type is: <class 'matplotlib.figure.Figure'>
fig2 = magic_visualization_2(data) # type is: <class 'matplotlib.figure.Figure'>
fig, axs = plt.subplots(2, 1, figsize=(10, 5))
# Somehow add fig1
# Somehow add fig2
plt.show()
# or like
fig = plt.figure(figsize=(10, 5))
gridspec = fig.add_gridspec(2, 1, left=0.05, right=0.95, wspace=0.1, hspace=0.15)
# Somehow add fig1
# Somehow add fig2
plt.show()
Example images
The two example figures:
fig1,
fig2
Photoshoped result
I should look like this(i made this by hand with gimp/photoshop)
fig1 on top of fig2
What i tried
The best idea i found was deepcopying every figure into the new subfigures but that feels to much like a hack-around.
Also i tried this solution with copying the two figures content.
Result:
vertical concatenation of the two figures
Say I have a figure which I am able to generate using plt.show. Now I wish to pass off this plt object to a generic function like this -
generate_figs(plt):
frmt = ['jpg','png']
for i in frmt:
plt.savefig('name.{}'.format(i))
generate_figs(plt)
Can something like this be done?
This depends on how many figures you have. If it is only one figure you can simply keep the function (mostly) as it is as plt.savefig will save the current figure.
def generate_figs():
frmt = ['jpg','png']
for i in frmt:
plt.savefig('name.{}'.format(i))
If you have multiple figures, then you can pass the specific figure object into the function and use fig.savefig
import matplotlob.pyplot as plt
def generate_figs(fig):
frmt = ['jpg','png']
for i in frmt:
fig.savefig('name.{}'.format(i))
fig1 = plt.figure()
plt.plot(some_data)
fig2 = plt.figure()
plt.plot(some_other_data)
generate_figs(fig1)
plt.show()
Note: you must save the figure before any call to plt.show()
I'm just starting using Matplotlib the "right" way. I'm writing various programs that will each give me back a time series, and I'm looking to superimpose the graphs of the various time series, like this:
I think what I want is a single Axes instance defined in the main function, then I call each of my little functions, and they all return a Line2D instance, and then I'll put them all on the Axes object I created.
But I'm having trouble taking an existing Line2D object and adding it to an existing Axes object (like I'd want to do with the output of my function.) I thought of taking a Line2D called a and say ax.add_line(a).
import matplotlib.pyplot as plt
a, = plt.plot([1,2,3], [3,4,5], label = 'a')
fig, ax = plt.subplots()
ax.add_line(a)
Gives me a RuntimeError: "Can not put single artist in more than one figure."
I'm guessing that over time Matplotlib has stopped wanting users to be able to add a given line to any Axes they want. A similar thing is discussed in the comments of this answer, except there they're talking about an Axes object in two different Figure objects.
What's the best way to accomplish what I want? I'd rather keep my main script tidy, and not say ax.plot(some_data) over and over when I want to superimpose these lines.
Indeed, you cannot add the same artist to more than one axes or figure.
But for what I understand from your question, that isn't really necessary.
So let's just do as you propose;
"I thought of taking a Line2D called a and say ax.add_line(a)."
import numpy as np
import matplotlib.pyplot as plt
def get_line(label="a"):
return plt.Line2D(np.linspace(0,1,10), np.random.rand(10), label = label)
fig, ax = plt.subplots()
ax.add_line(get_line(label="a"))
ax.add_line(get_line(label="b"))
ax.add_line(get_line(label="z"))
ax.legend()
plt.show()
The way matplotlib would recommend is to create functions that take an axes as input and plot to that axes.
import numpy as np
import matplotlib.pyplot as plt
def plot_line(ax=None, label="a"):
ax = ax or plt.gca()
line, = ax.plot(np.linspace(0,1,10), np.random.rand(10), label = label)
return line
fig, ax = plt.subplots()
plot_line(ax, label="a")
plot_line(ax, label="b")
plot_line(ax, label="z")
ax.legend()
plt.show()
A possible work around for your problem:
import matplotlib.pyplot as plt
x = np.array([1,2,3])
y = np.array([3,4,5])
label = '1'
def plot(x,y,label):
a, = plt.plot(x,y, label = label)
return a
fig, ax = plt.subplots()
plot(x,y,label)
plot(x,1.5*y,label)
You can put your plot command now in a loop with changing labels. You can still use the ax handle to modify/define the plot parameters.
Due to the 2nd answer of this question I supposed the following code
import matplotlib.pyplot as plt
for i1 in range(2):
plt.figure(1)
f, ax = plt.subplots()
plt.plot((0,3), (2, 2), 'b')
for i2 in range(2):
plt.figure(2)
f, ax = plt.subplots()
plt.plot([1,2,3], [1,2,3], 'r')
plt.savefig('foo_{}_bar_{}.jpg'.format(i2, i1))
plt.close()
plt.figure(1)
plt.plot( [1,2,3],[1,2,3], 'r')
plt.savefig('bar_{}.jpg'.format(i1))
plt.close()
to create plots bar_0.jpg and bar_1.jpg showing a blue and a red line each.
However, figures look like
instead of
How can I achieve the desired behaviour?
Note that plots foo_*.jpg have to be closed and saved during handling of the bar plots.
You're already saving the Axes objects, so instead of calling the PyPlot plot function (which draws on the last created or activated Axes), use the objects' plot function:
ax.plot(...)
If you then give both a different name, say ax1 and ax2, you can draw on the one you like without interfering with the other. All plt. commands also exist as an Axes member function, but sometimes the name changes (plt.xticks becomes ax.set_xticks for example). See the documentation of Axes for details.
To save to figures, use the Figure objects in the same way:
f.savefig(...)
This API type is only just coming to Matlab, FYI, and will probably replace the old-fashioned "draw on the last active plot" behaviour in the future. The object-oriented approach here is more flexible with minimal overhead, so I strongly recommend you use it everywhere.
If unsure, better to make it explicit:
import matplotlib.pyplot as plt
for i1 in range(2):
fig1,ax1 = plt.subplots()
fig2,ax2 = plt.subplots()
ax1.plot([0,4],[2,2],'b')
for i2 in range(2):
ax2.plot([1,2,3],[1,2,3],'r')
fig2.savefig('abc{}.png'.format(2*i1+i2))
plt.figure(1)
ax1.plot([1,2,3],[1,2,3],'r')
fig1.savefig('cba{}.png'.format(i1))
How can I use matplotlib to create many different chart objects and then have the ability to control each chart object separately (without affecting the other chart objects)?
Ideally, I'd like to have something of the following:
# creating the chart handler object
chartHandler = ChartHandler()
# plotting some values for chart #0
chartHandler[0].plot( range(0,100) )
# plotting some values for chart #5
chartHandler[5].plot( range(500,700) )
Unless you are talking about something that I haven't dealt with in matplotlib yet, I think that what you are looking for is figure.add_subplot(). You should be able to capture the return from each figure.add_subplot() and operate on each individually from then on, kind of like this:
import matplotlib.pyplot as plt
#Create an 11x5 figure
fig = plt.figure(figsize=(11,5))
#Create subplots[0]
subplts = []
subplt = fig.add_subplot(121)
subplts.append(subplt)
#Create subplots[1:20]
for xind in range(4,8):
for yind in range(0,5):
subplt = fig.add_subplot(5,8,(yind*8+xind))
subplts.append(subplt)
plt.show()
It should be noted that there are a few problems with the above script. Mainly, the subplots overlap slightly. This can be solved using the position keyword to add_subplot and some simple math.
In any case, you can now modify each subplot by referencing its index in subplots. It should be pretty simple to add plots, modify ranges, etc.