Search code examples
pythonpython-3.xpandasplotlyplotly-python

How to show individual values from specific condition of dataframe for each bar using plotly python?


I have a several dataframes with user's order information like that:

A = {
    'user': ['a', 'b', 'c', 'd', 'e', 'f'],
    'country': ['UK', 'US', 'US', 'UK', 'UK', 'US'],
    'order': [1, 2, 2, 4, 4, 4]}

B = {
    'user': ['a', 'b', 'c', 'd', 'e', 'f'],
    'country': ['US', 'US', 'UK', 'FR', 'UK', 'US'],
    'order': [2, 2, 3, 3, 3, 3]}

A = pd.DataFrame(A)
B = pd.DataFrame(B)
user country order
0 a UK 1
1 b US 2
2 c US 2
3 d UK 4
4 e UK 4
5 f US 4
user country order
0 a US 2
1 b US 2
2 c UK 3
3 d FR 3
4 e UK 3
5 f US 3

I am trying to plot this data in such a way that I can see number of users vs number of orders. And also show the (unique) countries related to the order group when I navigate to the bar on plot (pass these countries to hovertemplate function?). I can get list of lists with unique countries of each order group (country_list), but I am struggling to pass the correct list of countries separately to each corresponding bar. Like in the highlighted plot (dataframe:B, order group: 3, number of users: 4) I want it to display unique countries: ['US', 'UK', 'FR'] related to that order group . Can anyone help with it?

data_dict = {"A" : A, "B": B}

fig = go.Figure()

for i in data_dict:
    tmp = data_dict[i]
    X = tmp["order"].value_counts().keys()
    Y = tmp["order"].value_counts().to_list()
    country_list = [tmp[tmp['order']==k]['country'].unique().tolist() for k in X]
    fig = fig.add_trace(go.Bar(x = X,
                               y = Y, 
                               hovertemplate='Users: %s' % (country_list),
                               name = i))
    
fig['layout']['yaxis']['title']='Users Count'
fig.update_xaxes(title='Orders')
fig.update_layout(height=500, width=1000)
fig.update_traces(texttemplate='%{y}', textposition='outside')

Like currently it displays the whole list of unique country lists regardless of order group: enter image description here

enter image description here

But I want it to display only the list of countries specific to that order group:

enter image description here


Solution

  • To get the hover templates as you need, please change the hovertemplate line to this...

    hovertemplate="Users: %{text}", text = country_list,
    

    A bit more explanation - the country_list is a list of lists. For hovertemplate, it is expecting a list for each add_trace. The code is expected in the format mentioned above. Adding just (country_list) was causing the issue. Full updated code and working screenshot below.

    import plotly.graph_objects as go
    A = {
        'user': ['a', 'b', 'c', 'd', 'e', 'f'],
        'country': ['UK', 'US', 'US', 'UK', 'UK', 'US'],
        'order': [1, 2, 2, 4, 4, 4]}
    B = {
        'user': ['a', 'b', 'c', 'd', 'e', 'f'],
        'country': ['US', 'US', 'UK', 'FR', 'UK', 'US'],
        'order': [2, 2, 3, 3, 3, 3]}
    
    A = pd.DataFrame(A)
    B = pd.DataFrame(B)
    data_dict = {"A" : A, "B": B}
    
    fig = go.Figure()
    
    for i in data_dict:
        tmp = data_dict[i]
        X = tmp["order"].value_counts().keys()
        Y = tmp["order"].value_counts().to_list()
        country_list = [tmp[tmp['order']==k]['country'].unique().tolist() for k in X]
        fig = fig.add_trace(go.Bar(x = X, y = Y, 
                                   hovertemplate="Users: %{text}", text = country_list,
                                   name = i))    
    fig['layout']['yaxis']['title']='Users Count'
    fig.update_xaxes(title='Orders')
    fig.update_layout(height=500, width=1000)
    fig.update_traces(texttemplate='%{y}', textposition='outside')
    

    Output screenshots

    enter image description here