Insert shape in Dash DataTable - python

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

Getting error message when add the 'Ticker' in dataframe

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,
]
)

unable to add google form in plotly

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")

Filtering a column on Dash dataTable based on a list

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'])

How do I return a dataframe from an app.callback with my as output as dbc.Table.from_dataframe

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

Conditional styling a row, based on column value

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',
}
]

Categories