I have the below datatable in dash. Code for generating this table is below:
import dash
import dash_table
import pandas as pd
data = {'value':['very low','low','medium','high','very high'],'data':[1,3,5,7,10]}
df = pd.DataFrame(data)
app = dash.Dash(__name__)
app.layout = dash_table.DataTable(
id='table',
columns=[{"name": i, "id": i} for i in df.columns],
data=df.to_dict('records'),
)
if __name__ == '__main__':
app.run_server(debug=True)
But I want to generate the below table. How can i do this using dash? The indicator column is a shape that is color coded based on a scale (For eg. 5 is medium and hence yellow/amber, above 5 the value go from green to dark green. Similarly, values below 5 go from amber to red
Thanks to Eduardo on the plotly community forum I learned that we can now use html content for Markdown cells of a DataTable (plotly forum thread, github pull request).
This allows us to do something like this:
import dash
import dash_html_components as html
import dash_table
import pandas as pd
def get_svg_arrow(val):
if val > 7:
fill = "green"
elif val > 5:
fill = "blue"
elif val == 5:
fill = "yellow"
elif val >= 3:
fill = "orange"
else:
fill = "red"
if val >= 5:
path = f'<path d="M19.5 11L26 11L13 -1.1365e-06L7.97623e-09 11L6.5 11L6.5 22L19.5 22L19.5 11Z" fill="{fill}"/>'
else:
path = (
f'<path d="M6.5 11H0L13 22L26 11L19.5 11V0L6.5 0L6.5 11Z" fill="{fill}"/>'
)
return f'<svg width="26" height="22" viewBox="0 0 26 22" fill="none" xmlns="http://www.w3.org/2000/svg">{path}</svg>'
values = [1, 3, 5, 7, 10]
data = {
"value": ["very low", "low", "medium", "high", "very high"],
"indicator": [get_svg_arrow(val) for val in values],
"data": values,
}
df = pd.DataFrame(data)
app = dash.Dash(__name__)
app.layout = html.Div(
[
dash_table.DataTable(
css=[dict(selector="p", rule="margin: 0px; text-align: center")],
data=df.to_dict("records"),
style_cell={"textAlign": "center"},
columns=[
{"name": col, "id": col, "presentation": "markdown"}
if col == "indicator"
else {"name": col, "id": col}
for col in df.columns
],
markdown_options={"html": True},
)
]
)
if __name__ == "__main__":
app.run_server()
So the idea of the code above is to dynamically create an arrow svg with a fill color based on the data.
For creating the svg arrows I've used a vector drawing program and exported to svg, but you could construct the path manually if you wanted to.
Result
Related
Refer to the code below:
def layout(ticker=None, **other_unknown_query_strings):
# get data for stock ticker from yahoo finance
df = yf.Ticker(ticker).history(period="12mo").reset_index()
df["Date"] = pd.to_datetime(df["Date"])
How about can I apply the same in the dataframe if I change the data location which is come from the excel csv instead of yahoo finance.
I had tried but will getting an error message
AttributeError: 'DataFrame' object has no attribute 'Ticker'
code I tried:
def layout(ticker= None, **other_unknown_query_strings):
dff = pd.read_csv("dummy2.csv")
df = dfk.Ticker(ticker).reset_index()
Expected output:
When user click the 'Microsoft', the another page will display the 'Microsoft' information in graph and table format.
Referring to multi_page_table_links
page1.py
from dash import dash_table, dcc, html, register_page
import pandas as pd
import dash_bootstrap_components as dbc
register_page(__name__, path="/")
# Create dataframe
equities = {
"Apple": "AAPL",
"Microsoft": "MSFT",
"Amazon": "AMZN",
"Alphabet": "GOOGL",
"Berkshire Hathaway": "BRK.B",
"Johnson & Johnson": "JNJ",
}
data = {
"Equities": [f"[{stock}](/stocks/{ticker})" for stock, ticker in equities.items()],
"Quantity": [75, 40, 100, 5, 40, 60],
"Market Price": [131.55, 247.39, 105.80, 2143.50, 268.08, 169.85],
"Market Value": [9866.25, 9895.60, 10580.00, 10717.50, 10723.2, 10191.00],
}
df = pd.DataFrame(data)
# dash.DataTable with links formatted by setting the column to "presentation": "markdown"
datatable = dash_table.DataTable(
data=df.to_dict("records"),
columns=[{"id": "Equities", "name": "Equities", "presentation": "markdown"}]
+ [{"id": c, "name": c} for c in df.columns if c != "Equities"],
markdown_options={"link_target": "_self"},
css=[{"selector": "p", "rule": "margin: 0"}],
style_cell={"textAlign": "right"},
)
# html table with links formatted using dcc.Link()
df["Equities"] = [
dcc.Link(f"{stock}", href=f"/stocks/{ticker}") for stock, ticker in equities.items()
]
table = dbc.Table.from_dataframe(df, striped=True, bordered=True, hover=True)
layout = html.Div(
[
html.H5(
"html table with dcc.Link Note: No page refresh on navigation",
className="mt-5",
),
table,
html.H5(
"DataTable with Markdown links", className="mt-5"
),
datatable,
]
)
page2.py
import dash
from dash import Dash, dash_table, html, dcc, Input, Output
import plotly.graph_objects as go
import yfinance as yf
import pandas as pd
def title(ticker=None):
return f"{ticker} Analysis"
def description(ticker=None):
return f"News, financials and technical analysis for {ticker}"
dash.register_page(
__name__,
path_template="/stocks/<ticker>",
title=title,
description=description,
path="/stocks/aapl",
)
def layout(ticker=None, **other_unknown_query_strings):
# get data for stock ticker from yahoo finance
df = yf.Ticker(ticker).history(period="12mo").reset_index()
df["Date"] = pd.to_datetime(df["Date"])
if df.empty:
return html.H3("No data available")
table = dash_table.DataTable(
data=df.to_dict("records"),
columns=[{"name": i, "id": i} for i in df.columns],
sort_action="native",
style_table={"overflowX": "auto"},
page_size=10
)
# create a figure based on the ticker
fig = go.Figure(
go.Candlestick(
x=df["Date"],
open=df["Open"],
high=df["High"],
low=df["Low"],
close=df["Close"],
)
)
# stock page layout
return html.Div(
[
html.H3(f"Market prices last 12 months for: {ticker}"),
dcc.Graph(figure=fig),
table,
]
)
Below is my code, but the code not works,
first 5 options in dropdown returns a graph and
option 6 needs to display a google form
without the 6th option the code is working fine, but the 6th option for displaying gform is throwing errror in dash
help me solve this
app.layout=html.Div(children=[dcc.Dropdown(
id='FirstDropdown',
options=[
{'label':"graph1",'value':'v1'},
{'label':"graph2",'value':'v2'},
{'label':"graph3,'value':'v3'},
{'label':"graph4",'value':'v4'},
{'label':"graph 5",'value':'v5'},
{'label':"g-form",'value':'v6'}
],
placeholder="Please choose an option",
value='v1'
),
html.Div(dcc.Graph(id='graph'))
])
#app.callback(
[Output('graph','figure')],
[Input(component_id='FirstDropdown',component_property='value')]
)
def select_graph(value):
if value=='v1':
return fig11
elif value=='v2':
return fig21
elif value=='v3':
return fig31
elif value=='v4':
return fig411
elif value=='v5':
return fig_all
elif value == 'v6':
google_form_iframe = html.Iframe(
width='640px',
height='947px',
src="https://docs.google.com/forms/d/e/1FAIpQLSfkIgHkKlD5Jl4ewfWpA8y9D65UbhdrvZ0k7qXOBI7uFN1aNA/vi ewform?embedded=true"
)
return google_form_iframe
fundamentally dcc.Figure() and html.IFrame() are separate dash components. Hence if you what to display a figure of Iframe based on dropdown use a div container. From callback return child component that fits into this container
to make full working example, have used COVID vaccination data to generate 5 figures that can be selected from drop down.
if google form is selected then return that
import pandas as pd
import plotly.express as px
from jupyter_dash import JupyterDash
import dash
from dash import dcc, html
from dash.dependencies import Input, Output, State
import json
df = pd.read_csv(
"https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/vaccinations.csv"
)
df["date"] = pd.to_datetime(df["date"])
df = df.sort_values(["date", "iso_code"])
figs = {
f"v{n+1}": px.bar(
df.loc[(df["date"].dt.day_of_week == 6) & df["iso_code"].isin(["DEU", "FRA"])],
x="date",
y=c,
color="iso_code",
)
for n, c in zip(range(5), df.select_dtypes("number").columns)
}
# Build App
app = JupyterDash(__name__)
app.layout = dash.html.Div(
[
dcc.Dropdown(
id="FirstDropdown",
options=[
{"label": "graph1", "value": "v1"},
{"label": "graph2", "value": "v2"},
{"label": "graph3", "value": "v3"},
{"label": "graph4", "value": "v4"},
{"label": "graph 5", "value": "v5"},
{"label": "g-form", "value": "v6"},
],
placeholder="Please choose an option",
value="v1",
),
dash.html.Div(
id="graph_container",
),
]
)
#app.callback(
Output("graph_container", "children"),
Input("FirstDropdown", "value"),
)
def select_graph(value):
if value in figs.keys():
return dash.dcc.Graph(figure=figs[value])
else:
return html.Iframe(
width="640px",
height="947px",
src="https://docs.google.com/forms/d/e/1FAIpQLSfkIgHkKlD5Jl4ewfWpA8y9D65UbhdrvZ0k7qXOBI7uFN1aNA/vi ewform?embedded=true",
)
app.run_server(mode="inline")
I am very new to Dash. I have made a dataTable that includes several columns. These columns can be filtered and sorted. However, one problem with the filtering is that I cannot filter based on a list (like pandas .loc) e.g. if I want to filter the countries based on a list (say, ['India', 'United States']), the filter does not work. I have previously checked the advanced filtering here and found that I can use || operators; however,this would not be a good choice if the list is more than 4 or 5.
Here's the code:
import dash
from dash.dependencies import Input, Output
import dash_table
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import json
df = pd.read_csv(
'https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv')
app = dash.Dash(__name__)
app.layout = html.Div([
html.Div(id='heading-users', children='Users\' Country details', style={
'textAlign': 'center', 'font-family': 'Helvetica'}),
dash_table.DataTable( # users
id='datatable-users',
columns=[
{"name": i, "id": i, "deletable": True, "selectable": True} for i in df.columns
],
data=df.to_dict('records'),
editable=True,
filter_action="native",
sort_action="native",
sort_mode="multi",
column_selectable="single",
row_selectable="multi",
row_deletable=True,
selected_columns=[],
selected_rows=[],
page_action="native",
page_current=0,
page_size=20,
export_format='csv'
),
html.Div(id='datatable-users-container')
])
#app.callback(
Output('datatable-users-container', "children"),
Input('datatable-users', "derived_virtual_data"),
Input('datatable-users', "derived_virtual_selected_rows"))
def update_graphs(rows, derived_virtual_selected_rows):
if derived_virtual_selected_rows is None:
derived_virtual_selected_rows = []
dff = df if rows is None else pd.DataFrame(rows)
colors = ['#7FDBFF' if i in derived_virtual_selected_rows else '#0074D9'
for i in range(len(dff))]
return [
dcc.Graph(
id=column,
figure={
"data": [
{
"x": dff["country"],
"y": dff[column],
"type": "bar",
"marker": {"color": colors},
}
],
"layout": {
"xaxis": {"automargin": True},
"yaxis": {
"automargin": True,
"title": {"text": column}
},
"height": 250,
"margin": {"t": 10, "l": 10, "r": 10},
},
},
)
# check if column exists - user may have deleted it
# If `column.deletable=False`, then you don't
# need to do this check.
for column in ["pop", "lifeExp", "gdpPercap"] if column in dff
]
if __name__ == '__main__':
app.run_server(debug=True)
From that link - The 'native' filter function doesn't support 'OR' operations within a single column. Assign filter_action="custom" then create a callback to update the table children. See the 'Back-End Filtering section of that link.
You'll need to grab the filter query string in a callback and decompose to extract the column name and query string. With that you can query the pandas dataframe and return the results in a callback. I don't have the code for "OR" functionality but found some I used that can query pandas once you have the input values
def filter_df(df, filter_column, value_list):
conditions = []
for val in value_list:
conditions.append(f'{filter_column} == "{val}"')
query = ' or '.join(conditions)
print(f'querying with: {query}')
return df.query(query_expr)
filter_df(df, 'country', ['Albania', 'Algeria'])
I am trying to have a table load upon clicking a search button, and provide ID/password. My output is a dbc.Table.from_dataframe which allows an df argument; however when I use this as my output property, I am getting an error.
Here are the available properties in "my_table":
['children', 'id', 'style', 'className', 'key', 'tag', 'size', 'bordered', 'borderless', 'striped', 'dark', 'hover', 'responsive', 'loading_state']
I read the docs here
https://dash-bootstrap-components.opensource.faculty.ai/l/components/table
I tried such using 'children' and that didn't work either. I know with dcc table I need to return a dictionary, however I thought with dbc.Table.from_dataframe I can return a dataframe.
#app.callback(Output('my_table', 'df' ),
[Input('search-button','n_clicks')],
[State('input-id', 'value'),
State('input-password', 'value')]
)
def search_fi(n_clicks, iuser, ipasw):
if n_clicks > 0:
df = pd.DataFrame(
{
"First Name": ["Arthur", "Ford", "Zaphod", "Trillian"],
"Last Name": ["Dent", "Prefect", "Beeblebrox", "Astra"],
}
return df
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.Button('Table', id='table-but', n_clicks=0),
html.Div(id='container-button-basic')
])
#app.callback(
dash.dependencies.Output('container-button-basic', 'children'),
[dash.dependencies.Input('table-but', 'n_clicks')])
def search_fi(n_clicks):
if n_clicks > 0:
df = pd.DataFrame(
{
"First Name": ["Arthur", "Ford", "Zaphod", "Trillian"],
"Last Name": ["Dent", "Prefect", "Beeblebrox", "Astra"]
})
print(df)
return dbc.Table.from_dataframe(df)
if __name__ == '__main__':
app.run_server(debug=True)
or
https://plotly.com/python/table/ figure
Html dash table html-table
Example
I would like to style row based on a value of a column, I currently have this code:
import dash
import dash_table
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')
app = dash.Dash(__name__)
print([{"name": i, "id": i} for i in df.columns])
app.layout = dash_table.DataTable(
id='table',
columns=[{"name": i, "id": i} for i in df.columns],
data=df.to_dict("rows"),
style_data_conditional=[
{
'if': {
'column_id': 'Number of Solar Plants',
'filter': '"Number of Solar Plants" > num(100)'
},
'backgroundColor': '#3D9970',
'color': 'white',
}
],
)
if __name__ == '__main__':
app.run_server(debug=True)
Which produces the following result:
But what I really want is for the rows (tr 1 and 8 in this case) to be styled with a green background, not just the cells.
What can I do to achieve this?
to fix your issue you just have to remove the column_id parameter in your style_data_conditional. So all the row will be colored in green.
You should do this:
style_data_conditional=[
{
'if': {
'filter': '"Number of Solar Plants" > num(100)'
},
'backgroundColor': '#3D9970',
'color': 'white',
}
]