如何使用plotlyexpress在x轴上绘制一些事件随时间变化的图表?

发布于 2025-01-12 03:17:12 字数 3623 浏览 0 评论 0原文

我正在尝试使用plotly dash构建一个仪表板,我的数据如下所示:

data

这里是文本数据:

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 来显示每个事件的数字。 我想显示时间与打开/关闭/正常/控制、关闭等事件的关系。对于每个扇区,名称,adn point_name !

我设法从互联网上的代码中得到这样的

output

但我想不出一种显示时间的方法在 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 轴,那就太好了:

output

I'm trying to build a dashboard using plotly dash and I have data that looks like this :

data

Here the text data:

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)

I used pandas to show a number for every event.
I want to show the time versus the event of open/close/normal/control,close,etc. for every sector, name, adn point_name !

I manage to get it like this

output

from a code on the internet but I can't think of a way to show time in x-axis

Here is the code:

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()

would be nice to have it like this with time shows as x-axis:

output

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓦然回首 2025-01-19 03:17:12

我将 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)

,这样我就有了 startend在一排中,我可以用它们来绘制矩形。

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 轴上,它显示带有日期/日期的时间(因为 TIME 可能位于不同的日期),并且需要更改 xticks< /code> 设置不同的文本 - 但是我跳过这个问题。


如果您对不同的 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< /code> 或 broken_barh 但示例需要将时间转换为天数或秒数并进行更多其他计算。

请参阅一些文章 - 但他们可能需要登录门户。

使用 Python 的 Matplotlib 绘制甘特图 |蒂亚戈·卡瓦略 | 作者:蒂亚戈·卡瓦略迈向数据科学

在此处输入图像描述

完整代码:https://gist.github.com/Thiagobc23/ad0f228dd8a6b1c9a9e148f17de5b4b0

在 Python 中创建高级甘特图 |通过 Abhijith Chandradas |极客文化|中等

I convert TIME to datetime

df_ex['TIME'] = pd.to_datetime(df_ex['TIME'])

And late use shift(-1) to have time from next row in current row as TIME_END.

df_ex['TIME_END'] = df_ex['TIME'].shift(-1)

It needs also to add some value in last 'TIME_END' instead of NaT

df_ex.loc[last_index, 'TIME_END'] = df_ex.loc[last_index, 'TIME'] + dt.timedelta(minutes=25)

This way I have start and end in one row and I can use them to draw rectangles.

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)

I also use if/else to set different color for different VALUE.


Full working code:

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()

enter image description here

On X-axis it displays time with date/day (because TIME can be in different days) and it would need to changes xticks to set different text - but I skip this problem.


If you use different values y1 y2 for different VALUE then you can get

enter image description here

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')

BTW:

Meanwhile I realized that this type of chart can be called gantt and using this word in Google I found some interesting results with barh or broken_barh but examples needed to convert time to number of days or seconds and make more other calculations.

See some articles - but they may need to login to portal.

Gantt charts with Python’s Matplotlib | by Thiago Carvalho | Towards Data Science

enter image description here

Full code: https://gist.github.com/Thiagobc23/ad0f228dd8a6b1c9a9e148f17de5b4b0

Create an Advanced Gantt Chart in Python | by Abhijith Chandradas | Geek Culture | Medium

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文