Search code examples
pythonpandasmatplotlibhistogramsimulation

Integrating a histogram in a bootstrap simulation graph


I have a dataframe with 1000 simulations of a portfolio's returns. I am able to graph the simulations and do the respective histogram separately, but I have absolutely no idea how to merge them in order to resemble the following image:

Example of desired output

please take this example of data in order to facilitate answers:

import numpy as np
import pandas as pd

def simulate_panel(T, N):

    """" This function simulates return paths"""

    dates = pd.date_range("20210218", periods=T, freq='D')
    columns = []

    for i in range(N):
        columns.append(str(i+1))

    return pd.DataFrame(np.random.normal(0, 0.01, size=(T, N)), index=dates, 
    columns=columns)

df=(1+simulate_panel(1000,1000)).cumprod()

df.plot(figsize=(8,6),title=('Bootstrap'), legend=False)

Thank you very much in advance.


Solution

  • To color the curves via their last value, they can be drawn one-by-one. With a colormap and a norm, the value can be converted to the appropriate color. Using some transparency (alpha), the most visited positions will be colored stronger.

    In a second subplot, a vertical histogram can be drawn, with the bars colored similarly.

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    
    def simulate_panel(T, N):
        """" This function simulates return paths"""
        dates = pd.date_range("20210218", periods=T, freq='D')
        columns = [(str(i + 1)) for i in range(N)]
        return pd.DataFrame(np.random.normal(0, 0.01, size=(T, N)), index=dates, columns=columns)
    
    df = (1 + simulate_panel(1000, 1000)).cumprod()
    
    fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True, figsize=(12, 4),
                                   gridspec_kw={'width_ratios': [5, 1], 'wspace': 0})
    data = df.to_numpy().T
    cmap = plt.cm.get_cmap('turbo')
    norm = plt.Normalize(min(data[:, -1]), max(data[:, -1]))
    
    for row in data:
        ax1.plot(df.index, row, c=cmap(norm(row[-1])), alpha=0.1)
    ax1.margins(x=0)
    _, bin_edges, bars = ax2.hist(data[:, -1], bins=20, orientation='horizontal')
    for x0, x1, bar in zip(bin_edges[:-1], bin_edges[1:], bars):
        bar.set_color(cmap(norm((x0 + x1) / 2)))
    ax2.tick_params(left=False)
    plt.tight_layout()
    plt.show()
    

    brownian motion with histogram