Plot data being misdisplayed in matplotlib - python

Why are my datapoints being displayed like this when new data is being dumped via stream into "twitter-out"? Seems like it has to do with the animation, because when I rerun the file without streaming in new data it plots just fine.
style.use('ggplot')
fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)
def animate(self):
pullData = open("twitter-out.txt", "r").read()
lines = pullData.split('\n')
xar = []
yar = []
x = 0
y = 0
for l in lines[:]:
x += 1
if "['pos']" in l:
y += 1
elif "['neg']" in l:
y -= 1
xar.append(x)
yar.append(y)
ax1.plot(xar, yar,color='r')
ax1.set_xlabel('Number of Tweets')
ax1.set_ylabel('Sentiment')
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()

Fix 1:
The main fix for this is very easy : just add ax1.cla() before you call ax1.plot()
Explanation :
The reason for what you see is that the animation draws a new plot each time the animate function is called and stack it above all the previous ones.
So the figure you have attached in your question is actualy a superposition of the dozen figures that were drawn from the animate calls.
To solve that you just have to clear the previous plots that were contained in your axes with the clear axes command ax.cla().
Fix 2:
The reason for the horizontal bars to be there at all is because your dataPulled string always ends with a new line that turns in an empty string at the end of your list line.
See that example:
>>> 'a\nb\n'.split('\n')
['a', 'b', '']
So you have to cut that last one out in your for loop:
for l in lines[:-1]:

Related

Live Matplotlib plot is empty

def simulate(foo):
plt.cla()
for key in plotdata.keys():
plt.plot(plotdata[key],label = key[:-1],color = key[-1])
#do some stuff with data
ani = ani.FuncAnimation(plt.gcf(), simulate, interval = secsbetweengenerations * 100)
plt.legend()
plt.show()
The data is never empty, and the contents of them are always floats between 0 and 1. It shows an empty graph tho
I tried to remove
plt.cla()
and add
plt.axis([0,plotrange-1,0,1])
before the animation

Trying to plot real time data in plotly

I have this code were i want to draw a live cahrt
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
style.use('fivethirtyeight')
# Create figure for plotting
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs = []
ys = []
def animate(i, xs, ys):
# Read temperature (Celsius) from TMP102
polarity = open("sentiment2.txt", "r").read()
lines = polarity.split('\n')
print(lines)
for line in lines:
if len(line) > 1:
x,y = line.split(',')
xs.append(dt.datetime.now().strftime('%H:%M:%S.%f'))
ys.append(line)
# Add x and y to lists
# Limit x and y lists to 20 items
xs = xs[-20:]
ys = ys[-20:]
# Draw x and y lists
ax.clear()
ax.plot(xs, ys)
# Format plot
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.title('Etehreum Sentiment')
plt.ylabel('Sentiment')
# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig, animate, fargs=(xs, ys), interval=60000)
plt.show()
When i run it i get this error:
File "ploty.py", line 23, in animate
x,y = line.split(',')
ValueError: not enough values to unpack (expected 2, got 1)
I have this code from a tutorial and he does the same as i try to achieve so im not sure whats the problem here
What I try to achieve is to get the value(sentiment) from my text file- i run a senitment analysis every 10 minutes and whenever my sentiment.txt file gets updated i want to update my chart
the content of my sentiment.txt file:
-8.944388227513231
-7.731292989417991
-8.493252615440113
0.5413275613275612
Perhaps look at how you had generated the sentiment2.txt file.
Each line of your sentiment2.txt file has only one number and there is no comma.
so despite the line.split(','), there is only one of the coordinate but the code is expecting TWO, X AND Y.
Updated:
Currently, the chart is plotting xs and ys onto the chart; ys are values from the file and xs is the real-time when reading the value. If that is intended, then the split line is redundant and can be removed, and you can remove the 'commas' from your source file.
However, if the sentiment file should contains both x-axis and y-axis values; x and y should map into xs and ys instead:
x,y = line.split(',')
xs.append(x)
ys.append(y)
The latter can be improved further by working with panda which works with csv files see: Plot from CSV with Plotly Express

How to recursively adding a line of code for plot text with given a given condition

