Plotly (Python) 子图:填充面和共享图例 [英] Plotly (Python) Subplots: Padding Facets and Sharing Legends

查看:97
本文介绍了Plotly (Python) 子图:填充面和共享图例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

from plotly.offline import init_notebook_mode, iplotinit_notebook_mode(connected=True) # 使用 jupyter导入 plotly.graph_objs as go从情节导入工具将 numpy 导入为 npN = 100epoch_range = [i for i in range(N)]模型性能 = {}对于 ['acc','loss'] 中的 m:对于 ['train','validation'] 中的 sub:如果子 == '火车':历史目标 = 米别的:history_target = 'val_{}'.format(m)model_perf[history_target] = np.random.random(N)线型 = {'火车':字典(颜色='灰色',宽度=1,破折号='破折号'),'验证':字典(颜色='蓝色',宽度=4)}fig = tools.make_subplots(rows=2, cols=1, shared_xaxes=True, shared_yaxes=False, specs = [[{'b':10000}], [{'b':10000}]])我 = 0对于 ['acc','loss'] 中的 m:我 += 1对于 ['train','validation'] 中的 sub:如果子 == '火车':history_target = m别的:history_target = 'val_{}'.format(m)fig.append_trace({'x':纪元范围,'y':model_perf[history_target],#'type': '分散','名称':子,'传奇组':m,'yaxis': dict(title=m),'线':line_type[sub],'showlegend':真}, 我, 1)图['布局'].update(高度=600,宽度=800,xaxis = dict(title = '时代'),yaxis = dict(title='Accuracy', tickformat=".0%"),yaxis2 = dict(title='损失', tickformat=".0%"),标题='性能')iplot(图)

这是我得到的图像:

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

曼尼提前致谢!

按照 Farbice 的建议,我查看了 plotly.figure_factory 中的 create_facet_grid 函数(顺便说一下,它需要 plotly 2.0.12+),我确实设法重现了具有较少线条的相同图像,但它给了我较少的灵活性——例如,我认为你不能使用这个函数绘制线条,它也有图例重复问题,但如果你正在寻找一个特别的可视化,这可能是相当有效.它需要长格式的数据,请参见以下示例:

# 转成长格式将熊猫导入为 pdperf_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']}).堆().reset_index().重命名(列={'level_0': '纪元','level_1': '变量',0:'值'}))perf_df = pd.concat([perf_df,perf_df['变量'].str.extractall(r'(?P^.*)_(?P.*$)').reset_index()[['metric','set']]],轴=1).drop(['变量'], 轴=1)perf_df.head() # 结果时代价值度量集0 0.434349 准确度训练0 0.374607 精度验证0 0.864698 损失训练0 0.007445 损失验证1 0.553727 精度训练# 绘制它fig = ff.create_facet_grid(perf_df,x='纪元',y='值',facet_row='metric',颜色名称='设置',秤=free_y",ggplot2=真)图['布局'].update(高度=800,宽度=1000,yaxis1 = dict(tickformat=".0%"),yaxis2 = dict(tickformat=".0%"),标题='性能')iplot(图)

结果如下:

解决方案

经过更多的挖掘,我找到了解决我的两个问题的方法.

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

图例中重复的第二个问题有点棘手,但是

I'm trying to create 2 plots with a shared x-axis and I'm having 2 problems with this:

  1. As soon as I customise the layout with yaxis and yaxis2 titles and/or tickmarks, y-axes begin to overlap
  2. I would like the legends to be shared between the 2 plots, but instead they are duplicated

Here is the code to reproduce the problem I'm experiencing:

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)  

And here is the image that I get:

If you have any suggestions on how to solve these 2 problems, I'd love to hear from you.

Manny thanks in advance!

EDIT:

Following Farbice's advice, I looked into the create_facet_grid function from plotly.figure_factory (which by the way requires plotly 2.0.12+), I did manage to reproduce the same image with fewer lines but it gave me less flexibility -- for example I don't think you can plot lines using this function and it also has the legend duplication issue, but if you are looking for an ad hoc viz, this might be quite effective. It requires data in a long format, see the below example:

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

And here is the result:

解决方案

After doing a little more digging I've found the solution to both my problems.

First, the overlapping y-axis problem was caused by yaxis argument in the layout update, it had to be changed to yaxis1.

The second problem with duplications in the legend was a little trickier, but this post helped me work it out. The idea is that each trace can have a legend associated with it, so if you are plotting multiple traces, you may only want to use the legend from one of them (using the showlegend argument), but to make sure that one legend controls the toggle of multiple subplots, you can use the legendgroup parameter.

Here is the full code with the solution:

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)  

And here is the result:

这篇关于Plotly (Python) 子图:填充面和共享图例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