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

Using Plotly drop-down widgets

Hey everyone,

I have been trying to apply a drop-down widget on a bar chart I made, but I am having trouble applying the filter. I have been using this documentation guide:

Now, I have a dataset setup like this:

id    happiness_score   time_of_day   
01             3                    08
02             4                    16
03             1                    22
04             2                    03
05             5                    16

I am trying to create a bar graph, with the score as the x-axis, and count of Id as the y-axis, and the time of day as the dropdown widget.

so far I’ve been able to create the widget, which took a bit of time, but here is how I got it:

#make a copy of the original df
df2 = df1


#converting the score to an object
df1['survey_time'] = 1['surveyed_at']= pd.to_datetime(dfnoadmin['surveyed_at'])
df1['survey_time'] = df1.survey_time.map(lambda x: x.strftime('%H'))
df1['score'] = df1['score'].apply(str)
df1.dtypes

#for the widget

dfq = df1
# we will define a function that will handle the input from the dropdown widget
def update_plot(dfz):
    noadmin = dfq['score'] ==  dfz['new']
    temp = dfq[noadmin]
    data = temp.groupby(dfq['score'])['time_of_day'].count()

    x = []
    y = []
    for i in range(len(data)):
        x.append(data.index[i])
        y.append(data[i])

    graph.restyle({
                'x': [x],
                'y': [y],
            })
    graph.relayout({'title': 'blah of {} blah'.format(dfz['new'])})

w = widgets.Dropdown(
    options= list(dfq['score'].unique()),
    value='0',
    description='score',
)

#now for graphing`
#turn the score back to an int for organizational purposes    


df2['score'] = df2['score'].apply(int)
fq = df2
fq = fq.groupby(['survey_time']).agg({'id': 'count'})


x= fq['id'].nlargest(400)
data1 = [Bar(
            y=x,
            x=x.keys(),
            text=x,
            textposition = 'outside',
            marker = dict(
            color = 'rgba(158,202,225)',
                line=dict(
                    color='rgb(8,48,107)',
                    width=1.5),
            ),
            name = "Total Users",
            opacity=0.6
    )]

layout1 = go.Layout(
    title="Time of Day",
    xaxis=dict(
        title='Surveys Completed by the hour',
        titlefont=dict(
            family='Courier New, monospace',
            size=18,
            color='#7f7f7f'
        )
    ),
    yaxis=dict(
        title='Time of Day',
        titlefont=dict(
            family='Courier New, monospace',
            size=18,
            color='#7f7f7f'
        )
    )
)

#Execute

display(w)

myFigure2 = go.Figure(data = data1 , layout = layout1)
iplot(myFigure2)

However, all it does is ignore the filter, and graphs all the ids across the day, regardless of the score. If I group dataframe fq by surveytime AND score, then count the ids, then nothing appears.

How can I apply the drop down filters to the graph I made?

Hi @El_pwon,

We’re still working to clean out the old documentation, but the GraphWidget approach in that page is not the recommended approach at this point. The FigureWidget approach in plotly.py version 3 is much more capable and reliable.

I think the example in this page would be a good starting for you using FigureWidget: https://plot.ly/python/figurewidget-app/

Hope that helps get you going,
-Jon

Hello @jmmease

Thank you for responding and providing Fidget documentation. This looks far more impressive and now I can filter out other columns within my dataframe. Here is a more accurate representation of what I am working with:

id            score          survey_time     cohort        is_admin
01             3                    08           2016-02          yes
02             4                    16           2016-02          no
03             1                    22           2016-03          yes
04             2                    03           2016-04          yes
05             5                    16           2016-04          no

and so on…

So I tried entering my version of it by:

month = widgets.IntSlider(
    value=1.0,
    min=1.0,
    max=12.0,
    step=1.0,
    description='cohort:',
    continuous_update=False
)

use_date = widgets.Checkbox(
    description='Cohort Group: ',
    value=True,
)

container = widgets.HBox(children=[use_date, month])

textbox = widgets.Dropdown(
    description='score:   ',
    value='10',
    options=dfgoadmin['score'].unique().tolist())
    
score = widgets.Dropdown(
    options=list(dfgoadmin['is_admin'].unique()),
    value='0',
    description='Admin Status:',
)




# Assign an emptry figure widget with two traces
trace1 = go.Histogram(x=dfgoadmin['id'], opacity=0.75, name='number of users')
g = go.FigureWidget(data=[trace1],
                    layout=go.Layout({"barmode": "overlay"}))

def validate():
    if score.value in dfgoadmin['is_admin'].unique() and textbox.value in dfgoadmin['score'].unique():
        return True
    else:
        return False


def response(change):
    if validate():
        if use_date.value:
            filter_list = [i and j and k for i, j, k in
                           zip(dfgoadmin['cohort'] == month.value, dfgoadmin['score'] == textbox.value,
                               dfgoadmin['score'] == score.value)]
            temp_df = df[filter_list]

        else:
            filter_list = [i and j for i, j in
                           zip(dfgoadmin['score'] == '10', dfgoadmin['is_admin'] == score.value)]
            temp_df = dfgoadmin[filter_list]
        x1 = temp_df['id']
        x2 = temp_df['survey_time']
        with g.batch_update():
            g.data[0].x = x1
            g.layout.barmode = 'overlay'
            g.layout.xaxis.title = 'Time of Day'
            g.layout.yaxis.title = 'Number of Surveyed'


score.observe(response, names="value")
textbox.observe(response, names="value")
month.observe(response, names="value")
use_date.observe(response, names="value")


container2 = widgets.HBox([score, textbox])
widgets.VBox([container,
              container2,
              g])

However, instead of the survey_ time being displayed on the x axis, It’s tracking a variable that isn’t within my data set. Furthermore, changing the filters doesn’t seem to do anything.

Do you or anyone else have any suggestions?

Thank you.

Hi @El_pwon,

For what I can tell, it looks like you initialize the histogram’s x value to dfgoadmin['id']. Then in your callback you set it to x1, which is set to be temp_df['id'] . You create an x2 local variable in the callback that is equal to temp_df['survey_time'], but it doesn’t look like you use it anywhere. Did you mean to to set g.data[0].x = x2?

-Jon