Using a slider to add rows to Ploty's Dash "dash_table" - python-3.x

I'm currently working on a dash_table in which I have already incorporated an add row button as well as delete. I would like the user to also be able to add rows by using a slider value. How would I be able to do that with making changes to current code?
html.Div(children=[
html.Label('# of Wells on Pad', style={'color':colors['text']}),
dcc.Slider(
id='well_slider',
min=0,
max=12,
step=1,
marks={i: f' {i}' if i == 1 else str(i) for i in range(13)},
value=0,
),
], style={'padding': 10, 'flex': 1, 'background-color':colors['background'],'margin':20})
], style={'display': 'flex', 'flex-direction': 'row',}),
# html.
html.Div(children=[
dash_table.DataTable(
id='projection_table',
columns=[{
'name': i,
'id': i,
} for i in table_outputs],
style_cell={'text-align':'center'},
data=[
{'column-{}'.format(i): (j + (i-1)*5) for i in range(1, 5)}
for j in range(5)
],
editable=True,
fill_width=True,
row_deletable=True,
export_format='xlsx',
export_headers='display',
style_table={'overflowX':'scroll'}
),
html.Button('Add Row', id='editing-rows-button', n_clicks=0, style={'margin':5}),
html.Div(id='testingSlider', style={"color":colors['text']})
],style={'margin':10})
#app.callback(
Output('projection_table', 'data'),
Input('editing-rows-button', 'n_clicks'),
State('projection_table', 'data'),
State('projection_table', 'columns')
)
def add_row(n_clicks, rows, table_outputs):
if n_clicks > 0:
rows.append({c['id']: '' for c in table_outputs})
return rows
#app.callback(
Output('testingSlider', 'children'),
Input('well_slider', 'value'),
State('projection_table', 'data'),
State('projection_table', 'columns')
)
def add_row_slider(value, rows, table_outputs):
if value > 0:
rows.append({c['id']: '' for c in table_outputs})
return rows

Related

Using multiple sliders with Plotly Dashboard scatter plot 3D

I want to create three filters for my 3D scatter plot.
Based on what I read here: https://medium.com/left-join/building-a-plotly-dashboard-with-dynamic-sliders-in-python-f5cf84161dc5 and here: https://plotly.com/python/3d-scatter-plots/ I should put only the sliders and call them in #app.callback as a list with parameters.
I tried like this:
from dash import Dash, dcc, html, Input, Output
import plotly.express as px
app = Dash(__name__)
app.layout = html.Div([
html.H4('Iris samples filtered by petal width'),
dcc.Graph(id="3d-scatter-plot-x-graph"),
html.P("Petal Width:"),
dcc.RangeSlider(
id='3d-scatter-plot-x-range-slider',
min=0, max=2.5, step=0.1,
marks={0: '0', 2.5: '2.5'},
value=[0.5, 2]
),
html.P("Sepal Length:"),
dcc.RangeSlider(
id='3d-scatter-plot-y-range-slider',
min=0, max=2.5, step=0.1,
marks={0: '0', 2.5: '2.5'},
value=[0.5, 2]
),
html.P("Sepal Width:"),
dcc.RangeSlider(
id='3d-scatter-plot-z-range-slider',
min=0, max=5, step=0.1,
marks={0: '0', 5: '5'},
value=[0.5, 4.5]
),
])
#app.callback(
Output("3d-scatter-plot-x-graph", "figure"),
[Input("3d-scatter-plot-x-range-slider", "value"),
Input("3d-scatter-plot-y-range-slider", "value"),
Input("3d-scatter-plot-z-range-slider", "value")])
def update_bar_chart(slider_x, slider_y, slider_z):
df = px.data.iris() # replace with your own data source
low_x, high_x = slider_x
low_y, high_y = slider_y
low_z, high_z = slider_z
mask = (df.petal_width > low_x) & (df.petal_width < high_x) & (df.sepal_length > low_y) & (df.sepal_length < high_y)
fig = px.scatter_3d(df[mask],
x='sepal_length', y='sepal_width', z='petal_width',
color="species", hover_data=['petal_width'])
return fig
if __name__ == "__main__":
app.run_server(debug=True)
But I got nothing (empty plot with sliders)
And I didn't got any errors.
Any idea what can I do?
As you can see in #Kat's comment, you have to change the ranges and as I see Sepal Width slider does not take any effect, you have to add it to the update function.
from dash import Dash, dcc, html, Input, Output
import plotly.express as px
app = Dash(__name__)
app.layout = html.Div([
html.H4('Iris samples filtered by petal width'),
dcc.Graph(id="3d-scatter-plot-x-graph"),
html.P("Petal Width:"),
dcc.RangeSlider(
id='3d-scatter-plot-x-range-slider',
min=0, max=2.5, step=0.1,
marks={0: '0', 2.5: '2.5'},
value=[0.5, 2]
),
html.P("Sepal Length:"),
dcc.RangeSlider(
id='3d-scatter-plot-y-range-slider',
min=4.3, max=7.9, step=0.1,
marks={0: '0', 2.5: '2.5'},
value=[4.3, 7.9]
),
html.P("Sepal Width:"),
dcc.RangeSlider(
id='3d-scatter-plot-z-range-slider',
min=2, max=4, step=0.1,
marks={0: '0', 5: '5'},
value=[1.5, 4]
),
])
#app.callback(
Output("3d-scatter-plot-x-graph", "figure"),
[Input("3d-scatter-plot-x-range-slider", "value"),
Input("3d-scatter-plot-y-range-slider", "value"),
Input("3d-scatter-plot-z-range-slider", "value")])
def update_bar_chart(slider_x, slider_y, slider_z):
df = px.data.iris() # replace with your own data source
low_x, high_x = slider_x
low_y, high_y = slider_y
low_z, high_z = slider_z
mask = (df.petal_width > low_x) & (df.petal_width < high_x) & (df.sepal_length > low_y) & (df.sepal_length < high_y) & (df.sepal_width > low_z) & (df.sepal_width < high_z)
fig = px.scatter_3d(df[mask],
x='sepal_length', y='sepal_width', z='petal_width',
color="species", hover_data=['petal_width'])
return fig
if __name__ == "__main__":
app.run_server(debug=True)

