I have this data but graph is a horrendous mess Why can it not graph it properly? def generate_status_hourly_plot(): # Query and round to the hour qs = ( Status.objects .annotate(hour=TruncHour('status_at')) .values('hour', 'status') .annotate(count=Count('id')) .order_by('hour') ) df = pd.DataFrame(list(qs)) if df.empty: return go.Figure().update_layout(title='No status data available') # Ensure all statuses appear even if missing expected_statuses = ['Offline', 'Oncall', 'Online'] df_pivot = df.pivot(index='hour', columns='status', values='count').fillna(0) # Add any missing columns manually for status in expected_statuses: if status not in df_pivot.columns: df_pivot[status] = 0 # Sort by hour and by column name (to avoid plotting order issues) df_pivot = df_pivot[expected_statuses].sort_index() colors = { 'Offline': 'royalblue', 'Oncall': 'tomato', 'Online': 'mediumseagreen', } # Plot fig = go.Figure() for status in expected_statuses: fig.add_trace(go.Scatter( x=df_pivot.index, y=df_pivot[status], name=status, mode='lines', stackgroup='one', # Ensures stacked plot line=dict(width=0.5), fillcolor=colors[status], )) fig.update_layout( title='Psychic Statuses Over Time (Hourly) - Latest Status per Psychic', xaxis_title='Hour', yaxis_title='Status Count', hovermode='x unified', ) fig.update_xaxes( tickformat="%H:%M\n%b %d" ) return fig Continue reading...