Change stacked bar graph color with dropdown - python

I'm trying to create a stacked bar chart and then change color of it by dropdown value. Below is my sample code:
import pandas as pd
import numpy as np
import plotly.express as px
import dash
from dash import html
from dash import dcc
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
app = dash.Dash(__name__,external_stylesheets=[dbc.themes.LUX]) # You can change external_stylesheets
# Make the layout with two tabs
colorscales = dir(px.colors.qualitative)
df = px.data.medals_long()
app.layout = html.Div([
dbc.Row([html.H6('Color Palette',className='text-left'),
dcc.Dropdown(id='color_range',placeholder="Color", # Dropdown for heatmap color
options=colorscales,
value='aliceblue',
multi=False,
disabled=False,
clearable=True,
searchable=True),
dcc.Graph(id='bar_chart',figure={},style={'height':500,'width':'auto'})
])
])
#app.callback(Output('bar_chart','figure'),
[Input('color_range', 'value')])
def update_color(color_range):
fig = px.bar(df, x="medal", y="count", color="nation", text="nation",
color_discrete_sequence = color_range)
return fig
if __name__ == "__main__":
app.run_server(debug=False)
But it raised an error that said:
ValueError:
Invalid value of type 'builtins.str' received for the 'color' property of bar.marker
Received value: 'a'
The 'color' property is a color and may be specified as:
- A hex string (e.g. '#ff0000')
- An rgb/rgba string (e.g. 'rgb(255,0,0)')
- An hsl/hsla string (e.g. 'hsl(0,100%,50%)')
- An hsv/hsva string (e.g. 'hsv(0,100%,100%)')
- A named CSS color:
aliceblue, antiquewhite, aqua, aquamarine, azure,
I tried to change from colorscales = dir(px.colors.qualitative) to colorscales = px.colors.named_colorscales() and then change color_discrete_sequence to color_continuous_scale but it didn't work. It didn't raise error but color not change.
Thank you.

The modification is that the drop-down default should choose a qualitative color name. And the bar chart color specification needs to be written in the form px.colors.qualitative.G10.
app.layout = html.Div([
dbc.Row([html.H6('Color Palette',className='text-left'),
dcc.Dropdown(id='color_range',placeholder="Color", # Dropdown for heatmap color
options=colorscales,
value='Plotly',# update
multi=False,
disabled=False,
clearable=True,
searchable=True),
dcc.Graph(id='bar_chart',figure={},style={'height':500,'width':'auto'})
])
])
def update_color(color_range):
df = px.data.medals_long() # update
fig = px.bar(df, x="medal", y="count", color="nation", text="nation",
color_discrete_sequence = eval('px.colors.qualitative.{}'.format(color_range))) # update
return fig

Related

Dash app, plotly chart data outside the chart area

I have written following code which updates Plotly Chart with some random values every 5 seconds, however after few seconds the new data is located outside the chart and is not visible. Is there an easy way to reset the axes everytime it's needed?
Also how can I make this responsive so it will auto-scale to full window?
import requests
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
from datetime import datetime
import json
import plotly.graph_objs as go
import random
# Create empty lists to store x and y values
x_values = []
y_values = []
# Initialize the dash app
app = dash.Dash()
app.layout = html.Div([
dcc.Graph(id='live-graph', animate=True,responsive=True),
dcc.Interval(
id='graph-update',
interval=5000,
n_intervals=0
),
])
# Define the callback function
#app.callback(Output('live-graph', 'figure'), [Input('graph-update', 'n_intervals')])
def update_graph(n):
current_value= random.randint(2000, 8000)
# Get the current datetime
x = datetime.now()
x_values.append(x)
# Get the response value and append it to the y_values list
y = current_value
y_values.append(y)
# Create the line chart
trace = go.Scatter(x=x_values, y=y_values)
data = [trace]
layout = go.Layout(title='Real-time Data',
xaxis=dict(title='Datetime'),
yaxis=dict(title='Value'))
return go.Figure(data=data, layout=layout).update_layout(
autosize=True,
margin=dict(l=0, r=0, t=0, b=0)
)
if __name__ == '__main__':
app.run_server(debug=False)
Many thanks!
Using this method.
Fixed y axis range from 2000 to 8000
And x axis range find min and max every time.
layout = go.Layout(title='Real-time Data',
yaxis_range=[2000,8000],
xaxis_range=[min(x_values),max(x_values)],
xaxis=dict(title='Datetime'),
yaxis=dict(title='Value'))
return go.Figure(data=data, layout=layout).update_layout(
autosize=True,
margin=dict(l=0, r=0, t=50, b=50)
)