Add slider in plotly figure

I am visualizing the data stored in pandas dataframe via plotly.
import plotly.graph_objects as go
import numpy as np
import plotly.express as px
# ref: https://plotly.com/python/sliders/
if __name__ == '__main__':
df = px.data.iris()
df = df.iloc[0:10, :]
# print(df)
petal_width = [1.3, 1.4, 1.4]
# Create figure
fig = go.Figure()
# Add traces, one for each slider step
data = [
go.Scatter(
mode="lines+markers",
x=df['sepal_width'],
y=df['sepal_length'],
),
go.Scatter(
mode="lines+markers",
x=df['sepal_width'],
y=df['sepal_length']+2,
),
go.Scatter(
mode="lines+markers",
x=df['sepal_width'],
y=df['sepal_length'] + 3,
)
]
slider_range = min(petal_width), max(petal_width)
low, high = slider_range
# slides = []
# for i in range(3):
# slide = dict(
# method="update",
# args=[{"visible": [False] * len(fig.data)},
# {"title": "Slider switched to step: " + str(i)}], # layout attribute
# )
# slide["args"][0]["visible"][i] = True # Toggle i'th trace to "visible"
# slides.append(slide)
#
# sliders = [
# dict(
# active=10,
# currentvalue={"prefix": "Frequency: "},
# pad={"t": 50},
# steps=slides
# )
# ]
fig = go.Figure(data=data)
#fig.update_layout(
# sliders=slider
#)
# fig.show()
with open("check.html", 'a') as f:
f.write(fig.to_html(full_html=False, include_plotlyjs='cdn'))
Plot:
This figure shows three lines corresponding to the there dataset in data. These threee curves are associated with 3 values stored in petal_width = [1.3, 1.4, 1.4] .
I would like to add a slider like shown in the example (please see the example plot below) presented [here]
(https://plotly.com/python/line-and-scatter/)
I'm not really sure how to add the slider. Basically, I want to add the slider and based on the value selected in the slider the corresponding curves in the plot should appear. e.g. if 1.4 is selected in the slider (petal_width), I want the second and third curves to appear.
Suggestions will be helpful.
steps = []
for i in range(len(fig.data)):
step = dict(
method="update",
args=[{"visible": [False] * len(fig.data)},
{"title": "Slider switched to step: " + str(i)}], # layout attribute
)
visible = []
val = petal_width[i]
for j in range(len(petal_width)):
if petal_width[j] == val:
step["args"][0]["visible"][j] = True # Toggle i'th trace to "visible"
steps.append(step)
sliders = [dict(
active=1,
currentvalue={"prefix": "Frequency: "},
pad={"t": 50},
steps=steps
)]
fig.update_layout(
sliders=sliders
)
You just need to fix the colors, for all 3 categories.
steps output:
[{'method': 'update',
'args': [{'visible': [True, False, False]},
{'title': 'Slider switched to step: 0'}]},
{'method': 'update',
'args': [{'visible': [False, True, True]},
{'title': 'Slider switched to step: 1'}]},
{'method': 'update',
'args': [{'visible': [False, True, True]},
{'title': 'Slider switched to step: 2'}]}]
Output :
Step:0
Step:1 and 2

How to scale/drop NaN/0's from graph visually

I would like to start the graph from the first non-zero or non NaN value, also if possible, only connect non-zero/ non NaN terms.
def CreateAvgGraph(input_data):
KK = test3.loc[[input_data],:]
K = KK.T
K = K.fillna(0)
K = K.reset_index()
list1a = K['index'].tolist()
list2a = K[input_data].tolist()
return dcc.Graph(
id='example-graph2',
figure={
'data': [
{'x' : list1a , 'y': list2a, 'type':'line','name' :input_data},
],
'layout': {
'title': str(input_data) + ' Average Price'
}
}
)
[![enter image description here][1]][1]
Removing the fillNa doesn't really help as the view scale is too much.
def CreateAvgGraph(input_data):
KK = test3.loc[[input_data],:]
K = KK.T
K = K.reset_index()
list1a = K['index'].tolist()
list2a = K[input_data].tolist()
return dcc.Graph(
id='example-graph2',
figure={
'data': [
{'x' : list1a , 'y': list2a, 'type':'line','name' :input_data},
],
'layout': {
'title': str(input_data) + ' Average Price'
}
}
)
I have managed to do an ugly fix, but there has to be a better way?
def CreateAvgGraph(input_data):
KK = test3.loc[[input_data],:]
K = KK.T
K = K.fillna(0)
K = K.reset_index()
list1a = K['index'].tolist()
list2a = K[input_data].tolist()
list2aa = []
list1aa =[]
for i in range(0,len(list1a)):
if list2a[i] > 0:
list1aa.append(list1a[i])
list2aa.append(list2a[i])
else:
continue
return dcc.Graph(
id='example-graph2',
figure={
'data': [
{'x' : list1aa , 'y': list2aa, 'type':'line','name' :input_data},
],
'layout': {
'title': str(input_data) + ' Average Price'
If you simply want to plot all non-nan value, you should just drop the nan values rather than filling them with zeros, i.e. you should replace K.fillna(0) with K.dropna().

Duplicate Callback Output error in dash app

I am getting an error in dash app. The error: "You have already assigned a callback to the output with the ID "prediction" and property "children". An output can only have a single callback function. Try combining your inputs and callback functions together into one function."
I have only one callback function in my code.
How to resolve this?
My code below:
model_data = pd.read_csv("data.csv")
style = {'padding': '1.5em'}
app.layout = html.Div([
dcc.Markdown("""
### Predict
"""),
html.Div(id='prediction-content', style={'fontWeight': 'bold'}),
html.Div([
dcc.Markdown('###### Input1'),
dcc.Dropdown(
id='Input1',
options=[{'label': 1, 'value': 1}],
value= 1
),
], style=style),
html.Div([
dcc.Markdown('###### Input2'),
dcc.Slider(
id='Input2',
min=23,
max=27,
step=0.5,
value=23,
tooltip={'always_visible': True},
marks={
23: {'label': '23'},
24: {'label': '24'},
25: {'label': '25'},
26: {'label': '26'}
},
included=False
)
], style=style),
html.Div([
dcc.Markdown('###### Input3'),
dcc.Slider(
id='Input3',
min=10,
max=50,
step=1,
value=30,
tooltip={'always_visible': True},
marks={
10: {'label': '10'},
20: {'label': '20'},
30: {'label': '30'},
40: {'label': '40'},
50: {'label': '50'}
},
included=False
)
], style=style),
])
#app.callback(
Output('prediction-content', 'children'),
[Input('Input1', 'value'),
Input('Input2', 'value'),
Input('Input3', 'value')])
def predict(a, b, c):
data2 = pd.DataFrame(data = [[a, b, c,]],
columns = ['Input1', 'Input2','Input3']
, index = [36])
data3 = model_data.combine_first(data2)
#### full function hidden due to confidentiality
def calculate(df,i,j):
###
####
return(a1)
output = a1*2
results = f'Result is ${output:,.0f}.'
return results
if __name__ == '__main__':
app.run_server(debug=True)
i had the same issue using Jupiter notebook but solved it by killing the server and restarting my kernel, i assume that the callback assigns the function once and if you try to re-assign it again it will through that error. I guess this error will be thrown only when you are using hot reloading.

Python Dash Data Table should display only selected columns

I am trying to display only selected columns from my dataframe using datatable . i am able select how many rows i want . looking for a similar option like rows i want to select to display certain columns alone at the time of executing the code.
My dataframe has close to 25 columns . i dont want all of them to be displayed hence looking for this solution
here is my code :
import dash
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash_html_components as html
import dash_table as dt
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
df = pd.read_csv('E:\pylab\dshlab\infratickets.csv', low_memory = False )
app = dash.Dash(__name__)
#style={'visibility': 'hidden'}
dpdown = []
for i in df['ASSIGNED_GROUP'].unique() :
str(dpdown.append({'label':i,'value':(i)}))
app.layout = html.Div([
html.P([
html.Label("Choose a feature"),
html.Div(dcc.Dropdown(id='dropdown', options=dpdown),
style = {'width': '100px',
'fontSize' : '10px',
'padding-left' : '100px',
'display': 'inline-block'})]),
#style={'visibility': 'hidden'},
html.Div(id='table-container', className='tableDiv'),
dcc.Graph(id = 'plot',style={'height' : '25%', 'width' : '25%'})
])
#dcc.Dropdown(id='dropdown', style={'height': '30px', 'width': '100px'}, options=dpdown),
#dcc.Graph(id='graph'),
#html.Div(html.H3('country graph'),id='table-container1',className='tableDiv1')
#app.callback(
dash.dependencies.Output('table-container','children'),
[dash.dependencies.Input('dropdown', 'value')])
def display_table(dpdown):
df_temp = df[df['ASSIGNED_GROUP']==dpdown]
return html.Div([
dt.DataTable(
id='main-table',
columns=[{'name': i, 'id': i} for i in df_temp.columns],
data=df_temp[0:5].to_dict('rows'),
style_table={
'maxHeight': '20%',
#'overflowY': 'scroll',
'width': '30%',
'minWidth': '10%',
},
style_header={'backgroundColor': 'rgb(30, 30, 30)'},
style_cell={'backgroundColor': 'rgb(50, 50, 50)','color': 'white','height': 'auto','width': 'auto'},#minWidth': '0px', 'maxWidth': '180px', 'whiteSpace': 'normal'},
#style_cell={'minWidth': '120px', 'width': '150px', 'maxWidth': '180px'},
style_data={'whiteSpace': 'auto','height': 'auto','width': 'auto'}
)
])
if __name__ == '__main__':
app.run_server(debug=True)
Able to figure out the solution
changed the code
columns=[{'name': i, 'id': i} for i in df_temp.columns]
to
columns=[{'name': i, 'id': i} for i in df.loc[:,['Colname1','Colname2',...]
fixed it
You could also use by index:
df = pd.read_csv('E:\pylab\dshlab\infratickets.csv', low_memory = False ) # load in the dataframe, then ressign with just the columns you want
df = df.iloc[:,1:3] # Remember that Python does not slice inclusive of the ending index.
Would give all rows and columns 1 to 2 of the data frame.
You can change the
columns=[{'name': i, 'id': i} for i in df_temp.columns],
as below:
First define TABLE_SELECTED_COLUMNS = ['col1','col2'. ...]
and
columns=[{"name": i, "id": i} for i in TABLE_SELECTED_COLUMNS],

Resources