# Data Visualization > Interactive charts and graphs with Plotly integration --- .. llms_copy::Data Visualization .. toc:: ### Introduction This page demonstrates how to create **interactive data visualizations** using Plotly with your Dash Documentation Boilerplate. Plotly provides powerful, interactive charts that integrate seamlessly with Dash callbacks. --- ### Basic Chart Example Let's start with a simple bar chart example: .. exec::docs.data-visualization.basic_chart :code: false Source code: ```python # File: docs/data-visualization/basic_chart.py from dash import dcc, callback, Input, Output import dash_mantine_components as dmc import pandas as pd import plotly.express as px # Register Mantine templates dmc.add_figure_templates(default="mantine_light") # Sample data df = pd.DataFrame({ "Category": ["Product A", "Product B", "Product C", "Product D", "Product E"], "Sales": [120, 95, 180, 140, 165] }) # Create initial figure fig = px.bar( df, x="Category", y="Sales", title="Product Sales Comparison", color="Sales", color_continuous_scale="teal" ) fig.update_layout( xaxis_title="Product Category", yaxis_title="Sales (Units)", showlegend=False, height=400 ) component = dcc.Graph(figure=fig, id='figure-basic-chart', config={'displayModeBar': False}) @callback( Output('figure-basic-chart', "figure"), Input("color-scheme-storage", "data"), ) def update_figure_theme(theme): """Update chart template based on color scheme""" template = "mantine_dark" if theme == "dark" else "mantine_light" # Recreate the figure with the correct template fig = px.bar( df, x="Category", y="Sales", title="Product Sales Comparison", color="Sales", color_continuous_scale="teal", template=template ) fig.update_layout( xaxis_title="Product Category", yaxis_title="Sales (Units)", showlegend=False, height=400 ) return fig ``` :defaultExpanded: false :withExpandedButton: true --- ### Interactive Line Chart This example shows multiple lines with hover tooltips and a legend: .. exec::docs.data-visualization.line_chart :code: false Source code: ```python # File: docs/data-visualization/line_chart.py from dash import dcc, callback, Input, Output import dash_mantine_components as dmc import pandas as pd import plotly.express as px import numpy as np # Register Mantine templates dmc.add_figure_templates(default="mantine_light") # Generate sample time series data dates = pd.date_range('2024-01-01', periods=30, freq='D') np.random.seed(42) df = pd.DataFrame({ 'Date': dates, 'Revenue': np.cumsum(np.random.randn(30) * 10 + 100), 'Costs': np.cumsum(np.random.randn(30) * 8 + 80), 'Profit': np.cumsum(np.random.randn(30) * 5 + 20) }) # Melt the dataframe for plotting multiple lines df_melted = df.melt(id_vars=['Date'], var_name='Metric', value_name='Amount') # Create initial figure fig = px.line( df_melted, x='Date', y='Amount', color='Metric', title='Financial Metrics Over Time', color_discrete_map={ 'Revenue': '#12B886', # Teal 'Costs': '#FA5252', # Red 'Profit': '#228BE6' # Blue } ) fig.update_layout( xaxis_title='Date', yaxis_title='Amount ($)', hovermode='x unified', height=450, legend=dict( orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1 ) ) component = dcc.Graph(figure=fig, id='figure-line-chart') @callback( Output('figure-line-chart', "figure"), Input("color-scheme-storage", "data"), ) def update_figure_theme(theme): """Update chart template based on color scheme""" template = "mantine_dark" if theme == "dark" else "mantine_light" # Recreate the figure with the correct template fig = px.line( df_melted, x='Date', y='Amount', color='Metric', title='Financial Metrics Over Time', color_discrete_map={ 'Revenue': '#12B886', 'Costs': '#FA5252', 'Profit': '#228BE6' }, template=template ) fig.update_layout( xaxis_title='Date', yaxis_title='Amount ($)', hovermode='x unified', height=450, legend=dict( orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1 ) ) return fig ``` --- ### Scatter Plot with Filtering An interactive scatter plot with dropdown filtering: .. exec::docs.data-visualization.scatter_plot :code: false Source code: ```python # File: docs/data-visualization/scatter_plot.py from dash import html, dcc, callback, Input, Output, State import pandas as pd import plotly.express as px import dash_mantine_components as dmc import numpy as np # Register Mantine templates dmc.add_figure_templates(default="mantine_light") # Generate sample data np.random.seed(42) df = pd.DataFrame({ 'Height': np.random.normal(170, 10, 100), 'Weight': np.random.normal(70, 15, 100), 'Age': np.random.randint(20, 60, 100), 'Gender': np.random.choice(['Male', 'Female'], 100) }) component = html.Div([ dmc.Title("Height vs Weight Analysis", order=4, mb=10), dmc.Select( label="Filter by Gender", data=[ {"label": "All", "value": "all"}, {"label": "Male", "value": "Male"}, {"label": "Female", "value": "Female"} ], value="all", id="gender-filter", mb=15, style={"maxWidth": "200px"} ), dcc.Graph(id="scatter-chart") ]) @callback( Output("scatter-chart", "figure"), Input("gender-filter", "value"), Input("color-scheme-storage", "data"), ) def update_scatter(gender, theme): """Update scatter plot based on gender filter and theme""" template = "mantine_dark" if theme == "dark" else "mantine_light" if gender == "all": filtered_df = df else: filtered_df = df[df['Gender'] == gender] fig = px.scatter( filtered_df, x='Height', y='Weight', color='Gender', size='Age', title=f'Height vs Weight{" - " + gender if gender != "all" else ""}', hover_data=['Age'], color_discrete_map={'Male': '#228BE6', 'Female': '#FA5252'}, template=template ) fig.update_layout( xaxis_title='Height (cm)', yaxis_title='Weight (kg)', height=450 ) return fig ``` --- ### Real-Time Data Updates This example demonstrates how to update charts in real-time using intervals: .. exec::docs.data-visualization.realtime_chart :code: false Source code: ```python # File: docs/data-visualization/realtime_chart.py from dash import html, dcc, callback, Input, Output import dash_mantine_components as dmc import plotly.graph_objects as go from collections import deque import random from datetime import datetime, timedelta # Register Mantine templates dmc.add_figure_templates(default="mantine_light") # Initialize deque to store recent data points MAX_DATA_POINTS = 50 time_data = deque(maxlen=MAX_DATA_POINTS) value_data = deque(maxlen=MAX_DATA_POINTS) # Initialize with some data start_time = datetime.now() for i in range(20): time_data.append(start_time + timedelta(seconds=i)) value_data.append(random.uniform(20, 80)) component = html.Div([ dmc.Title("Real-Time Data Stream", order=4, mb=10), dmc.Alert( "This chart updates every 2 seconds with simulated real-time data", color="blue", mb=15 ), dcc.Graph(id="realtime-graph"), dcc.Interval( id="interval-component", interval=2000, # Update every 2 seconds n_intervals=0 ) ]) @callback( Output("realtime-graph", "figure"), Input("interval-component", "n_intervals"), Input("color-scheme-storage", "data"), ) def update_realtime(n, theme): """Update real-time chart with new data and theme""" template = "mantine_dark" if theme == "dark" else "mantine_light" # Add new data point time_data.append(datetime.now()) # Generate new value with some randomness if len(value_data) > 0: last_value = value_data[-1] new_value = last_value + random.uniform(-5, 5) # Keep value in reasonable range new_value = max(10, min(90, new_value)) else: new_value = 50 value_data.append(new_value) # Create figure fig = go.Figure() fig.add_trace(go.Scatter( x=list(time_data), y=list(value_data), mode='lines+markers', name='Sensor Reading', line=dict(color='#12B886', width=2), marker=dict(size=6) )) fig.update_layout( title='Live Sensor Data', xaxis_title='Time', yaxis_title='Value', yaxis_range=[0, 100], hovermode='x', height=400, showlegend=False, template=template ) return fig ``` --- ### Dashboard with Multiple Charts A comprehensive dashboard combining multiple chart types: .. exec::docs.data-visualization.dashboard :code: false Source code: ```python # File: docs/data-visualization/dashboard.py from dash import html, dcc, callback, Input, Output import pandas as pd import plotly.express as px import plotly.graph_objects as go import dash_mantine_components as dmc import numpy as np # Register Mantine templates dmc.add_figure_templates(default="mantine_light") # Generate comprehensive sample data np.random.seed(42) dates = pd.date_range('2024-01-01', periods=90, freq='D') df_sales = pd.DataFrame({ 'Date': dates, 'Sales': np.cumsum(np.random.randn(90) * 50 + 1000), 'Target': np.linspace(90000, 120000, 90) }) df_products = pd.DataFrame({ 'Product': ['Electronics', 'Clothing', 'Food', 'Books', 'Other'], 'Revenue': [45000, 32000, 28000, 15000, 12000] }) df_regions = pd.DataFrame({ 'Region': ['North', 'South', 'East', 'West'], 'Q1': [23000, 19000, 31000, 21000], 'Q2': [25000, 21000, 29000, 24000], 'Q3': [27000, 23000, 32000, 26000], 'Q4': [29000, 25000, 35000, 28000] }) # Melt regions data for plotting df_regions_melted = df_regions.melt( id_vars=['Region'], var_name='Quarter', value_name='Revenue' ) # KPI Cards Data total_revenue = df_products['Revenue'].sum() avg_daily_sales = df_sales['Sales'].tail(30).mean() target_achievement = (df_sales['Sales'].iloc[-1] / df_sales['Target'].iloc[-1]) * 100 # Create initial figures fig_sales = px.line( df_sales, x='Date', y=['Sales', 'Target'], title='Sales Performance vs Target', color_discrete_map={'Sales': '#12B886', 'Target': '#FA5252'} ) fig_sales.update_layout(height=300, margin=dict(l=20, r=20, t=40, b=20), showlegend=True) fig_products = px.pie( df_products, values='Revenue', names='Product', title='Revenue by Product Category', color_discrete_sequence=px.colors.qualitative.Set2 ) fig_products.update_layout(height=300, margin=dict(l=20, r=20, t=40, b=20)) fig_regions = px.bar( df_regions_melted, x='Region', y='Revenue', color='Quarter', title='Quarterly Revenue by Region', barmode='group' ) fig_regions.update_layout(height=300, margin=dict(l=20, r=20, t=40, b=20)) component = html.Div([ dmc.Title("Executive Dashboard", order=3, mb=20), # KPI Cards Row dmc.SimpleGrid([ dmc.Card([ dmc.Group([ dmc.ThemeIcon( dmc.Text("$", size="xl", fw=700), size="xl", radius="md", color="teal", variant="light" ), html.Div([ dmc.Text("Total Revenue", size="sm", c="dimmed"), dmc.Title(f"${total_revenue:,.0f}", order=4, c="teal") ]) ]), ], withBorder=True, p="md", radius="md"), dmc.Card([ dmc.Group([ dmc.ThemeIcon( dmc.Text("📊", size="xl"), size="xl", radius="md", color="blue", variant="light" ), html.Div([ dmc.Text("Avg Daily Sales", size="sm", c="dimmed"), dmc.Title(f"${avg_daily_sales:,.0f}", order=4, c="blue") ]) ]), ], withBorder=True, p="md", radius="md"), dmc.Card([ dmc.Group([ dmc.ThemeIcon( dmc.Text("🎯", size="xl"), size="xl", radius="md", color="green" if target_achievement >= 100 else "orange", variant="light" ), html.Div([ dmc.Text("Target Achievement", size="sm", c="dimmed"), dmc.Title( f"{target_achievement:.1f}%", order=4, c="green" if target_achievement >= 100 else "orange" ) ]) ]), ], withBorder=True, p="md", radius="md"), ], cols={"base": 1, "sm": 3}, mb=20), # Charts Grid dmc.SimpleGrid([ dmc.Card([ dcc.Graph(figure=fig_sales, id='dashboard-sales-chart', config={'displayModeBar': False}) ], withBorder=True, p="md", radius="md"), dmc.Card([ dcc.Graph(figure=fig_products, id='dashboard-products-chart', config={'displayModeBar': False}) ], withBorder=True, p="md", radius="md"), ], cols={"base": 1, "sm": 2}, mb=15), dmc.Card([ dcc.Graph(figure=fig_regions, id='dashboard-regions-chart', config={'displayModeBar': False}) ], withBorder=True, p="md", radius="md") ]) @callback( Output('dashboard-sales-chart', 'figure'), Output('dashboard-products-chart', 'figure'), Output('dashboard-regions-chart', 'figure'), Input("color-scheme-storage", "data"), ) def update_dashboard_theme(theme): """Update all dashboard charts based on theme""" template = "mantine_dark" if theme == "dark" else "mantine_light" # Sales chart fig_sales = px.line( df_sales, x='Date', y=['Sales', 'Target'], title='Sales Performance vs Target', color_discrete_map={'Sales': '#12B886', 'Target': '#FA5252'}, template=template ) fig_sales.update_layout(height=300, margin=dict(l=20, r=20, t=40, b=20), showlegend=True) # Products chart fig_products = px.pie( df_products, values='Revenue', names='Product', title='Revenue by Product Category', color_discrete_sequence=px.colors.qualitative.Set2, template=template ) fig_products.update_layout(height=300, margin=dict(l=20, r=20, t=40, b=20)) # Regions chart fig_regions = px.bar( df_regions_melted, x='Region', y='Revenue', color='Quarter', title='Quarterly Revenue by Region', barmode='group', template=template ) fig_regions.update_layout(height=300, margin=dict(l=20, r=20, t=40, b=20)) return fig_sales, fig_products, fig_regions ``` --- ### Chart Types Reference #### Available Plotly Chart Types Plotly Express provides many chart types: ##### Basic Charts - **Bar Charts** - `px.bar()` - **Line Charts** - `px.line()` - **Scatter Plots** - `px.scatter()` - **Pie Charts** - `px.pie()` - **Histograms** - `px.histogram()` ##### Statistical Charts - **Box Plots** - `px.box()` - **Violin Plots** - `px.violin()` - **Density Heatmaps** - `px.density_heatmap()` ##### Scientific Charts - **Scatter Matrix** - `px.scatter_matrix()` - **Parallel Coordinates** - `px.parallel_coordinates()` - **3D Scatter** - `px.scatter_3d()` ##### Financial Charts - **Candlestick** - `go.Candlestick()` - **OHLC** - `go.Ohlc()` - **Waterfall** - `go.Waterfall()` --- ### Customization Tips #### Theme Integration Make charts match your Mantine theme automatically using DMC figure templates: ```python import dash_mantine_components as dmc import plotly.express as px # Register Mantine templates (mantine_light and mantine_dark) dmc.add_figure_templates(default="mantine_light") # Charts now automatically use the Mantine template fig = px.bar(df, x="category", y="value") # The templates match your theme's colors, fonts, and styling # For more info: https://www.dash-mantine-components.com/plotly-templates ``` All examples on this page use `dmc.add_figure_templates()` to ensure charts render correctly in both light and dark modes. #### Responsive Charts Make charts responsive to window size: ```python fig.update_layout( autosize=True, margin=dict(l=20, r=20, t=40, b=20), ) # In your component dcc.Graph( figure=fig, config={'responsive': True}, style={'height': '400px'} ) ``` #### Interactive Features Enable useful interactions: ```python config = { 'displayModeBar': True, 'displaylogo': False, 'modeBarButtonsToRemove': ['pan2d', 'lasso2d'], 'toImageButtonOptions': { 'format': 'png', 'filename': 'chart', 'height': 1080, 'width': 1920, 'scale': 2 } } dcc.Graph(figure=fig, config=config) ``` --- ### Performance Tips #### 1. Limit Data Points For large datasets, consider: ```python # Sample data if too large if len(df) > 10000: df = df.sample(10000) ``` #### 2. Use Scattergl for Large Scatter Plots ```python import plotly.graph_objects as go fig = go.Figure(data=go.Scattergl( x=x_data, y=y_data, mode='markers' )) ``` #### 3. Optimize Update Frequency ```python # Use longer intervals for real-time updates dcc.Interval( interval=2000, # Update every 2 seconds n_intervals=0 ) ``` --- ### Common Patterns #### Pattern 1: Chart with Controls ```markdown ## My Visualization Use the controls below to customize the view: .. exec::docs.viz.controlled_chart ``` ```python component = html.Div([ dmc.Select( label="Metric", data=[...], id="metric-select" ), dcc.Graph(id="chart") ]) @callback(Output("chart", "figure"), Input("metric-select", "value")) def update(metric): return create_figure(metric) ``` #### Pattern 2: Multi-View Dashboard ```python component = dmc.SimpleGrid([ dmc.Card([dcc.Graph(figure=fig1)]), dmc.Card([dcc.Graph(figure=fig2)]), dmc.Card([dcc.Graph(figure=fig3)]), dmc.Card([dcc.Graph(figure=fig4)]), ], cols={"base": 1, "sm": 2}) ``` #### Pattern 3: Clickable Charts ```python @callback( Output("details", "children"), Input("chart", "clickData") ) def display_click_data(clickData): if not clickData: return "Click on a data point" return f"Selected: {clickData['points'][0]['x']}" ``` --- ### Best Practices #### 1. Add Axis Labels Always label your axes: ```python fig.update_layout( xaxis_title="Time (hours)", yaxis_title="Temperature (°C)" ) ``` #### 2. Include Titles Make charts self-explanatory: ```python fig.update_layout( title="Monthly Sales Performance", title_x=0.5 # Center the title ) ``` #### 3. Use Color Wisely Choose accessible colors: ```python # Good - accessible color palette colors = ['#1f77b4', '#ff7f0e', '#2ca02c'] # Even better - use colorblind-friendly palettes import plotly.express as px fig = px.bar(df, color_discrete_sequence=px.colors.qualitative.Safe) ``` #### 4. Add Hover Information Provide context on hover: ```python fig = px.scatter( df, x="x", y="y", hover_data=["category", "value", "date"] ) ``` #### 5. Handle Empty Data Always check for empty datasets: ```python if df.empty: return { 'data': [], 'layout': { 'xaxis': {'visible': False}, 'yaxis': {'visible': False}, 'annotations': [{ 'text': 'No data available', 'showarrow': False, 'font': {'size': 20} }] } } ``` --- ### Resources - **Plotly Express**: [plotly.com/python/plotly-express/](https://plotly.com/python/plotly-express/) - **Plotly Graph Objects**: [plotly.com/python/graph-objects/](https://plotly.com/python/graph-objects/) - **Dash Core Components**: [dash.plotly.com/dash-core-components/graph](https://dash.plotly.com/dash-core-components/graph) - **Color Scales**: [plotly.com/python/builtin-colorscales/](https://plotly.com/python/builtin-colorscales/) --- ### Next Steps - **Interactive Components** - Learn advanced callback patterns - **AI Integration** - Make your visualizations AI-friendly - **Getting Started** - Create your first documentation page --- Happy visualizing! 📊 --- *Source: /examples/visualization* *Generated with dash-improve-my-llms*