How do I include a histogram of the variables of my dataset to my dash app?

I want to add a histogram to my dash app where the user can select what variable they want to use from the given dataset. There are 11 variables and I want to have the user select a variable from the drop down menu and in response, a histogram will be created for said variable. I am having ALOT of trouble understanding how the input and out works and where I should place the graph. (I would like to have it placed under the description.) Here is what I have so far:
import dash
import pandas as pd
from dash import Input, Output
from dash import dash_table
from dash import dcc
from dash import html
app = dash.Dash(__name__)
df = pd.read_csv('C:\\Users\\Programming\\diamonds.csv')
app.layout = html.Div([
html.H1("Diamonds", style={'text-align': 'center'}),
html.Div(["Choose the number of observations x*: ",
dcc.Input(id='top_of_table', value=10, type='number')]),
dash_table.DataTable(id="any_id"),
html.H1("Description", style={'text-align': 'center'}),
html.Div("This is a dataframe containing 11 variables on Diamonds.
The variables are the "
"following: price, carat, clarity, cut, color, depth, table,
x, y, z, and date."
"Range in price is $338-$18791.Carats or weight of the
diamond ranges from .2-3.0."),
])
#app.callback(
Output(component_id="any_id", component_property='data'),
Input(component_id='top_of_table', component_property='value'),
)
def diamond_function(num_observ):
df1 = df.head(10)
return df1.to_dict('records')
if __name__ == '__main__':
app.run_server(debug=True)
Any help? I really appreciate it! Thanks!
I don't have your dataframe so that I just make below code as referrence:
import dash
import pandas as pd
import plotly.express as px
from dash import Input, Output
from dash import dash_table
from dash import dcc
from dash import html
app = dash.Dash(__name__)
app.layout = html.Div([
html.H1("Diamonds", style={'text-align': 'center'}),
html.Div(["Choose the number of observations x*: ",
dcc.Input(id='top_of_table', value=10, type='number')]),
dash_table.DataTable(id="any_id"),
html.H1("Description", style={'text-align': 'center'}),
html.Div("This is a dataframe containing 11 variables on Diamonds. The variables are the "
"following: price, carat, clarity, cut, color, depth, table, x, y, z, and date."
"Range in price is $338-$18791.Carats or weight of the diamond ranges from .2-3.0."),
html.Div([
dcc.Dropdown(id='variables',
options=[{'label':x,'name':x} for x in df.sort_values('Variables')['Variables'].unique()],
value=[],
multi=False,
disabled=False,
clearable=True,
searchable=True
)
]),
html.Div([
dcc.Graph(id='figure_1',figure={})
])
])
#app.callback(Output('figure_1','figure'),
[Input('variables','value')])
def update_graph(variables):
if variables != []:
dff = df[df['Variables'] == variables]
fig = px.histogram(...)
else:
dff= df.copy()
fig = px.histogram(...)
return fig
if __name__ == '__main__':
app.run_server(debug=False)
So you will need to add dcc.Dropdown as variables and dcc.Graph to show histogram for each variable.

Plotly go: how to add an image to the hover feature?