So, from this graph below, I find discrete points and their indexes. When we draw a final figure, the figure should have the information of when is the exact time that discontinuity happened and vertical line at the discontinuity should be added. In order to do that, I had to add "plt.axvline" and "plt.text" together as a pair.
I wrote out the code like this here:
However, whenever new index comes, it's very inconvenient to add two lines of code manually, and what if 100 discontinuities manifested than it's almost nearly impossible to add them.
I am thinking of object oriented method for this like "class" but I have no idea where to start..
Any idea of how to recursively adding it with knowing length of indexes?
if len(idx) == 1 :
plt.figure(figsize = (20,10))
plt.axvline(x=idx[0], color = 'r')
plt.text(idx[0],.13, '{}'.format(send_time[idx[0]-1]))
plt.title(var)
plt.scatter(x, result, alpha = alp)
plt.savefig("XXX.png")
plt.close()
elif len(idx) == 2:
plt.figure(figsize = (20,10))
plt.axvline(x=idx[0], color = 'r')
plt.text(idx[0],.10, '{}\n{}'.format(send_time[idx[0]], time1[idx[0]]))
plt.axvline(x=idx[1], color = 'b')
plt.text(idx[1],.10, '{}'.format(send_time[idx[1]-1]))
plt.title(var)
plt.scatter(x, result, alpha = alp)
plt.savefig("XXX.png")
plt.close()
elif len(idx) == 3:
plt.figure(figsize = (20,10))
plt.axvline(x=idx[0], color = 'r')
plt.text(idx[0],.13, '{}\n{}'.format(send_time[idx[0]],time1[idx[0]]))
plt.axvline(x=idx[1], color = 'b')
plt.text(idx[1],.12, '{}\n{}'.format(send_time[idx[1]],time1[idx[1]]))
plt.axvline(x=idx[2], color = 'y')
plt.text(idx[2],.11, '{}'.format(send_time[idx[2]-1]))
plt.title(var)
plt.scatter(x, result, alpha = alp)
plt.savefig("XXX.png")
plt.close()
In general, it's better to loop over a collection directly for item in collection rather than using indices.
plt.figure(figsize = (20,10))
for num in idx:
plt.axvline(num, color = 'r')
plt.text(num, .13, '{}'.format(send_time[num-1]))
plt.title(var)
plt.scatter(x, result, alpha = alp)
plt.savefig("XXX.png")
plt.close()

python animation reading data from file

I'm trying to plot the time evolution of a function f(x,t). The data is stored in a file which has the following format:
1st row:f(0,0) f(0,1) f(0,2) ....f(0,N)
2nd row:f(1,0) f(1,1) f(1,2) ....f(1,N)
Mth row:f(M,0) f(M,1) f(M,2) ....f(M,N)
where N is the no: of points of the simulation box and M is the number of timesteps.
I used basic_animation by Jake Vanderplas (https://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/) to start with, the original example works fine as long as i put blit=False.
Then i tried to replace x by :
x= np.arange(0,192)
and y by the contents of the file mentioned above.
If i do just plt.plot(x,y), it does plot f(x,t) at a given time t, but I want the animation of f(x,t) in time.
set_data should accept 2 1Darrays and I've checked that len(x)=len(y).
But I get the following error message:
'RuntimeError: xdata and ydata must be the same length'
This is the code (in the future i would like to plot multiple functions):
"""
Modified Matplotlib Animation Example
original example:
email: vanderplas#astro.washington.edu
website: http://jakevdp.github.com
license: BSD
Feel free to use and modify this, but keep the above information.
"""
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
from itertools import islice
filename = 'DensityByPropagation__a_0_VHxcS_kick'
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 192), ylim=(-2, 2))
lineS, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
lineS.set_data([], [])
return lineS,
# animation function. This is called sequentially
def animate(i):
w = np.linspace(0, 2, 1000)
z = np.sin(2 * np.pi * (w - 0.01 * i))
x= np.arange(0,192)
with open(filename) as fobj:
ketchup = islice(fobj, 0, None, 10)
for line in ketchup:
x,y = x,zip(*([float(y) for y in line.split("\t")] for line in fobj))
#plt.plot(x,y)
#plt.show()
#print len(x)
#print len(y)
#lineS.set_data(w,z)
lineS.set_data(x,y)
return lineS,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=False)
# save the animation as an mp4. This requires ffmpeg or mencoder to be
# installed. The extra_args ensure that the x264 codec is used, so that
# the video can be embedded in html5. You may need to adjust this for
# your system: for more information, see
# http://matplotlib.sourceforge.net/api/animation_api.html
anim.save('movieJoh.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()
I'm not sure what exactly is causing your error, but let me point something out, then I'll make a toy example that should help clarify what's happening.
These lines seem unnecessarily complicated.
with open(filename) as fobj:
ketchup = islice(fobj, 0, None, 10)
for line in ketchup:
x,y = x,zip(*([float(y) for y in line.split("\t")] for line in fobj))
If your data is in fact in the simple format you stated, i.e., values separated by spaces, np.loadtxt() would load all the values into an easy to manage array.
Example
Lets assume this is your data file (10 time steps, 2 points on plot at each step):
0 0 0 0 0 0 0 0 0 0
9 8 7 6 5 4 3 2 1 0
Now some code:
filename = 'data.txt'
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 1), ylim=(0, 9))
lineS, = ax.plot([], [], lw=2)
x = range(2) # the domain
Now we load the data in with np.loadtxt(), this creates a 2-d matrix with t in the columns and x in the rows. We then transpose it to make indexing each time step possible in animate().
# load the data from file
data = np.loadtxt(filename)
# transpose so we could easily index in the animate() function
data = np.transpose(data)
Now for animation functions. This part is really quite simple. animate(i) takes one argument - the frame number. Using the frame number, we extract the values of f(x,t=frameNumber) and set that as the data on the plot.
# initialization function: plot the background of each frame
def init():
lineS.set_data([], [])
return lineS,
# animation function. This is called sequentially
def animate(i):
lineS.set_data(x, data[i])
return lineS,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=10, interval=100, blit=True)
plt.show()
This is the working code:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# Input
filename = 'PeriodicDensity' # Filename
x = np.linspace(-7.5,7.5,192) # Domain
xLimits=[-7.5,7.5] # x limits
yLimits=[0,1] # y limits
framesToUse = range(1,9000,150)# The time-steps to plot
# load the data from file
data = np.loadtxt(filename)
# Set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=xLimits,ylim=yLimits)
lineS, = ax.plot([], [], lw=2)
# Initialisation function
def init():
lineS.set_data([],[])
return lineS,
# Animation function (called sequentially)
def animate(i):
lineS.set_data(x,data[i])
return lineS,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,interval=1000, frames=framesToUse, blit=True)
# save the animation as an mp4. This requires ffmpeg or mencoder to be
# installed. The extra_args ensure that the x264 codec is used, so that
# the video can be embedded in html5. You may need to adjust this for
# your system: for more information, see
# http://matplotlib.sourceforge.net/api/animation_api.html
anim.save('movieDensity.mp4', fps=1, extra_args=['-vcodec', 'libx264'])
plt.show()

