如何使用 plotly express 在 x 轴上绘制一些随时间变化的事件?
How to graph some events with time on x-axis with plotly express?
我正在尝试使用 plotly dash 构建仪表板,我的数据如下所示:
这里是文本数据:
data={'SECTOR':['KHN','KHN','KHN','KHN','KHN','KHN'],
"NAME": ["ELSILATE","ELSILATE","ELSILATE","ELSILATE","ELSILATE","ELSILATE"],
"TIME" : ["4:00", "4:25","4:45", "5:03", "6:00","7:00"],
"POINT_NAME":["ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN"],
"MESSAGE":["Change Status","Operator Control","Return to Normal",
"Operator Control", "Return to Normal","Return to Normal"],
"VALUE":["OPEN","CLOSE","NORMAL","OPEN","NORMAL","CLOSE"],
"ch_open":[1,0,0,0,0,0],
"ch_close":[0,2,0,0,0,0],
"normal_open":[0,0,3,0,0,0],
"command_open":[0,0,0,4,0,0],
"command_close":[0,0,0,0,5,0],
"normal_close":[0,0,0,0,0,6]}
df_cb=pd.DataFrame(data)
我使用 pandas 来显示每个事件的编号。
我想显示时间与 open/close/normal/control、关闭等事件的关系。对于每个部门,名称,广告 point_name !
我这样搞定了
来自互联网上的代码,但我想不出一种在 x 轴上显示时间的方法
代码如下:
import matplotlib.pyplot as plt
import numpy as np
#for a specific line cb :
df_ex = df_cb.loc[df_cb['POINT_NAME'].str.contains('ZERAEIN')]
ch_open=list(df_ex["ch_open"])
ch_close=list(df_ex["ch_close"])
normal_open=list(df_ex["normal_open"])
normal_close=list(df_ex["normal_close"])
command_open=list(df_ex["command_open"])
command_close=list(df_ex["command_close"])
data = [ch_open,
ch_close,
normal_open,
normal_close,
command_open,
command_close]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.axes.get_yaxis().set_visible(False)
ax.set_aspect(1)
def avg(a, b):
return (a + b) / 2.0
for y, row in enumerate(data):
for x, col in enumerate(row):
x1 = [x, x+1]
y1 = [0, 0]
y2 = [1, 1]
if col == 1:
plt.fill_between(x1, y1, y2=y2, color='yellow')
plt.text(avg(x1[0], x1[1]), avg(y1[0], y2[0]), "A",
horizontalalignment='center',
verticalalignment='center')
if col == 2:
plt.fill_between(x1, y1, y2=y2, color='red')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "B",
horizontalalignment='center',
verticalalignment='center')
if col == 3:
plt.fill_between(x1, y1, y2=y2, color='orange')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "C",
horizontalalignment='center',
verticalalignment='center')
if col == 4:
plt.fill_between(x1, y1, y2=y2, color='brown')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "D",
horizontalalignment='center',
verticalalignment='center')
if col == 5:
plt.fill_between(x1, y1, y2=y2, color='green')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "E",
horizontalalignment='center',
verticalalignment='center')
if col == 6:
plt.fill_between(x1, y1, y2=y2, color='black')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "F",
horizontalalignment='center',
verticalalignment='center')
plt.ylim(1, 0)
plt.show()
最好是这样,时间显示为 x 轴:
我把TIME
转换成datetime
df_ex['TIME'] = pd.to_datetime(df_ex['TIME'])
并且迟到使用 shift(-1)
从当前行的下一行开始有时间作为 TIME_END
。
df_ex['TIME_END'] = df_ex['TIME'].shift(-1)
还需要在最后 'TIME_END'
中添加一些值,而不是 NaT
df_ex.loc[last_index, 'TIME_END'] = df_ex.loc[last_index, 'TIME'] + dt.timedelta(minutes=25)
这样我就把 start
和 end
排成一行,我可以用它们画矩形。
for index, row in df_ex.iterrows():
x = [row['TIME'], row['TIME_END']]
y1 = [0, 0]
y2 = [1, 1]
ax.fill_between(x, y1, y2=y2, color=color)
我也用if/else
为不同的VALUE
设置不同的颜色。
完整的工作代码:
import pandas as pd
import matplotlib.pyplot as plt
import datetime as dt
data = {
'SECTOR': ['KHN','KHN','KHN','KHN','KHN','KHN'],
"NAME": ["ELSILATE","ELSILATE","ELSILATE","ELSILATE","ELSILATE","ELSILATE"],
"TIME": ["4:00", "4:25","4:45", "5:03", "6:00","7:00"],
"POINT_NAME": ["ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN"],
"MESSAGE": ["Change Status","Operator Control","Return to Normal",
"Operator Control", "Return to Normal","Return to Normal"],
"VALUE": ["OPEN","CLOSE","NORMAL","OPEN","NORMAL","CLOSE"],
}
df_cb = pd.DataFrame(data)
mask = df_cb['POINT_NAME'].str.contains('ZERAEIN')
df_ex = df_cb[mask].copy()
# convert to datetime
df_ex['TIME'] = pd.to_datetime(df_ex['TIME'])
# move one row up
df_ex['TIME_END'] = df_ex['TIME'].shift(-1)
# put some value in last row (instead of NaT)
#df_ex['TIME_END'].iloc[-1] = df_ex['TIME'].iloc[-1] + dt.timedelta(minutes=25) # warning: set value on copy
last_index = df_ex.index[-1]
df_ex.loc[last_index, 'TIME_END'] = df_ex.loc[last_index, 'TIME'] + dt.timedelta(minutes=25)
# --- plot ---
fig, ax = plt.subplots(1, figsize=(16,3))
for index, row in df_ex.iterrows():
#print(index, row)
x = [row['TIME'], row['TIME_END']]
y1 = [0, 0]
y2 = [1, 1]
if row['VALUE'] == 'OPEN':
color = 'green'
elif row['VALUE'] == 'CLOSE':
color = 'red'
else:
color = 'yellow'
ax.fill_between(x, y1, y2=y2, color=color)
center_x = x[0] + (x[1] - x[0])/2
center_y = (y2[0] + y1[0]) / 2
#print(center_x, center_y)
ax.text(center_x, center_y, row['VALUE'], horizontalalignment='center', verticalalignment='center')
plt.show()
在 X-axis 上它显示 date/day 的时间(因为 TIME
可以在不同的日期)并且它需要更改 xticks
以设置不同的文本 - 但是我跳过这个问题。
如果你对不同的VALUE
使用不同的值y1
y2
那么你可以得到
or index, row in df_ex.iterrows():
#print(index, row)
if row['VALUE'] == 'OPEN':
color = 'green'
y = 1
elif row['VALUE'] == 'CLOSE':
color = 'red'
y = 2
else:
color = 'yellow'
y = 0
x = [row['TIME'], row['TIME_END']]
y1 = [y, y]
y2 = [y+1, y+1]
ax.fill_between(x, y1, y2=y2, color=color)
center_x = x[0] + (x[1] - x[0])/2
center_y = (y2[0] + y1[0]) / 2
#print(center_x, center_y)
ax.text(center_x, center_y, row['VALUE'], horizontalalignment='center', verticalalignment='center')
顺便说一句:
与此同时,我意识到这种类型的图表可以称为 gantt 并在 Google 中使用这个词,我在 barh
或 broken_barh
中发现了一些有趣的结果,但示例需要将时间转换为天数或秒数并进行更多其他计算。
查看一些文章 - 但他们可能需要登录门户。
Gantt charts with Python’s Matplotlib | by Thiago Carvalho | Towards Data Science
完整代码:https://gist.github.com/Thiagobc23/ad0f228dd8a6b1c9a9e148f17de5b4b0
Create an Advanced Gantt Chart in Python | by Abhijith Chandradas | Geek Culture | Medium
我正在尝试使用 plotly dash 构建仪表板,我的数据如下所示:
这里是文本数据:
data={'SECTOR':['KHN','KHN','KHN','KHN','KHN','KHN'],
"NAME": ["ELSILATE","ELSILATE","ELSILATE","ELSILATE","ELSILATE","ELSILATE"],
"TIME" : ["4:00", "4:25","4:45", "5:03", "6:00","7:00"],
"POINT_NAME":["ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN"],
"MESSAGE":["Change Status","Operator Control","Return to Normal",
"Operator Control", "Return to Normal","Return to Normal"],
"VALUE":["OPEN","CLOSE","NORMAL","OPEN","NORMAL","CLOSE"],
"ch_open":[1,0,0,0,0,0],
"ch_close":[0,2,0,0,0,0],
"normal_open":[0,0,3,0,0,0],
"command_open":[0,0,0,4,0,0],
"command_close":[0,0,0,0,5,0],
"normal_close":[0,0,0,0,0,6]}
df_cb=pd.DataFrame(data)
我使用 pandas 来显示每个事件的编号。 我想显示时间与 open/close/normal/control、关闭等事件的关系。对于每个部门,名称,广告 point_name !
我这样搞定了
来自互联网上的代码,但我想不出一种在 x 轴上显示时间的方法
代码如下:
import matplotlib.pyplot as plt
import numpy as np
#for a specific line cb :
df_ex = df_cb.loc[df_cb['POINT_NAME'].str.contains('ZERAEIN')]
ch_open=list(df_ex["ch_open"])
ch_close=list(df_ex["ch_close"])
normal_open=list(df_ex["normal_open"])
normal_close=list(df_ex["normal_close"])
command_open=list(df_ex["command_open"])
command_close=list(df_ex["command_close"])
data = [ch_open,
ch_close,
normal_open,
normal_close,
command_open,
command_close]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.axes.get_yaxis().set_visible(False)
ax.set_aspect(1)
def avg(a, b):
return (a + b) / 2.0
for y, row in enumerate(data):
for x, col in enumerate(row):
x1 = [x, x+1]
y1 = [0, 0]
y2 = [1, 1]
if col == 1:
plt.fill_between(x1, y1, y2=y2, color='yellow')
plt.text(avg(x1[0], x1[1]), avg(y1[0], y2[0]), "A",
horizontalalignment='center',
verticalalignment='center')
if col == 2:
plt.fill_between(x1, y1, y2=y2, color='red')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "B",
horizontalalignment='center',
verticalalignment='center')
if col == 3:
plt.fill_between(x1, y1, y2=y2, color='orange')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "C",
horizontalalignment='center',
verticalalignment='center')
if col == 4:
plt.fill_between(x1, y1, y2=y2, color='brown')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "D",
horizontalalignment='center',
verticalalignment='center')
if col == 5:
plt.fill_between(x1, y1, y2=y2, color='green')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "E",
horizontalalignment='center',
verticalalignment='center')
if col == 6:
plt.fill_between(x1, y1, y2=y2, color='black')
plt.text(avg(x1[0], x1[0]+1), avg(y1[0], y2[0]), "F",
horizontalalignment='center',
verticalalignment='center')
plt.ylim(1, 0)
plt.show()
最好是这样,时间显示为 x 轴:
我把TIME
转换成datetime
df_ex['TIME'] = pd.to_datetime(df_ex['TIME'])
并且迟到使用 shift(-1)
从当前行的下一行开始有时间作为 TIME_END
。
df_ex['TIME_END'] = df_ex['TIME'].shift(-1)
还需要在最后 'TIME_END'
中添加一些值,而不是 NaT
df_ex.loc[last_index, 'TIME_END'] = df_ex.loc[last_index, 'TIME'] + dt.timedelta(minutes=25)
这样我就把 start
和 end
排成一行,我可以用它们画矩形。
for index, row in df_ex.iterrows():
x = [row['TIME'], row['TIME_END']]
y1 = [0, 0]
y2 = [1, 1]
ax.fill_between(x, y1, y2=y2, color=color)
我也用if/else
为不同的VALUE
设置不同的颜色。
完整的工作代码:
import pandas as pd
import matplotlib.pyplot as plt
import datetime as dt
data = {
'SECTOR': ['KHN','KHN','KHN','KHN','KHN','KHN'],
"NAME": ["ELSILATE","ELSILATE","ELSILATE","ELSILATE","ELSILATE","ELSILATE"],
"TIME": ["4:00", "4:25","4:45", "5:03", "6:00","7:00"],
"POINT_NAME": ["ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN","ZERAEIN"],
"MESSAGE": ["Change Status","Operator Control","Return to Normal",
"Operator Control", "Return to Normal","Return to Normal"],
"VALUE": ["OPEN","CLOSE","NORMAL","OPEN","NORMAL","CLOSE"],
}
df_cb = pd.DataFrame(data)
mask = df_cb['POINT_NAME'].str.contains('ZERAEIN')
df_ex = df_cb[mask].copy()
# convert to datetime
df_ex['TIME'] = pd.to_datetime(df_ex['TIME'])
# move one row up
df_ex['TIME_END'] = df_ex['TIME'].shift(-1)
# put some value in last row (instead of NaT)
#df_ex['TIME_END'].iloc[-1] = df_ex['TIME'].iloc[-1] + dt.timedelta(minutes=25) # warning: set value on copy
last_index = df_ex.index[-1]
df_ex.loc[last_index, 'TIME_END'] = df_ex.loc[last_index, 'TIME'] + dt.timedelta(minutes=25)
# --- plot ---
fig, ax = plt.subplots(1, figsize=(16,3))
for index, row in df_ex.iterrows():
#print(index, row)
x = [row['TIME'], row['TIME_END']]
y1 = [0, 0]
y2 = [1, 1]
if row['VALUE'] == 'OPEN':
color = 'green'
elif row['VALUE'] == 'CLOSE':
color = 'red'
else:
color = 'yellow'
ax.fill_between(x, y1, y2=y2, color=color)
center_x = x[0] + (x[1] - x[0])/2
center_y = (y2[0] + y1[0]) / 2
#print(center_x, center_y)
ax.text(center_x, center_y, row['VALUE'], horizontalalignment='center', verticalalignment='center')
plt.show()
在 X-axis 上它显示 date/day 的时间(因为 TIME
可以在不同的日期)并且它需要更改 xticks
以设置不同的文本 - 但是我跳过这个问题。
如果你对不同的VALUE
使用不同的值y1
y2
那么你可以得到
or index, row in df_ex.iterrows():
#print(index, row)
if row['VALUE'] == 'OPEN':
color = 'green'
y = 1
elif row['VALUE'] == 'CLOSE':
color = 'red'
y = 2
else:
color = 'yellow'
y = 0
x = [row['TIME'], row['TIME_END']]
y1 = [y, y]
y2 = [y+1, y+1]
ax.fill_between(x, y1, y2=y2, color=color)
center_x = x[0] + (x[1] - x[0])/2
center_y = (y2[0] + y1[0]) / 2
#print(center_x, center_y)
ax.text(center_x, center_y, row['VALUE'], horizontalalignment='center', verticalalignment='center')
顺便说一句:
与此同时,我意识到这种类型的图表可以称为 gantt 并在 Google 中使用这个词,我在 barh
或 broken_barh
中发现了一些有趣的结果,但示例需要将时间转换为天数或秒数并进行更多其他计算。
查看一些文章 - 但他们可能需要登录门户。
Gantt charts with Python’s Matplotlib | by Thiago Carvalho | Towards Data Science
完整代码:https://gist.github.com/Thiagobc23/ad0f228dd8a6b1c9a9e148f17de5b4b0
Create an Advanced Gantt Chart in Python | by Abhijith Chandradas | Geek Culture | Medium