dash-app-gallery
dash-app-gallery copied to clipboard
Adding Parallel Coordinates app
Hi @IcToxi , That parellel coordinates app you proposed is really good. Thanks for sharing. Can you please use the final app code below that I modified to create a pull request and add that app to the gallery.
I would prefer being more explicit with constraintrange so it's easier for beginners to understand what's happening. Thus, instead of:
for i, v in enumerate(f.get("data")[0].get("dimensions")):
v.update({"constraintrange": [row[i] - row[i] / 100000, row[i]]})
I modified it to:
fig.update_traces(dimensions=list([
dict(constraintrange=[row[0] - row[0] / 100000, row[0]]),
dict(constraintrange=[row[1] - row[1] / 100000, row[1]]),
dict(constraintrange=[row[2] - row[2] / 100000, row[2]]),
dict(constraintrange=[row[3] - row[3] / 100000, row[3]]),
dict(constraintrange=[row[4] - row[4] / 100000, row[4]])
]))
Final app code:
from dash import Dash, html, dcc, dash_table, Output, Input, State
from dash.exceptions import PreventUpdate
import plotly.express as px
df = px.data.iris()
fig = px.parallel_coordinates(
df,
color="species_id",
labels={
"species_id": "Species",
"sepal_width": "Sepal Width",
"sepal_length": "Sepal Length",
"petal_width": "Petal Width",
"petal_length": "Petal Length",
},
color_continuous_scale=px.colors.diverging.Tealrose,
color_continuous_midpoint=2,
)
app = Dash(__name__)
app.layout = html.Div(
[
my_graph := dcc.Graph(figure=fig),
my_table := dash_table.DataTable(
df.to_dict("records"),
row_selectable="single",
),
]
)
@app.callback(
Output(my_graph, "figure"),
Input(my_table, "selected_rows"),
State(my_graph, "figure"),
)
def pick(r, f):
if r is None:
raise PreventUpdate
row = (
df[["sepal_length", "sepal_width", "petal_length", "petal_width", "species_id"]]
.loc[r[0]]
.to_list()
)
fig = px.parallel_coordinates(
df,
color="species_id",
labels={
"species_id": "Species",
"sepal_width": "Sepal Width",
"sepal_length": "Sepal Length",
"petal_width": "Petal Width",
"petal_length": "Petal Length",
},
color_continuous_scale=px.colors.diverging.Tealrose,
color_continuous_midpoint=2,
)
fig.update_traces(dimensions=list([
dict(constraintrange=[row[0] - row[0] / 100000, row[0]]),
dict(constraintrange=[row[1] - row[1] / 100000, row[1]]),
dict(constraintrange=[row[2] - row[2] / 100000, row[2]]),
dict(constraintrange=[row[3] - row[3] / 100000, row[3]]),
dict(constraintrange=[row[4] - row[4] / 100000, row[4]])
]))
return fig
if __name__ == "__main__":
app.run_server(debug=True)
Actually, I don't think this is more clear. How about adding a comment to the code to say why this is needed? And/or a link to the docs for more info?
fig.update_traces(dimensions=list([
dict(constraintrange=[row[0] - row[0] / 100000, row[0]]),
dict(constraintrange=[row[1] - row[1] / 100000, row[1]]),
dict(constraintrange=[row[2] - row[2] / 100000, row[2]]),
dict(constraintrange=[row[3] - row[3] / 100000, row[3]]),
dict(constraintrange=[row[4] - row[4] / 100000, row[4]])
]))
Good point. Maybe something like this:
from dash import Dash, html, dcc, dash_table, Output, Input, State
from dash.exceptions import PreventUpdate
import plotly.express as px
df = px.data.iris()
fig = px.parallel_coordinates(
df,
color="species_id",
labels={
"species_id": "Species",
"sepal_width": "Sepal Width",
"sepal_length": "Sepal Length",
"petal_width": "Petal Width",
"petal_length": "Petal Length",
},
color_continuous_scale=px.colors.diverging.Tealrose,
color_continuous_midpoint=2,
)
app = Dash(__name__)
app.layout = html.Div(
[
my_graph := dcc.Graph(figure=fig),
my_table := dash_table.DataTable(
df.to_dict("records"),
row_selectable="single",
),
]
)
@app.callback(
Output(my_graph, "figure"),
Input(my_table, "selected_rows"),
State(my_graph, "figure"),
)
def pick(r, f):
if r is None:
raise PreventUpdate
row = (
df[["sepal_length", "sepal_width", "petal_length", "petal_width", "species_id"]]
.loc[r[0]]
.to_list()
)
fig = px.parallel_coordinates(
df,
color="species_id",
labels={
"species_id": "Species",
"sepal_width": "Sepal Width",
"sepal_length": "Sepal Length",
"petal_width": "Petal Width",
"petal_length": "Petal Length",
},
color_continuous_scale=px.colors.diverging.Tealrose,
color_continuous_midpoint=2,
)
# Use `constraintrange` to filter a certain trace. Read more in docs:
# https://plotly.com/python/reference/parcoords/#parcoords-dimensions
fig.update_traces(dimensions=list([
dict(constraintrange=[row[0] - row[0] / 100000, row[0]]),
dict(constraintrange=[row[1] - row[1] / 100000, row[1]]),
dict(constraintrange=[row[2] - row[2] / 100000, row[2]]),
dict(constraintrange=[row[3] - row[3] / 100000, row[3]]),
dict(constraintrange=[row[4] - row[4] / 100000, row[4]])
]))
return fig
if __name__ == "__main__":
app.run_server(debug=True)
The thing is, the documentation tells me that there can be <= but it's actually <. I also don't think it's clear here, so that's why I discuss it first.
Yes, I think you're right. It has to be <.
Closing this since it's related to the PR that was closed.