1
votes

I'm creating a bar chart in Plotly Express and would like to sum the "text" values displayed on the plot.

My data is as follows:

import plotly.express as px
import pandas as pd
df = pd.DataFrame({'Make':['Mercedes', 'BMW', 'Mercedes', 'Mercedes', 'Chrysler', 'Chrysler', 'Chrysler', 'Chrysler', 'BMW', 'Chrysler', 'BMW', 'Mercedes', 'BMW', 'Mercedes'],
                          'Dimension':['Styling', 'Styling', 'Price', 'Styling', 'MPG', 'MPG', 'Styling', 'Styling', 'MPG', 'MPG', 'Price', 'Price', 'Styling', 'MPG'],
                          'Country':['USA', 'USA', 'USA', 'Germany', 'USA', 'USA', 'USA', 'England', 'Germany', 'USA', 'Germany', 'Poland', 'Italy', 'USA'],
                          'LowValue':['64', '61', '70', '65', '59', '68', '63', '57', '58', '55', '69', '63', '69', '61'],
                          'HighValue':['82', '95', '93', '95', '87', '93', '85', '85', '95', '92', '83', '87', '80', '80']})

I plot this data in Plotly Express using the following:

px.bar(df, x='Make', y='LowValue', color='Dimension', 
       barmode='group', text='LowValue')

As you can see, the Styling bar for Mercedes shows two values: 65 and 64 (because those are the underlying data points).

Question: Is there a way to coalesce the underlying data into a single value and only display that single summed up value?

For example, displaying 129 (the sum of the underlying data points) at the top of the Styling bar for Mercedes (instead of displaying 65 and 64).

Thanks!

2
Just to clarify do you want to show 64, 65 and 129 on top?rpanai
No, I do not want to show 64 and 65. I only want to show the summed up values at the top of the bars.equanimity
It seems to me that there is not a simple way to do it and that you should play with annotation and offsets for every 'offsetgroup'rpanai

2 Answers

1
votes

You could use the groupby() function in pandas to calculate the total LowValue by Make and Dimension before creating the bar chart. I included an example below.

import plotly.express as px
import pandas as pd

df = pd.DataFrame({'Make': ['Mercedes', 'BMW', 'Mercedes', 'Mercedes', 'Chrysler', 'Chrysler', 'Chrysler', 'Chrysler', 'BMW', 'Chrysler', 'BMW', 'Mercedes', 'BMW', 'Mercedes'],
                   'Dimension': ['Styling', 'Styling', 'Price', 'Styling', 'MPG', 'MPG', 'Styling', 'Styling', 'MPG', 'MPG', 'Price', 'Price', 'Styling', 'MPG'],
                   'Country': ['USA', 'USA', 'USA', 'Germany', 'USA', 'USA', 'USA', 'England', 'Germany', 'USA', 'Germany', 'Poland', 'Italy', 'USA'],
                   'LowValue': ['64', '61', '70', '65', '59', '68', '63', '57', '58', '55', '69', '63', '69', '61'],
                   'HighValue': ['82', '95', '93', '95', '87', '93', '85', '85', '95', '92', '83', '87', '80', '80']})

df['LowValue'] = df['LowValue'].astype(int)

df1 = pd.DataFrame(df.groupby(by=['Make', 'Dimension'])['LowValue'].sum())

df1.reset_index(inplace=True)

fig = px.bar(df1, x='Make', y='LowValue', color='Dimension', barmode='group', text='LowValue')

fig.show()

enter image description here

0
votes

I guess that there is a way as long as you are willing to modify your original df

Data sample

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

df = pd.DataFrame({'Make':['Mercedes', 'BMW', 'Mercedes', 'Mercedes', 'Chrysler', 'Chrysler', 'Chrysler', 'Chrysler', 'BMW', 'Chrysler', 'BMW', 'Mercedes', 'BMW', 'Mercedes'],
                          'Dimension':['Styling', 'Styling', 'Price', 'Styling', 'MPG', 'MPG', 'Styling', 'Styling', 'MPG', 'MPG', 'Price', 'Price', 'Styling', 'MPG'],
                          'Country':['USA', 'USA', 'USA', 'Germany', 'USA', 'USA', 'USA', 'England', 'Germany', 'USA', 'Germany', 'Poland', 'Italy', 'USA'],
                          'LowValue':['64', '61', '70', '65', '59', '68', '63', '57', '58', '55', '69', '63', '69', '61'],
                          'HighValue':['82', '95', '93', '95', '87', '93', '85', '85', '95', '92', '83', '87', '80', '80']})

# we better use int here
df[["LowValue", "HighValue"]] = df[["LowValue", "HighValue"]].astype(int)

Arrange Data

Now you want to have sum for LowValue but as you want to display only one you need to play a bit

df["LowValueSum"] = df.groupby(["Make", "Dimension"])["LowValue"]\
                      .transform(sum)

# Here we consider the latest index within the goupby only 
df["idx_max"] = df.groupby(["Make", "Dimension"])["LowValueSum"]\
                  .transform(lambda x: x.index.max())

df.loc[df["idx_max"] != df.index, "LowValueSum"] = np.nan

# now you can eventually drop the previous colums
# df = df.drop("idx_max", axis=1)

Plot

fig = px.bar(df, 
             x='Make', 
             y='LowValue',
             color='Dimension', 
             barmode='group',
             text='LowValueSum',
             hover_data={"Country":True,
                         "Dimension":False,
                         "Make":False},
             hover_name="Dimension")
fig.update_traces(textposition="outside")

enter image description here

Update Given that 182 looks really close to the upper range you can eventually add this line

fig.update_yaxes(range=[0, df["LowValueSum"].max() * 1.2])