The first segment of code below (code # 1) generates a graph for which 1) when you hover over each point, the data associated with each point is displayed and 2) when you click on each point, the data associated with each point is saved to a list. For this code, I would also like to display the image associated with each point. Assume the dataframe df has a column 'image' which contains the image pixel/array data of each point. I found code online (code #2) that implements this image hover feature but without the click feature. I'm having a hard time combining the image hover feature with the click feature. So, basically, I'm trying to combine the click feature (click on point, it's data is saved to a list) of code # 2 into code # 1.
CODE # 1 (with click feature):
import json
from textwrap import dedent as d
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
from dash import dcc
import dash_html_components as html
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
# app info
app = JupyterDash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
# data
df = px.data.gapminder().query("continent=='Oceania'")
# plotly figure
fig = px.line(df, x="year", y="lifeExp", color="country", title="No label selected")
fig.update_traces(mode="markers+lines")
app.layout = html.Div([
dcc.Graph(
id='figure1',
figure=fig,
),
html.Div(className
='row', children=[
html.Div([
dcc.Markdown(d("""Hoverdata using figure references""")),
html.Pre(id='hoverdata2', style=styles['pre']),
], className='three columns'),
html.Div([
dcc.Markdown(d("""
Full hoverdata
""")),
html.Pre(id='hoverdata1', style=styles['pre']),
], className='three columns')
]),
])
# container for clicked points in callbacks
store = []
#app.callback(
Output('figure1', 'figure'),
Output('hoverdata1', 'children'),
Output('hoverdata2', 'children'),
[Input('figure1', 'clickData')])
def display_hover_data(hoverData):
if hoverData is not None:
traceref = hoverData['points'][0]['curveNumber']
pointref = hoverData['points'][0]['pointNumber']
store.append([fig.data[traceref]['name'],
fig.data[traceref]['x'][pointref],
fig.data[traceref]['y'][pointref]])
fig.update_layout(title = 'Last label was ' + fig.data[traceref]['name'])
return fig, json.dumps(hoverData, indent=2), str(store)
else:
return fig, 'None selected', 'None selected'
app.run_server(mode='external', port = 7077, dev_tools_ui=True,
dev_tools_hot_reload =True, threaded=True)
CODE # 2 (includes image hover feature):
from jupyter_dash import JupyterDash
from dash import Dash, dcc, html, Input, Output, no_update
import plotly.graph_objects as go
import pandas as pd
## create sample random data
df = pd.DataFrame({
'x': [1,2,3],
'y': [2,3,4],
'z': [3,4,5],
'color': ['red','green','blue'],
'img_url': [
"https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Stack_Overflow_logo.svg/2880px-Stack_Overflow_logo.svg.png",
"https://upload.wikimedia.org/wikipedia/commons/3/37/Plotly-logo-01-square.png",
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Pandas_logo.svg/2880px-Pandas_logo.svg.png"
]
})
fig = go.Figure(data=[
go.Scatter3d(
x=df['x'],
y=df['y'],
z=df['z'],
mode='markers',
marker=dict(color=df['color'])
)
])
# turn off native plotly.js hover effects - make sure to use
# hoverinfo="none" rather than "skip" which also halts events.
fig.update_traces(hoverinfo="none", hovertemplate=None)
fig.update_layout(
scene = dict(
xaxis = dict(range=[-1,8],),
yaxis = dict(range=[-1,8],),
zaxis = dict(range=[-1,8],),
),
)
app = JupyterDash(__name__)
server = app.server
app.layout = html.Div([
dcc.Graph(id="graph-basic-2", figure=fig, clear_on_unhover=True),
dcc.Tooltip(id="graph-tooltip"),
])
#app.callback(
Output("graph-tooltip", "show"),
Output("graph-tooltip", "bbox"),
Output("graph-tooltip", "children"),
Input("graph-basic-2", "hoverData"),
)
def display_hover(hoverData):
if hoverData is None:
return False, no_update, no_update
# demo only shows the first point, but other points may also be available
pt = hoverData["points"][0]
bbox = pt["bbox"]
num = pt["pointNumber"]
df_row = df.iloc[num]
img_src = df_row['img_url']
children = [
html.Div([
html.Img(src=img_src, style={"width": "100%"}),
], style={'width': '100px', 'white-space': 'normal'})
]
return True, bbox, children
app.run_server(mode="inline")
you want a callback that does hover and click
on hover display image associated with point and full hover info
on click update list of clicked points and figure title
Assume the dataframe df has a column 'image' have created one that is a b64 encoded image
have inserted this into the figure by using customdata (hover_data parameter in px)
have added an additional div image
have changed callback to behave as it did before and also contents on new div. This uses b64 encoded image, extending with necessary "data:image/png;base64,"
need to take note of this https://dash.plotly.com/vtk/click-hover and https://dash.plotly.com/advanced-callbacks
import json
from textwrap import dedent as d
import pandas as pd
import plotly.graph_objects as go
import numpy as np
import dash
import plotly.express as px
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash
import warnings
import base64, io, requests
from PIL import Image
from pathlib import Path
warnings.simplefilter(action="ignore", category=FutureWarning)
# app info
app = JupyterDash(__name__)
styles = {"pre": {"border": "thin lightgrey solid", "overflowX": "scroll"}}
# data for whare images can be found
df_flag = pd.read_csv(
io.StringIO(
"""country,Alpha-2 code,Alpha-3 code,URL
Australia,AU,AUS,https://www.worldometers.info//img/flags/small/tn_as-flag.gif
New Zealand,NZ,NZL,https://www.worldometers.info//img/flags/small/tn_nz-flag.gif"""
)
)
# ensure that images exist on your file system...
f = Path.cwd().joinpath("flags")
if not f.exists():
f.mkdir()
# download some images and use easy to use filenames...
for r in df_flag.iterrows():
flag_file = f.joinpath(f'{r[1]["Alpha-3 code"]}.gif')
if not flag_file.exists():
r = requests.get(r[1]["URL"], stream=True, headers={"User-Agent": "XY"})
with open(flag_file, "wb") as fd:
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
# encode
def b64image(country):
b = io.BytesIO()
im = Image.open(Path.cwd().joinpath("flags").joinpath(f"{country}.gif"))
im.save(b, format="PNG")
b64 = base64.b64encode(b.getvalue())
return b64.decode("utf-8")
df_flag["image"] = df_flag["Alpha-3 code"].apply(b64image)
# data
df = px.data.gapminder().query("continent=='Oceania'")
df = df.merge(df_flag, on="country") # include URL and b64 encoded image
# plotly figure. Include URL and image columns in customdata by using hover_data
fig = px.line(
df,
x="year",
y="lifeExp",
color="country",
title="No label selected",
hover_data={"URL": True, "image": False},
)
fig.update_traces(mode="markers+lines")
app.layout = dash.html.Div(
[
dash.dcc.Graph(
id="figure1",
figure=fig,
),
dash.html.Div(
className="row",
children=[
dash.html.Div(id="image"),
dash.html.Div(
[
dash.dcc.Markdown(d("""Hoverdata using figure references""")),
dash.html.Pre(id="hoverdata2", style=styles["pre"]),
],
className="three columns",
),
dash.html.Div(
[
dash.dcc.Markdown(
d(
"""
Full hoverdata
"""
)
),
dash.html.Pre(id="hoverdata1", style=styles["pre"]),
],
className="three columns",
),
],
),
]
)
# container for clicked points in callbacks
store = []
#app.callback(
Output("figure1", "figure"),
Output("hoverdata1", "children"),
Output("hoverdata2", "children"),
Output("image", "children"),
[Input("figure1", "clickData"), Input("figure1", "hoverData")],
)
def display_hover_data(clickData, hoverData):
# is it a click or hover event?
ctx = dash.callback_context
if ctx.triggered[0]["prop_id"] == "figure1.clickData":
traceref = clickData["points"][0]["curveNumber"]
pointref = clickData["points"][0]["pointNumber"]
store.append(
[
fig.data[traceref]["name"],
fig.data[traceref]["x"][pointref],
fig.data[traceref]["y"][pointref],
]
)
fig.update_layout(title="Last label was " + fig.data[traceref]["name"])
return fig, dash.no_update, str(store), dash.no_update
elif ctx.triggered[0]["prop_id"] == "figure1.hoverData":
# simpler case of just use a URL...
# dimg = dash.html.Img(src=hoverData["points"][0]["customdata"][0], style={"width": "30%"})
# question wanted image encoded in dataframe....
dimg = dash.html.Img(
src="data:image/png;base64," + hoverData["points"][0]["customdata"][1],
style={"width": "30%"},
)
return fig, json.dumps(hoverData, indent=2), dash.no_update, dimg
else:
return fig, "None selected", "None selected", "no image"
# app.run_server(mode='external', port = 7077, dev_tools_ui=True,
# dev_tools_hot_reload =True, threaded=True)
app.run_server(mode="inline")

