Download simple_app.py from mic3333/dash-mcp: direct link, hf CLI and curl.
- Browser
- Download file 14.6 kB
-
https://huggingface.co/spaces/mic3333/dash-mcp/resolve/main/simple_app.py
- Command line
-
hf download hf://spaces/mic3333/dash-mcp/simple_app.py
-
curl -L -o simple_app.py https://huggingface.co/spaces/mic3333/dash-mcp/resolve/main/simple_app.py
14.6 kB
| import os | |
| import base64 | |
| import io | |
| import pandas as pd | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| from dash import Dash, html, dcc, Input, Output, State, callback_context | |
| import dash_bootstrap_components as dbc | |
| # Initialize Dash app | |
| app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) | |
| server = app.server | |
| # App layout | |
| app.layout = dbc.Container([ | |
| dbc.Row([ | |
| dbc.Col([ | |
| html.H1("π Interactive Data Dashboard", className="text-center mb-4"), | |
| html.P("Upload data and create interactive visualizations with different chart types!", | |
| className="text-center text-muted"), | |
| html.Hr(), | |
| ], width=12) | |
| ]), | |
| dbc.Row([ | |
| dbc.Col([ | |
| dbc.Card([ | |
| dbc.CardBody([ | |
| html.H4("π Data Upload", className="card-title"), | |
| dcc.Upload( | |
| id='upload-data', | |
| children=html.Div([ | |
| 'Drag and Drop or ', | |
| html.A('Select Files') | |
| ]), | |
| style={ | |
| 'width': '100%', | |
| 'height': '60px', | |
| 'lineHeight': '60px', | |
| 'borderWidth': '1px', | |
| 'borderStyle': 'dashed', | |
| 'borderRadius': '5px', | |
| 'textAlign': 'center', | |
| 'margin': '10px' | |
| }, | |
| multiple=False, | |
| accept='.csv,.xlsx,.txt' | |
| ), | |
| html.Div(id='upload-status', className="mt-2"), | |
| html.Hr(), | |
| html.H4("π Quick Analytics", className="card-title"), | |
| dbc.ButtonGroup([ | |
| dbc.Button("Summary Stats", id="stats-btn", size="sm"), | |
| dbc.Button("Correlations", id="corr-btn", size="sm"), | |
| dbc.Button("Missing Data", id="missing-btn", size="sm"), | |
| ], className="w-100"), | |
| html.Div(id="quick-analytics", className="mt-3") | |
| ]) | |
| ]) | |
| ], width=4), | |
| dbc.Col([ | |
| dbc.Card([ | |
| dbc.CardBody([ | |
| html.H4("π Visualizations", className="card-title"), | |
| # Chart controls | |
| dbc.Row([ | |
| dbc.Col([ | |
| html.Label("Chart Type:", className="form-label"), | |
| dcc.Dropdown( | |
| id='chart-type', | |
| options=[ | |
| {'label': 'Scatter Plot', 'value': 'scatter'}, | |
| {'label': 'Line Chart', 'value': 'line'}, | |
| {'label': 'Bar Chart', 'value': 'bar'}, | |
| {'label': 'Histogram', 'value': 'histogram'}, | |
| {'label': 'Box Plot', 'value': 'box'}, | |
| {'label': 'Heatmap', 'value': 'heatmap'}, | |
| {'label': 'Pie Chart', 'value': 'pie'} | |
| ], | |
| value='scatter', | |
| className="mb-2" | |
| ) | |
| ], width=6), | |
| dbc.Col([ | |
| html.Label("Color By:", className="form-label"), | |
| dcc.Dropdown( | |
| id='color-column', | |
| placeholder="Select column (optional)", | |
| className="mb-2" | |
| ) | |
| ], width=6) | |
| ]), | |
| dbc.Row([ | |
| dbc.Col([ | |
| html.Label("X-Axis:", className="form-label"), | |
| dcc.Dropdown( | |
| id='x-column', | |
| placeholder="Select X column" | |
| ) | |
| ], width=6), | |
| dbc.Col([ | |
| html.Label("Y-Axis:", className="form-label"), | |
| dcc.Dropdown( | |
| id='y-column', | |
| placeholder="Select Y column" | |
| ) | |
| ], width=6) | |
| ], className="mb-3"), | |
| dcc.Graph(id='main-graph', style={'height': '500px'}), | |
| ]) | |
| ]), | |
| dbc.Card([ | |
| dbc.CardBody([ | |
| html.H4("π Data Explorer", className="card-title"), | |
| html.Div(id='data-table') | |
| ]) | |
| ], className="mt-3") | |
| ], width=8) | |
| ], className="mt-4"), | |
| # Store components | |
| dcc.Store(id='stored-data'), | |
| ], fluid=True) | |
| def parse_contents(contents, filename): | |
| """Parse uploaded file contents""" | |
| content_type, content_string = contents.split(',') | |
| decoded = base64.b64decode(content_string) | |
| try: | |
| if 'csv' in filename: | |
| df = pd.read_csv(io.StringIO(decoded.decode('utf-8'))) | |
| elif 'xls' in filename: | |
| df = pd.read_excel(io.BytesIO(decoded)) | |
| else: | |
| return None, "Unsupported file type" | |
| return df, None | |
| except Exception as e: | |
| return None, f"Error processing file: {str(e)}" | |
| def update_data(contents, filename): | |
| """Update data when file is uploaded""" | |
| if contents is None: | |
| return None, "", "", [], [], [], None, None | |
| df, error = parse_contents(contents, filename) | |
| if error: | |
| return None, dbc.Alert(error, color="danger"), "", [], [], [], None, None | |
| # Create data table preview | |
| table = dbc.Table.from_dataframe( | |
| df.head(10), | |
| striped=True, | |
| bordered=True, | |
| hover=True, | |
| size='sm' | |
| ) | |
| success_msg = dbc.Alert([ | |
| html.H6(f"β File uploaded successfully!"), | |
| html.P(f"Shape: {df.shape[0]} rows Γ {df.shape[1]} columns"), | |
| html.P(f"Columns: {', '.join(df.columns.tolist())}") | |
| ], color="success") | |
| # Create column options for dropdowns | |
| all_columns = [{'label': col, 'value': col} for col in df.columns] | |
| numeric_columns = [{'label': col, 'value': col} for col in df.select_dtypes(include=['number']).columns] | |
| # Set default values - prefer numeric columns for x and y | |
| default_x = numeric_columns[0]['value'] if numeric_columns else all_columns[0]['value'] if all_columns else None | |
| default_y = numeric_columns[1]['value'] if len(numeric_columns) > 1 else (numeric_columns[0]['value'] if numeric_columns else (all_columns[1]['value'] if len(all_columns) > 1 else None)) | |
| return df.to_dict('records'), success_msg, table, all_columns, all_columns, all_columns, default_x, default_y | |
| def quick_analytics(stats_clicks, corr_clicks, missing_clicks, data): | |
| """Handle quick analytics buttons""" | |
| if not data: | |
| return "" | |
| df = pd.DataFrame(data) | |
| ctx = callback_context | |
| if not ctx.triggered: | |
| return "" | |
| button_id = ctx.triggered[0]['prop_id'].split('.')[0] | |
| if button_id == 'stats-btn': | |
| stats = df.describe() | |
| return dbc.Alert([ | |
| html.H6("π Summary Statistics"), | |
| dbc.Table.from_dataframe(stats.reset_index(), size='sm') | |
| ], color="light") | |
| elif button_id == 'corr-btn': | |
| numeric_df = df.select_dtypes(include=['number']) | |
| if len(numeric_df.columns) > 1: | |
| corr = numeric_df.corr() | |
| fig = px.imshow(corr, text_auto=True, aspect="auto", | |
| title="Correlation Matrix") | |
| return dcc.Graph(figure=fig, style={'height': '300px'}) | |
| return dbc.Alert("No numeric columns for correlation analysis", color="warning") | |
| elif button_id == 'missing-btn': | |
| missing = df.isnull().sum() | |
| missing = missing[missing > 0] | |
| if missing.empty: | |
| return dbc.Alert("β No missing values!", color="success") | |
| return dbc.Alert([ | |
| html.H6("β οΈ Missing Values"), | |
| html.Pre(missing.to_string()) | |
| ], color="warning") | |
| return "" | |
| def update_main_graph(data, chart_type, x_col, y_col, color_col): | |
| """Update main visualization based on user selections""" | |
| if not data: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Upload data to see visualizations", | |
| x=0.5, y=0.5, showarrow=False, | |
| font=dict(size=16, color="gray")) | |
| fig.update_layout(template="plotly_white") | |
| return fig | |
| df = pd.DataFrame(data) | |
| # Handle cases where columns aren't selected yet | |
| if not x_col and not y_col: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Select columns to create visualization", | |
| x=0.5, y=0.5, showarrow=False, | |
| font=dict(size=16, color="gray")) | |
| fig.update_layout(template="plotly_white") | |
| return fig | |
| try: | |
| # Create visualization based on chart type | |
| if chart_type == 'scatter': | |
| if x_col and y_col: | |
| fig = px.scatter(df, x=x_col, y=y_col, color=color_col, | |
| title=f"Scatter Plot: {y_col} vs {x_col}") | |
| else: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Select both X and Y columns for scatter plot", | |
| x=0.5, y=0.5, showarrow=False) | |
| elif chart_type == 'line': | |
| if x_col and y_col: | |
| fig = px.line(df, x=x_col, y=y_col, color=color_col, | |
| title=f"Line Chart: {y_col} vs {x_col}") | |
| else: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Select both X and Y columns for line chart", | |
| x=0.5, y=0.5, showarrow=False) | |
| elif chart_type == 'bar': | |
| if x_col and y_col: | |
| fig = px.bar(df, x=x_col, y=y_col, color=color_col, | |
| title=f"Bar Chart: {y_col} by {x_col}") | |
| elif x_col: | |
| fig = px.bar(df[x_col].value_counts().reset_index(), | |
| x='index', y=x_col, | |
| title=f"Value Counts: {x_col}") | |
| else: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Select at least X column for bar chart", | |
| x=0.5, y=0.5, showarrow=False) | |
| elif chart_type == 'histogram': | |
| if x_col: | |
| fig = px.histogram(df, x=x_col, color=color_col, | |
| title=f"Histogram: {x_col}") | |
| else: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Select X column for histogram", | |
| x=0.5, y=0.5, showarrow=False) | |
| elif chart_type == 'box': | |
| if y_col: | |
| fig = px.box(df, x=color_col, y=y_col, | |
| title=f"Box Plot: {y_col}" + (f" by {color_col}" if color_col else "")) | |
| elif x_col: | |
| fig = px.box(df, y=x_col, | |
| title=f"Box Plot: {x_col}") | |
| else: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Select a column for box plot", | |
| x=0.5, y=0.5, showarrow=False) | |
| elif chart_type == 'heatmap': | |
| numeric_cols = df.select_dtypes(include=['number']).columns | |
| if len(numeric_cols) > 1: | |
| corr_matrix = df[numeric_cols].corr() | |
| fig = px.imshow(corr_matrix, | |
| text_auto=True, | |
| aspect="auto", | |
| title="Correlation Heatmap", | |
| color_continuous_scale='RdBu_r') | |
| else: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Need at least 2 numeric columns for heatmap", | |
| x=0.5, y=0.5, showarrow=False) | |
| elif chart_type == 'pie': | |
| if x_col: | |
| value_counts = df[x_col].value_counts() | |
| fig = px.pie(values=value_counts.values, | |
| names=value_counts.index, | |
| title=f"Pie Chart: {x_col}") | |
| else: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Select X column for pie chart", | |
| x=0.5, y=0.5, showarrow=False) | |
| else: | |
| fig = go.Figure() | |
| fig.add_annotation(text="Select a chart type", | |
| x=0.5, y=0.5, showarrow=False) | |
| fig.update_layout(template="plotly_white", height=500) | |
| return fig | |
| except Exception as e: | |
| fig = go.Figure() | |
| fig.add_annotation(text=f"Error creating chart: {str(e)}", | |
| x=0.5, y=0.5, showarrow=False, | |
| font=dict(color="red")) | |
| fig.update_layout(template="plotly_white") | |
| return fig | |
| if __name__ == '__main__': | |
| app.run_server(host='0.0.0.0', port=8050, debug=True) |