Black Lives Matter. Please consider donating to Black Girls Code today.

Update dropdown onclick

How can I populate the dropdown list on “onclick” event? I can get the list updated when someone selects the value but I can’t get it to update when the user clicks on the down arrow. My option list the files from a folder. I want to re-populate the list every time list is shown to catch new files added to a folder. callback happens when I select something on the dropdown but I can’t get the callback to happen when someone just clicks the dropdown arrow.

pathway = ‘C:/temp’
app.layout = html.Div([dcc.Dropdown(id=“filename”)])

@app.callback(Output(‘filename’, ‘options’), [Input(‘filename’, ‘value’)])
def updateOptionList(n):
files=[f for f in listdir(pathway) if f.endswith(‘csv’)]
options=[ {‘label’: i, ‘value’: i} for i in files]
return options

I don’t believe there is a way to do something like that in the manner that you described, but you could update your drop down menu’s options using the Dash Interval component. Essentially whenever the Interval ticks, search for that directory to see if there are any new files, and if there are, add them to your drop down options.

Thanks for your feedback, yes I can add the timer to refresh the list. If there is nothing I can do on event base, I will do what you suggested.

You could wrap the options in a parent and test when that is clicked. Here’s a demo, you’ll see there is a delay on updating but for your use case that might not be an issue:

import random
import dash
import dash_core_components as dcc
import dash_html_components as html


app = dash.Dash(__name__)

app.layout = html.Div(
    id='my-dropdown-parent',
    children=[
        dcc.Dropdown(
            id='my-dropdown',
            options=[{'label': 'foo', 'value': 'foo'}]
        )
    ]
)

@app.callback(output=dash.dependencies.Output('my-dropdown', 'options'),
              inputs=[dash.dependencies.Input('my-dropdown-parent', 'n_clicks')])
def change_my_dropdown_options(n_clicks):
    if n_clicks is None:
        raise dash.exceptions.PreventUpdate

    options = random.choice(['foo', 'bar', 'baz'])
    return [{'label': options, 'value': options}]

if __name__ == '__main__':
    app.run_server()

Option update works great, I see there is a bit of delay but it’s ok for my use case. Here is what I am doing, drawing chart using the data from CSV file

import pandas as pd
import plotly.graph_objects as go
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output

import os
from os import listdir
from collections import deque

yMinValue = 50
yMaxValue = 60

xMin = deque(maxlen=2)
xMax = deque(maxlen=2)  

yMin = deque(maxlen=2)
yMax = deque(maxlen=2)  

app = dash.Dash(__name__)

pathway = 'C:/temp'

files=[f for f in listdir(pathway) if f.endswith('csv')]

app.layout = html.Div(id='my-dropdown-parent',children=[
               dcc.Dropdown(id='filename',placeholder="Select a file...",
                            style={'width': '30em', 'padding': '0em'}
                          ),
          dcc.Graph(id='output-graph')
	])

@app.callback(Output('filename', 'options'), [Input('my-dropdown-parent', 'n_clicks')])
def updateOptionList(n_clicks):
    if n_clicks is None:
        raise dash.exceptions.PreventUpdate

    files=[f for f in listdir(pathway) if f.endswith('csv')]

    options=[
                {'label': i, 'value': i} for i in files
            ]

    return options


@app.callback(Output('output-graph', 'figure'), [Input('filename', 'value')])
def showGraph(n):
 fig = go.Figure()
 if n is not None:
    with open(n) as f:
      df = pd.read_csv(n, header=None, usecols=[0,1], names=['time', 'value'])
      beginDate = df['time'].iloc[0]
      endDate = df['time'].iloc[-1]
    
    xMin.append(beginDate)
    yMin.append(yMinValue)
    xMin.append(endDate)
    yMin.append(yMinValue)

    xMax.append(beginDate)
    yMax.append(yMaxValue)
    xMax.append(endDate)
    yMax.append(yMaxValue)

    fig.add_trace(go.Scatter(x = df['time'], y = df['value'],
                    mode='lines',
                    line= dict(color="#66ff00")))
    fig.add_trace(go.Scatter(x=list(xMin), y=list(yMin),
                  name= 'Minimum Threshold',
                  mode = 'lines',
                  connectgaps = True,
                  line = dict(color="yellow")))

    fig.add_trace(go.Scatter(x=list(xMax), y=list(yMax),
                  name= 'Maximum Threshold',
                  mode = 'lines',
                  connectgaps = True,
                  line = dict(color="red")))

    fig.update_layout(
       		title_text='Graph',
       		titlefont=dict(family='Courier New, monospace', size=20, color='#FFFFFF'),
       		legend=go.layout.Legend(
           		traceorder="normal",
           		font=dict(
                       		family="Courier New, monospace",
                       		size=12,
                       		color="#FFFFFF"
                   		),
              xanchor= 'right',
              borderwidth = 1
          ),
       		xaxis=go.layout.XAxis(
           		title_text="Time", 
           		showgrid=True, gridcolor='#343434', dtick=3600
      		),
       		yaxis=go.layout.YAxis(
           		title_text="Value", 
           		showgrid=True, gridcolor='#343434', dtick=0.01
      		)
    )
  return fig

if __name__ == '__main__':
	app.run_server(debug=False,port=8090,host='0.0.0.0')