【问题标题】:Plotly (Python) Subplots: Padding Facets and Sharing LegendsPlotly (Python) 子图:填充构面和共享图例
【发布时间】:2017-12-21 21:12:43
【问题描述】:

我正在尝试创建 2 个具有共享 x 轴的图,但我遇到了 2 个问题:

  1. 只要我使用 yaxisyaxis2 标题和/或刻度线自定义布局,y 轴就会开始重叠
  2. 我希望在 2 个地块之间共享图例,但它们是重复的

这是重现我遇到的问题的代码:

from plotly.offline import init_notebook_mode, iplot
init_notebook_mode(connected=True) # using jupyter
import plotly.graph_objs as go
from plotly import tools
import numpy as np

 N = 100
epoch_range = [i for i in range(N)]
model_perf = {}
for m in ['acc','loss']:
    for sub in ['train','validation']:
        if sub == 'train':
            history_target = m
        else:
            history_target = 'val_{}'.format(m)
        model_perf[history_target] = np.random.random(N)

line_type = {
    'train': dict(
        color='grey',
        width=1,
        dash='dash'
    ),
    'validation': dict(
        color='blue',
        width=4
    )
}

fig = tools.make_subplots(rows=2, cols=1, shared_xaxes=True, shared_yaxes=False, specs = [[{'b':10000}], [{'b':10000}]])
i = 0
for m in ['acc','loss']:

    i += 1

    for sub in ['train','validation']:

        if sub == 'train':
            history_target = m
        else:
            history_target = 'val_{}'.format(m)

        fig.append_trace({
            'x': epoch_range,
            'y': model_perf[history_target],
            #'type': 'scatter',
            'name': sub,
            'legendgroup': m,
            'yaxis': dict(title=m),
            'line': line_type[sub],
            'showlegend': True
        }, i, 1)

fig['layout'].update(
    height=600, 
    width=800, 
    xaxis = dict(title = 'Epoch'),
    yaxis = dict(title='Accuracy', tickformat=".0%"),
    yaxis2 = dict(title='Loss', tickformat=".0%"),
    title='Performance'
)
iplot(fig)  

这是我得到的图像:

如果您对如何解决这两个问题有任何建议,我很乐意听取您的意见。

提前谢谢你!

编辑:

按照 Farbice 的建议,我查看了 plotly.figure_factory 中的 create_facet_grid 函数(顺便说一下,这需要情节 2.0.12+),我确实设法用更少的行重现了相同的图像,但它给了我更少的灵活性 - - 例如,我不认为您可以使用此功能绘制线条,并且它也存在图例重复问题,但如果您正在寻找一个临时可视化,这可能非常有效。它需要长格式的数据,见下面的例子:

# converting into the long format
import pandas as pd
perf_df = (
    pd.DataFrame({
        'accuracy_train': model_perf['acc'],
        'accuracy_validation': model_perf['val_acc'],
        'loss_train': model_perf['loss'],
        'loss_validation': model_perf['val_loss']
    })
    .stack()
    .reset_index()
    .rename(columns={
        'level_0': 'epoch',
        'level_1': 'variable',
        0: 'value'
    })
)

perf_df = pd.concat(
    [
        perf_df,
        perf_df['variable']
        .str
        .extractall(r'(?P<metric>^.*)_(?P<set>.*$)')
        .reset_index()[['metric','set']]   
    ], axis=1
).drop(['variable'], axis=1)

perf_df.head() # result

epoch  value     metric     set
0      0.434349  accuracy   train
0      0.374607  accuracy   validation
0      0.864698  loss       train
0      0.007445  loss       validation
1      0.553727  accuracy   train

# plot it
fig = ff.create_facet_grid(
    perf_df,
    x='epoch',
    y='value',
    facet_row='metric',
    color_name='set',
    scales='free_y',
    ggplot2=True
)

fig['layout'].update(
    height=800, 
    width=1000, 
    yaxis1 = dict(tickformat=".0%"),
    yaxis2 = dict(tickformat=".0%"),
    title='Performance'
)

iplot(fig)

结果如下:

