如何使用Python API中的plotly绘制一个垂直线,使其位于x轴范围的中位数位置?

9

我正在尝试绘制一条垂直线,该线的位置是动态确定的。当发生过滤时,该线将相应地移动位置。例如,在下面的代码中,我可以在25K处绘制一个静态的竖直线,它在完整数据集中作为中位数起作用。但是当数据被过滤为仅“美洲”时,由于x轴范围现在是45K,所以该线不再在中位数位置。

那么,如何绘制一条垂直线,使其位于x轴范围的中位数位置呢?谢谢

import pandas as pd
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot

init_notebook_mode(connected=True)


df = pd.read_csv('https://raw.githubusercontent.com/yankev/test/master/life-expectancy-per-GDP-2007.csv')

americas = df[(df.continent=='Americas')]
europe = df[(df.continent=='Europe')]

trace_comp0 = go.Scatter(
    x=americas.gdp_percap,
    y=americas.life_exp,
    mode='markers',
    marker=dict(size=12,
                line=dict(width=1),
                color="navy"
               ),
    name='Americas',
    text=americas.country,
    )

trace_comp1 = go.Scatter(
    x=europe.gdp_percap,
    y=europe.life_exp,
    mode='markers',
    marker=dict(size=12,
                line=dict(width=1),
                color="red"
               ),
    name='Europe',
    text=europe.country,
        )

data_comp = [trace_comp0, trace_comp1]
layout_comp = go.Layout(
    title='Life Expectancy v. Per Capita GDP, 2007',
    hovermode='closest',
    xaxis=dict(
        title='GDP per capita (2000 dollars)',
        ticklen=5,
        zeroline=False,
        gridwidth=2,
        range=[0, 50_000],
    ),
    yaxis=dict(
        title='Life Expectancy (years)',
        ticklen=5,
        gridwidth=2,
        range=[0, 90],
    ),
    shapes=[
        {
            'type': 'line',
            'x0': 25000,
            'y0': 0,
            'x1': 25000,
            'y1': 85,
            'line': {
                'color': 'black',
                'width': 1
            }
        }
    ]
)
fig_comp = go.Figure(data=data_comp, layout=layout_comp)
iplot(fig_comp)

enter image description here


这是一个非常好的问题。我为您的 xaxisyaxis 添加了范围。 - rpanai
也许你已经听说过,但是 plotly_express 可以做魔术。除了中位数之外,你可以用一行代码得到相同的图表。在导入 import plotly_express as px 后,你可以运行 px.scatter(df, x="gdp_percap", y="life_exp", color="continent", range_x=[0,50_000], range_y=[0,90], hover_name="country") - rpanai
谢谢 @user32185!这很有见地,但是仍然不能满足我的需求,我需要的是一个动态垂直线,位于xrange的中位数位置 - 因此,当由于过滤而改变xrange时,中位数也会移动。 - George Liu
3个回答

7
借助 @rpanai 的回答和使用 plotly 的更新按钮,我们开发了以下解决方案。请查看此链接。
import pandas as pd
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot

init_notebook_mode(connected=True)

df = pd.read_csv('https://raw.githubusercontent.com/yankev/test/master/life-expectancy-per-GDP-2007.csv')

americas = df[(df.continent=='Americas')]
europe = df[(df.continent=='Europe')]
# med_eur = europe["gdp_percap"].median()
# med_ame = americas["gdp_percap"].median()
# med_total=pd.DataFrame(list(europe["gdp_percap"])+list(americas["gdp_percap"])).median()[0]
med_eur = europe["gdp_percap"].max()/2
med_ame = americas["gdp_percap"].max()/2
med_total=25000

trace_median0 =  go.Scatter(x=[med_total, med_total],
                            y=[0,85],
                            mode="lines",
                            legendgroup="a",
                            showlegend=False,
                            marker=dict(size=12,
                                       line=dict(width=0.8),
                                       color="green"
                                       ),
                            name="Median Total"
                            )

trace_comp1 = go.Scatter(
    x=americas.gdp_percap,
    y=americas.life_exp,
    mode='markers',
    marker=dict(size=12,
                line=dict(width=1),
                color="navy"
               ),
    name='Americas',
    text=americas.country
    )

trace_median1 =  go.Scatter(x=[med_ame, med_ame],
                            y=[0,90],
                            mode="lines",
                            legendgroup="a",
                            showlegend=False,
                            marker=dict(size=12,
                                       line=dict(width=0.8),
                                       color="navy"
                                       ),
                            name="Median Americas",
                            visible=False
                            )
trace_comp2 = go.Scatter(
    x=europe.gdp_percap,
    y=europe.life_exp,
    mode='markers',
    marker=dict(size=12,
                line=dict(width=1),
                color="red"
               ),
    name='Europe',
    text=europe.country,
        )

trace_median2 =  go.Scatter(x=[med_eur, med_eur],
                            y=[0,90],
                            mode="lines",
                            legendgroup="b",
                            showlegend=False,
                            marker=dict(size=12,
                                       line=dict(width=0.8),
                                       color="red"
                                       ),
                            name="Median Europe",
                            visible=False
                            )

