Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
794 views
in Technique[技术] by (71.8m points)

scatter - Matplotlib: animate scatterplot with time axis

I used this question to make an animated scatterplot like this:

import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.collections import PathCollection


df = pd.DataFrame({"x": [1, 2, 6, 4, 5, 6], "y": [1, 4, 36, 16, 25, 36]})
plt.ion()
fig: plt.Figure = plt.figure
ax = fig.subplots()
path_collection: PathCollection = ax.scatter(df.loc[0:2, "x"], df.loc[0:2, "y"])
# Note: I don't use pandas built in DataFrame.plot.scatter function so I can get the PathCollection object to later change the scatterpoints.
fig.canvas.draw()
path_collection.set_offsets([[row.x, row.y] for index, row in df.loc[3:].iterrows()])
# Due to the format of offset (array-like (N,2)) this seems to be the best way to provide the data.

fig.canvas.draw()

This works perfectly but I'd like to have times on the x-axis so I tried changing the above code to this:

import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.collections import PathCollection

df = pd.DataFrame({'time': [pd.Timestamp('2021-02-04 00:00:01'),
                            pd.Timestamp('2021-02-04 00:00:02'),
                            pd.Timestamp('2021-02-04 00:00:10'),
                            pd.Timestamp('2021-02-04 00:00:05'),
                            pd.Timestamp('2021-02-04 00:00:06'),
                            pd.Timestamp('2021-02-04 00:00:08')],
                   'y': [5, 6, 10, 8, 9, 10]})
fig: plt.Figure = plt.figure()
ax = fig.subplots()
sc: PathCollection = ax.scatter(df.loc[0:2, "time"], df.loc[0:2, "y"])
fig.canvas.draw()    
sc.set_offsets([[row.time, row.y] for index, row in df.loc[3:].iterrows()])

fig.canvas.draw()

The second to last line throws this error: TypeError: float() argument must be a string or a number, not 'Timestamp'. This seems to be caused by the fact that PathCollection stores it _offsets as a numpy array which cannot contain a Timestamp. So I was wondering, is there a workaround to animate scatterpoints with a time axis?

Thanks in advance.

question from:https://stackoverflow.com/questions/66048025/matplotlib-animate-scatterplot-with-time-axis

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For anyone who has the same problem, I found a solution that is probably far from ideal but it does the job. It turns out that PathCollection stores the times as np.float64 representing the days since 1/1/0001. And since using set_offset seems to be only possible with array-like objects of size (N, 2), I reformated the pd.Timestamp to days since 1/1/0001 like this:

time = pd.Timestamp('2021-02-04 00:00:01')
sec_since_1970 = time.timestamp()           # pd.Timestamp.timestamp() gives seconds since epox.
days_since_1970 = sec_since_1970/60/60/24   # Seconds to days.
days_since_0001 = days_since_1970 + 719163  # 719163 = number of days from 1/1/0001 until 1/1/1970  

Implementing this in the question gives the following:

df = pd.DataFrame({'time': [pd.Timestamp('2021-02-04 00:00:01'),
                            pd.Timestamp('2021-02-04 00:00:02'),
                            pd.Timestamp('2021-02-04 00:00:10'),
                            pd.Timestamp('2021-02-04 00:00:05'),
                            pd.Timestamp('2021-02-04 00:00:06'),
                            pd.Timestamp('2021-02-04 00:00:08')],
                   'y': [5, 6, 10, 8, 9, 10]})
data = [[719163 + row.time.timestamp()/60/60/24, row.y] for index, row in df.loc[3:].iterrows()]
sc.set_offsets(data)
# Set axis limits
ax.set_ylim(bottom=df.y.loc[3:].min() -1, top=df.y.loc[3:].max()+1)
ax.set_xlim(left= (df.time.loc[3:].min().timestamp()-1)/60/60/24+719163,
            right=(df.time.loc[3:].max().timestamp()+1)/60/60/24+719163)
fig.canvas.draw()

So this solves the problem, it is probably not the most efficient way but for small datasets, it works fine.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...