import dash
from dash import html, dcc, Input, Output, callback
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Register the page (if using multi-page app)
dash.register_page(__name__, path="/comparison_for_dataset_2", title="Dataset 2 Comparison", name="Dataset 2 Comparison")
df = pd.read_csv(file_path1)
df1 = pd.read_csv(file_path2)
cols = df.columns
cols1 = df1.columns
# Data cleaning and merging function
def process_data(df, df1):
df_cleaned = df.dropna()
df1_cleaned = df1.dropna()
df1_cleaned_2 = df1_cleaned.drop(cols1[0], axis=1)
# Merge the cleaned DataFrames
conc_df = pd.concat([df_cleaned, df1_cleaned_2], axis=1)
cleaned_merged_df = conc_df.fillna(0)
cleaned_merged_df_min_max_scaled = cleaned_merged_df.copy()
for col in cleaned_merged_df_min_max_scaled.columns:
if col != cols1[0] and cleaned_merged_df_min_max_scaled[col].max() != cleaned_merged_df_min_max_scaled[col].min():
cleaned_merged_df_min_max_scaled[col] = (
(cleaned_merged_df_min_max_scaled[col] - cleaned_merged_df_min_max_scaled[col].min()) /
(cleaned_merged_df_min_max_scaled[col].max() - cleaned_merged_df_min_max_scaled[col].min())
)
return cleaned_merged_df_min_max_scaled
# Apply data cleaning and merging
merged_df = process_data(df, df1)
# Page Layout
layout = html.Div([
html.H2("Dynamic Graph Visualization with Double Y-axis", style={'textAlign': 'center'}),
html.Label("Select Graph Type:"),
dcc.Dropdown(
id='graph-type',
options=[
{'label': 'Line Graph', 'value': 'line'},
{'label': 'Scatter Plot', 'value': 'scatter'},
{'label': 'Bar Chart', 'value': 'bar'},
{'label': 'Histogram', 'value': 'histogram'}
],
value='line',
style={'width': '300px'}
),
html.Br(),
html.Label("Select X-axis:"),
dcc.Dropdown(
id='x-axis',
options=[{'label': col, 'value': col} for col in merged_df.columns],
value=merged_df.columns[0],
style={'width': '300px'}
),
html.Br(),
html.Label("Select Y-axis for Primary Axis (can select multiple):"),
dcc.Dropdown(
id='primary-y-axis',
options=[{'label': col, 'value': col} for col in merged_df.columns if col != 'Time'],
value=[merged_df.columns[1]],
multi=True,
style={'width': '300px'}
),
html.Br(),
html.Label("Select Y-axis for Secondary Axis (can select multiple):"),
dcc.Dropdown(
id='secondary-y-axis',
options=[{'label': col, 'value': col} for col in merged_df.columns if col != 'Time'],
value=[],
multi=True,
style={'width': '300px'}
),
html.Br(),
dcc.Graph(id='graph-output', style={'height': '800px'})
])
# Callback for dynamic graph updates
@callback(
Output('graph-output', 'figure'),
[Input('graph-type', 'value'),
Input('x-axis', 'value'),
Input('primary-y-axis', 'value'),
Input('secondary-y-axis', 'value')]
)
def update_graph(graph_type, x_col, primary_y_cols, secondary_y_cols):
"""
Update the graph based on selected options for graph type, X-axis, primary Y-axis, and secondary Y-axis.
"""
# Ensure selected columns exist in the merged DataFrame
if x_col not in merged_df.columns:
return go.Figure()
for y_col in primary_y_cols + secondary_y_cols:
if y_col not in merged_df.columns:
return go.Figure()
# Drop rows with NaN in selected columns
cleaned_df = merged_df.dropna(subset=[x_col] + primary_y_cols + secondary_y_cols)
# Create a figure with secondary Y-axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
# Add traces for primary Y-axis
for col in primary_y_cols:
if graph_type == 'line':
fig.add_trace(go.Scatter(x=cleaned_df[x_col], y=cleaned_df[col], name=col, mode='lines'), secondary_y=False)
elif graph_type == 'scatter':
fig.add_trace(go.Scatter(x=cleaned_df[x_col], y=cleaned_df[col], name=col, mode='markers'), secondary_y=False)
elif graph_type == 'bar':
fig.add_trace(go.Bar(x=cleaned_df[x_col], y=cleaned_df[col], name=col), secondary_y=False)
elif graph_type == 'histogram':
fig.add_trace(go.Histogram(x=cleaned_df[x_col], y=cleaned_df[col], name=col), secondary_y=False)
# Add traces for secondary Y-axis
for col in secondary_y_cols:
if graph_type == 'line':
fig.add_trace(go.Scatter(x=cleaned_df[x_col], y=cleaned_df[col], name=col, mode='lines', line=dict(dash='dot')), secondary_y=True)
elif graph_type == 'scatter':
fig.add_trace(go.Scatter(x=cleaned_df[x_col], y=cleaned_df[col], name=col, mode='markers'), secondary_y=True)
elif graph_type == 'bar':
fig.add_trace(go.Bar(x=cleaned_df[x_col], y=cleaned_df[col], name=col, marker=dict(opacity=0.5)), secondary_y=True)
elif graph_type == 'histogram':
fig.add_trace(go.Histogram(x=cleaned_df[x_col], y=cleaned_df[col], name=col), secondary_y=True)
# Update layout
fig.update_layout(
title=f"{graph_type.capitalize()} with {x_col}, Primary Y-axis: {', '.join(primary_y_cols)}, Secondary Y-axis: {', '.join(secondary_y_cols)}",
xaxis_title=x_col,
yaxis_title=", ".join(primary_y_cols),
yaxis2_title=", ".join(secondary_y_cols),
legend_title="Legend",
)
return fig
The datasets are omitted for my own protection. But they are there. Every time I run the app, when I go to this page, the graph plots straight lines going straight up. When I run it in my debugging code, the graph is just fine. Is it something with the normalisation? If anyone can help, it would be greatly appreciated, thanks!