# check out https://dash.plotly.com/ for documentation
# And check out https://py.cafe/maartenbreddels for more examples
from dash import Dash, Input, Output, callback, dcc, html
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import dash_bootstrap_components as dbc
# Load and prepare data
df = pd.read_csv('risky_habits.csv')
df.columns = df.columns.str.strip()
# Define custom ordering for categorical variables
income_order = [
'$0 - $24,999',
'$25,000 - $49,999',
'$50,000 - $99,999',
'$100,000 - $149,999',
'$150,000+'
]
education_order = [
'Less than high school degree',
'High school degree',
'Some college or Associate degree',
'Bachelor degree',
'Graduate degree'
]
# Apply custom ordering
df['Household_Income'] = pd.Categorical(df['Household_Income'], categories=income_order, ordered=True)
df['Education'] = pd.Categorical(df['Education'], categories=education_order, ordered=True)
# Define all risk habits and characteristics
all_risk_habits = [
'Do_you_ever_smoke_cigarettes',
'Do_you_ever_drink_alcohol',
'Do_you_ever_gamble',
'Have_you_ever_been_skydiving',
'Do_you_ever_drive_above_the_speed_limit',
'Have_you_ever_cheated_on_your_significant_other',
'Do_you_eat_steak'
]
all_characteristics = [
'Gender',
'Age',
'Household_Income',
'Education',
'Location'
]
# Create nice display names for dropdowns
habit_options = []
for habit in all_risk_habits:
# Clean up names for display
display_name = habit.replace('Do_you_ever_', '').replace('Have_you_ever_', '')
display_name = display_name.replace('_', ' ').title()
habit_options.append({'label': display_name, 'value': habit})
char_options = []
for char in all_characteristics:
display_name = char.replace('_', ' ').title()
char_options.append({'label': display_name, 'value': char})
# Initialize Dash app
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# Define app layout
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
html.H1("Risky Habits Analysis Dashboard", className="text-center mb-4"),
html.Hr()
])
]),
# Risk Habits dropdown - full width, centered
dbc.Row([
dbc.Col([
html.Label("Select Risk Habits:", className="fw-bold text-center d-block mb-2"),
dcc.Dropdown(
id='habit-dropdown',
options=habit_options,
value=all_risk_habits[:3], # Default to first 3
multi=True,
placeholder="Select one or more risk habits...",
style={'width': '100%'}
)
], width="auto", className="mx-auto")
], className="mb-3"),
# Characteristics dropdown - centered
dbc.Row([
dbc.Col([
html.Label("Select Characteristic:", className="fw-bold text-center d-block mb-2"),
dcc.Dropdown(
id='char-dropdown',
options=char_options,
value='Gender', # Default to Gender
multi=False,
placeholder="Select a characteristic...",
style={'width': '100%'}
)
], width="auto", className="mx-auto")
], className="mb-4"),
# Chart section with padding
dbc.Row([
dbc.Col([
dcc.Graph(id='risk-chart')
], width=10, className="mx-auto")
], className="mb-3"),
# Summary section - centered
dbc.Row([
dbc.Col([
html.Div(id='data-summary', className="text-center")
], width=8, className="mx-auto")
])
], fluid=True, style={'backgroundColor': '#9cabb8', 'minHeight': '100vh', 'padding': '20px'})
# Callback for updating the chart
@app.callback(
[Output('risk-chart', 'figure'),
Output('data-summary', 'children')],
[Input('habit-dropdown', 'value'),
Input('char-dropdown', 'value')]
)
def update_chart(selected_habits, selected_char):
# Error handling
if not selected_habits or not selected_char:
empty_fig = go.Figure()
empty_fig.add_annotation(
text="Please select at least one risk habit and one characteristic",
xref="paper", yref="paper", x=0.5, y=0.5,
showarrow=False, font=dict(size=16)
)
return empty_fig, "No data to display"
try:
# Check if columns exist
missing_cols = []
for habit in selected_habits:
if habit not in df.columns:
missing_cols.append(habit)
if selected_char not in df.columns:
missing_cols.append(selected_char)
if missing_cols:
error_fig = go.Figure()
error_fig.add_annotation(
text=f"Missing columns: {missing_cols}",
xref="paper", yref="paper", x=0.5, y=0.5,
showarrow=False, font=dict(size=16, color="red")
)
return error_fig, f"Error: Missing columns {missing_cols}"
# Filter data for 'Yes' responses
mask = df[selected_habits].eq('Yes').any(axis=1)
filtered_df = df[mask]
if len(filtered_df) == 0:
empty_fig = go.Figure()
empty_fig.add_annotation(
text="No 'Yes' responses found for selected habits",
xref="paper", yref="paper", x=0.5, y=0.5,
showarrow=False, font=dict(size=16)
)
return empty_fig, "No 'Yes' responses found"
# Count 'Yes' responses by characteristic
risk_counts = filtered_df.groupby(selected_char)[selected_habits].apply(
lambda x: (x == 'Yes').sum()
).reset_index()
# Melt for plotting
risk_melted = risk_counts.melt(
id_vars=selected_char,
var_name='Risk_Habit',
value_name='Count'
)
# Clean up habit names for display
risk_melted['Risk_Habit_Display'] = risk_melted['Risk_Habit'].str.replace('Do_you_ever_', '', regex=False)
risk_melted['Risk_Habit_Display'] = risk_melted['Risk_Habit_Display'].str.replace('Have_you_ever_', '', regex=False)
risk_melted['Risk_Habit_Display'] = risk_melted['Risk_Habit_Display'].str.replace('_', ' ', regex=False)
risk_melted['Risk_Habit_Display'] = risk_melted['Risk_Habit_Display'].str.title()
# Create grouped bar chart
fig = px.bar(
risk_melted,
x=selected_char,
y='Count',
color='Risk_Habit_Display',
barmode='group',
title=f"Risk Habits by {selected_char.replace('_', ' ').title()}",
labels={
'Count': 'Number of "Yes" Responses',
selected_char: selected_char.replace('_', ' ').title(),
'Risk_Habit_Display': 'Risk Habit'
},
color_discrete_sequence=px.colors.qualitative.Dark2
)
fig.update_layout(
height=500,
xaxis_title=selected_char.replace('_', ' ').title(),
yaxis_title='Number of "Yes" Responses',
legend_title="Risk Habits",
font=dict(size=12),
title_font_size=16
)
# Create summary text
total_responses = len(filtered_df)
unique_chars = filtered_df[selected_char].nunique()
summary = html.Div([
html.P(f"Total respondents with at least one 'Yes': {total_responses}"),
html.P(f"Number of {selected_char.replace('_', ' ').lower()} categories: {unique_chars}"),
html.P(f"Analyzing {len(selected_habits)} risk habit(s)")
])
return fig, summary
except Exception as e:
error_fig = go.Figure()
error_fig.add_annotation(
text=f"Error: {str(e)}",
xref="paper", yref="paper", x=0.5, y=0.5,
showarrow=False, font=dict(size=16, color="red")
)
return error_fig, f"Error occurred: {str(e)}"
# Run the app
if __name__ == '__main__':
app.run(debug=True)