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

Distplot in Dash

Hi Everyone,

I’m trying to build dashboard using dash framework. I’m currently stuck with plotting a distplot. Is dash supports plotting distplot with plotly ?

Thanks
Ray

Hey @pray

Good question. Yes it does, you should be able to pass in the figure of the displot into the Graph component. For example:

import plotly.figure_factory as ff

import numpy as np

x = np.random.randn(1000)  
hist_data = [x]
group_labels = ['distplot']

fig = ff.create_distplot(hist_data, group_labels)

dcc.Graph(
    id='my-graph', 
    figure=fig
)

Does that work for you? If not, what have you tried so far?

2 Likes

Hi chriddyp,

Thanks a lot for your help. I apologize for getting back late. The solution you have provided here works for me, with minor layout issues. I was trying the below before which was giving me empty ploy.

dcc.Graph(
        id='abc',
        figure={
            'data':[
                (
                    ff.create_distplot(hist_data,group_labels,bin_size=.1,colors=colors)
                )

            ],
            'layout': {
                'margin': {'b': 0, 'r': 10, 'l': 60, 't': 0},
                'legend': {'x': 0}
            }

        }
    )
])
1 Like

Ah I see. Yes, that code block will not work as all figure_factory (ff) functions return a figure, which includes both data and layout.

Thanks a lot Chris. I have just started working on dash and still trying to
figure out the nitty gritty of it. Thanks again for helping me out.

1 Like

Hey chriddyp,
First of all thanks for such a great app. I am really intrigued by its potential to create really nice visualizations.

Btw, I am having problem with creating an interactive distplot. Below is my attempt to create the same.

@app.callback(
dash.dependencies.Output('density-plot', 'figure'),
[dash.dependencies.Input('variables-dropdown', 'value')]
)
def update_distplot(column_name):
    group_labels = [column_name]
    return { 
        'figure' : ff.create_distplot(input_df[input_df['Labels'] == 1][column_name], group_labels)
    }

I am having a drop down based on which this plot will be updated, I am able to interact with a boxplot but not with displot.

Any guidance would be highly appreciable. Thanks in advance.

@anurag - your callbacks only need to return the value of the property your updating, so do

    return ff.create_displot(...)

rather than

    return {
        'figure': ff.create_displot(...)
    }

I have tried doing the above and I believe the plotly api for distplot says something like below.

import plotly.plotly as py

import plotly.figure_factory as ff

import numpy as np

x = np.random.randn(1000)
hist_data = [x]
group_labels = [‘distplot’]

fig = ff.create_distplot(hist_data, group_labels)
py.iplot(fig, filename=‘Basic Distplot’)

I have tried doing as you suggested, but the plotly api for displot say something like below.
import plotly.plotly as py
import plotly.figure_factory as ff

import numpy as np

x = np.random.randn(1000)  
hist_data = [x]
group_labels = ['distplot']

fig = ff.create_distplot(hist_data, group_labels)
py.iplot(fig, filename='Basic Distplot')

When using the iplot option or plot option the graph is being rendered in another tab in the browser instead of the div tag.
I am able to see the boxplot btw and I can interact with it as well.

@anurag - Did my suggestion work for you? In the code snippet you posted, you could use it in Dash like:

import numpy as np

x = np.random.randn(1000)  
hist_data = [x]
group_labels = ['distplot']

fig = ff.create_distplot(hist_data, group_labels)

app.layout = html.Div([
    dcc.Graph(id='my-distplot', figure=fig)
])

Yes your suggestion worked for me today just now :slight_smile: :wink:

Thank you so much.

Hey @chriddyp,

I’m trying to create an interactive distplot for a dashboard. But ff.create_distplot gives me an error : TypeError: unhashable type: ‘Figure’. Can you please help with this?

Here’s my code :

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
import plotly.plotly as py
import plotly.figure_factory as ff
import numpy as np


app = dash.Dash()


attr=pd.read_csv("/Users/anvayapratyush/Documents/Segments/batch_offload_22ndApril/attributes.csv")

del attr["metadata_user_id"]

