Update subplots in Matplotlib figure that is already open - python

I have a matplotlib window with multiple subplots in it. I want to be able to dynamically update the contents of each subplot whenever a method is called. The simplified code looks like this:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(1)
fig, ax_list = plt.subplots(3, 2)
image1 = plt.imread("image1.jpg")
image2 = plt.imread("image2.jpg")
ax_list = ax_list.ravel()
ax_list[0].imshow(image1)
ax_list[1].imshow(image2)
plt.show()
def update_subplots():
# I want this method to change the contents of the subplots whenever it is called
pass

I've managed to figure out how to get this working- it's not very clean but it gets the job done.
We can set the figure to a global variable like so:
fig, ax_list = plt.subplots(4, 2)
We can then modify the contents of the subplots from any method like so:
def update_subplot(image):
global fig, ax_list
ax_list = ax_list.ravel()
# ax_list[0] refers to the first subplot
ax_list[0].imshow(image)
plt.draw()

Related

How to show multiple already plotted matplotlib figures side-by-side or on-top in Python without re-plotting them?

I have already plotted two figures separately in a single jupyter notebook file, and exported them.
What I want is to show them side by side, but not plot them again by using matplotlib.pyplot.subplots.
For example, in Mathematica, it's easier to do this by just saving the figures into a Variable, and displaying them afterwards.
What I tried was saving the figures, using
fig1, ax1 = plt.subplots(1,1)
... #plotting using ax1.plot()
fig2, ax2 = plt.subplots(1,1)
... #plotting using ax2.plot()
Now, those fig1 or fig2 are of type Matplotlib.figure.figure which stores the figure as an 'image-type' instance. I can even see them separately by calling just fig1 or fig2 in my notebook.
But, I can not show them together as by doing something like
plt.show(fig1, fig2)
It returns nothing since, there wasn't any figures currently being plotted.
You may look at this link or this, which is a Mathematica version of what I was talking about.
assuming u want to merge those subplots in the end.
Here is the code
import numpy as np
import matplotlib.pyplot as plt
#e.x function to plot
x = np.linspace(0, 10)
y = np.exp(x)
#almost your code
figure, axes = plt.subplots(1,1)
res_1, = axes.plot(x,y) #saving the results in a tuple
plt.show()
plt.close(figure)
figure, axes = plt.subplots(1,1)
res_2, = axes.plot(x,-y) #same before
plt.show()
#restructure to merge
figure_2, (axe_1,axe_2) = plt.subplots(1,2) #defining rows and columns
axe_1.plot(res_1.get_data()[0], res_1.get_data()[1]) #using the already generated data
axe_2.plot(res_2.get_data()[0], res_2.get_data()[1])
#if you want show them in one
plt.show()
Not quite sure what you mean with:
but not plot them again by using matplotlib.pyplot.subplots.
But you can display two figures next to each other in a jupyter notebook by using:
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0] = ... # Code for first figure
ax[1] = ... # Code for second figure
plt.show()
Or above each other:
fig, ax = plt.subplots(nrows=2, ncols=1)
ax[0] = ... # Top figure
ax[1] = ... # Bottom figure
plt.show()

How to combine two matplotlib figures as subfigures without replotting them

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

Activate a figure in matplotlib

It seems easy but I could not find any solution for opening multiple figures and save them by their name. I look for something like this:
fig1, ax1 = pl.subplots(1)
fig2, ax2 = pl.subplots(1)
...
pl.savefig('f1.png', fig1)
pl.savefig('f2.png', fig2)
usually pl.savefig acts on the last active figure. So how one can activate a figure and save it, then repeat the process for the rest of the figures?
You can save an image using the figure object itself:
fig1.savefig(...)
Alternatively, you can change the current figure by calling plt.figure(1) to select the first figure that was create and then use plt.savefig(). Or, you can use plt.figure(fig1.number) to switch focus to fig1
import matplotlib.pyplot as plt
fig1, ax1 = plt.subplots(1)
fig2, ax2 = plt.subplots(1)
# Can choose one of the below to change the current figure
plt.figure(1)
# plt.figure(fig1.number)
plt.savefig(...) # will save fig1

Matplotlib: collecting lines onto the same axis

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.

how do I redraw an image using python's matplotlib?

What I am trying to do seems to be fairly straightforward, but I'm having a heck of a time trying to get it to work. I am simply trying to draw an image using imshow and then re-draw it periodically as new data arrives.
I've started out with this:
fig = figure()
ax = plt.axes(xlim=(0,200),ylim=(0,200))
myimg = ax.imshow(zeros((200,200),float))
Then I'm assuming I can call set_data like this to update the image:
myimg.set_data(newdata)
I've tried many other things, for example I've called ax.imshow(newdata) instead or I've tried using figure.show() after set_data().
You can simply call figure.canvas.draw() each time you append something new to the figure. This will refresh the plot.
from matplotlib import pyplot as plt
from builtins import input
fig = plt.figure()
ax = fig.gca()
fig.show()
block = False
for i in range(10):
ax.plot(i, i, 'ko')
fig.canvas.draw()
if block:
input('pause : press any key ...')
else:
plt.pause(0.1)
plt.close(fig)

Categories

Resources