Matplotlib stops animating after first frame

I'm trying to animate two subplots, each with multiple lines. I am using Matplotlib, and I am using the FuncAnimation, which is used by many of the animation examples.
Using animation:
If I try to animate it, I only get the result of the first frame:
Without using animation:
If I manually call my update_lines function, it works fine.
Code:
Below is the full code (uncommenting the 3 indicated lines in main() works, but I would like to see it update in real-time, hence trying to use the animation).
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def make_subplots():
def setup_axes(axes):
for ax in axes:
ax.set_xbound(0, 100) # bound will change as needed.
ax.set_ylim(0, 1) # limit won't change automatically.
def make_lines(axes):
labels = ('a', 'b', 'c')
lines = []
for ax in axes:
ax_lines = []
for label in labels:
x, y = [0], [0]
line, = ax.plot(x, y, label=label) # comma for unpacking.
ax_lines.append((line, x, y))
lines.append(ax_lines)
return lines
fig, axes = plt.subplots(2, 1, sharex=True, sharey=True)
lines = make_lines(axes)
setup_axes(axes)
return fig, axes, lines
def make_data():
for i in xrange(100):
print 'make_data():', i
data = dict()
for label in ('a', 'b', 'c'):
from random import random
data[label] = random()
yield (i + 1, data)
def update_lines(data, lines):
print 'update_lines():', data, lines
updated_lines = []
for ax_lines in lines:
for line, x, y in ax_lines:
label = line.get_label()
x.append(data[0])
y.append(data[1][label])
line.set_data(x, y)
updated_lines.append(line)
def main():
fig, axes, lines = make_subplots()
# Uncomment these 3 lines, and it works!
# new_data = make_data()
# for data in new_data:
# update_lines(data, lines)
FuncAnimation(fig=fig,
func=update_lines,
frames=make_data,
fargs=(lines,),
interval=10,
blit=False)
plt.show()
if __name__ == '__main__':
main()
(Undocumented?) Hooks
So, I was digging around the source-code of matplotlib.animation.Animation, and I noticed these lines in the __init__() function:
# Clear the initial frame
self._init_draw()
# Instead of starting the event source now, we connect to the figure's
# draw_event, so that we only start once the figure has been drawn.
self._first_draw_id = fig.canvas.mpl_connect('draw_event', self._start)
Sounds familiar...
This looks right so far. The self._init_draw() call draws my first frame immediately. Then the animation-object hooks into the figure-object and waits for the figure to be shown before attempting to draw any more frames for the animation.
Eureka!
The keyword is: animation-object. Since I wasn't planning on using the animation instance later (for example, to draw a movie), I didn't assign it to a variable. In fact, I was being yelled at by pyflakes because Local variable '...' is assigned to but never used.
But because all of the functionality relies on the hook, when the canvas is finally shown I presume Python's garbage collection has removed the Animation instance---since it was never assigned to a variable---and therefore the animation can never be started.
The fix
Simply assign the instance FuncAnimation instance to a variable, and everything works as expected!
anim = FuncAnimation(fig=fig,
func=update_lines,
frames=make_data,
fargs=(lines,),
interval=10,
blit=False)

Categories