Plotting second figure with matplotlib while first is still open - python

K here's a more precise example of what I am trying to do. I am using WXBuilder for Python as my user interface with multiple plotting functionality i.e. the user must be able to plot a graph based on their chosen parameters. After a graph is plotted I want the user to be able to plot a second without closing the first figure. This is for comparison purposes. Below is an oversimplified example of what I am looking to do.
import matplotlib as plt
def OnPlotClick1(self, event):
plt.plot(self.DateArray1, self.kVAArray2)
plt.show()
def OnPlotClick2(self, event):
plt.plot(self.DateArray1, self.kVAArray2)
plt.show()
Now I am assuming my problem is arising due plotting and showing() the graph, and therefore the program somehow is blocked from functionality until the first figure or plot window is closed.
I hope this explains my problem better.

You should not block show. Use:
import matplotlib.pylab as plt
plt.plot([1,2,3]) # first plot
plt.show(block=False) # do not block
plt.plot([11,21,31]) # second plot

Each window is in matplotlib parlance, a new figure. You can call plt.subplots twice to create two figures:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
y1 = np.sin(x)*np.exp(-x/5.0)
y2 = np.sin(x**2)*x
fig1, ax1 = plt.subplots()
ax1.plot(x, y1)
fig2, ax2 = plt.subplots()
ax2.plot(x, y2)
plt.show()
Note that plt.show() starts a GUI event loop and so generally it should only be called once per script.

You can also draw 2 or more than 2 plotters in the same figure
import matplotlib.pyplot as plt
def my_plotter(ax, data1, data2, param_dict):
out = ax.plot(data1, data2, **param_dict)
return out
fig, (ax1, ax2) = plt.subplots(1, 2)
#here you put your data
data1=[0,1,2,3,8]
data2=[0,1,2,3,8]
data3=[0,1,2,3,8]
data4=[0,1,2,3,8]
my_plotter(ax1, data1, data2, {'marker':'x'})
my_plotter(ax2, data3, data4, {'marker':'o'})
plt.show()

You can either follow #(Corrupted MyStack) suggestion or with interactive graphic devide. Run
plt.ion()
once, anytime before you start the plots. To turn it off
plt.ioff()

Related

Dynamically update plot Matplotlib Python (for unsteady heat diffusion)

I am new to python and trying to do what have been doing in MATLAB for so long. My current challenge is to dynamically update a plot without drawing a new figure in a for or while loop. I am aware there are similar questions and answers but most of them are too complicated and I believe it should be easier.
I got the example from here
https://pythonspot.com/matplotlib-update-plot/
But I can't see the figure, no error, no nothing. I added two lines just to see if I can see the static plot and I can.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10*np.pi, 100)
y = np.sin(x)
# This is just a test just to see if I can see the plot window
plt.plot(x, y)
plt.show()
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x, y, 'b-')
for phase in np.linspace(0, 10*np.pi, 100):
line1.set_ydata(np.sin(0.5 * x + phase))
fig.canvas.draw()
Any idea why I can't see the dynamic plot?
Thank you
Erdem
try to add plt.pause(0.0001) inside the loop after plt.show(block=False), and a final plt.show() outside the loop. This should work fine with plt.ion(); ref to some older answers Plot one figure at a time without closing old figure (matplotlib)

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.

Matplotlib needs careful timing? (Or is there a flag to show plotting is done?)

