Search code examples
pythonplotly

Combine two plotly graphs


I wrote a script for a dashboard that displays a loading schedule. Successful tasks are green, and erroneous tasks are red. There is also a graph of CPU and memory load. I tried to display two graphs one under the other. However, because the legend of the first chart is displayed as text and takes up some space, the second chart does not exactly coincide on the X-axis. Then I tried to combine the two charts into one. But then the red entries are lost from the first chart. At first, I thought it was because of different timestamps (there are different tables and microseconds have a different format). But then I made a test script with arrays-constants, and the problem remained. Is this a bug or a feature of the plotly library? Can I somehow display the process graph differently, so that it is possible to combine the graphs? I want to use plotly to possibly interact with charts. I tried using scatter for the loading schedule - but I didn't particularly appreciate how it looks like. It is not clear how long the process takes time.

Here is my code and examples of graphs.

import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

# creating data for df_1
np.random.seed(42)
n_rows = 50
start_time = datetime(2023, 9, 21, 0, 0, 0)
end_time = start_time + timedelta(days=1)
chain_ids = np.random.choice(['Chain_01', 'Chain_02', 'Chain_03'], n_rows)
colors = np.random.choice(['green', 'red'], n_rows)
timestamps_start = pd.date_range(start=start_time, end=end_time, periods=n_rows)
timestamps_end = timestamps_start + pd.to_timedelta(np.random.randint(10, 1600, n_rows), unit='s')

df_1 = pd.DataFrame({
    'CHAIN_ID': chain_ids,
    'Color': colors,
    'TSTMP_START': timestamps_start,
    'TSTMP_END': timestamps_end
})

# creating data for df_2
n_rows_p = 150
timestamps_p = pd.date_range(start=start_time, end=end_time, periods=n_rows_p)
peak_used_gb = np.random.uniform(500, 1200, n_rows_p)
used_physical_gb = np.random.uniform(1200, 1800, n_rows_p)

df_2 = pd.DataFrame({
    'SERVER_TIMESTAMP': timestamps_p,
    'Peak_Used_GB': peak_used_gb,
    'Used_physical_GB': used_physical_gb
})

color_map = {'green': 'green', 'red': 'red', 'yellow': 'yellow'}

fig1 = px.timeline(df_1,
                   x_start='TSTMP_START',
                   x_end='TSTMP_END',
                   y='CHAIN_ID',
                   color='Color',
                   color_discrete_map=color_map)

fig2 = go.Figure()
fig2.add_trace(go.Scatter(x=df_2['SERVER_TIMESTAMP'], y=df_2['Peak_Used_GB'], mode='lines', name='Peak_Used_GB', line=dict(color='blue')))
fig2.add_trace(go.Scatter(x=df_2['SERVER_TIMESTAMP'], y=df_2['Used_physical_GB'], mode='lines', name='Used_physical_GB', line=dict(color='orange')))

fig_c = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.06, row_width=[0.1, 0.4])
fig_c.add_trace(fig1.data[0], row=1, col=1)
fig_c.add_trace(fig2.data[0], row=2, col=1)
fig_c.add_trace(fig2.data[1], row=2, col=1)

fig_c.update_layout(height=600)
fig_c.update_xaxes(type='date')

fig1.show()
fig_c.show()

fig1 and fig2 chart: fig1 chart

Combined chart: combined chart

I expect chart like this: Target chart design


Solution

  • You need to add the second Bar in fig1.data as secondary

    fig_c = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.06, row_width=[0.1, 0.4], specs=[[{"secondary_y": True}]] * len(fig1.data))
    fig_c.add_trace(fig1.data[0], row=1, col=1)
    fig_c.add_trace(fig1.data[1], row=1, col=1, secondary_y=True)
    fig_c.add_trace(fig2.data[0], row=2, col=1)
    fig_c.add_trace(fig2.data[1], row=2, col=1)
    

    enter image description here