0

I have monthly sales information on various companies (Amount, Profit) and would like to display all of this information in a single interactive Plotly chart - I.e. for each unique company, there should be a bar chart displaying sales amount per month as well as a line chart displaying profit per month, the two charts will share the x axis for time but have separate y axes (see example below).

This is simple enough to do for a single company using subplots, but I would like to be able to switch between companies using a dropdown menu. I have been able to get soething working, but am running into various bugs that I cannot get around.

Code to Reproduce Data:

import pandas as pd
import numpy as np
import itertools
from datetime import datetime

np.random.seed(2021)

company_list = ['Company_A', 'Company_B', 'Company_C', 'Company_D', 'Company_E']
datelist = pd.date_range(start="2020-01-01", end='2021-01-01', freq='MS').to_list()

df = pd.DataFrame(list(itertools.product(company_list, datelist)))
df.columns = ['Company', 'Date']

df['Amount'] = np.random.choice(range(0,10000), df.shape[0])
df['Profit'] = np.random.choice(range(0,10000), df.shape[0])


df.head()

enter image description here

I have a function which takes a data frame (assuming the same format as the one just created above) and creates a Plotly chart which has the two plots (Amount and Profit) for each company, and has a drop down menu to change from company to company.

Function to Make Multiple Plots and Dropdown Menu:

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

def make_multi_plot(df):
    
    fig = make_subplots(rows=2, cols=1,
                    shared_xaxes=True,
                    vertical_spacing=0.02)

    for customer in list(df.Company.unique()):
        
        trace1 = go.Bar(
            x=df.loc[df.Company.isin([customer])].Date, 
            y=df.loc[df.Company.isin([customer])].Amount, 
            name = "Amount - " + str(customer))

        trace2 = go.Scatter(
                x=df.loc[df.Company.isin([customer])].Date,
                y=df.loc[df.Company.isin([customer])].Profit,
                name = "Profit - " + str(customer)
            )

        fig.append_trace(trace1,1,1)
        fig.append_trace(trace2,2,1)


    def create_layout_button(customer):
        return dict(label = customer,
                    method = 'restyle',
                    args = [{'visible': [cust == customer for cust in list(df.Company.unique())],
                             'title': customer,
                             'showlegend': True}])

    fig.update_layout(
        updatemenus=[go.layout.Updatemenu(
            active = 0,
            buttons = [create_layout_button(customer) for customer in list(df.Company.unique())]
            )
        ])
    
    fig.show()

At first glance, this seems to be doing what I want. However, I am running into 2 issues which I can't solve:

  1. When the function is first called, it plots the data for ALL of the companies on the two plots, rather than just the first company (which is what I want). This does fix itself once you do select a company from the dropdown menu, although that introduces us to our next issue...Output when you first call the make_multi_plot function

  2. When you do select a Company from the dropdown menu, it doesn't actually update the plots correctly, it is using the wrong company's data to make the plots. If you look at the legend for the two plots, you can see that it is actually plotting the data for different companies in the set. I have no idea why this is happening and haven't been able to find any real pattern in how it's confusing the various plots with the buttons. When you choose a company from the dropdown, it doesn't update the plots with the right data

Appreciate any and all help!

  • I also have experienced issue #1 from your question and haven't seen to have found a solution yet. Although, just to force the end-user in a way to update the plot with one series set the `active = -1` (which selects a blank drop down option). Also here's the [link](https://stackoverflow.com/questions/64893793/add-index-as-dropdown-menu-in-plotly/64898132#64898132) to my solution on dropdown menus and how to create buttons if you are using multiple traces per option (in your case each company has an amount and profit trace). – Jacob K Jan 29 '21 at 03:23
  • @JacobK thanks for the message, your solution for the dropdown menus worked for my case as well! With regards to the first problem, my work around as of now is to add an "All" button to the dropdown menu, so that it at least looks like I meant to display all of the plots at the beginning haha – Chelsea Boy Jan 29 '21 at 14:16

0 Answers0