[英]Plotly: How to animate a bar chart with multiple groups using plotly express?
I have a dataframe that looks like this:我有一个看起来像这样的数据框:
I want to have one bar for old freq and one for new freq.我想要一个用于旧频率和一个用于新频率的条。 Currently I have graph that looks like this:
目前我的图表如下所示:
This is what the code looks like:这是代码的样子:
freq_df['date'] = pd.to_datetime(freq_df['date'])
freq_df['hour'] = freq_df['hour'].astype(str)
fig = px.bar(freq_df, x="hour", y="old freq",hover_name = "date",
animation_frame= freq_df.date.dt.day)
fig.update_layout(transition = {'duration': 2000})
How do I add another bar?我如何添加另一个酒吧?
Explanation about DF:关于DF的说明:
It has frequencies relevant to each hour in a specific date.它具有与特定日期中的每个小时相关的频率。
Edit: One approach could be to create a category column and add old and new freq and assign values in another freq column.编辑:一种方法可能是创建一个类别列并添加旧的和新的频率并在另一个频率列中分配值。 How do I do that :p ?
我该怎么做:p?
Edit: Here is the DF编辑:这是DF
,date,hour,old freq,new freq
43,2020-09-04,18,273,224.0
44,2020-09-04,19,183,183.0
45,2020-09-04,20,99,111.0
46,2020-09-04,21,130,83.0
47,2020-09-04,22,48,49.0
48,2020-09-04,23,16,16.0
49,2020-09-05,0,8,6.0
50,2020-09-05,1,10,10.0
51,2020-09-05,2,4,4.0
52,2020-09-05,3,7,7.0
53,2020-09-05,4,25,21.0
54,2020-09-05,5,114,53.0
55,2020-09-05,6,284,197.0
56,2020-09-05,7,343,316.0
57,2020-09-05,8,418,419.0
58,2020-09-05,9,436,433.0
59,2020-09-05,10,469,396.0
60,2020-09-05,11,486,300.0
61,2020-09-05,12,377,140.0
62,2020-09-05,13,552,103.0
63,2020-09-05,14,362,117.0
64,2020-09-05,15,512,93.0
65,2020-09-05,16,392,41.0
66,2020-09-05,17,268,31.0
67,2020-09-05,18,223,30.0
68,2020-09-05,19,165,24.0
69,2020-09-05,20,195,15.0
70,2020-09-05,21,90,
71,2020-09-05,22,46,1.0
72,2020-09-05,23,17,1.0
1. Perform a slight transformation of your data using pd.wide_to_long : 1.使用pd.wide_to_long对数据进行轻微转换:
df_long = pd.wide_to_long(freq_df, stubnames='freq',
i=['date', 'hour'], j='type',
sep='_', suffix='\w+').reset_index()
2. Plot two groups of bar traces using: 2. 使用以下方法绘制两组条形轨迹:
fig1 = px.bar(df_long, x='hour', y = 'freq', hover_name = "date", color='type',
animation_frame= 'date', barmode='group')
If I understand your question correctly, you'd like to animate a bar chart where you've got one bar for each hour for your two frequencies freq_old
and freq_new
like this:如果我正确理解您的问题,您想为条形图制作动画,其中每小时为两个频率
freq_old
和freq_new
设置一个条形图,如下所示:
If that's the case, then you sample data is no good since your animation critera is hour
per date
and you've only got four observations (hours) for 2020-09-04
and then 24 observations for 2020-09-05
.如果是这种情况,那么您的样本数据就不好了,因为您的动画标准是每个
date
hour
数,并且您只有2020-09-04
四个观察值(小时)和2020-09-04
24 个观察2020-09-05
。 But don't worry, since your question triggered my interest I just as well made some sample data that will in fact work the way you seem to want them to.但别担心,既然你的问题引起了我的兴趣,我也制作了一些示例数据,这些数据实际上会按照你希望的方式工作。
The only real challenge is that px.bar
will not accept y= [freq_old, freq_new]
, or something to that effect, to build your two bar series of different categories for you.唯一真正的挑战是
px.bar
不会接受y= [freq_old, freq_new]
或类似的东西来为您构建不同类别的两个条形系列。 But you can make px.bar
build two groups of bars by providing a color
argument.但是您可以通过提供
color
参数使px.bar
构建两组条形。 However, you'll need a column to identify your different freqs
like this:但是,您需要一列来识别您的不同
freqs
如下所示:
0 new
1 old
2 new
3 old
4 new
5 old
6 new
7 old
8 new
9 old
In other words, you'll have to transform your dataframe, which originally has a wide format, to a long format like this:换句话说,您必须将最初具有宽格式的数据帧转换为长格式,如下所示:
date hour type day freq
0 2020-01-01 0 new 1 7.100490
1 2020-01-01 0 old 1 2.219932
2 2020-01-01 1 new 1 7.015528
3 2020-01-01 1 old 1 8.707323
4 2020-01-01 2 new 1 7.673314
5 2020-01-01 2 old 1 2.067192
6 2020-01-01 3 new 1 9.743495
7 2020-01-01 3 old 1 9.186109
8 2020-01-01 4 new 1 3.737145
9 2020-01-01 4 old 1 4.884112
And that's what this snippet does:这就是这个片段的作用:
df_long = pd.wide_to_long(freq_df, stubnames='freq',
i=['date', 'hour'], j='type',
sep='_', suffix='\w+').reset_index()
stubnames
uses a prefix to identify the columns you'd like to stack into a long format. stubnames
使用前缀来标识您想要堆叠为长格式的列。 And that's why I've renamed new_freq
and old_freq
to freq_new
and freq_old
, respectively.这就是我将
freq_new
和freq_old
分别重命名为new_freq
和old_freq
的原因。 j='type'
simply takes the last parts of your cartegory names using sep='_'
and produces the column that we need to tell the freqs from eachother: j='type'
简单地使用sep='_'
获取类别名称的最后部分,并生成我们需要告诉彼此频率的列:
type
old
new
old
...
suffix='\\w+'
tells pd.wide_to_long
that we're using non-integers as suffixes. suffix='\\w+'
告诉pd.wide_to_long
我们使用非整数作为后缀。 And that's it!就是这样!
# imports
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
import random
# sample data
observations = 24*5
np.random.seed(5); cols = list('a')
freq_old = np.random.uniform(low=-1, high=1, size=observations).tolist()
freq_new = np.random.uniform(low=-1, high=1, size=observations).tolist()
date = [t[:10] for t in pd.date_range('2020', freq='H', periods=observations).format()]
hour = [int(t[11:13].lstrip()) for t in pd.date_range('2020', freq='H', periods=observations).format()]
# sample dataframe of a wide format such as yours
freq_df=pd.DataFrame({'date': date,
'hour':hour,
'freq_new':freq_new,
'freq_old':freq_old})
freq_df['day']=pd.to_datetime(freq_df['date']).dt.day
# attempt to make my random data look a bit
# like your real world data.
# but don't worry too much about that...
freq_df.freq_new = abs(freq_df.freq_new.cumsum())
freq_df.freq_old = abs(freq_df.freq_old.cumsum())
# sample dataframe of a long format that px.bar likes
df_long = pd.wide_to_long(freq_df, stubnames='freq',
i=['date', 'hour'], j='type',
sep='_', suffix='\w+').reset_index()
# plotly express bar chart with multiple bar groups.
fig = px.bar(df_long, x='hour', y = 'freq', hover_name = "date", color='type',
animation_frame= 'date', barmode='group')
# set up a sensible range for the y-axis
fig.update_layout(yaxis=dict(range=[df_long['freq'].min()*0.8,df_long['freq'].max()*1.2]))
fig.show()
I was able to create the bars for both the old and new frequencies, however using a separate plot for each day (Plotly Express Bar Charts don't seem to have support for multiple series).我能够为旧的和新的频率创建条形图,但是每天使用一个单独的图(Plotly Express 条形图似乎不支持多个系列)。 Here is the code for doing so:
这是这样做的代码:
# Import packages
import pandas as pd
import numpy as np
import plotly.graph_objs as go
import plotly
import plotly.express as px
from plotly.offline import init_notebook_mode, plot, iplot, download_plotlyjs
init_notebook_mode(connected=True)
plotly.offline.init_notebook_mode(connected=True)
# Start formatting data
allDates = np.unique(df.date)
numDates = allDates.shape[0]
print(numDates)
for i in range(numDates):
df = original_df.loc[original_df.date == allDates[i]]
oldFreqData = go.Bar(x=df["hour"].to_numpy(), y=df["old_freq"].to_numpy(), name="Old Frequency")
newFreqData = go.Bar(x=df["hour"].to_numpy(), y=df["new_freq"].to_numpy(), name="New Frequency")
fig = go.Figure(data=[oldFreqData,newFreqData])
fig.update_layout(title=allDates[i])
fig.update_xaxes(title='Hour')
fig.update_yaxes(title='Frequency')
fig.show()
where df
is the dataframe DF from your question.其中
df
是您问题中的数据框 DF。
However, if you prefer the use of the animation frame from Plotly Express, you can have two separate plots: one for old frequencies and one for new using this code:但是,如果您更喜欢使用 Plotly Express 中的动画帧,您可以有两个单独的图:一个用于旧频率,另一个用于使用以下代码的新频率:
# Reformat data
df = original_df
dates = pd.to_datetime(np.unique(df.date)).strftime('%Y-%m-%d')
numDays = dates.shape[0]
print(numDays)
hours = np.arange(0,24)
numHours = hours.shape[0]
allDates = []
allHours = []
oldFreqs = []
newFreqs = []
for i in range(numDays):
for j in range(numHours):
allDates.append(dates[i])
allHours.append(j)
if (df.loc[df.date == dates[i]].loc[df.hour == j].shape[0] != 0): # If data not missing
oldFreqs.append(df.loc[df.date == dates[i]].loc[df.hour == j].old_freq.to_numpy()[0])
newFreqs.append(df.loc[df.date == dates[i]].loc[df.hour == j].new_freq.to_numpy()[0])
else:
oldFreqs.append(0)
newFreqs.append(0)
d = {'Date': allDates, 'Hour': allHours, 'Old_Freq': oldFreqs, 'New_Freq': newFreqs, 'Comb': combined}
df2 = pd.DataFrame(data=d)
# Create px plot with animation
fig = px.bar(df2, x="Hour", y="Old_Freq", hover_data=["Old_Freq","New_Freq"], animation_frame="Date")
fig.show()
fig2 = px.bar(df2, x="Hour", y="New_Freq", hover_data=["Old_Freq","New_Freq"], animation_frame="Date")
fig2.show()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.