To give you a sense of what I'm looking for, it looks like this:
Up until now I have used matplotlib for all my plotting, and timing hasn't been critical (it's been done in postprocessing).
I'm wondering if there is a lighter weight way to plot other than shifting my data to the left and redrawing the entire plot.
Have a look at the Matplotlib Animations Examples. The main trick is to not completely redraw the graph but rather use the OO interface of matplotlib and set the x/ydata of the plot-line you created. If you've integrated your plot with some GUI, e.g., GTK, then definitely do it like proposed in the respective section of the plot, otherwise you might interfere with the event-loop of your GUI toolkit.
For reference, if the link ever dies:
from pylab import *
import time
ion()
tstart = time.time() # for profiling
x = arange(0,2*pi,0.01) # x-array
line, = plot(x,sin(x))
for i in arange(1,200):
line.set_ydata(sin(x+i/10.0)) # update the data
draw() # redraw the canvas
print 'FPS:' , 200/(time.time()-tstart)
You could try streamlit lib.
Should be the lightest one.
In the python wiki there is a list of suggestions with short descriptions: link.
Related
I am interested in making movies using matplotlib. Examples I've seen so far, such as this one for moviewriter, seem to have you editing the data in-place for each frame. This is very efficient, avoiding redrawing the parts of the image that stay the same each time. However, it can be clunky for rapid data exploration. I would like a recipe that lets me simply take a fully drawn figure as each frame (clearing the same figure object each time is fine).
The reason for this: I often create moderately complicated figures using custom functions, with a form like plotme(ax, data, **options). Often I develop these functions without animations in mind, and later want to animate the figures by calling the plotting function in a loop. I don't want to have to change the logic of the functions to "setData" of existing artists in the figure for each frame.
Although the example code you've shown updates existing plot objects, there is no reason that you need to do so. The critical part of the attached code is the writer.grab_frame() which simply gets a screen capture of the current figure.
Here is an example without using existing plot objects
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.animation as manimation
FFMpegWriter = manimation.writers['ffmpeg']
metadata = dict(title='Movie Test', artist='Matplotlib',
comment='Movie support!')
writer = FFMpegWriter(fps=15, metadata=metadata)
fig = plt.figure()
with writer.saving(fig, "writer_test.mp4", 100):
for k in range(10):
# Create a new plot object
plt.plot(range(k), range(k), 'o')
writer.grab_frame()
I want to make an animated barchart in Python and save this animation in mp4 format. My problem is that the frames in the saved video overlay, although I use "blit=True" to tell the animation that only the things that change from frame to frame are drawn. Surprisingly, this problem does not occur in the built-in preview of Python.
Here is a minimal that reflects my situation:
import matplotlib.pyplot as plt
from matplotlib import animation
def barlist(n): #That's the list of bars I want to display
C=[]
for k in range(1,6):
C.append(1/float(n*k))
return C
fig=plt.figure()
n=100 #Number of frames
def animate(i):
x=range(1,6)
y=barlist(i+1)
return plt.bar(x,y)
anim=animation.FuncAnimation(fig,animate,repeat=False,blit=True,frames=n,
interval=50)
anim.save('barchart_animated_'+str(n)+'.mp4')
plt.show()
I must admit that I'm not pretty sure what I should do to remove this flaw. The only example I know of where the bars do not overlay in the frames is here (more exactly, I'm referring to the code of the first answer of the following link):
Dynamically updating a bar plot in matplotlib
It seems that I somehow have to tell the animation how it should set the height of each bar at each frame with the set_height-method. But as I said, I don't really know what's wrong in the above example. Thanks for any help!
Martin
The problem you have here is that you create a new barplot in every iteration of the animation. They will one by one be added to the plot, but since their height is shrinking over time, it may look as though only the first bar is present.
There are two ways to overcome this. First option is to clear the axes before plotting a new bar plot. This however will rescale the axis limits, which should then be constantly set to the same value.
The other option is to manipulate the one and only bar plot in the axes and adapt it's height for every frame. This is shown in the code below.
import matplotlib.pyplot as plt
from matplotlib import animation
def barlist(n):
return [1/float(n*k) for k in range(1,6)]
fig=plt.figure()
n=100 #Number of frames
x=range(1,6)
barcollection = plt.bar(x,barlist(1))
def animate(i):
y=barlist(i+1)
for i, b in enumerate(barcollection):
b.set_height(y[i])
anim=animation.FuncAnimation(fig,animate,repeat=False,blit=False,frames=n,
interval=100)
anim.save('mymovie.mp4',writer=animation.FFMpegWriter(fps=10))
plt.show()
Answers to the questions from the comments:
Blotting is a technique where all the parts of the figure which do not change are stored as a background. Then for each animated frame, only the changing parts are redrawn. This avoids the background to be redrawn from scratch and thus allows for much faster animations. Blitting will only affect the on-screen animation, because saving the animation to a file is not performed in real-time (and doesn't need to anyways).
Using blit=False here allows to make the code more simple because we do not need to care about the differences between the animation on screen and the one saved - they are just the same.
The enumerate function yields both the index as well as the object from the enumerated sequence. I did use it here, because it is a convenient way to obtain both in the same loop. It is not at all important here, you could alternatively do something like
for i in range(len(barcollection)):
barcollection[i].set_height(y[i])
I'm new in matplotlib.
I want to update a data in an endless while loop in a different thread
in addition to updating the plot in the pyplot.show method.
I tried using the threading import but it isn't working
well together with pyplot.show method.
I know I can use pyplot.ion and it works fine with the threads.
The problem with pyplot.ion is that it is not efficient.
Is there any way that i could use pyplot.show instead?
To make myself clear, I don't want the solution:
pyplot.ion()
....
while True:
....
pyplot.show()
I'm not sure if this solves your problem, but you could try to use pyplot.draw()instead of pyplot.show(). If you already have used show() once, will it update the plot? draw() should update the plot though.
I do not know how you plot the data, but assuming that the data-set you're plotting is of the same size every time one trick to speed things up is to use set_data(), if you the first time you plot store the line-artist as
x, y = generate_data_function()
line, = pyplot.plot(x, y)
pyplot.show()
while True:
x, y = generate_data_function()
line.set_data(x, y)
pyplot.draw()
Hope it helps! As I said, I'm not completely sure if it really solves your problem but it could be worth trying at least.
I have found gobject.idle_add() and gobject.threads_init() to be very useful. It was almost exactly what I needed.
I also found these resources useful:
Can you plot live data in matplotlib?
http://wiki.scipy.org/Cookbook/Matplotlib/Animations
I've done a search on SO but haven't quite found the right "solution" to my problem. I am running a loop on some data that I wish to plot. At each step of the loop -- I plot the figure with plt.show(). However, since this is a blocking function, i am stuck until I manually close the window and then the loop continues and the next plot shows up.
What I would like to do is be able to bind a key press event to close the figure and continue the loop (rather than using the mouse to "X" out of the figure).
If this is not possible, I would like to set a timer to close the figure and continue the loop.
All my issues seem to deal with the fact that plt.show() is blocking everything else -- any way around this?
Some notes on my plots: They use the same axes, but contain a scatter plot, fill boxes, and annotations -- which are always changing.
Thanks!
Try using ion from matplotlib.pyplot:
import matplotlib.pyplot as pp
pp.ion()
fig = pp.figure()
More info about ion and interactive vs non-interactive usage here
Alternatively if you want to go with the button press approach assign a callback
def moveon(event):
pp.close()
cid = fig.canvas.mpl_connect('key_press_event', moveon)
pp.show()
An event timer is more tricky because the show command is blocking, so it would probably have to involve threading.
I need to plot some data in various forms. Currently I'm using Matplotlib and I'm fairly happy with the plots I'm able to produce.
This question is on how to plot the last one. The data is similar to the "distance table", like this (just bigger, my table is 128x128 and still have 3 or more number per element).
Now, my data is much better "structured" than a distance table (my data doesn't varies "randomly" like in a alphabetically sorted distance table), thus a 3D barchart, or maybe 3 of them, would be perfect. My understanding is that such a chart is missing in Matplotlib.
I could use a (colored) Countor3d like these or something in 2D like imshow, but it isn't really well representative of what the data is (the data has meaning just in my 128 points, there isn't anything between two points). And the height of bars is more readable than color, IMO.
Thus the questions:
is it possible to create 3D barchart in Matplotlib? It should be clear that I mean with a 2D domain, not just a 2D barchart with a "fake" 3D rendering for aesthetics purposes
if the answer to the previous question is no, then is there some other library able to do that? I strongly prefer something Python-based, but I'm OK with other Linux-friendly possibilities
if the answer to the previous question is no, then do you have any suggestions on how to show that data? E.g. create a table with the values, superimposed to the imshow or other colored way?
For some time now, matplotlib had no 3D support, but it has been added back recently. You will need to use the svn version, since no release has been made since, and the documentation is a little sparse (see examples/mplot3d/demo.py). I don't know if mplot3d supports real 3D bar charts, but one of the demos looks a little like it could be extended to something like that.
Edit: The source code for the demo is in the examples but for some reason the result is not. I mean the test_polys function, and here's how it looks like:
example figure http://www.iki.fi/jks/tmp/poly3d.png
The test_bar2D function would be even better, but it's commented out in the demo as it causes an error with the current svn version. Might be some trivial problem, or something that's harder to fix.
MyavaVi2 can make 3D barcharts (scroll down a bit). Once you have MayaVi/VTK/ETS/etc. installed it all works beautifully, but it can be some work getting it all installed. Ubuntu has all of it packaged, but they're the only Linux distribution I know that does.
One more possibility is Gnuplot, which can draw some kind of pseudo 3D bar charts, and gnuplot.py allows interfacing to Gnuplot from Python. I have not tried it myself, though.
This is my code for a simple Bar-3d using matplotlib.
import mpl_toolkits
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
%matplotlib inline
## The value you want to plot
zval=[0.020752244,0.078514652,0.170302899,0.29543857,0.45358061,0.021255922,0.079022499,\
0.171294169,0.29749654,0.457114286,0.020009631,0.073154019,0.158043498,0.273889264,0.419618287]
fig = plt.figure(figsize=(12,9))
ax = fig.add_subplot(111,projection='3d')
col=["#ccebc5","#b3cde3","#fbb4ae"]*5
xpos=[1,2,3]*5
ypos=range(1,6,1)*5
zpos=[0]*15
dx=[0.4]*15
dy=[0.5]*15
dz=zval
for i in range(0,15,1):
ax.bar3d(ypos[i], xpos[i], zpos[i], dx[i], dy[i], dz[i],
color=col[i],alpha=0.75)
ax.view_init(azim=120)
plt.show()
http://i8.tietuku.com/ea79b55837914ab2.png
You might check out Chart Director:
http://www.advsofteng.com
It has a pretty wide variety of charts and graphs and has a nice Python (and several other languages) API.
There are two editions: The free version puts a blurb on the generated image, and the
pay version is pretty reasonably priced.
Here's one of the more interesting looking 3d stacked bar charts:
(source: advsofteng.com)