Plotly Distplot subplots

Viewed 1809

I am trying to write a for loop that for distplot subplots. I have a dataframe with many columns of different lengths. (not including the NaN values)

fig = make_subplots(
    rows=len(assets), cols=1,
    y_title = 'Hourly Price Distribution')

i=1 
for col in df_all.columns:
    fig = ff.create_distplot([[df_all[[col]].dropna()]], col)
    fig.append()
    i+=1
fig.show()

I am trying to run a for loop for subplots for distplots and get the following error:

PlotlyError: Oops! Your data lists or ndarrays should be the same length.

UPDATE: This is an example below:

df = pd.DataFrame({'2012': np.random.randn(20),
           '2013': np.random.randn(20)+1})
df['2012'].iloc[0] = np.nan
fig = ff.create_distplot([df[c].dropna() for c in df.columns],
df.columns,show_hist=False,show_rug=False)
fig.show()

I would like to plot each distribution in a different subplot.

Thank you.

1 Answers

Update: Distribution plots

Calculating the correct values is probably both quicker and more elegant using numpy. But I often build parts of my graphs using one plotly approach(figure factory, plotly express) and then use them with other elements of the plotly library (plotly.graph_objects) to get what I want. The complete snippet below shows you how to do just that in order to build a go based subplot with elements from ff.create_distplot. I'd be happy to give further explanations if the following suggestion suits your needs.

Plot

enter image description here

Complete code

import numpy as np
import pandas as pd
import plotly.express as px
import plotly.figure_factory as ff
from plotly.subplots import make_subplots
import plotly.graph_objects as go

df = pd.DataFrame({'2012': np.random.randn(20),
           '2013': np.random.randn(20)+1})
df['2012'].iloc[0] = np.nan

df = df.reset_index()
dfm = pd.melt(df, id_vars=['index'], value_vars=df.columns[1:])
dfm = dfm.dropna()

dfm.rename(columns={'variable':'year'}, inplace = True)
cols = dfm.year.unique()
nrows = len(cols)

fig = make_subplots(rows=nrows, cols=1)

for r, col in enumerate(cols, 1):
    dfs = dfm[dfm['year']==col]
    fx1 = ff.create_distplot([dfs['value'].values], ['distplot'],curve_type='kde')
    fig.add_trace(go.Scatter(
                                x= fx1.data[1]['x'],
                                y =fx1.data[1]['y'],
                              ), row = r, col = 1)

fig.show()

First suggestion


You should:

1. Restructure your data with pd.melt(df, id_vars=['index'], value_vars=df.columns[1:]),

2. and the use the occuring column 'variable' to build subplots for each year through the facet_row argument to get this:

enter image description here

In the complete snippet below you'll see that I've changed 'variable' to 'year' in order to make the plot more intuitive. There's one particularly convenient side-effect with this approach, namely that running dfm.dropna() will remove the na value for 2012 only. If you were to do the same thing on your original dataframe, the corresponding value in the same row for 2013 would also be removed.

import numpy as np
import pandas as pd
import plotly.express as px

df = pd.DataFrame({'2012': np.random.randn(20),
           '2013': np.random.randn(20)+1})
df['2012'].iloc[0] = np.nan

df = df.reset_index()
dfm = pd.melt(df, id_vars=['index'], value_vars=df.columns[1:])
dfm = dfm.dropna()

dfm.rename(columns={'variable':'year'}, inplace = True)
fig = px.histogram(dfm, x="value",
                   facet_row = 'year')
fig.show()
Related