Plotting to browser continuously using serve_figure - python

I want to see plots in progress continuously driven by the plot program using browser whenever it is connected. I searched and found serve_figure.py examples that are similar to what I need. But I cant get the following test code to work. Serve_figure.py holds up the for-loop after the first plot. At the browser only the first plot is shown. I don't need the mouse event in serve_figure.py. If there is another way to do this will be most welcome.
#!/usr/bin/env pythonnter
import serve_figure
import time
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
def animate():
x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x, np.sin(x))
for i in np.arange(1,200):
line.set_ydata(np.sin(x+i/10.0))
fig.canvas.draw()
time.sleep(1)
serve_figure.serve_figure(fig, port=8888)
win = fig.canvas.manager.window
fig.canvas.manager.window.after(200, animate)
plt.show()

BTW, the link to serve_figure.py is
https://github.com/mdboom/mpl_browser_experiments/blob/master/serve_figure.py

Related

update matplotlib scatter data [duplicate]

I am trying to automatically update a scatter plot.
The source of my X and Y values is external, and the data is pushed automatically into my code in a non-predicted time intervals (rounds).
I have only managed to plot all the data when the whole process ended, whereas I am trying to constantly add and plot data into my canvas.
What I DO get (at the end of the whole run) is this:
Whereas, what I am after is this:
A simplified version of my code:
import matplotlib.pyplot as plt
def read_data():
#This function gets the values of xAxis and yAxis
xAxis = [some values] #these valuers change in each run
yAxis = [other values] #these valuers change in each run
plt.scatter(xAxis,yAxis, label = 'myPlot', color = 'k', s=50)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
There are several ways to animate a matplotlib plot. In the following let's look at two minimal examples using a scatter plot.
(a) use interactive mode plt.ion()
For an animation to take place we need an event loop. One way of getting the event loop is to use plt.ion() ("interactive on"). One then needs to first draw the figure and can then update the plot in a loop. Inside the loop, we need to draw the canvas and introduce a little pause for the window to process other events (like the mouse interactions etc.). Without this pause the window would freeze. Finally we call plt.waitforbuttonpress() to let the window stay open even after the animation has finished.
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
fig, ax = plt.subplots()
x, y = [],[]
sc = ax.scatter(x,y)
plt.xlim(0,10)
plt.ylim(0,10)
plt.draw()
for i in range(1000):
x.append(np.random.rand(1)*10)
y.append(np.random.rand(1)*10)
sc.set_offsets(np.c_[x,y])
fig.canvas.draw_idle()
plt.pause(0.1)
plt.waitforbuttonpress()
(b) using FuncAnimation
Much of the above can be automated using matplotlib.animation.FuncAnimation. The FuncAnimation will take care of the loop and the redrawing and will constantly call a function (in this case animate()) after a given time interval. The animation will only start once plt.show() is called, thereby automatically running in the plot window's event loop.
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
fig, ax = plt.subplots()
x, y = [],[]
sc = ax.scatter(x,y)
plt.xlim(0,10)
plt.ylim(0,10)
def animate(i):
x.append(np.random.rand(1)*10)
y.append(np.random.rand(1)*10)
sc.set_offsets(np.c_[x,y])
ani = matplotlib.animation.FuncAnimation(fig, animate,
frames=2, interval=100, repeat=True)
plt.show()
From what I understand, you want to update interactively your plot. If so, you can use plot instead of scatter plot and update the data of your plot like this.
import numpy
import matplotlib.pyplot as plt
fig = plt.figure()
axe = fig.add_subplot(111)
X,Y = [],[]
sp, = axe.plot([],[],label='toto',ms=10,color='k',marker='o',ls='')
fig.show()
for iter in range(5):
X.append(numpy.random.rand())
Y.append(numpy.random.rand())
sp.set_data(X,Y)
axe.set_xlim(min(X),max(X))
axe.set_ylim(min(Y),max(Y))
raw_input('...')
fig.canvas.draw()
If this is the behaviour your are looking for, you just need to create a function appending the data of sp, and get in that function the new points you want to plot (either with I/O management or whatever the communication process you're using).
I hope it helps.

A blocking, interactive plot in Jupyter notebook

I am trying to get an interactive, blocking matplotlib window out of Jupyter notebook. That is, I want the matplotlib window to come up and for execution in the notebook to pause until it closes. But various, reasonable-seeming permutations of my code don't seem to work.
The following produces the expected result:
%matplotlib
import matplotlib.pyplot as plt
a=[1,2,3]
b=[4,5,6]
plt.figure()
plt.plot(a,b)
plt.show(block=True)
print("hi")
But only once. If the code is run the second time, the kernel seems to lock up and I have to restart it, which is a no-go for my application.
The following alternatives produce an interactive window, but the code proceeds directly to the print statement without waiting for the window to be closed:
%matplotlib
import matplotlib.pyplot as plt
a=[1,2,3]
b=[4,5,6]
plt.figure()
plt.plot(a,b)
plt.show()
print("hi")
I get the same result from:
%matplotlib
import matplotlib.pyplot as plt
a=[1,2,3]
b=[4,5,6]
plt.figure()
plt.plot(a,b)
plt.ioff()
plt.show()
print("hi")
and
%matplotlib
import matplotlib.pyplot as plt
a=[1,2,3]
b=[4,5,6]
plt.figure()
plt.plot(a,b)
plt.ion()
plt.show()
print("hi")
How can I accomplish this goal? (The goal being to have print("hi") not execute until after the interactive matplotlib window closes.)
(I'm using Python 3.5.3 and Jupyter notebook server 5.0.0.)
I guess you cannot block the execution of a cell in the middle. However the usecase described in the comments seems to allow to process everything within the event loop of the figure itself.
# cell 1:
%matplotlib
import matplotlib.pyplot as plt
import numpy as np
class InterAct():
def __init__(self):
self.fig, self.ax = plt.subplots()
self.ax.axis([0,1,0,1])
self.ax.set_title("Click to choose points, close to proceed")
self.plot, = self.ax.plot([],[], color="crimson", ls="", marker="o")
self.points = []
self.fig.canvas.mpl_connect("button_press_event", self.select_point)
self.fig.canvas.mpl_connect("close_event", self.process)
plt.show()
def select_point(self, event):
self.points.append((event.xdata,event.ydata))
x,y = list(zip(*self.points))
self.plot.set_data(x,y)
self.fig.canvas.draw_idle()
def process(self, event):
points = np.array(self.points)
mean = points.mean(axis=0)
r = np.sqrt(np.sum((points-mean)**2, axis=1)).max()
self.fig2, self.ax2 = plt.subplots()
self.ax2.axis([0,1,0,1])
self.ax2.set_title("The result is:")
poly = plt.Polygon(points, edgecolor="C0", fill=True, alpha=0.5)
circ = plt.Circle(mean, r, color="crimson", fill=False)
self.ax2.add_patch(circ)
self.ax2.add_patch(poly)
self.fig2.show()
#plt.show()
And then
# cell 2
i = InterAct()
This would first show a matplotlib figure, where the user can interactively do something (in this case click to select points). Then when the user closes the figure, the points are processed and a new figure with the result is shown.
In case anybody looks for "blocking execution" until window is closed, here is a simple solution. Put this code in a cell.
# Provided the backend is interactive
# e.g. %matplotlib qt5
fig = plt.figure()
plt.show()
try:
while fig.number in plt.get_fignums():
plt.pause(0.1)
except:
plt.close(fig.number)
raise
print("hi!")
The loop in this snippet waits until the current figure is in the list of active figures. When a user closes the figure's window, its number disappears from the list returned by plt.get_fignums().
To make the cell interruptable the snippet catches exceptions. When the user stops the cell by Interrupt the kernel (aka Stop) button then KeyboardInterrupt error is injected into the Python event loop. The snippet catches it and closes the figure fig.
The duration in plt.pause defines delay in the script reaction. The bigger this value is, the longer is the delay between closing the window and printing hi!
The cell could be re-executed any number of times.

python matplotlib update scatter plot from a function

I am trying to automatically update a scatter plot.
The source of my X and Y values is external, and the data is pushed automatically into my code in a non-predicted time intervals (rounds).
I have only managed to plot all the data when the whole process ended, whereas I am trying to constantly add and plot data into my canvas.
What I DO get (at the end of the whole run) is this:
Whereas, what I am after is this:
A simplified version of my code:
import matplotlib.pyplot as plt
def read_data():
#This function gets the values of xAxis and yAxis
xAxis = [some values] #these valuers change in each run
yAxis = [other values] #these valuers change in each run
plt.scatter(xAxis,yAxis, label = 'myPlot', color = 'k', s=50)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
There are several ways to animate a matplotlib plot. In the following let's look at two minimal examples using a scatter plot.
(a) use interactive mode plt.ion()
For an animation to take place we need an event loop. One way of getting the event loop is to use plt.ion() ("interactive on"). One then needs to first draw the figure and can then update the plot in a loop. Inside the loop, we need to draw the canvas and introduce a little pause for the window to process other events (like the mouse interactions etc.). Without this pause the window would freeze. Finally we call plt.waitforbuttonpress() to let the window stay open even after the animation has finished.
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
fig, ax = plt.subplots()
x, y = [],[]
sc = ax.scatter(x,y)
plt.xlim(0,10)
plt.ylim(0,10)
plt.draw()
for i in range(1000):
x.append(np.random.rand(1)*10)
y.append(np.random.rand(1)*10)
sc.set_offsets(np.c_[x,y])
fig.canvas.draw_idle()
plt.pause(0.1)
plt.waitforbuttonpress()
(b) using FuncAnimation
Much of the above can be automated using matplotlib.animation.FuncAnimation. The FuncAnimation will take care of the loop and the redrawing and will constantly call a function (in this case animate()) after a given time interval. The animation will only start once plt.show() is called, thereby automatically running in the plot window's event loop.
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
fig, ax = plt.subplots()
x, y = [],[]
sc = ax.scatter(x,y)
plt.xlim(0,10)
plt.ylim(0,10)
def animate(i):
x.append(np.random.rand(1)*10)
y.append(np.random.rand(1)*10)
sc.set_offsets(np.c_[x,y])
ani = matplotlib.animation.FuncAnimation(fig, animate,
frames=2, interval=100, repeat=True)
plt.show()
From what I understand, you want to update interactively your plot. If so, you can use plot instead of scatter plot and update the data of your plot like this.
import numpy
import matplotlib.pyplot as plt
fig = plt.figure()
axe = fig.add_subplot(111)
X,Y = [],[]
sp, = axe.plot([],[],label='toto',ms=10,color='k',marker='o',ls='')
fig.show()
for iter in range(5):
X.append(numpy.random.rand())
Y.append(numpy.random.rand())
sp.set_data(X,Y)
axe.set_xlim(min(X),max(X))
axe.set_ylim(min(Y),max(Y))
raw_input('...')
fig.canvas.draw()
If this is the behaviour your are looking for, you just need to create a function appending the data of sp, and get in that function the new points you want to plot (either with I/O management or whatever the communication process you're using).
I hope it helps.

MatPlotLib's ion() and draw() not working

I am trying to plot figures in real time using a for loop. I have the following simple code:
import matplotlib.pyplot as plt
plt.ion()
plt.figure()
for i in range(100):
plt.plot([i], [i], 'o')
plt.draw()
plt.pause(0.0001)
This code does not show the figure until it has finished computing, which I don't want. I want it to draw the figure after every loop. If I replace plt.draw() with plt.show, multiple figures are output in real time, but I want them all to appear in the same figure. Any ideas?
EDIT:
I downloaded PyCharm with Anaconda and everything works fine. I guess it's a problem with Spyder since I tried a few different versions of it without success. If anyone has any clue what is causing this problem in Spyder, let me know!
Adapted for your case from : Python realtime plotting
import matplotlib.pyplot as plt
import numpy as np
import time
fig = plt.figure()
ax = fig.add_subplot(111)
# some X and Y data
x = [0]
y = [0]
li, = ax.plot(x, y,'o')
# draw and show it
fig.canvas.draw()
plt.show(block=False)
# loop to update the data
for i in range(100):
try:
x.append(i)
y.append(i)
# set the new data
li.set_xdata(x)
li.set_ydata(y)
ax.relim()
ax.autoscale_view(True,True,True)
fig.canvas.draw()
time.sleep(0.01)
except KeyboardInterrupt:
plt.close('all')
break
This solution example has worked for me on multiple machines. Try adjusting plt.pause(...)
import matplotlib.pyplot as plt
import numpy as np
F = lambda x: np.sin(2*x)
plt.ion()
x = np.linspace(0, 1, 200)
plt.plot(x, F(x))
for i in range(100):
if 'ax' in globals(): ax.remove()
newx = np.random.choice(x, size = 10)
ax = plt.scatter(newx, F(newx))
plt.pause(0.05)
plt.ioff()
plt.show()
Hey I was having the same problem, I checked other questions and my issue was solved when I plugged a pause into my solution. Here's some example code that worked for me.
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
x = np.arange(0, 4*np.pi, 0.1)
y = [np.sin(i) for i in x]
plt.plot(x, y, 'g-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
plt.plot(x, [i**2 for i in y], 'g-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
plt.plot(x, [i**2*i+0.25 for i in y], 'r-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
The solution was posted here:
Matplotlib ion() and subprocesses
The problem - and the solution - is highly dependent on the plot.draw() function within the Python environment and back end, and may even vary in different product releases. It manifests itself in different ways depending on the environment. The problem shows up in many places on stackoverflow with some solutions working for some people and not for others.
The gold standard on my Windows laptop is running the Python from the command line - no IDE, just plain vanilla Python3. draw() as shown in the example always works fine there.
If I try it in Jupyter notebook on the same machine, no amount of draw(), plot.pause(), plot.show(), or any other suggestion works. I tried %matplotlib with notebook, widget and ipympl. Nothing gets drawn until complete end of cell code execution.
Some other sources on stackoverflow suggested using figure.canvas.flush_events(). I had some success with that and investigated further.
The best solution turned out to be to run the draw() at the figure.canvas level instead of the axes or plot level.
You can get the figure by creating your plot with command:
fig, graph, = plt.subplots()
or, if you've already created the plot, as in the code at the top of the ticket, put the following outside the loop:
fig = plt.gcf() #get current figure
Inside the loop, instead of plt.draw(), use
fig.canvas.draw()
It's proven reliable in my Jupyter Notebook environment even when running multiple axes/plots across multiple figures. I can drop in sleep() statements and everything appears when expected.
Your mileage may vary.

What is the currently correct way to dynamically update plots in Jupyter/iPython?

In the answers to how to dynamically update a plot in a loop in ipython notebook (within one cell), an example is given of how to dynamically update a plot inside a Jupyter notebook within a Python loop. However, this works by destroying and re-creating the plot on every iteration, and a comment in one of the threads notes that this situation can be improved by using the new-ish %matplotlib nbagg magic, which provides an interactive figure embedded in the notebook, rather than a static image.
However, this wonderful new nbagg feature seems to be completely undocumented as far as I can tell, and I'm unable to find an example of how to use it to dynamically update a plot. Thus my question is, how does one efficiently update an existing plot in a Jupyter/Python notebook, using the nbagg backend? Since dynamically updating plots in matplotlib is a tricky issue in general, a simple working example would be an enormous help. A pointer to any documentation on the topic would also be extremely helpful.
To be clear what I'm asking for: what I want to do is to run some simulation code for a few iterations, then draw a plot of its current state, then run it for a few more iterations, then update the plot to reflect the current state, and so on. So the idea is to draw a plot and then, without any interaction from the user, update the data in the plot without destroying and re-creating the whole thing.
Here is some slightly modified code from the answer to the linked question above, which achieves this by re-drawing the whole figure every time. I want to achieve the same result, but more efficiently using nbagg.
%matplotlib inline
import time
import pylab as pl
from IPython import display
for i in range(10):
pl.clf()
pl.plot(pl.randn(100))
display.display(pl.gcf())
display.clear_output(wait=True)
time.sleep(1.0)
Here is an example that updates a plot in a loop. It updates the data in the figure and does not redraw the whole figure every time. It does block execution, though if you're interested in running a finite set of simulations and saving the results somewhere, it may not be a problem for you.
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import time
def pltsin(ax, colors=['b']):
x = np.linspace(0,1,100)
if ax.lines:
for line in ax.lines:
line.set_xdata(x)
y = np.random.random(size=(100,1))
line.set_ydata(y)
else:
for color in colors:
y = np.random.random(size=(100,1))
ax.plot(x, y, color)
fig.canvas.draw()
fig,ax = plt.subplots(1,1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for f in range(5):
pltsin(ax, ['b', 'r'])
time.sleep(1)
I put this up on nbviewer here.
There is an IPython Widget version of nbagg that is currently a work in progress at the Matplotlib repository. When that is available, that will probably be the best way to use nbagg.
EDIT: updated to show multiple plots
I'm using jupyter-lab and this works for me (adapt it to your case):
from IPython.display import clear_output
from matplotlib import pyplot as plt
import numpy as np
import collections
%matplotlib inline
def live_plot(data_dict, figsize=(7,5), title=''):
clear_output(wait=True)
plt.figure(figsize=figsize)
for label,data in data_dict.items():
plt.plot(data, label=label)
plt.title(title)
plt.grid(True)
plt.xlabel('epoch')
plt.legend(loc='center left') # the plot evolves to the right
plt.show();
Then in a loop you populate a dictionary and you pass it to live_plot():
data = collections.defaultdict(list)
for i in range(100):
data['foo'].append(np.random.random())
data['bar'].append(np.random.random())
data['baz'].append(np.random.random())
live_plot(data)
make sure you have a few cells below the plot, otherwise the view snaps in place each time the plot is redrawn.
If you don't want to clear all outputs, you can use display_id=True to obtain a handle and use .update() on it:
import numpy as np
import matplotlib.pyplot as plt
import time
from IPython import display
def pltsin(ax, *,hdisplay, colors=['b']):
x = np.linspace(0,1,100)
if ax.lines:
for line in ax.lines:
line.set_xdata(x)
y = np.random.random(size=(100,1))
line.set_ydata(y)
else:
for color in colors:
y = np.random.random(size=(100,1))
ax.plot(x, y, color)
hdisplay.update(fig)
fig,ax = plt.subplots(1,1)
hdisplay = display.display("", display_id=True)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for f in range(5):
pltsin(ax, colors=['b', 'r'], hdisplay=hdisplay)
time.sleep(1)
plt.close(fig)
(adapted from #pneumatics)
I've adapted #Ziofil answer and modified it to accept x,y as list and output a scatter plot plus a linear trend on the same plot.
from IPython.display import clear_output
from matplotlib import pyplot as plt
%matplotlib inline
def live_plot(x, y, figsize=(7,5), title=''):
clear_output(wait=True)
plt.figure(figsize=figsize)
plt.xlim(0, training_steps)
plt.ylim(0, 100)
x= [float(i) for i in x]
y= [float(i) for i in y]
if len(x) > 1:
plt.scatter(x,y, label='axis y', color='k')
m, b = np.polyfit(x, y, 1)
plt.plot(x, [x * m for x in x] + b)
plt.title(title)
plt.grid(True)
plt.xlabel('axis x')
plt.ylabel('axis y')
plt.show();
you just need to call live_plot(x, y) inside a loop.
here's how it looks:
The canvas.draw method of the figure dynamically updates its graphs, for the current figure:
from matplotlib import pyplot as plt
plt.gcf().canvas.draw()

Categories