# Issue

This Content is from Stack Overflow. Question asked by finman69

so I am graphing some simulations of time series data where I want to be able to visualize the distribution of the ending values in Python. Given the plot of simulated paths, I want to be able to take the values at the end (time = T) and use a distribution graph (just line, not box) that shows up on the right side of the graph showing the skew. I’ve provided an image example here: I’m using plotly to generate the graph as I want to be able to have hover data for each point in time. The data I’m using is generic, so any form of simulated path over any time horizon works. My current graph code goes as follows:

``````import plotly.express as px
import plotly.graph_objects as go
from plotly.graph_objs.scatter.marker import Line

fig = go.Figure(go.Scatter(
x=y_testing.index,
y=y_testing.iloc[:, 0]
))

for i in range(1, len(y_testing.columns)-1):
x=y_testing.index,
y=y_testing.iloc[:, i]
))

fig.show()
``````
• y_testing.index is the time period
• y_testing.iloc[:, 0] is the actual data
• y_testing.iloc[:, i] is each respective simulated path

# Solution

You can use subplots and place a one sided violin plot next to your `go.Scatter` traces. To make the figure easier to read, I added a secondary yaxis so that the yaxis tick marks from the violin plot aren’t between the scatter and violin plot, and I reduced the spacing between the two plots.

One useful tip is that in plotly, the default yaxis range is `[min-range/16, max+range/16]`, which I used to manually set the range of the violin plot so it matches the scatter.

``````import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots

from plotly.graph_objs.scatter.marker import Line
import numpy as np

## use a sample timeseries data set
df = px.data.stocks()

y_testing = df.set_index('date')
y_testing.drop(columns=['AAPL', 'AMZN', 'FB', 'NFLX', 'MSFT'], inplace=True)

np.random.seed(42)
for i in range(20):
y_testing[f'GOOG_{i}'] = y_testing['GOOG'] + np.random.normal(loc=0.0, scale=0.05, size=len(y_testing))

fig = make_subplots(rows=1, cols=2, column_widths=[0.8, 0.2], horizontal_spacing=0.01, specs=[[{"secondary_y": False}, {"secondary_y": True}]])

x=y_testing.index,
y=y_testing.iloc[:, 0]
),row=1, col=1
)

for i in range(1, len(y_testing.columns)-1):
x=y_testing.index,
y=y_testing.iloc[:, i]
),row=1, col=1
)

y=y_testing.iloc[-1],
side='positive'
),row=1, col=2, secondary_y=True,
)

## determine yaxis range for the scatter
y_testing_min = y_testing.min().min()
y_testing_max = y_testing.max().max()
y_testing_range = y_testing_max - y_testing_min
y_range = [y_testing_min - y_testing_range/16, y_testing_max + y_testing_range/16]
fig.update_yaxes(range=y_range, secondary_y=True)

fig.show()
`````` ``` This Question was asked in  StackOverflow by  finman69 and Answered by Derek O It is licensed under the terms of
CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.```