【问题标题】:Plotly: How to hide axis titles in a plotly express figure with facets?情节:如何在带有刻面的情节表达图中隐藏轴标题?
【发布时间】:2020-12-02 19:25:49
【问题描述】:

有没有一种简单的方法可以使用 plotly express 隐藏多面图中的重复轴标题?我试过设置

visible=True

在下面的代码中,但这也隐藏了 y 轴刻度标签(值)。理想情况下,我想将隐藏重复的轴标题设置为一般多面图的默认设置(或者甚至更好,只是默认为整个多面图显示单个 x 和 y 轴标题。

这里是测试代码:

import pandas as pd
import numpy as np
import plotly.express as px
import string

# create a dataframe
cols = list(string.ascii_letters)
n = 50

df = pd.DataFrame({'Date': pd.date_range('2021-01-01', periods=n)})

# create data with vastly different ranges
for col in cols:
    start = np.random.choice([1, 10, 100, 1000, 100000])
    s = np.random.normal(loc=0, scale=0.01*start, size=n)
    df[col] = start + s.cumsum()

# melt data columns from wide to long
dfm = df.melt("Date")

fig = px.line(
    data_frame=dfm,
    x = 'Date',
    y = 'value',
    facet_col = 'variable',
    facet_col_wrap=6,
    facet_col_spacing=0.05,
    facet_row_spacing=0.035,
    height = 1000,
    width = 1000,
    title = 'Value vs. Date'
)

fig.update_yaxes(matches=None, showticklabels=True, visible=True)
fig.update_annotations(font=dict(size=16))
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))

最终代码(已接受的答案)。注意情节 >= 4.9

import pandas as pd
import numpy as np
import plotly.express as px
import string
import plotly.graph_objects as go

# create a dataframe
cols = list(string.ascii_letters)
n = 50

df = pd.DataFrame({'Date': pd.date_range('2021-01-01', periods=n)})

# create data with vastly different ranges
for col in cols:
    start = np.random.choice([1, 10, 100, 1000, 100000])
    s = np.random.normal(loc=0, scale=0.01*start, size=n)
    df[col] = start + s.cumsum()

# melt data columns from wide to long
dfm = df.melt("Date")

fig = px.line(
    data_frame=dfm,
    x = 'Date',
    y = 'value',
    facet_col = 'variable',
    facet_col_wrap=6,
    facet_col_spacing=0.05,
    facet_row_spacing=0.035,
    height = 1000,
    width = 1000,
    title = 'Value vs. Date'
)

fig.update_yaxes(matches=None, showticklabels=True, visible=True)
fig.update_annotations(font=dict(size=16))
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))

# hide subplot y-axis titles and x-axis titles
for axis in fig.layout:
    if type(fig.layout[axis]) == go.layout.YAxis:
        fig.layout[axis].title.text = ''
    if type(fig.layout[axis]) == go.layout.XAxis:
        fig.layout[axis].title.text = ''
        
# keep all other annotations and add single y-axis and x-axis title:
fig.update_layout(
    # keep the original annotations and add a list of new annotations:
    annotations = list(fig.layout.annotations) + 
    [go.layout.Annotation(
            x=-0.07,
            y=0.5,
            font=dict(
                size=16, color = 'blue'
            ),
            showarrow=False,
            text="single y-axis title",
            textangle=-90,
            xref="paper",
            yref="paper"
        )
    ] +
    [go.layout.Annotation(
            x=0.5,
            y=-0.08,
            font=dict(
                size=16, color = 'blue'
            ),
            showarrow=False,
            text="Dates",
            textangle=-0,
            xref="paper",
            yref="paper"
        )
    ]
)

fig.show()

