Search code examples
pythonpandasplotly

Add second y-axis with percentage in bar chart plotly


Given df:

  names  values  pct
0     a      10  0.1
1     b      20  0.2
2     c      70  0.7

Return a bar chart with secondary y-axis as a percentage (col pct)

Current code:


import pandas as pd
import numpy as np
import plotly.express as px

df = pd.DataFrame({'names':['a', 'b', 'c'], 'values':[10,20,70], 'pct':[0.1, 0.2, 0.7]})

# the figure 
fig = px.bar(df, x='names', y='values')
fig.show()

expected outcome: enter image description here

EDIT: the solution provided works, is there a way to also add color to the bars, whilst not messing up the look (bar distance/alignment with xticks)

Here is my attempt modifying the solution provided:

import pandas as pd
import numpy as np
import plotly.express as px
from plotly.subplots import make_subplots

df = pd.DataFrame({'names':['a', 'b', 'c'], 'values':[10,20,70], 'pct':[0.1, 0.2, 0.7]})

fig = make_subplots(specs=[[{"secondary_y": True}]])

fig1 = px.bar(df, x='names', y='values', color='names'  ) # added color 
fig2 = px.bar(df, x='names', y='pct', color='names')
 # plot singulalry all the bars provided. 
for i in range(len(fig1.data)): 
  fig.add_trace(fig1.data[i], secondary_y=False)
  fig.add_trace(a.data[i], secondary_y=True)

fig.update_layout(yaxis2=dict(tickvals=[0.1,0.2,0.7], tickformat='.1%', title_text='Secondary y-axis percentage'))
fig.update_layout(xaxis=dict(title_text='name'), yaxis=dict(title_text='values'))
fig.update_layout(bargap=0.0)
fig.show()

However it is producing double legend entry and misaligned x-axis labels

OUT:

enter image description here


Solution

  • To change the color of the bar chart by category, it is necessary to correspond with the markers in the graph object. in express, each is a bar chart by color, understood as 6 categorical variables, and I assume you are drawing abc categorical variables on top of each other. In the graph object, two graphs are drawn and the designated color is specified with a marker; it is set in hexadecimal format, but may be specified as red, blue, or green.

    import pandas as pd
    from plotly.subplots import make_subplots
    import plotly.graph_objects as go
    
    df = pd.DataFrame({'names':['a', 'b', 'c'], 'values':[10,20,70], 'pct':[0.1, 0.2, 0.7]})
    
    colors = ['#636efa','#EF553B','#00cc96']
    
    fig = make_subplots(specs=[[{"secondary_y": True}]])
    
    fig.add_trace(go.Bar(x=df['names'], y=df['values'], marker_color=colors, showlegend=False), secondary_y=False)
    fig.add_trace(go.Bar(x=df['names'], y=df['pct'], marker_color=colors, showlegend=False), secondary_y=True)
    
    fig.update_layout(yaxis2=dict(tickvals=[0.1,0.2,0.7], tickformat='.1%', title_text='Secondary y-axis percentage'))
    fig.update_layout(xaxis=dict(title_text='name'), yaxis=dict(title_text='values'))
    fig.show()
    

    enter image description here