How to add values from selectedData input to a list?

I build a Plotly Dash web app to display sensor data. I want to have a map where I can select the stations and therefore I can see the time series chart.
This is my callback right now:
#app.callback(
Output('time_series1', 'figure'),
Input('map_sensors', 'selectedData'))
def display_selected_data(selectedData):
if selectedData is None: # Plot whole Dataframe if nothing is selected.
fig = px.line(data_frame=df, x='date.utc', y='value', color='location')
return fig
else:
selectedData['points'][0]['customdata'][0] # This line shows me the name of the location and I want to add this to a list
return
I can show the location in the selected data. Now my question is, how can I add this to a list?
My goal ist to filter the dataframe like this dff2 = df[df.location.isin(selected_locations)] so that I only plot the selected locations.
My full app right now:
from jupyter_dash import JupyterDash
import plotly.graph_objs as go
from dash import Dash, dcc, html, Input, Output, State
import pandas as pd
import plotly.express as px
import json
loc = pd.read_csv('location_sensors.csv')
df = pd.read_csv('measurement.csv')
style = {'width': '50%', 'height': '500px', 'float': 'left'}
# Build small example app.
app = dash.Dash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
fig_map = px.scatter_mapbox(loc, lat="lat", lon="lon", hover_name="location",
hover_data={'location':True, 'lat':False, 'lon':False}, zoom=3, height=600,
color='location', mapbox_style="open-street-map")
fig_map.update_layout(clickmode='event+select')
app.layout = html.Div([
dcc.Graph(id='map_sensors', figure=fig_map , className='six columns'),
html.Div([dcc.Graph(
id='time_series1',
style={'height': 400}
),
])
])
#app.callback(
Output('time_series1', 'figure'),
Input('map_sensors', 'selectedData'))
def display_selected_data(selectedData):
if selectedData is None:
fig = px.line(data_frame=df, x='date.utc', y='value', color='location')
return fig
else:
# Here I want to filter the dataframe to the selected locations.
return
if __name__ == '__main__':
app.run_server()
Locations csv data:
lat,lon,location
51.20966,4.43182,BETR801
48.83722,2.3939,FR04014
51.49467,-0.13193,London Westminster
Time series data:
https://github.com/pandas-dev/pandas/blob/master/doc/data/air_quality_long.csv
For your #app.callback decorator, I think you want your input to be clickData instead of selectionData. If you look at the first example in the documentation here, once you click a location on the map and it is greyed out, when you click it again at a later time, clickData will input a dictionary with marker information, while selectionData will input null (this means that dash will have trouble knowing when you click on a point again after it's been greyed out if you use selectionData instead of clickData)
You can then have a dynamic list that changes depending on locations the user selects and deselects. Also a very minor point, but I changed your DataFrame variable name from loc to locs since .loc is a pandas DataFrame method.
from jupyter_dash import JupyterDash
import plotly.graph_objs as go
import dash
from dash import Dash, dcc, html, Input, Output, State
import pandas as pd
import plotly.express as px
import json
locs = pd.read_csv('location_sensors.csv')
df = pd.read_csv('https://raw.githubusercontent.com/pandas-dev/pandas/master/doc/data/air_quality_long.csv')
style = {'width': '50%', 'height': '500px', 'float': 'left'}
# Build small example app.
app = dash.Dash(__name__)
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
fig_map = px.scatter_mapbox(locs, lat="lat", lon="lon", hover_name="location",
hover_data={'location':True, 'lat':False, 'lon':False}, zoom=3, height=600,
color='location', mapbox_style="open-street-map")
fig_map.update_layout(clickmode='event+select')
app.layout = html.Div([
dcc.Graph(id='map_sensors', figure=fig_map , className='six columns'),
html.Div([dcc.Graph(
id='time_series1',
style={'height': 400}
),
])
])
## define a list that will hold the columns of the dataframe
## this will be used to modify the px.line chart
selected_locations = list(locs['location'])
#app.callback(
Output('time_series1', 'figure'),
Input('map_sensors', 'clickData'))
def display_selected_data(clickData):
## when the app initializes
if clickData is None:
fig = px.line(data_frame=df, x='date.utc', y='value', color='location')
## when the user clicks on one of the loc points
else:
selection = clickData['points'][0]['customdata'][0]
if selection in selected_locations:
selected_locations.remove(selection)
else:
selected_locations.append(selection)
fig = px.line(data_frame=df[df.location.isin(selected_locations)], x='date.utc', y='value', color='location')
return fig
if __name__ == '__main__':
app.run_server(debug=True)