【问题讨论】:

    标签: python express plotly facet axis-labels


    【解决方案1】:

    这个答案有五个部分:

    1. 隐藏子情节标题(虽然不是 100% 确定你想这样做...)
    2. 使用fig.layout[axis].tickfont = dict(color = 'rgba(0,0,0,0)')隐藏 y 轴刻度值
    3. 使用go.layout.Annotation(xref="paper", yref="paper")设置单轴标签
    4. 情节人物
    5. 完整的代码sn-p在最后

    这里有一个非常重要的收获是,您可以使用plotly.graph_object 引用编辑使用px 函数生成的任何元素,例如go.layout.XAxis


    1。隐藏子情节标题

    如果您对设置 fig 的方式感到满意,您可以添加

    for anno in fig['layout']['annotations']:
        anno['text']=''
        
    fig.show()
    

    2。隐藏 yaxis 文本

    您可以在循环中使用以下命令将 yaxis tickfont 设置为透明

    fig.layout[axis].tickfont = dict(color = 'rgba(0,0,0,0)')
    

    确切的线包含在下面的 sn-p 中,它也删除了每个子图的 y 轴标题。

    3。单轴标签

    删除轴标签和包含单个标签需要更多工作,但这里有一个非常灵活的设置,可以完全满足您的需求,更多如果您想编辑新的任何方式的标签:

    # hide subplot y-axis titles and x-axis titles
    for axis in fig.layout:
        if type(fig.layout[axis]) == go.layout.YAxis:
            fig.layout[axis].title.text = ''
        if type(fig.layout[axis]) == go.layout.XAxis:
            fig.layout[axis].title.text = ''
            
    # keep all other annotations and add single y-axis and x-axis title:
    fig.update_layout(
        # keep the original annotations and add a list of new annotations:
        annotations = list(fig.layout.annotations) + 
        [go.layout.Annotation(
                x=-0.07,
                y=0.5,
                font=dict(
                    size=16, color = 'blue'
                ),
                showarrow=False,
                text="single y-axis title",
                textangle=-90,
                xref="paper",
                yref="paper"
            )
        ] +
        [go.layout.Annotation(
                x=0.5,
                y=-0.08,
                font=dict(
                    size=16, color = 'blue'
                ),
                showarrow=False,
                text="Dates",
                textangle=-0,
                xref="paper",
                yref="paper"
            )
        ]
    )
    
    fig.show()
    

    4。情节

    5。完整代码:

    import pandas as pd
    import numpy as np
    import plotly.express as px
    import string
    import plotly.graph_objects as go
    
    # create a dataframe
    cols = list(string.ascii_letters)
    cols[0]='zzz'
    n = 50
    
    df = pd.DataFrame({'Date': pd.date_range('2021-01-01', periods=n)})
    
    # create data with vastly different ranges
    for col in cols:
        start = np.random.choice([1, 10, 100, 1000, 100000])
        s = np.random.normal(loc=0, scale=0.01*start, size=n)
        df[col] = start + s.cumsum()
    
    # melt data columns from wide to long
    dfm = df.melt("Date")
    
    fig = px.line(
        data_frame=dfm,
        x = 'Date',
        y = 'value',
        facet_col = 'variable',
        facet_col_wrap=6,
        #facet_col_spacing=0.05,
        #facet_row_spacing=0.035,
        height = 1000,
        width = 1000,
        title = 'Value vs. Date'
    )
    
    fig.update_yaxes(matches=None, showticklabels=True, visible=True)
    fig.update_annotations(font=dict(size=16))
    fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
    
    # subplot titles
    for anno in fig['layout']['annotations']:
        anno['text']=''
    
    # hide subplot y-axis titles and x-axis titles
    for axis in fig.layout:
        if type(fig.layout[axis]) == go.layout.YAxis:
            fig.layout[axis].title.text = ''
        if type(fig.layout[axis]) == go.layout.XAxis:
            fig.layout[axis].title.text = ''
            
    # keep all other annotations and add single y-axis and x-axis title:
    fig.update_layout(
        # keep the original annotations and add a list of new annotations:
        annotations = list(fig.layout.annotations) + 
        [go.layout.Annotation(
                x=-0.07,
                y=0.5,
                font=dict(
                    size=16, color = 'blue'
                ),
                showarrow=False,
                text="single y-axis title",
                textangle=-90,
                xref="paper",
                yref="paper"
            )
        ] +
        [go.layout.Annotation(
                x=0.5,
                y=-0.08,
                font=dict(
                    size=16, color = 'blue'
                ),
                showarrow=False,
                text="Dates",
                textangle=-0,
                xref="paper",
                yref="paper"
            )
        ]
    )
    
    
    fig.show()
    

    【讨论】:

    • 感谢您的快速回复。也许我的OP不清楚。我只想消除重复的 X 轴和 Y 轴标题(“日期”和“值”),保持图表的所有其他元素不变。 y 轴值都是相同的度量单位(例如,美元、计数等),但范围大不相同,因此仍然需要刻度标签。我确实运行了代码,它与发布的屏幕截图不同,更接近所需的输出,但缺少构面标题(字母)并且构面之间的间距关闭(垂直太少,水平太多)。跨度>
    • 好的,通过一些调整,我能够获得所需的输出,并将其标记为已回答(并将添加完整代码)。我正在使用 plotly 4.9,这样就解决了间距问题(我没有注意到您注释掉了这些行 :)。仅供参考 - 我希望完全在 plotly express 中作为一个更简单的选项来做到这一点(更像是 lattice,R 语言中的 ggplot2 有)。再次感谢您的回复!
    • @RandallGoodwin 这个问题不太清楚,但我似乎也误读了部分内容。但是不用担心,我学会了一堆解决它的方法。很高兴它最终为你解决了!并感谢您将我的建议标记为已接受的答案。
    • :) 重新阅读我自己的 OP 后,我不确定我是否理解自己的问题!您的回复符合要求,再次感谢!
    • @RandallGoodwin 没问题!乐于助人!
    【解决方案2】:

    作为旁注,我找到了一种更直接的方法,可以使用 labels 参数从 plotly express 调用中消除轴标签,并为我想要的标签提供值为 '' 的标签字典消除。

    虽然这不会导致整体图形级别的单个标签,但如果图形标题足以描述“Y vs. X”,那么可能缺少轴标签可以“原谅”? (或如@vestland 演示的那样添加)

    请注意,您可以“几乎”消除在每个子批次中具有“=value”的烦人重复方面标题。即,如果您在标签字典中再添加一个条目:

    '变量':''

    然后,您只需获取 facet 变量 level,而不是获取“variable=variable level”,前面是“=”,如下图所示。

    完整代码

    import pandas as pd
    import numpy as np
    import plotly.express as px
    import string
    
    # create a dataframe
    cols = list(string.ascii_letters)
    n = 50
    
    df = pd.DataFrame({'Date': pd.date_range('2021-01-01', periods=n)})
    
    # create data with vastly different ranges
    for col in cols:
        start = np.random.choice([1, 10, 100, 1000, 100000])
        s = np.random.normal(loc=0, scale=0.01*start, size=n)
        df[col] = start + s.cumsum()
    
    # melt data columns from wide to long
    dfm = df.melt("Date")
    
    # make the plot
    fig = px.line(
        data_frame=dfm,
        x = 'Date',
        y = 'value',
        facet_col = 'variable',
        facet_col_wrap=6,
        facet_col_spacing=0.05,
        facet_row_spacing=0.035,
        height = 1000,
        width = 1000,
        title = 'Value vs. Date',
        labels = {
            'Date': '',
            'value': '',
            'variable': ''
        }
    )
    
    # ensure that each chart has its own y rage and tick labels
    fig.update_yaxes(matches=None, showticklabels=True, visible=True)
    
    fig.show()
    

    【讨论】:

      猜你喜欢
      • 2022-01-21
      • 1970-01-01
      • 2021-02-20
      • 2021-12-27
      • 2021-11-25
      • 2010-11-23
      • 1970-01-01
      • 2019-12-05
      • 2018-07-03
      相关资源
      最近更新 更多