George Liu
George Liu

Reputation: 3583

How to plot a vertical line at the x-axis range median position using plotly in Python API?

I'm trying to plot a vertical line that's dynamically positioned so that when filtering happens, the line will move accordingly. For example, with the below code, I can plot a stationary vertical line at 25K which works with the full dataset as the median, but when the data is filtered to "Americas" only since the x-axis range is now 45K, the line is not at the median position anymore.

So how can I plot a vertical line that's positioned at the x-axis range's median position? Thanks

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

Upvotes: 9

Views: 6127

Answers (3)

Shehan Ishanka
Shehan Ishanka

Reputation: 593

With the help of the @rpanai's answer and using plotly update buttons, the following solution is developed. Check this.

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

Upvotes: 7

rpanai
rpanai

Reputation: 13437

This is not quite exactly what you asked. As I doubt you can achieve to show the median of visible traces only without dash as correctly pointed out by Mike_H. Anyway it could be useful if you want to use a plotly only solution. So if you are happy with this outputs enter image description here

enter image description here

You can use the following code. Where the main differences is that we use traces for vertical lines instead of shapes and we play with legendgroup and showlegend parameters

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)

Upvotes: 1

Mike_H
Mike_H

Reputation: 1455

You need to add so called callbacks to your program, so that the whole figure is updated when the database changes. Then you include a mean() to the definition of your x1 and x0 shape definitions. However this requires you to use dash.

Upvotes: 4

Related Questions