[Python] Combine separate plots into one plot in Python

Discussão em 'Python' iniciado por Stack, Setembro 1, 2025.

  1. Stack

    Stack Membro Participativo

    I have created the following pandas dataframe:

    ds = {
    'Date' : ['2025-08-22 16:00:00', '2025-08-22 16:01:00', '2025-08-22 16:02:00', '2025-08-22 16:03:00', '2025-08-22 16:04:00', '2025-08-22 16:05:00', '2025-08-22 16:06:00', '2025-08-22 16:07:00', '2025-08-22 16:08:00', '2025-08-22 16:09:00', '2025-08-22 16:10:00', '2025-08-22 16:11:00', '2025-08-22 16:12:00', '2025-08-22 16:13:00', '2025-08-22 16:14:00', '2025-08-22 16:15:00', '2025-08-22 16:16:00', '2025-08-22 16:17:00', '2025-08-22 16:18:00', '2025-08-22 16:19:00', '2025-08-22 16:20:00', '2025-08-22 16:21:00', '2025-08-22 16:22:00', '2025-08-22 16:23:00', '2025-08-22 16:24:00'],
    'Open': [ 11717.9, 11717.95, 11716.6, 11717.4, 11719.5, 11727.25, 11725.55, 11724.35, 11725.45, 11724.15, 11728.2, 11726.6, 11727.6, 11729.1, 11724.1, 11722.8, 11721.8, 11720.8, 11718.8, 11716.7, 11716.9, 11722.5, 11721.6, 11727.8, 11728.1],
    'Low': [ 11715.9, 11716, 11715.35, 11716.45, 11719.5, 11724.3, 11723.55, 11723.15, 11723.85, 11724.15, 11725.2, 11726.6, 11727.6, 11724.2, 11722.6, 11721.6, 11719.7, 11715.8, 11716.5, 11716, 11716.9, 11721.3, 11721.4, 11726.35, 11727],
    'High': [ 11718.1, 11718.1, 11717.9, 11719.4, 11727.15, 11727.45, 11726, 11725.65, 11727.2, 11727.85, 11728.2, 11728.7, 11729.5, 11729.1, 11725.5, 11723.9, 11722, 11720.8, 11719.8, 11717.7, 11722.9, 11724.3, 11727.8, 11728.3, 11728.8],
    'Close' : [11718.05, 11716.5, 11717, 11719.3, 11727.15, 11725.65, 11724.15, 11725.35, 11724.05, 11727.65, 11726.7, 11727.8, 11729.2, 11724.2, 11722.6, 11721.7, 11721.2, 11718.7, 11716.6, 11716.8, 11722.6, 11721.5, 11727.6, 11728, 11727.2],
    'Volume': [ 130, 88, 125, 93, 154, 102, 118, 92, 105, 116, 84, 88, 108, 99, 82, 109, 98, 130, 71, 86, 96, 83, 80, 93, 73],
    'Regime': [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3],
    }

    df = pd.DataFrame(data=ds)


    The dataframe contains a field called Regime, which has three values:1,2 and 3.

    I have created a volume profile plot for each of those Regimes after grouping the records by 5 minutes.

    df['Date'] = pd.to_datetime(df['Date'])
    df.set_index('Date', inplace=True)

    # Resample to 5-minute intervals
    df_30 = df.resample('5T').agg({'Open': 'first', 'High': 'max', 'Low': 'min', 'Close': 'last', 'Volume': 'sum','Regime':'last'})
    df_30 = df_30.dropna()

    # Add date column for grouping
    df_30['date'] = df_30.index.date


    # For volume profile, use the original 1min df
    df['date'] = df.index.date

    # Group by regime
    for regime in df['Regime'].unique():
    daily_30 = df_30[df_30['Regime'] == regime]
    daily_1 = df[df['Regime'] == regime]

    if daily_30.empty:
    continue

    # For candlestick plotting
    daily_30 = daily_30.reset_index()
    xdates = np.arange(len(daily_30))

    # For volume profile
    min_price = daily_1['Low'].min()
    max_price = daily_1['High'].max()
    num_bins = 200
    bins = np.linspace(min_price, max_price, num_bins + 1)
    bin_size = bins[1] - bins[0]
    bin_centers = (bins[:-1] + bins[1:]) / 2
    volume_profile = np.zeros(num_bins)

    display(volume_profile)

    for _, row in daily_1.iterrows():
    low = row['Low']
    high = row['High']
    vol = row['Volume']
    if high == low:
    bin_idx = np.digitize(low, bins) - 1
    if 0 <= bin_idx < num_bins:
    volume_profile[bin_idx] += vol
    else:
    vol_per_unit = vol / (high - low)
    start_bin = np.digitize(low, bins)
    end_bin = np.digitize(high, bins)
    for b in range(start_bin, end_bin + 1):
    if b > 0 and b <= num_bins:
    bin_start = bins[b - 1]
    bin_end = bins
    start = max(low, bin_start)
    end = min(high, bin_end)
    portion = (end - start) * vol_per_unit
    volume_profile[b - 1] += portion

    # Normalize for plotting (scale to chart width)
    chart_width = len(daily_30)
    if max(volume_profile) > 0:
    scaled_volume = (volume_profile / max(volume_profile)) * chart_width
    else:
    scaled_volume = volume_profile

    display(scaled_volume)
    # POC (Point of Control)
    poc_idx = np.argmax(volume_profile)
    poc_price = bin_centers[poc_idx]

    # print(poc_price)
    # Plot
    fig, ax = plt.subplots(figsize=(10, 6))

    # Plot volume profile first (as background)
    ax.fill_betweenx(bin_centers, 0, scaled_volume, color='blue', alpha=0.3, step='mid')

    # Plot POC
    ax.axhline(poc_price, color='red', linestyle='-', linewidth=1)

    # Plot candlesticks on top
    candle_width = 0.6
    for i in range(len(daily_30)):
    o = daily_30['Open']
    h = daily_30['High']
    l = daily_30['Low']
    c = daily_30['Close']
    if c > o:
    color = 'green'
    bottom = o
    height = c - o
    else:
    color = 'red'
    bottom = c
    height = o - c
    # Wick
    ax.vlines(xdates, l, h, color='black', linewidth=0.5)
    # Body
    ax.bar(xdates, height, candle_width, bottom, color=color, edgecolor='black')

    ax.set_xlim(-1, chart_width + 1)
    ax.set_ylim(min_price - bin_size, max_price + bin_size)
    ax.set_xticks(xdates)
    ax.set_xticklabels(daily_30['Date'].dt.strftime('%H:%M'), rotation=45)
    ax.set_title(f'30-min Candlestick with Volume Profile - Regime: {regime}')
    ax.set_xlabel('Time')
    ax.set_ylabel('Price')
    plt.tight_layout()
    plt.show()


    The code creates three separate volume profile plots.

    [​IMG] [​IMG] [​IMG]

    I need to combine the three plots into one single plot, such that on the x-axis Plot2 follows Plot 1, and Plot 3 follows Plot 2. Basically, I'd like to see a graph similar (but of course not exactly the same) to this.

    [​IMG]

    Does someone know how to do it?

    Continue reading...

Compartilhe esta Página