The following code does not work as expected:
import matplotlib.pyplot as plt
plt.plot(range(100000), '.')
plt.draw()
ax = plt.gca()
lblx = ax.get_xticklabels()
lblx[1]._text = 'hello!'
ax.set_xticklabels(lblx)
plt.draw()
plt.show()
I'm getting the following figure:
I imagine that the reason is that the automatic xticklabels did not have time to be fully created when get_xticklabels() was called. And indeed, by adding plt.pause(1)
import matplotlib.pyplot as plt
plt.plot(range(100000), '.')
plt.draw()
plt.pause(1)
ax = plt.gca()
lblx = ax.get_xticklabels()
lblx[1]._text = 'hello!'
ax.set_xticklabels(lblx)
plt.draw()
plt.show()
would give the expected
I'm not very happy with this state (having to manually insert delays). And my main concern is: How can I know how much time I need to wait? Surely it depends on number of figure elements, machine strength, etc..
So my question is: Is there some flag to know that matplotlib has finished drawing all the elements? Or is there a better way to do what I'm doing?
First it should be noted that you may make an arbitrarily short pause
plt.pause(1e-18)
The issue here is that plt.draw() calls plt.gcf().canvas.draw_idle(). This means that the figure is drawn at some arbitrary point when there is time to do it - hence the _idle.
Instead you would probably want to draw the figure at the specific point in the code you need.
plt.gcf().canvas.draw()
Full code:
import matplotlib.pyplot as plt
plt.plot(range(100000), '.')
plt.gcf().canvas.draw()
ax = plt.gca()
lblx = ax.get_xticklabels()
lblx[1]._text = 'hello!'
ax.set_xticklabels(lblx)
plt.show()

Sequential plotting on one pair of axes using python

The following is code to plot cosine and sine on one pair of axes, from DeCaria's wonderful book Python Programming and Visualization for Scientists. How to I produce the same plot but by plotting cos first, pausing, then plotting sin? Ultimately, I want to plot many functions sequentially and be able to watch for patterns in the family of functions as they emerge.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0,100.0)
y1 = np.cos(2*np.pi*x/50.0)
y2 = np.sin(2*np.pi*x/50.0)
plt.plot(x, y1, 'b-', label = 'Cosine')
plt.plot(x, y2, 'r--', label = 'Sine')
plt.legend(('Cosine', 'Sine'))
plt.show()
Thank you for any help that might be available.
A simple way to do what you want is to set block = False in your plt.show() command and then update the figure with Figure.canvas.draw() every time you draw a new curve. Here is an example that illustrates how this would work:
import matplotlib.pyplot as plt
import numpy as np
fig,ax = plt.subplots()
x = np.arange(0,100.0)
functions = [
('Cosine', np.cos(2*np.pi*x/50.0), 'b-'),
('Sine', np.sin(2*np.pi*x/50.0), 'r--'),
]
plt.show(block = False)
for label, y, style in functions:
ax.plot(x, y, style, label = label)
ax.legend()
fig.canvas.draw()
input('press <ENTER>')
This code will loop through all the functions that you define in functions (here I used tuples that hold the function name, the y-values, and the plot style) and pause after every update, waiting for keyboard input in the terminal. If you somehow want to only interact with the figure (no terminal input), you will have to start fiddling with matplotlib events. Hope this helps.

Python: get corresponding information of data points interactively with mouse

I have a set of data in my research project, and each data point contains lots of related information and it is impossible to show all of them in a figure. What I would like to do to visualize these data is to plot the data points using their two key parameters, and when the mouse cursor hovers over one data point, it shows all information related to this data point. I am wondering if there are any ways to implement this?
Thanks!
You have a matplotlib example that provides something like what you are asking here. #root gave an answer here that provides a basic interface with output for the console (by mouse click over the points):
from matplotlib.pyplot import figure, show
import numpy as npy
from numpy.random import rand
if 1: # picking on a scatter plot (matplotlib.collections.RegularPolyCollection)
x, y, c, s = rand(4, 100)
def onpick3(event):
ind = event.ind
print 'onpick3 scatter:', ind, npy.take(x, ind), npy.take(y, ind)
fig = figure()
ax1 = fig.add_subplot(111)
col = ax1.scatter(x, y, 100*s, c, picker=True)
#fig.savefig('pscoll.eps')
fig.canvas.mpl_connect('pick_event', onpick3)
show()
Yet I would suggest mpldatacursor. #moooeeeep gave an example of it's use here:
import matplotlib.pyplot as plt
from mpldatacursor import datacursor
import random
fig, ax = plt.subplots()
ax.set_title('Click on a dot to display its label')
# Plot a number of random dots
for i in range(1, 1000):
ax.scatter([random.random()], [random.random()], label='$ID: {}$'.format(i))
# Use a DataCursor to interactively display the label for a selected line...
datacursor(formatter='{label}'.format)
plt.show()
With this result:

Categories

Resources