Python Plotly Dash dropdown Adding a "select all" for scatterplot

I would like to add a select all for my dropdown, and make it the default when the app opens up, with the ability to then one by one remove capsule and also to unselect the select all button and select a group of capsule. I managed to find several ways that other people have use the select all option but none seems to work for my situation. Thank you!
Data looks this this.
Dash look like this.
import pandas as pd
import plotly.express as px # (version 4.7.0)
import plotly.graph_objects as go
import dash # (version 1.12.0) pip install dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
app = dash.Dash(__name__)
server = app.server
df = pd.read_csv("tcd vs rh.csv")
print(df)
capsuleID = df['Capsule_ID'].unique()
print(capsuleID)
capsuleID_names = list(capsuleID)
print(capsuleID_names)
capsuleID_names_1 = [{'label': k, 'value': k } for k in sorted(capsuleID)]
capsuleID_names_2 = [{'label': '(Select All)', 'value': 'All'}]
capsuleID_names_all = capsuleID_names_1 + capsuleID_names_2
app.layout = html.Div([
html.H1("Web Application Dashboards with Dash", style={'text-align': 'center'}),
dcc.Dropdown(id="capsule_select",
options=capsuleID_names_all,
optionHeight=25,
multi=True,
searchable=True,
placeholder='Please select...',
clearable=True,
value=[''],
style={'width': "40%"}
),
html.Div([
dcc.Graph(id="the_graph")
]),
])
# -----------------------------------------------------------
#app.callback(
Output('the_graph', 'figure'),
[Input('capsule_select', 'value')]
)
def update_graph(capsule_chosen):
if capsule_chosen == 'all_values':
dff = df['Capsule_ID']
else:
dff = df[df['Capsule_ID'].isin(capsule_chosen)] # filter all rows where capsule ID is the capsule ID selected
scatterplot = px.scatter(
data_frame=dff,
x="tcd",
y="humidity",
)
scatterplot.update_traces(textposition='top center')
return scatterplot
# ------------------------------------------------------------------------------
if __name__ == '__main__':
app.run_server(debug=True)
If by default you want to select everything from df['Capsule_ID'] you can simply pass it to the value of your dropdown.
Then you can change your callback to something like this for the 'select all' functionality:
#app.callback(
Output("the_graph", "figure"),
Output("capsule_select", "value"),
Input("capsule_select", "value"),
)
def update_graph(capsules_chosen):
dropdown_values = capsules_chosen
if "All" in capsules_chosen:
dropdown_values = df["Capsule_ID"]
dff = df
else:
dff = df[df["Capsule_ID"].isin(capsules_chosen)]
scatterplot = px.scatter(
data_frame=dff,
x="tcd",
y="humidity",
)
scatterplot.update_traces(textposition="top center")
return scatterplot, dropdown_values
In addition to your check not working with the default dropdown value, you were doing this:
dff = df['Capsule_ID']
which means you were setting dff to a single column. This is not what want since 'tcd' and 'humidity' columns don't exist on df['Capsule_ID'].

Categories