0

I am new to Plotly and fascinated by its interactive features. I have three pandas dataframes of electricity generation mix of three countries, which looks like this: enter image description here

I have been able to create an interactive bar chart using Plotly for electricity generation mix based on df1 using

import plotly.express as px fig=px.bar(df1, title="Electricity generation mix of Germany in TWh (2000-2019)", color_discrete_sequence=colors) fig

enter image description here

I intend to add a button or dropdown to this bar chart, where I can select countries based on each data frame (df1,df2 and df3). What would be the best approach to do it? Should I rather have the data of all three countries in one dataframe?

hbstha123
  • 1,260
  • 11
  • 23
  • Check out my two posts ([one](https://stackoverflow.com/questions/64893793/add-index-as-dropdown-menu-in-plotly/64898132#64898132) and [two](https://stackoverflow.com/questions/65605076/plotly-how-to-give-different-label-names-in-a-dropdown-menu/65621014#65621014)) for some general pointers. If you're still stuck, you're more than welcome to ask me for help in your specific case – Jacob K Jan 13 '21 at 22:37

1 Answers1

3

The easiest way to do this is to use the graph objects library and iterate through your data with the "add_trace" method of a Plotly figure.

import pandas as pd
import plotly.graph_objects as go

#Dummy data
df_germany = pd.DataFrame({'Fuels':[2010,2011],'Coal':[200,250],'Gas':[400,500]})
df_poland = pd.DataFrame({'Fuels':[2010,2011],'Coal':[500,150],'Gas':[600,100]})
df_spain = pd.DataFrame({'Fuels':[2010,2011],'Coal':[700,260],'Gas':[900,400]})

#put dataframes into object for easy access:
df_dict = {'Germany': df_germany, 
           'Poland': df_poland, 
           'Spain': df_spain}

#create a figure from the graph objects (not plotly express) library
fig = go.Figure()

buttons = []
i = 0

#iterate through dataframes in dict
for country, df in df_dict.items():
    #iterate through columns in dataframe (not including the year column)
    for column in df.drop(columns=['Fuels']):
        #add a bar trace to the figure for the country we are on
        fig.add_trace(go.Bar(
                          name = column,
                          #x axis is "fuels" where dates are stored as per example
                          x = df.Fuels.to_list(),
                          #y axis is the data for the column we are on
                          y = df[column].to_list(),
                          #setting only the first country to be visible as default
                          visible = (i==0)
                        )
                     )
        
    #args is a list of booleans that tells the buttons which trace to show on click
    args = [False] * len(df_dict)
    args[i] = True
    
    #create a button object for the country we are on
    button = dict(label = country,
                  method = "update",
                  args=[{"visible": args}])
    
    #add the button to our list of buttons
    buttons.append(button)
    
    #i is an iterable used to tell our "args" list which value to set to True
    i+=1
        
fig.update_layout(
    updatemenus=[
        dict(
        #change this to "buttons" for individual buttons
        type="dropdown",
        #this can be "left" or "right" as you like
        direction="down",
        #(1,1) refers to the top right corner of the plot
        x = 1,
        y = 1,
        #the list of buttons we created earlier
        buttons = buttons)
    ],
    #stacked bar chart specified here
    barmode = "stack",
    #so the x axis increments once per year
    xaxis = dict(dtick = 1))

fig.show()
        

Should yield: Plotly stacked bar with dropdown example

Python on Toast
  • 254
  • 1
  • 5
  • Could you specify how I can also define color sequence, e.g. black color for Coal and grey for Gas? – hbstha123 Jan 14 '21 at 21:52
  • @HimalayaBirShrestha Regarding your comment, didn't you ask a very similar question yesterday? – vestland Jan 14 '21 at 22:17
  • @vestland yes, i did. But it's a different case since plotly.express is different as compared to plotly.graph_objects. I tried to loop through the colors in fig.add_trace(go.Bar(marker_color=color). I was able to get the desired color for the first option but as soon as I selected the second or third option from the dropdown or the button, the color got distorted. Therefore, I wanted to ask what would be the appropriate way to define color sequence in this case. – hbstha123 Jan 14 '21 at 22:24
  • add "marker = dict(color = ["colour for column we are on"] * len(df.Fuels.to_list())" to the for loop inside of the "Bar" object – Python on Toast Jan 14 '21 at 22:27