@nicolaskruchten – thank you for responding.
Firstly, here is my (toy) data set:
df = pd.DataFrame({'Make':['Ford', 'Ford', 'Ford', 'BMW', 'BMW', 'BMW', Mercedes', 'Mercedes', 'Mercedes'],
'Score':['88.6', '76.6', '100', '79.1', '86.8', '96.4', '97.3', '98.7', '98.5'],
'Dimension':['Speed', 'MPG', 'Styling', 'Speed', 'MPG', 'Styling', 'Speed', 'MPG', 'Styling'],
'Month':['Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19']})
Originally, I used go.Bar(), but couldn’t figure out how to dynamically add n number of bars to the plot. So, I added them manually (knowing in advance that this particular data set contains 3 unique values for Make). Here is that code:
fig_01 = go.Figure(data=[
go.Bar(name='Ford', x=df['Make'], y=df['Score'], text=df['Score'], textposition='auto'),
go.Bar(name='BMW', x=df['Make'], y=df['Score'], text=df['Score'], textposition='auto'),
go.Bar(name='Mercedes', x=df['Make']y=df['Score'], text=df['Score'], textposition='auto')
])
The problem with this approach is that it breaks once the number of unique values in Make is anything other than 3.
Then, I stumbled upon px.bar(), which seems to dynamically add the required number of bars for you. This is great!
Using px.bar(), I’m tried to add some data labels to the bars using the text and textposition arguments that the go.Bar() function offers.
And, here is full code:
import base64
import datetime
import io
import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import plotly.graph_objects as go
import dash_table
import pandas as pd
app = dash.Dash()
app.layout = html.Div([
dcc.Upload(
id='upload-data',
children=html.Div([
'Drag and Drop or ',
html.A('Select Files')
]),
style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
# Allow multiple files to be uploaded
multiple=True
),
html.Div(id='output-data-upload'),
])
def parse_contents(contents, filename, date):
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'csv' in filename:
# Assume that the user uploaded a CSV file
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')))
elif 'xls' in filename:
# Assume that the user uploaded an excel file
df = pd.read_excel(io.BytesIO(decoded))
except Exception as e:
print(e)
return html.Div([
'There was an error processing this file.'
])
return html.Div([
html.H5(filename),
html.H6(datetime.datetime.fromtimestamp(date)),
dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'name': i, 'id': i} for i in df.columns]
),
html.Hr(), # horizontal line
dcc.Graph(
figure =
px.bar(df, x='Make', y='Score', color='Dimension', barmode='group', text='Score', textposition='auto'),
),
html.Hr(),
# For debugging, display the raw contents provided by the web browser
html.Div('Raw Content'),
html.Pre(contents[0:200] + '...', style={
'whiteSpace': 'pre-wrap',
'wordBreak': 'break-all'
})
])
@app.callback(Output('output-data-upload', 'children'),
[Input('upload-data', 'contents')],
[State('upload-data', 'filename'),
State('upload-data', 'last_modified')])
def update_output(list_of_contents, list_of_names, list_of_dates):
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)]
return children
if __name__ == '__main__':
app.run_server(debug=True)
As you can see in bold text above, I tried:
px.bar(df, x='Make', y='Score', color='Dimension', barmode='group', text='Score', textposition='auto'),
But, that results in this error message:
TypeError: bar() got an unexpected keyword argument 'textposition'
Questions:
-
Is there a one-to-one mapping between the px.Bar() arguments and the go.Bar() arguments? Is it possible to control textposition in px.Bar()?
-
Why would one use go.Bar() instead of px.Bar()? (px.Bar seems like it’s easier to use, but perhaps a bit less flexible)
-
Have I structured the code above in such a way that it conforms to “best practices” when using Plotly Dash? (or, as a complete newbie to Python, Plotly and Dash, have I completely “hacked” it together?) 
Thanks in advance!