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("📊 Dynamic Dashboard Creator", className="text-center mb-4"), html.Hr(), ], width=12) ]), dbc.Row([ dbc.Col([ dbc.Card([ dbc.CardBody([ html.H4("Upload Dataset", 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' ), html.Div(id='upload-status', className="mt-2"), html.Hr(), html.H5("Chart Configuration"), dbc.Row([ dbc.Col([ dbc.Label("Chart Type"), dcc.Dropdown( id='chart-type', options=[ {'label': 'Bar Chart', 'value': 'bar'}, {'label': 'Line Chart', 'value': 'line'}, {'label': 'Scatter Plot', 'value': 'scatter'}, {'label': 'Histogram', 'value': 'histogram'}, {'label': 'Box Plot', 'value': 'box'}, {'label': 'Heatmap', 'value': 'heatmap'}, ], value='bar' ) ], width=12, className="mb-3"), dbc.Col([ dbc.Label("X-axis Column"), dcc.Dropdown(id='x-column') ], width=6, className="mb-3"), dbc.Col([ dbc.Label("Y-axis Column"), dcc.Dropdown(id='y-column') ], width=6, className="mb-3"), dbc.Col([ dbc.Label("Color Column (Optional)"), dcc.Dropdown(id='color-column') ], width=6, className="mb-3"), dbc.Col([ dbc.Label("Size Column (Optional)"), dcc.Dropdown(id='size-column') ], width=6, className="mb-3"), ]), dbc.Button( "Generate Dashboard", id="generate-btn", color="primary", className="w-100 mt-3" ) ]) ]) ], width=4), dbc.Col([ dbc.Card([ dbc.CardBody([ html.H4("Dashboard", className="card-title"), dcc.Graph(id='main-graph', style={'height': '500px'}), ]) ]), dbc.Card([ dbc.CardBody([ html.H4("Dataset Preview", className="card-title"), html.Div(id='data-table') ]) ], className="mt-3") ], width=8) ], className="mt-4"), # Store component to hold the dataframe 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)}" @app.callback( [Output('stored-data', 'data'), Output('upload-status', 'children'), Output('x-column', 'options'), Output('y-column', 'options'), Output('color-column', 'options'), Output('size-column', 'options'), Output('data-table', 'children')], [Input('upload-data', 'contents')], [State('upload-data', 'filename')] ) def update_data(contents, filename): """Update data when file is uploaded""" if contents is None: return None, "", [], [], [], [], "" df, error = parse_contents(contents, filename) if error: return None, dbc.Alert(error, color="danger"), [], [], [], [], "" # Create column options columns = [{'label': col, 'value': col} for col in df.columns] columns_with_none = [{'label': 'None', 'value': None}] + columns # 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("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") return df.to_dict('records'), success_msg, columns, columns, columns_with_none, columns_with_none, table @app.callback( Output('main-graph', 'figure'), [Input('generate-btn', 'n_clicks')], [State('stored-data', 'data'), State('chart-type', 'value'), State('x-column', 'value'), State('y-column', 'value'), State('color-column', 'value'), State('size-column', 'value')] ) def update_graph(n_clicks, data, chart_type, x_col, y_col, color_col, size_col): """Generate graph based on selections""" if not n_clicks or not data: return {} df = pd.DataFrame(data) try: # Generate different chart types if chart_type == 'bar': fig = px.bar(df, x=x_col, y=y_col, color=color_col, title=f"Bar Chart: {y_col} by {x_col}") elif chart_type == 'line': fig = px.line(df, x=x_col, y=y_col, color=color_col, title=f"Line Chart: {y_col} vs {x_col}") elif chart_type == 'scatter': fig = px.scatter(df, x=x_col, y=y_col, color=color_col, size=size_col, title=f"Scatter Plot: {y_col} vs {x_col}") elif chart_type == 'histogram': fig = px.histogram(df, x=x_col, color=color_col, title=f"Histogram: Distribution of {x_col}") elif chart_type == 'box': fig = px.box(df, x=x_col, y=y_col, color=color_col, title=f"Box Plot: {y_col} by {x_col}") elif chart_type == 'heatmap': # Create correlation heatmap for numeric columns 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 Heatmap") else: fig = go.Figure() fig.add_annotation(text="Not enough numeric columns for heatmap", showarrow=False, x=0.5, y=0.5) else: fig = {} fig.update_layout(template="plotly_white") return fig except Exception as e: fig = go.Figure() fig.add_annotation(text=f"Error: {str(e)}", showarrow=False, x=0.5, y=0.5) return fig if __name__ == '__main__': app.run_server(host='0.0.0.0', port=7860, debug=False)