Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically updating plot in matplotlib

I am making an application in Python which collects data from a serial port and plots a graph of the collected data against arrival time. The time of arrival for the data is uncertain. I want the plot to be updated when data is received. I searched on how to do this and found two methods:

  1. Clear the plot and re-draw the plot with all the points again.
  2. Animate the plot by changing it after a particular interval.

I do not prefer the first one as the program runs and collects data for a long time (a day for example), and redrawing the plot will be pretty slow. The second one is also not preferable as time of arrival of data is uncertain and I want the plot to update only when the data is received.

Is there a way in which I can update the plot just by adding more points to it only when the data is received?

like image 391
Shadman Anwer Avatar asked Jun 08 '12 07:06

Shadman Anwer


People also ask

How do you update a dynamic plot in Matplotlib?

To dynamically update plot in Python matplotlib, we can call draw after we updated the plot data. to define the update_line function. In it, we call set_xdata to set the data form the x-axis. And we call set_ydata to do the same for the y-axis.

How do you update a plot on the same figure during the loop?

We can use matplotlib to update a plot on every iteration during the loop. With the help of matplotlib. pyplot. draw() function we can update the plot on the same figure during the loop.


2 Answers

Is there a way in which I can update the plot just by adding more point[s] to it...

There are a number of ways of animating data in matplotlib, depending on the version you have. Have you seen the matplotlib cookbook examples? Also, check out the more modern animation examples in the matplotlib documentation. Finally, the animation API defines a function FuncAnimation which animates a function in time. This function could just be the function you use to acquire your data.

Each method basically sets the data property of the object being drawn, so doesn't require clearing the screen or figure. The data property can simply be extended, so you can keep the previous points and just keep adding to your line (or image or whatever you are drawing).

Given that you say that your data arrival time is uncertain your best bet is probably just to do something like:

import matplotlib.pyplot as plt import numpy  hl, = plt.plot([], [])  def update_line(hl, new_data):     hl.set_xdata(numpy.append(hl.get_xdata(), new_data))     hl.set_ydata(numpy.append(hl.get_ydata(), new_data))     plt.draw() 

Then when you receive data from the serial port just call update_line.

like image 95
Chris Avatar answered Nov 04 '22 08:11

Chris


In order to do this without FuncAnimation (eg you want to execute other parts of the code while the plot is being produced or you want to be updating several plots at the same time), calling draw alone does not produce the plot (at least with the qt backend).

The following works for me:

import matplotlib.pyplot as plt plt.ion() class DynamicUpdate():     #Suppose we know the x range     min_x = 0     max_x = 10      def on_launch(self):         #Set up plot         self.figure, self.ax = plt.subplots()         self.lines, = self.ax.plot([],[], 'o')         #Autoscale on unknown axis and known lims on the other         self.ax.set_autoscaley_on(True)         self.ax.set_xlim(self.min_x, self.max_x)         #Other stuff         self.ax.grid()         ...      def on_running(self, xdata, ydata):         #Update data (with the new _and_ the old points)         self.lines.set_xdata(xdata)         self.lines.set_ydata(ydata)         #Need both of these in order to rescale         self.ax.relim()         self.ax.autoscale_view()         #We need to draw *and* flush         self.figure.canvas.draw()         self.figure.canvas.flush_events()      #Example     def __call__(self):         import numpy as np         import time         self.on_launch()         xdata = []         ydata = []         for x in np.arange(0,10,0.5):             xdata.append(x)             ydata.append(np.exp(-x**2)+10*np.exp(-(x-7)**2))             self.on_running(xdata, ydata)             time.sleep(1)         return xdata, ydata  d = DynamicUpdate() d() 
like image 34
Zah Avatar answered Nov 04 '22 09:11

Zah