I'm trying to have my matplotlib plot update in real-time as data is added to a CSV file. The plot is of a small geographic location, axes given by longitude and latitude. This is what I have so far:
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
df = pd.read_csv("cayugacoords.txt")
BoundaryBox = [-76.5119, -76.5013, 42.4596, 42.4642]
ruh_m = plt.imread('map.png')
fig, ax = plt.subplots(figsize=(8, 7))
ax.scatter(df.longitude, df.latitude, zorder=1, alpha=1, c='r', s=10)
ax.set_title('Cayuga Lake Shore')
ax.set_xlim(BoundaryBox[0], BoundaryBox[1])
ax.set_ylim(BoundaryBox[2], BoundaryBox[3])
ax.imshow(ruh_m, zorder=0, extent=BoundaryBox, aspect='equal')
plt.show()
And this is what shows when I run the code (the three points on the bottom left are already in the CSV file):
Current plot
And here's the background image on its own: Cayuga Lake
I want the map to be regularly updated as new coordinates are added to the CSV file. How can this be done? I've looked into animation tools but I'm having trouble retaining the background image of the map while updating the plot. For reference, the CSV file "cayugacoords.txt" looks like this:
longitude,latitude
-76.51,42.46
-76.511,42.46
-76.5105,42.46
Thank you!
An alternative solution which updates only the points on the background image is provided by using ax.collections = [] which clears ALL lines plotted on the image. For the sake of demonstration I plot each coordinate per frame.
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
df = pd.read_csv("cayugacoords.txt")
BoundaryBox = [-76.5119, -76.5013, 42.4596, 42.4642]
ruh_m = plt.imread('map.png')
fig, ax = plt.subplots(figsize=(8, 7))
ax.set_title('Cayuga Lake Shore')
ax.set_xlim(BoundaryBox[0], BoundaryBox[1])
ax.set_ylim(BoundaryBox[2], BoundaryBox[3])
ax.imshow(ruh_m, zorder=0, extent=BoundaryBox, aspect='equal')
def animate(nframe):
ax.collections = []
points = ax.scatter(df.longitude[nframe], df.latitude[nframe], zorder=1,
alpha=1, c='r', s=10)
return
anim = animation.FuncAnimation(fig, animate, frames=3)
This code worked for me. It seems quite hacky but it works. You can adjust the time.sleep to your liking.
from matplotlib import pyplot as plt
from IPython.display import clear_output
import pandas as pd
import numpy as np
import time
%matplotlib inline
ruh_m = plt.imread('map.png')
BoundaryBox = [-76.5119, -76.5013, 42.4596, 42.4642]
while True:
clear_output(wait=True)
df = pd.read_csv("cayugacoords.txt")
fig, ax = plt.subplots(figsize=(10, 10))
ax.scatter(df.longitude, df.latitude, zorder=1, alpha=1, c='r', s=10)
ax.set_title('Cayuga Lake Shore')
ax.set_xlim(BoundaryBox[0], BoundaryBox[1])
ax.set_ylim(BoundaryBox[2], BoundaryBox[3])
ax.imshow(ruh_m, zorder=0, extent=BoundaryBox, aspect='equal')
plt.show()
time.sleep(1E-3)
Related
I want to do an animated scatter plot with one only pair of x,y data for each frame.
The code I wrote creates an animated scatter plot but the old dots appear in the plot, that means that new dots are added on the plot, keeping the old ones.
For the code below I want a dot per frame like a moving dot on x axis and not adding one more value.
I tried with plt.clf() but then all data disappear.
%matplotlib notebook
from bokeh.plotting import figure, output_file, show
import pandas
import numpy as np
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation, PillowWriter
import matplotlib.pyplot as plt
writer = PillowWriter(fps=10)
list_x=[1,2,3,4,5,6,7,8,9]
list_y=[5,5,5,5,5,5,5,5,5]
def plot(listax, listay):
plt.scatter(listax, listay, c='blue', alpha=0.5)
plt.show()
fig2 = plt.figure()
plt.xlim([0, 10])
plt.ylim([0, 10])
with writer.saving(fig2, "plotvideo.gif", 100):
for i in range(0, len(list_x)):
x_value = list_x[i]
y_value = list_y[i]
writer.grab_frame()
plot(x_value, y_value)
Use the .remove() method on the point objects to remove them from the figure.
I would try this:
from bokeh.plotting import figure, output_file, show
import pandas
import numpy as np
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation, PillowWriter
import matplotlib.pyplot as plt
import time
writer = PillowWriter(fps=10)
list_x=[1,2,3,4,5,6,7,8,9]
list_y=[5,5,5,5,5,5,5,5,5]
points = []
def plot(listax, listay, j):
points.append(plt.scatter(listax[j], listay[j], c='blue', alpha=0.5))
if len(points) == 2:
points[0].remove()
points.pop(0)
plt.show(block=False)
fig2 = plt.figure()
plt.xlim([0, 10])
plt.ylim([0, 10])
with writer.saving(fig2, "plotvideo.gif", 100):
for i in range(0, len(list_x)):
x_value = list_x
y_value = list_y
writer.grab_frame()
print(points)
plot(x_value, y_value, i)
See this link for a better explanation (albeit with a different implementation):
How to remove points from a plot?
I am working on a code to visualize slices from a volume. I have no problem when I have to visualize only one volume as shown on the first code.
#Code working properly
import numpy as np
import matplotlib.pyplot as plt
from skimage.morphology import ball
plt.ion()
plt.show()
sphere = ball(50)
for i in range(len(sphere[0,0])):
plt.clf()
plt.title(i)
plt.imshow(sphere[:,:,i],cmap='gray')
plt.axis('off')
plt.draw()
plt.pause(0.01)
I am having trouble when I want to create a subplot and visualize more than one image simultaneously. With this code I’m able to visualize the volume but it takes too long, and it lags a lot. I have tried clearing the axes before each iteration, but I couldn’t make it work.
This is where my current attempt is at:
#Code that is not working properly
import numpy as np
import matplotlib.pyplot as plt
from skimage.morphology import ball
sphere = ball(50)
plt.ion()
plt.show()
fig, grilla = plt.subplots(1,2, figsize = (20,10))
for i in range(len(sphere[0,0])):
grilla[0].imshow(sphere[:,:,i], cmap = 'gray')
grilla[0].axis('off')
grilla[0].set_title('Slice' +str(i))
grilla[1].imshow(sphere[:,:,i], cmap = 'gray')
grilla[1].axis('off')
grilla[1].set_title('Slice' +str(i))
plt.draw()
plt.pause(0.01)
So I am trying to create histograms for each specific variable in my dataset and then save it as a PNG file.
My code is as follows:
import pandas as pd
import matplotlib.pyplot as plt
x=combined_databook.groupby('x_1').hist()
x.figure.savefig("x.png")
I keep getting "AttributeError: 'Series' object has no attribute 'figure'"
Use matplotlib to create a figure and axis objects, then tell pandas which axes to plot on using the ax argument. Finally, use matplotlib (or the fig) to save the figure.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Sample Data (3 groups, normally distributed)
df = pd.DataFrame({'gp': np.random.choice(list('abc'), 1000),
'data': np.random.normal(0, 1, 1000)})
fig, ax = plt.subplots()
df.groupby('gp').hist(ax=ax, ec='k', grid=False, bins=20, alpha=0.5)
fig.savefig('your_fig.png', dpi=200)
your_fig.png
Instead of using *.hist() I would use matplotlib.pyplot.hist().
Example :
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
y =[10, 20,30,40,100,200,300,400,1000,2000]
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
ax.plot(x, y, label='$y = Values')
plt.title('my plot')
ax.legend()
plt.show()
fig.savefig('tada.png')
I have been trying to create a horizontal bar chart where the title and data change during each frame. The issue I am running into is that if I use blit=True, the data updates but not the title. When I use blit=False the title changes but not the data (it only increases).
I have read through dozens of answers and tried everything including set_title and set_text but I am at a total loss. Thank you for your help.
%matplotlib
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
import csv
people = ('','Jim', 'Dan')
plt.rcdefaults()
fig, ax = plt.subplots()
y_pos = np.arange(len(people))
ax.set_xlim(0,10)
ax.set_yticks(y_pos)
ax.set_yticklabels(people)
ax.invert_yaxis()
ax.set_xlabel('Skill')
titleList=['Basketball','Hockey']
df=[[0,5,7],[0,4,9]]
title = ax.text(0.5,0.95, "Test", bbox={'facecolor':'w', 'alpha':0.5, 'pad':5},transform=ax.transAxes, ha="center")
def animate(i):
# Example data
while i<2:
ax.set_yticks(y_pos)
ax.set_yticklabels(people)
ax.set_xlabel(titleList[i])
performance=df[i]
title.set_text(str(titleList[i]))
line= ax.barh(y_pos, performance, align='center',
color='blue', ecolor='None')
return line
ani = animation.FuncAnimation(fig,animate, frames=5, blit=True
,interval=2000,repeat=False)
plt.show()
You call a FuncAnimation() with frames=5, animate(i) will thus try to set label and titel via titleList[i] which however only has 2 entries. Especially with blit=True, this will throw errors.
Your animate() functions returns line; if we print(line), we find it is rather a <BarContainer object of 3 artists> than a line, i.e. the three rectangles of barh(). You should rather store the barh() in rects and then return [rect for rect in rects], see this question
Complete Code:
import pandas as pd
import matplotlib as mpl ## uncomment this if you are running this on a Mac
mpl.use('TkAgg') ## and want to use blit=True
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
import csv
people = ('','Jim', 'Dan')
plt.rcdefaults()
fig, ax = plt.subplots()
y_pos = np.arange(len(people))
ax.set_xlim(0,10)
ax.set_yticks(y_pos)
ax.set_yticklabels(people)
ax.invert_yaxis()
ax.set_xlabel('Skill')
titleList=['Basketball','Hockey']
df=[[0,5,7],[0,4,9]]
def animate(i):
# Example data
while i<2:
ax.set_yticks(y_pos)
ax.set_yticklabels(people)
ax.set_xlabel(titleList[i])
performance=df[i]
title = ax.text(0.5,0.95,str(titleList[i]), bbox={'facecolor':'w', 'alpha':0.5, 'pad':5},transform=ax.transAxes, ha="center")
rects = ax.barh(y_pos, performance, align='center',
color='blue', ecolor='None')
return [rect for rect in rects] + [title]
ani = animation.FuncAnimation(fig,animate, frames=2, blit=True
,interval=2000,repeat=False)
plt.show()
I'd like to update a matrix text in dynamic by using animation function of matplotlib. But I found that if the data array is too large , the animation will become very very slow. Is there any way to improve it ?
from matplotlib import animation
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(10,20))
def updatefig(i):
plt.cla()
ax.grid()
data = np.random.rand(50,50)
ax.set_xticks(np.arange(data.shape[1]+1))
ax.set_yticks(np.arange(data.shape[0]+1))
for y in range(data.shape[0]):
for x in range(data.shape[1]):
plt.text(x + 0.5 , y + 0.5, '%.1f' % data[y, x],horizontalalignment='center',verticalalignment='center',color='b',size = 6)
plt.draw()
anim = animation.FuncAnimation(fig, updatefig,interval=50)
plt.show()
Actually, I wants to create a heatmmap plot with data values like below link. But use annotations is the only way i could figure out.
Heamap with values
Find a workaround by import seaborn module.
But how to avoid the graph keep flashing
from matplotlib import animation
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
fig, ax = plt.subplots(figsize=(10,20))
sns.set()
def updatefig(i):
plt.clf()
data = np.random.rand(10,10)
sns.heatmap(data, annot=True, linewidths=.5,cbar=False)
anim = animation.FuncAnimation(fig, updatefig,interval=50)
plt.show()