5

我有 5 个不同列的数据,它们的值彼此不同。

Actual gen  Storage Solar Gen   Total Gen   Frequency
  1464      1838    1804         18266        51 
  2330      2262    518          4900         51
  2195      923     919          8732         49
  2036      1249    1316         3438         48
  2910      534     1212         4271         47
  857       2452    1272         6466         50
  2331      990     2729         14083        51
  2604      767     2730         19037        47
  993       2606    705          17314        51
  2542      213     548          10584        52
  2030      942     304          11578        52
  562       414     2870         840          52
  1111      1323    337          19612        49   
  1863      2498    1992         18941        48
  1575      2262    1576         3322         48
  1223      657     661          10292        47
  1850      1920    2986         10130        48
  2786      1119    933          2680         52
  2333      1245    1909         14116        48
  1606      2934    1547         13767        51

因此,从这些数据中,我想绘制一个带有 3 个 y 轴的图形。一个代表frequency,第二个代表 ,Total Gen第三个代表Actual genStorageSolar Gen。频率应在辅助 Y 轴(右侧),其余应在左侧。

  • 对于频率,您可以看到值在 47 到 52 之间非常随机,这就是为什么它应该在右侧,如下所示: 在此处输入图像描述

  • 与其他人相比,Total Gen 值非常高,因为它们在 100-20000 之间,所以我无法将它们与其他人合并,如下所示: 在此处输入图像描述 我想要:

  • Y 轴标题 1 = 实际发电、存储和太阳能发电

  • Y 轴标题 2 = 总代

  • Y 轴标题 3 = 频率

我的做法:

import logging

import pandas as pd
import plotly.graph_objs as go
import plotly.offline as pyo
import xlwings as xw
from plotly.subplots import make_subplots

app = xw.App(visible=False)
try:
    wb = app.books.open('2020 10 08 0000 (Float).xlsx')
    sheet = wb.sheets[0]
    
    actual_gen = sheet.range('A2:A21').value
    frequency = sheet.range('E2:E21').value
    storage = sheet.range('B2:B21').value
    total_gen = sheet.range('D2:D21').value
    solar_gen = sheet.range('C2:C21').value

except Exception as e:
    logging.exception("Something awful happened!")
    print(e)
finally:
    app.quit()
    app.kill()

# Create figure with secondary y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])

# Add traces
fig.add_trace(
    go.Scatter(y=storage, name="BESS(KW)"),
)
fig.add_trace(
    go.Scatter(y=actual_gen, name="Act(KW)"),
)
fig.add_trace(
    go.Scatter(y=solar_gen, name="Solar Gen")
)
fig.add_trace(
    go.Scatter(x=x_values, y=total_gen, name="Total Gen",yaxis = 'y2')
)
fig.add_trace(
    go.Scatter(y=frequency, name="Frequency",yaxis = 'y1'),
)

fig.update_layout( title_text = '8th oct BESS',
    yaxis2=dict(title="BESS(KW)",titlefont=dict(color="red"), tickfont=dict(color="red")),
    yaxis3=dict(title="Actual Gen(KW)",titlefont=dict(color="orange"),tickfont=dict(color="orange"), anchor="free", overlaying="y2", side="left"),
    yaxis4=dict(title="Solar Gen(KW)",titlefont=dict(color="pink"),tickfont=dict(color="pink"), anchor="x2",overlaying="y2", side="left"),
    yaxis5=dict(title="Total Gen(KW)",titlefont=dict(color="cyan"),tickfont=dict(color="cyan"), anchor="free",overlaying="y2", side="left"),
    yaxis6=dict(title="Frequency",titlefont=dict(color="purple"),tickfont=dict(color="purple"), anchor="free",overlaying="y2", side="right"))

fig.show()

有人可以帮忙吗?

4

2 回答 2

4

这是一个如何创建多级 y 轴的示例。

本质上,关键是:

  • 在字典中为每个轴创建一个键layout,然后为该轴分配一条轨迹。
  • 将 设置为xaxis domain[0, 1](例如[0.2, 1])窄,从而将图形的左边缘向右推,为多级 y 轴腾出空间。

有关该主题的官方 Plotly 文档的链接。

为了让这个演示中的数据更容易阅读,我冒昧地将您的数据集存储为 CSV 文件,而不是 Excel - 然后使用该pandas.read_csv()函数将数据集加载到 apandas.DataFrame中,然后将其作为数据列传递给绘图函数.

例子:

读取数据集:

df = pd.read_csv('energy.csv')

示例绘图代码:

layout = {'title': '8th Oct BESS'}
traces = []

traces.append({'y': df['storage'], 'name': 'Storage'})
traces.append({'y': df['actual_gen'], 'name': 'Actual Gen'})
traces.append({'y': df['solar_gen'], 'name': 'Solar Gen'})
traces.append({'y': df['total_gen'], 'name': 'Total Gen', 'yaxis': 'y2'})
traces.append({'y': df['frequency'], 'name': 'Frequency', 'yaxis': 'y3'})

layout['xaxis'] = {'domain': [0.12, 0.95]}
layout['yaxis1'] = {'title': 'Actual Gen, Storage, Solar Gen', 'titlefont': {'color': 'orange'}, 'tickfont': {'color': 'orange'}}
layout['yaxis2'] = {'title': 'Total Gen', 'side': 'left', 'overlaying': 'y', 'anchor': 'free', 'titlefont': {'color': 'red'}, 'tickfont': {'color': 'red'}}
layout['yaxis3'] = {'title': 'Frequency', 'side': 'right', 'overlaying': 'y', 'anchor': 'x', 'titlefont': {'color': 'purple'}, 'tickfont': {'color': 'purple'}}
    
pio.show({'data': traces, 'layout': layout})

图形:

鉴于这些痕迹的性质,它们相互重叠,这可能使图形解释变得困难。

有几个选项可用:

  • 更改range每个 y 轴的参数,使轴仅占据图形的一部分。例如,如果数据集的范围为 0-5,则将相应的yaxis range参数设置为[-15, 5],这会将轨迹推到靠近图表顶部的位置。

  • 考虑使用子图,其中可以对相似的轨迹进行分组……或者每个轨迹都可以有自己的图形。 这是 Plotly 关于子图的文档。

在此处输入图像描述

评论(TL;DR):

此处显示的示例代码使用较低级别的 Plotly API,而不是诸如graph_objectsor之类的便利包装器express。原因是我(个人)觉得展示“幕后”发生的事情对用户很有帮助,而不是用方便的包装器掩盖底层代码逻辑。

这样,当用户需要修改图形的更精细细节时,他们将对Plotly 为底层图形引擎(orca)构建的lists 和s 有更好的理解。dict

于 2020-11-27T14:37:57.663 回答
2

这是我在 x 轴上绘制索引为 x 的任何数据帧的函数。应该支持任何大小的数据框

def plotly_multi(data):
    if data.shape[1]>2:
        fig = go.Figure()
        fig.add_trace(
            go.Scatter(x=data.index, y=data.iloc[:, 0], name=data.columns[0]))
    
        fig.update_layout(
            xaxis=dict(domain=[0.1, 0.9]),
            yaxis=dict(title=data.columns[0]),
            yaxis2=dict(title=data.columns[1], anchor="x", overlaying="y", side="right"))
    
        for i, col in enumerate(data.columns[1:], 1):
            fig.add_trace(
                go.Scatter(x=data.index,y=data[col],name=col,yaxis=f"y{i+1}"))
    
        for i, col in enumerate(data.columns[2:], 2):
            axis = f"yaxis{i+1}"
    
            if i%2 == 0:
                side = "left"
                position = (i-1)*0.05
            else:
                side = "right"
                position = 1 - (i-2)*0.05
    
            axis_value = dict(
                title=col,
                anchor="free",
                overlaying="y",
                side=side,
                position=position)
            exec(f"fig.update_layout({axis} = axis_value)")
    if data.shape[1]==2:
        fig = make_subplots(specs=[[{"secondary_y": True}]])
        # Add traces
        fig.add_trace(
            go.Scatter(x=data.index, y=data.iloc[:, 0], name=data.columns[0]),
            secondary_y=False,)
        fig.add_trace(
            go.Scatter(x=data.index, y=data.iloc[:, 1], name=data.columns[1]),
            secondary_y=True,)
        # Set x-axis title
        fig.update_xaxes(title_text="Date")
        # Set y-axes titles
        fig.update_yaxes(title_text=data.columns[0], secondary_y=False)
        fig.update_yaxes(title_text=data.columns[0], secondary_y=True)
    if data.shape[1] == 1:
        fig = px.line(data.reset_index(), x = data.index.name, y = data.columns)
    
    fig.update_layout(
    title_text="Data",
    width=800,)
    
    fig.show()
于 2021-12-10T16:27:29.820 回答