【问题讨论】:

    标签: python plotly


    【解决方案1】:

    在进行了更多挖掘之后,我找到了解决这两个问题的方法。

    首先,y轴重叠问题是由于布局更新中的yaxis参数引起的,必须将其更改为yaxis1

    图例中重复的第二个问题有点棘手,但this 的帖子帮助我解决了这个问题。这个想法是每条迹线都可以有一个与之关联的图例,因此如果您要绘制多条迹线,您可能只想使用其中一条迹线的图例(使用showlegend 参数),但要确保一个图例控制多个子图的切换,可以使用legendgroup参数。

    这是解决方案的完整代码:

    from plotly.offline import init_notebook_mode, iplot
    init_notebook_mode(connected=True) # using jupyter
    import plotly.graph_objs as go
    from plotly import tools
    import numpy as np
    
    N = 100
    epoch_range = [i for i in range(N)]
    model_perf = {}
    for m in ['acc','loss']:
        for sub in ['train','validation']:
            if sub == 'train':
                history_target = m
            else:
                history_target = 'val_{}'.format(m)
    
            model_perf[history_target] = np.random.random(N)
    
    line_type = {
        'train': dict(
            color='grey',
            width=1,
            dash='dash'
        ),
        'validation': dict(
            color='blue',
            width=4
        )
    }
    
    fig = tools.make_subplots(
        rows=2, 
        cols=1, 
        shared_xaxes=True, 
        shared_yaxes=False
    )
    
    i = 0
    for m in ['acc','loss']:
    
        i += 1
    
        if m == 'acc':
            legend_display = True
        else:
            legend_display = False
    
        for sub in ['train','validation']:
    
            if sub == 'train':
                history_target = m
            else:
                history_target = 'val_{}'.format(m)
    
            fig.append_trace({
                'x': epoch_range,
                'y': model_perf[history_target],
                'name': sub,
                'legendgroup': sub, # toggle train / test group on all subplots
                'yaxis': dict(title=m),
                'line': line_type[sub],
                'showlegend': legend_display # this is now dependent on the trace
            }, i, 1)
    
    fig['layout'].update(
        height=600, 
        width=800, 
        xaxis = dict(title = 'Epoch'),
        yaxis1 = dict(title='Accuracy', tickformat=".0%"),
        yaxis2 = dict(title='Loss', tickformat=".0%"),
        title='Performance'
    )
    iplot(fig)  
    

    结果如下:

    【讨论】:

    • 实际上,如果您希望 x 轴标题出现在底部 facet 下方,请将布局更新块中的 xaxis 替换为 xaxis1
    【解决方案2】:

    根据我的经验,可视化工具更喜欢长格式的数据。 您可能希望将数据调整为包含以下列的表:

    • 时代
    • 变量:“acc”或“loss”
    • 设置:“验证”或“训练”
    • value : 给定 epoch/variable/set 的值

    通过这样做,您可能会发现通过在“变量”上使用具有 x=epoch,y=value 的“set”-trace 的 facetting 来创建所需的图形会更容易

    如果您需要编码解决方案,请提供一些数据。

    希望这对您有所帮助。

    【讨论】:

    • 感谢您的建议,我习惯使用 ggplot,它确实更喜欢您描述的格式的数据,但是,情节似乎对您的数据的底层结构无动于衷,结构是派生的从声明的痕迹中,所以如果您对如何使用任何数据格式解决我描述的问题有任何建议,那么我想了解更多。干杯
    • 我也是从 ggplot 开始的,但现在我使用的是 python 而不是 R,并且 plotly 的 create_facet_grid 函数的行为方式与 ggplot 在此选项中的行为方式相同。
    • 可能确实有另一种解决方案,但他们总是告诉我:'先让它工作,然后让它变得更好'。目前,这是我唯一能想到的。
    • 谢谢,我会尝试 create_facet_grid 并告诉你进展如何!
    猜你喜欢
    • 2020-06-30
    • 1970-01-01
    • 2021-06-04
    • 2022-11-21
    • 1970-01-01
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    相关资源
    最近更新 更多