attr_wide=attr.pivot(index='user_id', columns='attribute_name', values='attribute_value') #long to wide format

attr_wide.reset_index(level=0,inplace=True)

attr_options=attr_wide.columns.values





app.layout = html.Div([
    html.H2("Journeys Attributes Distribution"),
    html.Div(
        [
            dcc.Dropdown(
                id="attr",
                options=[{
                    'label': i,
                    'value': i
                } for i in attr_options],
                placeholder="Select one or more Attributes)",
                value=['activity.first.time.value'],
                multi=True),
        ],
        style={'width': '50%',
               'display': 'inline-block'}),
    dcc.Graph(
    id='density-plot'
),
])



@app.callback(
dash.dependencies.Output('density-plot', 'figure'),
[dash.dependencies.Input('attr', 'value')]
)
def update_distplot(attr):
    group_labels = attr
    print(attr_wide[attr])
    arr=np.array(attr_wide[attr]).astype(float)
    arr2=arr.reshape(arr.shape[0])
    hist_data=[arr2]
    print(arr2.shape)
    print(hist_data)
    print(group_labels)
    return { 
        ff.create_distplot(hist_data, group_labels)
    }





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

Regards

Never mind. It was the curly braces (hence, the hashing) around the return statement that was causing the error.

This should just be

return ff.create_distplot(hist_data, group_labels)

@chriddyp Thanks a lot it worked fine for me but i want to add title to the Dist plot,
I tried

hist_data = list(data_final[param_to_plot]),
group_labels = ["-"]
fig=ff.create_distplot(hist_data, group_labels)
return {fig,
           fig['layout'].update(title='Curve and Rug Plot')
           }

but no luck…please let me know any other way of doing this

Hi @chriddyp

I’m trying to create a dynamic distplot, using the below code. I’m trying to do the following steps:

  • read data from json, create dataframe (stored none displayable, as per dash examples)
    -Create a list of unique entrys in ‘values’ column (which is determined from a dropdown selection).
    -Iterate through list of unique entries, appending data hist_data=[x,x1…] etc
  • Do a bit of filtering of the dataframe
  • Create a distplot for ‘ProcessDuration’ with multiple line histograms for each of the unique groups.

def dff_to_table(dff_json,value,mode):
dff=[]
dff = pd.read_json(dff_json)
Types=tuple(dff[value].unique())
dffIndexed=dff[dff[‘State’]==‘Indexed’]
hist_data = []
group_labels=[]
for i in Types:
group_labels.append(i)
result=dffIndexed[dffIndexed[value]==i]
x=result.ProcessDuration.values.tolist()
hist_data.append(x)

return ff.create_distplot(hist_data, group_labels, show_hist=False) 

I’m sure there are lots of improvements I could make to the above (I’m a bit of a rookie!), but can you see why this isn’t working?

I think it is the way I am creating the hist_data array…

Many Thanks!
Ryan

I had difficulty with distplots until I took the time to replicate exactly how Plotly Figure Factory generates them (https://plot.ly/python/distplot/) You will notice that the hist_data argument takes an array of arrays, and I had to boil down my pandas dataframe into arrays to make it work. Don’t pay attention to the xaxis and yaxis column names, I have two dropdowns controlling a scatterplot and generating a distplot underneath, so they were recycled.

# distplot callback
@app.callback(
    Output('distplot','figure'),
    [Input('country-selector','value'),
    Input('xaxis-column','value'),
    Input('yaxis-column','value')])

def update_distplot(country_selector,xaxis_column,yaxis_column):

    # Filter by the country selector box
    distplot_country = df[df['country'] == country_selector]
    # Create the group labels list
    group_labels = [xaxis_column,yaxis_column]
    # Reduce the filtered dataframe to 2 numpy arrays
    distplot_array = [np.double(distplot_country[xaxis_column]),np.double(distplot_country[yaxis_column])]
    # Figure Factory (ff) returns both data and layout
    return ff.create_distplot(distplot_array,group_labels,bin_size=.01)

A post was split to a new topic: Code is not working when deployed