使用plotly Python组合x轴和表格标题

问题描述 投票:0回答:2

我想在Python上用plotly做一些与图片非常相似的事情。我试图找到一种使用子图和共享轴的方法,但找不到正确的方法。是否可以将条形图的 x 轴与表格的列标题共享?

具有共享 x 轴的条形图 graph bar with shared xaxis

python plotly
2个回答
0
投票
  • 这可以用两条迹线来模拟
  • 第一条轨迹是标准条形图,其中 yaxis domain 限制为图形的 80%
  • 第二条轨迹是一个条形图,将值显示为文本,并且相对于第二个 y 轴具有固定高度。 yaxis2 被限制为 domain
  • 的 10%
import plotly.express as px
import pandas as pd
import numpy as np

df = pd.DataFrame({"year": range(2011, 2022)}).assign(
    pct=lambda d: np.random.uniform(-0.08, 0.08, len(d))
)

px.bar(df, x="year", y="pct").add_traces(
    px.bar(df, x="year", y=np.full(len(df), 1), text="pct")
    .update_traces(
        yaxis="y2",
        marker={"line": {"color": "black", "width": 1.5}, "color": "#E5ECF6"},
        texttemplate="%{text:,.2%}",
    )
    .data
).update_layout(
    yaxis={"domain": [0.2, 1], "tickformat": ",.2%"},
    yaxis2={"domain": [0, 0.1], "visible": False},
    xaxis={"title": "", "dtick": 1},
)


0
投票

基于 matplotlib 的 this 答案,我能够使用 Plotly 中的注释进行类似的操作。您可以通过添加实际行而不是

|
来改进,但这对于我的目的来说效果很好。这样做的好处是它是交互式的,当您移动或调整大小时,标签会随着栏左右移动。

import plotly.graph_objects as go
import pandas as pd
import numpy as np
from itertools import groupby


def test_table():
    data_table = pd.DataFrame({'Room':['Room A']*4 + ['Room B']*4,
                               'Shelf':(['Shelf 1']*3 + ['Shelf 2']*1)*2,
                               'Staple':['Milk','Water','Sugar','Honey','Wheat','Corn','Chicken','Cow'],
                               'Quantity':[10,20,5,6,4,7,2,1],
                               'Ordered':np.random.randint(0,10,8)
                               })
    return data_table

def add_line(fig, xpos, ypos):
    # print(xpos, ypos)
    fig.add_annotation(
        x=xpos,
        xref="x",
        xanchor="center",
        y=ypos,
        yref="paper",
        text="|",
        showarrow=False
    )

def add_text(fig, text, xpos, ypos, xanchor="center"):
    # print(text, xpos, ypos)
    fig.add_annotation(
        x=xpos,
        xref="x",
        xanchor=xanchor,
        y=ypos,
        yref="paper",
        text=text,
        showarrow=False
    )

def label_len(my_index, level):
    # returns list of tuple: [(level label, count)]
    labels = my_index.get_level_values(level)
    return [(k, sum(1 for i in g)) for k,g in groupby(labels)]
    
def label_group_bar_table(fig, df, y_scale=0.1):
    for ii, level in enumerate(range(df.index.nlevels)[::-1]):
        pos = 0
        ypos = -y_scale * (ii + 1)
        lv_name = df.index.names[level]
        add_text(fig, f"{lv_name}:  ", -0.5, ypos, xanchor="right")
        add_line(fig, -0.5, ypos)
        for label, rpos in label_len(df.index, level):
            lbpos = (pos + 0.5 * (rpos - 1))
            lnpos = (pos + rpos - 0.5)
            # print(lbpos, lnpos, ypos, label)
            pos += rpos
            add_text(fig, label, lbpos, ypos)
            add_line(fig, lnpos, ypos)
    return fig

df = test_table().groupby(['Room','Shelf','Staple']).sum()
# display(df)
fig = go.Figure()
fig.add_trace(
    go.Bar(y=df["Quantity"], name="Quantity")
)
fig.add_trace(
    go.Bar(y=df["Ordered"], name="Ordered")
)
fig.update_layout(
    barmode="stack",
    xaxis_showticklabels=False,
    margin=dict(b=100)
    )
fig = label_group_bar_table(fig, df)
fig.show()

© www.soinside.com 2019 - 2024. All rights reserved.