matplotlibplotlysubplotplotly.graph-objects

Having a hard time overlaying graphs with plotly.graph_objects


I tried to overlay a 'threashold' line on a bar graph but didn't managed to have a clean graph.

Here is my pandas DataFrame:

import pandas as pd 
df = pd.DataFrame({'Nutriment' : ['Glucides (g)', 'Lipides (g)', 'Protéines (g)'],
      'ail' : [4, 0.056, 7.82],
      'basilic' : [0.05, 0.009, 0.42],
      'carotte' : [2.6, 0.1, 3.44],
      'citron vert' : [0.063, 0.0, 0.14]})

and this is what I tried to do :

from plotly.subplots import make_subplots
import plotly.graph_objects as go

fig = make_subplots()
fig.update_layout(xaxis2= {'anchor' : 'y', 'overlaying' : 'x', 'side' : 'bottom'})

ingredients = df.columns[1:]
clrs = {}
n = 100
for ingredient in ingredients : 
    clrs[ingredient] = 'rgb(0,' + str(n) + ',' + str(n) + ')'
    n += 40
    
                    
for ingredient in ingredients :
    fig.add_trace(go.Bar(x=df['Nutriment'], 
                         y=df[ingredient], 
                         name=ingredient, 
                         marker= {'color' : clrs[ingredient]}, xaxis = 'x2'))
    
fig.add_trace(go.Scatter(x=[0,1], y=[4.5, 4.5], name='Apport recommandé en glucides (min)', line_color='#ff0040'))
fig.add_trace(go.Scatter(x=[1,2], y=[1.9, 1.9], name='Apport recommandé en lipides (min)', line_color='#00ff00'))
fig.add_trace(go.Scatter(x=[2,3], y=[1, 1], name='Apport recommandé en protéines (min)', line_color='#0000f0'))

fig.update_layout(width=800, height=500, title_text='Apports nutritionnels par portion', barmode='stack')

this is what I get

this is what I expect :

Could somebody help me ? Thanks !!!


Solution

  • I think the best way to resolve the mix of numerical and categorical axes would be to code the categorical variable and once the x-axis is on the numerical axis, then update that numerical axis to a string scale at the end.

    df['Nutriment'] = df['Nutriment'].astype('category')
    df['Nutriment_cd'] = df['Nutriment'].astype('category').cat.codes
    
    from plotly.subplots import make_subplots
    import plotly.graph_objects as go
    
    fig = make_subplots()#specs=[[{"secondary_y": True}]]
    
    ingredients = df.columns[1:]
    clrs = {}
    n = 100
    for ingredient in ingredients : 
        clrs[ingredient] = 'rgb(0,' + str(n) + ',' + str(n) + ')'
        n += 40
    
    for ingredient in ingredients :
        fig.add_trace(go.Bar(x=df['Nutriment_cd'], 
                             y=df[ingredient], 
                             name=ingredient, 
                             marker= {'color' : clrs[ingredient]}, xaxis = 'x2'), secondary_y=False)
    
    fig.add_trace(go.Scatter(x=[-0.5,0.5], y=[4.5, 4.5], name='Apport recommandé en glucides (min)', line_color='#ff0040'))
    fig.add_trace(go.Scatter(x=[0.5,1.5], y=[1.9, 1.9], name='Apport recommandé en lipides (min)', line_color='#00ff00'))
    fig.add_trace(go.Scatter(x=[1.5,2.5], y=[1, 1], name='Apport recommandé en protéines (min)', line_color='#0000f0'))
    
    fig.update_layout(xaxis2= {'anchor' : 'y', 'overlaying' : 'x', 'side' : 'bottom'})
    fig.update_layout(width=800, height=500, title_text='Apports nutritionnels par portion', barmode='stack')
    fig.update_xaxes(tickvals=[0,1,2], ticktext=df['Nutriment'].tolist())
    fig.show()
    

    enter image description here