data_comp = [trace_comp1,trace_median1]+[trace_comp2,trace_median2]+[trace_median0]
layout_comp = go.Layout(
    title='Life Expectancy v. Per Capita GDP, 2007',
    hovermode='closest',
    xaxis=dict(
        title='GDP per capita (2000 dollars)',
        ticklen=5,
        zeroline=False,
        gridwidth=2,
        range=[0, 50_000],
    ),
    yaxis=dict(
        title='Life Expectancy (years)',
        ticklen=5,
        gridwidth=2,
        range=[0, 90],
    ),
    showlegend=False
)
updatemenus = list([
    dict(type="buttons",
         active=-1,
         buttons=list([
            dict(label = 'Total Dataset ',
                 method = 'update',
                 args = [{'visible': [True,False,True,False,True]},
                         {'title': 'Life Expectancy v. Per Capita GDP, 2007'}]),
            dict(label = 'Americas',
                 method = 'update',
                 args = [{'visible': [True,True, False, False,False]},
                         {'title': 'Americas'}]),
            dict(label = 'Europe',
                 method = 'update',
                 args = [{'visible': [False, False,True,True,False]},
                         {'title': 'Europe'}])
        ]),
    )
])

annotations = list([
    dict(text='Trace type:', x=0, y=1.085, yref='paper', align='left', showarrow=False)
])
layout_comp['updatemenus'] = updatemenus
layout_comp['annotations'] = annotations
fig_comp = go.Figure(data=data_comp, layout=layout_comp)
iplot(fig_comp)

enter image description here

enter image description here


4

您需要在程序中添加所谓的回调函数,以便在数据库更改时更新整个图形。然后在x1x0形状定义的定义中包含mean()。但是这需要您使用Dash


1
谢谢。有没有办法获取自动设置的xrange,这样我就可以在形状定义中使用它了?(不使用破折号) - George Liu
我猜应该有一种方法可以在不使用虚线的情况下绘制这个图形。你可以在同一个图例子组上使用追踪,并将图例设置为false。 - rpanai
@user32185,您能否发布代码?如果它可以按照上述描述在中位数位置创建动态垂直线,我会接受的。谢谢。 - George Liu
我脑海中最简单的想法是使用两个中位数,一个用于每个大陆。它们可以与一个图例相关联,并在选择某个大陆时消失。就像这个答案中提到的,要想有三种状态的中位数,你应该使用虚线。 - rpanai
我是@user32185,我刚刚更改了我的显示名称。 - rpanai

1
这不完全是你要求的。像Mike_H正确指出的那样,我怀疑你无法仅显示可见轨迹的中位数而不使用dash。无论如何,如果你想使用plotly的解决方案,这可能会有用。因此,如果您对此输出感到满意enter image description here

enter image description here

你可以使用以下代码。主要区别在于我们使用跟踪线代替形状,并且使用legendgroupshowlegend参数进行调整。
import pandas as pd
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot

init_notebook_mode(connected=True)


df = pd.read_csv('https://raw.githubusercontent.com/yankev/test/master/life-expectancy-per-GDP-2007.csv')

americas = df[(df.continent=='Americas')]
europe = df[(df.continent=='Europe')]
med_eur = europe["gdp_percap"].median()
med_ame = americas["gdp_percap"].median()

trace_comp0 = go.Scatter(
    x=americas.gdp_percap,
    y=americas.life_exp,
    mode='markers',
    marker=dict(size=12,
                line=dict(width=1),
                color="navy"
               ),
    name='Americas',
    text=americas.country,
    legendgroup="a",
    )

trace_median0 =  go.Scatter(x=[med_ame, med_ame],
                            y=[0,90],
                            mode="lines",
                            legendgroup="a",
                            showlegend=False,
                            marker=dict(size=12,
                                       line=dict(width=0.8),
                                       color="navy"
                                       ),
                            name="Median Americas",
                            )


trace_comp1 = go.Scatter(
    x=europe.gdp_percap,
    y=europe.life_exp,
    mode='markers',
    marker=dict(size=12,
                line=dict(width=1),
                color="red"
               ),
    name='Europe',
    text=europe.country,
    legendgroup="b",
        )

trace_median1 =  go.Scatter(x=[med_eur, med_eur],
                            y=[0,90],
                            mode="lines",
                            legendgroup="b",
                            showlegend=False,
                            marker=dict(size=12,
                                       line=dict(width=0.8),
                                       color="red"
                                       ),
                            name="Median Europe",
                            )
data_comp = [trace_comp0, trace_median0,
             trace_comp1, trace_median1]

layout_comp = go.Layout(
    title='Life Expectancy v. Per Capita GDP, 2007',
    hovermode='closest',
    xaxis=dict(
        title='GDP per capita (2000 dollars)',
        ticklen=5,
        zeroline=False,
        gridwidth=2,
        range=[0, 50_000],
    ),
    yaxis=dict(
        title='Life Expectancy (years)',
        ticklen=5,
        gridwidth=2,
        range=[0, 90],
    ),
)
fig_comp = go.Figure(data=data_comp, layout=layout_comp)
iplot(fig_comp)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接