# MUI Charts > Professional data visualization with MUI X Charts for Dash — line, pie, scatter, heatmap, sparkline, composite, and live trading charts with free and pro features. --- .. toc:: .. llms_copy::MUI Charts # MUI Charts `dash-mui-charts` brings [MUI X Charts](https://mui.com/x/react-charts/) to Plotly Dash — professional-grade data visualization with 7 chart components, interactive features, and an optional Pro tier for zoom, pan, brush, and heatmaps. | Component | License | Key Features | |:----------|:--------|:-------------| | **LineChart** | Free + Pro | Line/area, stacking, zoom/pan (Pro), brush (Pro), reference lines, dateFormat (1.1.0) | | **PieChart** | Free | Pie, donut, nested/concentric, gauge-arc, arc labels | | **ScatterChart** | Free | Multi-series, z-axis color mapping, voronoi interaction | | **CompositeChart** | Free + Pro | Layer scatter + line, zoom/pan (Pro), biaxial axes | | **Heatmap** | Pro | Matrix visualization, continuous/piecewise color scales | | **SparklineChart** | Free | Compact inline charts for KPI cards and tables | | **LiveTradingChart** | Free + Pro | Real-time OHLCV candlestick streaming, volume, forecast, alerts | ## Installation [Visit GitHub Repo](https://github.com/pip-install-python/dash-mui-charts) ```bash pip install dash-mui-charts ``` For Pro features, set your license key in `.env`: ``` MUI_PRO_API_KEY=your-license-key-here ``` --- ## Line Charts .. exec::docs.dash_mui_charts.line_basic :code: false ```python # File: docs/dash_mui_charts/line_basic.py import os import random import math import dash_mantine_components as dmc from dash_mui_charts import LineChart MUI_KEY = os.getenv('MUI_PRO_API_KEY', '') random.seed(42) months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] revenue = [random.randint(30, 90) for _ in months] expenses = [random.randint(20, 65) for _ in months] profit = [r - e for r, e in zip(revenue, expenses)] temp_data = [round(18 + 12 * math.sin(2 * math.pi * i / 12 - math.pi / 2) + random.uniform(-2, 2), 1) for i in range(12)] # Extra datasets random.seed(77) organic = [random.randint(10, 30) for _ in months] paid = [random.randint(8, 25) for _ in months] referral = [random.randint(5, 15) for _ in months] # Curve comparison data random.seed(11) curve_data = [random.randint(20, 80) for _ in range(8)] curve_labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon'] GLASS = { "background": "light-dark(rgba(255,255,255,0.55), rgba(30,30,30,0.55))", "backdropFilter": "blur(16px) saturate(1.8)", "WebkitBackdropFilter": "blur(16px) saturate(1.8)", "border": "1px solid light-dark(rgba(255,255,255,0.5), rgba(255,255,255,0.08))", } component = dmc.Stack([ dmc.Text("Line Charts", fw=700, size="xl"), dmc.Text("Versatile line and area charts with stacking, curves, reference lines, and biaxial axes.", size="sm", c="dimmed"), # --- Multi-Series --- dmc.Paper( dmc.Stack([ dmc.Text("Multi-Series Line Chart", fw=600), dmc.Text("Revenue vs expenses with profit area fill.", size="sm", c="dimmed"), LineChart( id="mc-line-basic", licenseKey=MUI_KEY, series=[ {'data': revenue, 'label': 'Revenue ($k)', 'color': '#1976d2', 'curve': 'monotoneX', 'showMark': True}, {'data': expenses, 'label': 'Expenses ($k)', 'color': '#f57c00', 'curve': 'monotoneX', 'showMark': True}, {'data': profit, 'label': 'Profit ($k)', 'color': '#388e3c', 'curve': 'monotoneX', 'area': True}, ], xAxis=[{'data': months, 'scaleType': 'point', 'label': 'Month'}], yAxis=[{'label': 'Amount ($k)'}], grid={'horizontal': True, 'vertical': False}, height=350, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), # --- Stacked Area --- dmc.Paper( dmc.Stack([ dmc.Text("Stacked Area Chart", fw=600), dmc.Text("Stacked areas showing cumulative traffic sources.", size="sm", c="dimmed"), LineChart( id="mc-line-stacked", licenseKey=MUI_KEY, series=[ {'data': organic, 'label': 'Organic', 'color': '#66bb6a', 'area': True, 'stack': 'traffic', 'curve': 'monotoneX'}, {'data': paid, 'label': 'Paid', 'color': '#42a5f5', 'area': True, 'stack': 'traffic', 'curve': 'monotoneX'}, {'data': referral, 'label': 'Referral', 'color': '#ab47bc', 'area': True, 'stack': 'traffic', 'curve': 'monotoneX'}, ], xAxis=[{'data': months, 'scaleType': 'point'}], yAxis=[{'label': 'Visitors (k)'}], grid={'horizontal': True}, height=300, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), # --- Curve Interpolation Comparison --- dmc.Paper( dmc.Stack([ dmc.Text("Curve Interpolation", fw=600), dmc.Text("Same data rendered with different curve algorithms.", size="sm", c="dimmed"), dmc.SimpleGrid(cols={"base": 1, "md": 2}, children=[ dmc.Stack([ dmc.Badge("linear", color="blue", variant="light", size="sm"), LineChart( id="mc-line-curve-linear", licenseKey=MUI_KEY, series=[{'data': curve_data, 'label': 'Value', 'color': '#1976d2', 'curve': 'linear', 'showMark': True}], xAxis=[{'data': curve_labels, 'scaleType': 'point'}], height=180, grid={'horizontal': True}, ), ], gap=4), dmc.Stack([ dmc.Badge("monotoneX", color="green", variant="light", size="sm"), LineChart( id="mc-line-curve-mono", licenseKey=MUI_KEY, series=[{'data': curve_data, 'label': 'Value', 'color': '#388e3c', 'curve': 'monotoneX', 'showMark': True}], xAxis=[{'data': curve_labels, 'scaleType': 'point'}], height=180, grid={'horizontal': True}, ), ], gap=4), dmc.Stack([ dmc.Badge("natural", color="orange", variant="light", size="sm"), LineChart( id="mc-line-curve-natural", licenseKey=MUI_KEY, series=[{'data': curve_data, 'label': 'Value', 'color': '#f57c00', 'curve': 'natural', 'showMark': True}], xAxis=[{'data': curve_labels, 'scaleType': 'point'}], height=180, grid={'horizontal': True}, ), ], gap=4), dmc.Stack([ dmc.Badge("step", color="violet", variant="light", size="sm"), LineChart( id="mc-line-curve-step", licenseKey=MUI_KEY, series=[{'data': curve_data, 'label': 'Value', 'color': '#7b1fa2', 'curve': 'step', 'showMark': True}], xAxis=[{'data': curve_labels, 'scaleType': 'point'}], height=180, grid={'horizontal': True}, ), ], gap=4), ]), ], gap="sm"), p="lg", radius="md", style=GLASS, ), # --- Reference Lines --- dmc.Paper( dmc.Stack([ dmc.Text("Reference Lines", fw=600), dmc.Text("Temperature curve with comfort zone boundaries and a vertical launch marker.", size="sm", c="dimmed"), LineChart( id="mc-line-ref", licenseKey=MUI_KEY, series=[ {'data': temp_data, 'label': 'Temperature (°C)', 'color': '#ef5350', 'curve': 'natural', 'area': True}, ], xAxis=[{'data': months, 'scaleType': 'point', 'label': 'Month'}], yAxis=[{'label': '°C', 'min': 0, 'max': 40}], referenceLines=[ {'y': 25, 'label': 'Upper comfort', 'lineStyle': {'stroke': '#ff9800', 'strokeDasharray': '5 3'}}, {'y': 18, 'label': 'Lower comfort', 'lineStyle': {'stroke': '#2196f3', 'strokeDasharray': '5 3'}}, {'x': 'Jun', 'label': 'Summer', 'lineStyle': {'stroke': '#9e9e9e', 'strokeDasharray': '3 3'}}, ], grid={'horizontal': True}, height=320, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), # --- Biaxial --- dmc.Paper( dmc.Stack([ dmc.Text("Biaxial (Dual Y-Axis)", fw=600), dmc.Text("Revenue on the left axis, growth rate on the right. Independent scales for different units.", size="sm", c="dimmed"), LineChart( id="mc-line-biaxial", licenseKey=MUI_KEY, series=[ {'data': revenue, 'label': 'Revenue ($k)', 'color': '#1976d2', 'curve': 'monotoneX', 'showMark': True, 'yAxisId': 'left'}, {'data': [round(random.uniform(-5, 20), 1) for _ in months], 'label': 'Growth (%)', 'color': '#ef5350', 'curve': 'monotoneX', 'area': True, 'yAxisId': 'right'}, ], xAxis=[{'data': months, 'scaleType': 'point'}], yAxis=[ {'id': 'left', 'label': 'Revenue ($k)', 'position': 'left'}, {'id': 'right', 'label': 'Growth (%)', 'position': 'right'}, ], grid={'horizontal': True}, height=320, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), ], gap="lg") ``` --- ## Line Charts — Pro Features .. exec::docs.dash_mui_charts.line_pro :code: false ```python # File: docs/dash_mui_charts/line_pro.py import os import random import math from datetime import datetime, timedelta import dash_mantine_components as dmc from dash_mui_charts import LineChart MUI_KEY = os.getenv('MUI_PRO_API_KEY', '') random.seed(99) # --- Signal vs Noise (100 points) --- n = 100 x_vals = list(range(n)) signal = [round(50 + 20 * math.sin(2 * math.pi * i / 25) + random.gauss(0, 5), 1) for i in range(n)] noise = [round(50 + random.gauss(0, 12), 1) for i in range(n)] # --- Simulated 2-month hourly sensor data for slider preview --- random.seed(42) start_date = datetime(2025, 1, 1) hours = 24 * 45 # 45 days timestamps = [] temperature = [] humidity = [] for h in range(hours): dt = start_date + timedelta(hours=h) timestamps.append(int(dt.timestamp() * 1000)) day_of_year = dt.timetuple().tm_yday hour = dt.hour seasonal = 2.0 + 8.0 * math.sin(2 * math.pi * (day_of_year - 30) / 365) daily_cycle = 4.0 * math.sin(2 * math.pi * (hour - 6) / 24) temp = seasonal + daily_cycle + random.gauss(0, 1.2) temperature.append(round(temp, 1)) hum_base = 65 - 1.5 * (temp - 5) humidity.append(round(max(20, min(95, hum_base + random.gauss(0, 3))), 1)) # --- Brush data --- random.seed(55) brush_data = [random.randint(10, 90) for _ in range(50)] GLASS = { "background": "light-dark(rgba(255,255,255,0.55), rgba(30,30,30,0.55))", "backdropFilter": "blur(16px) saturate(1.8)", "WebkitBackdropFilter": "blur(16px) saturate(1.8)", "border": "1px solid light-dark(rgba(255,255,255,0.5), rgba(255,255,255,0.08))", } component = dmc.Stack([ dmc.Text("Line Charts — Pro Features", fw=700, size="xl"), dmc.Badge("Requires MUI Pro License", color="violet", variant="light", size="sm"), # --- Zoom + Pan + Slider --- dmc.Paper( dmc.Stack([ dmc.Text("Zoom, Pan & Toolbar", fw=600), dmc.Text("Scroll to zoom, drag to pan. Toolbar provides zoom in/out and export. 100 data points.", size="sm", c="dimmed"), LineChart( id="mc-line-zoom", licenseKey=MUI_KEY, series=[ {'data': signal, 'label': 'Signal', 'color': '#1976d2', 'curve': 'monotoneX'}, {'data': noise, 'label': 'Noise', 'color': '#ef5350', 'curve': 'linear', 'showMark': False}, ], xAxis=[{ 'id': 'x-axis', 'data': x_vals, 'scaleType': 'linear', 'label': 'Sample Index', 'zoom': {'minSpan': 10, 'maxSpan': 100, 'panning': True}, }], yAxis=[{'label': 'Value', 'min': 0, 'max': 100}], initialZoom=[{'axisId': 'x-axis', 'start': 0, 'end': 40}], showSlider=True, showToolbar=True, grid={'horizontal': True}, height=400, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), # --- Zoom Slider with Preview (Time Series) --- dmc.Paper( dmc.Stack([ dmc.Text("Zoom Slider with Preview", fw=600), dmc.Group([ dmc.Text("45 days of simulated hourly sensor data. The slider shows a miniature preview of the full dataset.", size="sm", c="dimmed"), dmc.Badge("slider.preview", color="teal", variant="light", size="xs"), ]), LineChart( id="mc-line-slider-preview", licenseKey=MUI_KEY, height=420, series=[{ 'id': 'temperature', 'data': temperature, 'label': 'Temperature (°C)', 'color': '#ef5350', 'showMark': False, 'area': True, 'curve': 'natural', }], xAxis=[{ 'id': 'time-axis', 'data': timestamps, 'scaleType': 'time', 'label': 'Date', 'tickMinStep': 3600 * 1000 * 24, 'tickLabelStyle': {'angle': 35, 'fontSize': 11, 'textAnchor': 'start'}, 'height': 50, 'zoom': { 'minSpan': 2, 'panning': True, 'filterMode': 'discard', 'slider': {'enabled': True, 'preview': True}, }, }], yAxis=[{'label': '°C', 'width': 55, 'domainLimit': 'nice'}], grid={'horizontal': True}, margin={'left': 65, 'right': 20, 'top': 20, 'bottom': 70}, initialZoom=[{'axisId': 'time-axis', 'start': 0, 'end': 25}], ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), # --- Biaxial with Slider Preview --- dmc.Paper( dmc.Stack([ dmc.Text("Biaxial Chart with Slider Preview", fw=600), dmc.Text("Temperature and humidity on dual axes. filterMode='discard' auto-adjusts y-axis to visible range.", size="sm", c="dimmed"), LineChart( id="mc-line-biaxial-preview", licenseKey=MUI_KEY, height=420, series=[ {'id': 'temp', 'data': temperature, 'label': 'Temperature (°C)', 'color': '#ef5350', 'showMark': False, 'curve': 'natural', 'yAxisId': 'temp-axis'}, {'id': 'hum', 'data': humidity, 'label': 'Humidity (%)', 'color': '#42a5f5', 'showMark': False, 'curve': 'natural', 'yAxisId': 'hum-axis'}, ], xAxis=[{ 'id': 'biaxial-time', 'data': timestamps, 'scaleType': 'time', 'tickMinStep': 3600 * 1000 * 24, 'tickLabelStyle': {'angle': 35, 'fontSize': 11, 'textAnchor': 'start'}, 'height': 50, 'zoom': { 'minSpan': 2, 'panning': True, 'filterMode': 'discard', 'slider': {'enabled': True, 'preview': True}, }, }], yAxis=[ {'id': 'temp-axis', 'label': '°C', 'position': 'left', 'width': 50, 'domainLimit': 'nice', 'labelStyle': {'fill': '#ef5350'}}, {'id': 'hum-axis', 'label': '%', 'position': 'right', 'width': 50, 'domainLimit': 'nice', 'labelStyle': {'fill': '#42a5f5'}}, ], grid={'horizontal': True}, margin={'left': 60, 'right': 60, 'top': 20, 'bottom': 70}, initialZoom=[{'axisId': 'biaxial-time', 'start': 30, 'end': 60}], ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), # --- Brush Selection --- dmc.Paper( dmc.Stack([ dmc.Text("Brush Selection", fw=600), dmc.Text("Click and drag to select a range. The brush overlay shows selected values.", size="sm", c="dimmed"), LineChart( id="mc-line-brush", licenseKey=MUI_KEY, series=[ {'data': brush_data, 'label': 'Metric A', 'color': '#7b1fa2', 'curve': 'monotoneX'}, ], xAxis=[{'data': list(range(50)), 'scaleType': 'linear', 'label': 'Day'}], brushConfig={'enabled': True, 'preventTooltip': True}, brushOverlay='values', grid={'horizontal': True}, height=300, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), # --- Highlighting --- dmc.Paper( dmc.Stack([ dmc.Text("Item & Axis Highlighting", fw=600), dmc.Text("Hover to see per-series highlight scoping — the active series stays vivid while others fade.", size="sm", c="dimmed"), LineChart( id="mc-line-highlight", licenseKey=MUI_KEY, series=[ {'data': [random.randint(100, 250) for _ in range(12)], 'label': 'Sales 2023', 'color': '#1976d2', 'curve': 'monotoneX', 'showMark': True, 'highlightScope': {'highlight': 'series', 'fade': 'global'}}, {'data': [random.randint(120, 280) for _ in range(12)], 'label': 'Sales 2024', 'color': '#388e3c', 'curve': 'monotoneX', 'showMark': True, 'highlightScope': {'highlight': 'series', 'fade': 'global'}}, {'data': [random.randint(80, 200) for _ in range(12)], 'label': 'Sales 2025', 'color': '#f57c00', 'curve': 'monotoneX', 'showMark': True, 'highlightScope': {'highlight': 'series', 'fade': 'global'}}, ], xAxis=[{'data': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], 'scaleType': 'point'}], yAxis=[{'label': 'Revenue ($k)'}], axisHighlight={'x': 'band', 'y': 'line'}, grid={'horizontal': True}, height=350, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), ], gap="lg") ``` --- ## Tick Configuration & Date Formatting New in **1.1.0** — `dateFormat` and `dateTickFormat` let you format time-scale axes directly from Python without writing JavaScript. Use `scaleType: 'time'` with epoch-ms timestamps, control tick density with `tickMinStep`, and rotate labels with `tickLabelStyle`. | Prop | Description | |:-----|:------------| | `dateFormat` | Format string for **tooltip** labels (e.g. `"MMM d, YYYY"`) | | `dateTickFormat` | Format string for **axis tick** labels (e.g. `"M/d"`) | | `tickMinStep` | Minimum ms between ticks — use `86400000 * 7` for weekly ticks | | `tickNumber` | Approximate target tick count (D3 rounds for readability) | | `tickLabelStyle` | `{angle, fontSize, textAnchor}` for rotated labels | **Format tokens:** `YYYY` (2025), `MMM` (Jan), `MM` (01), `M` (1), `dd` (01), `d` (1), `HH` (00–23), `mm` (00–59) .. exec::docs.dash_mui_charts.tick_hover :code: false ```python # File: docs/dash_mui_charts/tick_hover.py """Tick Configuration & Date Formatting — v1.1.0 dateFormat/dateTickFormat.""" import os import math import random import json from datetime import datetime, timedelta import dash_mantine_components as dmc from dash import html, callback, Input, Output from dash_mui_charts import LineChart MUI_KEY = os.getenv('MUI_PRO_API_KEY', '') GLASS = { "background": "light-dark(rgba(255,255,255,0.55), rgba(30,30,30,0.55))", "backdropFilter": "blur(16px) saturate(1.8)", "WebkitBackdropFilter": "blur(16px) saturate(1.8)", "border": "1px solid light-dark(rgba(255,255,255,0.5), rgba(255,255,255,0.08))", } # --------------------------------------------------------------------------- # Data — 90-day sensor readings, two sensors # --------------------------------------------------------------------------- random.seed(42) def _make_sensor(start, n, base, noise, trend): vals = [] for i in range(n): vals.append(round(base + trend * i + noise * math.sin(i * 0.3) + random.gauss(0, noise * 0.3), 1)) return vals _start = datetime(2025, 1, 1) _n = 90 # Epoch-ms timestamps — required for scaleType: 'time' timestamps = [ int((_start + timedelta(days=i)).timestamp()) * 1000 for i in range(_n) ] sensor_a = _make_sensor(_start, _n, base=68, noise=5, trend=0.04) sensor_b = _make_sensor(_start, _n, base=55, noise=3.5, trend=0.02) WARNING_THRESHOLD = 78 # Day-45 event marker (epoch-ms) event_ts = int((_start + timedelta(days=45)).timestamp()) * 1000 # --------------------------------------------------------------------------- # Chart 1 — dateFormat / dateTickFormat (v1.1.0) + reference lines # --------------------------------------------------------------------------- chart_time_scale = dmc.Paper(dmc.Stack([ dmc.Group([ dmc.Text("Time-Scale Axis (v1.1.0 dateFormat)", fw=600), dmc.Badge("1.1.0", color="teal", variant="light", size="sm"), ]), dmc.Text( "Use scaleType: 'time' with epoch-ms timestamps. " "dateFormat controls the tooltip label; dateTickFormat controls axis tick labels. " "tickMinStep limits density; tickLabelStyle.angle rotates labels for readability.", size="sm", c="dimmed", ), LineChart( id="mc-th-time", licenseKey=MUI_KEY, height=340, series=[ { "data": sensor_a, "label": "Sensor A (°F)", "color": "#1976d2", "curve": "monotoneX", "showMark": False, "highlightScope": {"highlight": "series", "fade": "global"}, }, { "data": sensor_b, "label": "Sensor B (°F)", "color": "#7b1fa2", "curve": "monotoneX", "showMark": False, "highlightScope": {"highlight": "series", "fade": "global"}, }, ], xAxis=[{ "id": "mc-th-x", "data": timestamps, "scaleType": "time", # v1.1.0 built-in date formatting — no JavaScript needed "dateFormat": "MMM d, YYYY", # tooltip label "dateTickFormat": "M/d", # axis tick labels "tickMinStep": 86400 * 1000 * 7, # min 1 week between ticks "tickNumber": 10, "tickLabelStyle": {"angle": 35, "fontSize": 11, "textAnchor": "start"}, "height": 70, # extra space for angled labels }], yAxis=[{"label": "Temperature (°F)", "min": 48, "max": 85}], grid={"horizontal": True}, axisHighlight={"x": "line"}, tooltip={"trigger": "axis"}, margin={"left": 65, "right": 20, "top": 20, "bottom": 90}, referenceLines=[ { "y": WARNING_THRESHOLD, "label": "Warning (78°F)", "lineStyle": {"stroke": "#ff9800", "strokeWidth": 2, "strokeDasharray": "5 5"}, "labelStyle": {"fill": "#ff9800", "fontWeight": "bold"}, "labelAlign": "end", }, { "x": event_ts, "label": "Calibration", "lineStyle": {"stroke": "#9c27b0", "strokeWidth": 2, "strokeDasharray": "4 4"}, "labelStyle": {"fill": "#9c27b0"}, "labelAlign": "start", }, ], ), dmc.Alert( dmc.Code( 'xAxis=[{"scaleType": "time", "data": epoch_ms, ' '"dateFormat": "MMM d, YYYY", "dateTickFormat": "M/d", ' '"tickMinStep": 86400_000 * 7}]' ), color="blue", variant="light", ), ], gap="sm"), p="lg", radius="md", style=GLASS) # --------------------------------------------------------------------------- # Chart 2 — axis highlight + click event # --------------------------------------------------------------------------- chart_click = dmc.Paper(dmc.Stack([ dmc.Text("Axis Highlight & Click Events", fw=600), dmc.Text( "axisHighlight: {'x': 'line'} draws a crosshair; " "tooltip: {'trigger': 'axis'} shows all series. " "Click any point to capture data via the clickData output prop.", size="sm", c="dimmed", ), LineChart( id="mc-th-click", licenseKey=MUI_KEY, height=300, series=[ { "data": sensor_a, "label": "Sensor A", "color": "#1976d2", "curve": "monotoneX", "showMark": True, "highlightScope": {"highlight": "item", "fade": "global"}, }, { "data": sensor_b, "label": "Sensor B", "color": "#7b1fa2", "curve": "monotoneX", "showMark": True, "highlightScope": {"highlight": "item", "fade": "global"}, }, ], xAxis=[{ "data": timestamps, "scaleType": "time", "dateFormat": "MMM d", "dateTickFormat": "M/d", "tickMinStep": 86400 * 1000 * 14, "tickNumber": 6, }], yAxis=[{"label": "°F"}], grid={"horizontal": True}, axisHighlight={"x": "line", "y": "line"}, tooltip={"trigger": "item"}, margin={"left": 55, "right": 20, "top": 20, "bottom": 50}, ), dmc.Text("Click output:", size="xs", c="dimmed"), html.Pre( id="mc-th-click-out", children="Click a point to see data...", style={ "fontSize": "11px", "margin": 0, "padding": "8px 12px", "borderRadius": "6px", "background": "light-dark(#f8f9fa, #1a1b1e)", "border": "1px solid light-dark(#dee2e6, #373a40)", }, ), ], gap="sm"), p="lg", radius="md", style=GLASS) component = dmc.Stack([ dmc.Text("Tick Configuration & Date Formatting", fw=700, size="xl"), dmc.Text( "Best practices for time-scale axes — epoch-ms data, " "built-in date formatting (v1.1.0), angled ticks, reference lines, and click events.", size="sm", c="dimmed", ), chart_time_scale, chart_click, ], gap="lg") # --------------------------------------------------------------------------- # Callback — click event display # --------------------------------------------------------------------------- @callback( Output("mc-th-click-out", "children"), Input("mc-th-click", "clickData"), prevent_initial_call=True, ) def show_click(data): if not data: return "Click a point to see data..." return json.dumps(data, indent=2) ``` --- ## Pie Charts .. exec::docs.dash_mui_charts.pie_charts :code: false ```python # File: docs/dash_mui_charts/pie_charts.py import random import dash_mantine_components as dmc from dash_mui_charts import PieChart random.seed(77) PALETTE = ['#1976d2', '#388e3c', '#f57c00', '#d32f2f', '#7b1fa2', '#00838f', '#c62828', '#4527a0'] GLASS = { "background": "light-dark(rgba(255,255,255,0.55), rgba(30,30,30,0.55))", "backdropFilter": "blur(16px) saturate(1.8)", "WebkitBackdropFilter": "blur(16px) saturate(1.8)", "border": "1px solid light-dark(rgba(255,255,255,0.5), rgba(255,255,255,0.08))", } market_data = [ {'id': 0, 'value': 35, 'label': 'Chrome', 'color': '#4285f4'}, {'id': 1, 'value': 25, 'label': 'Safari', 'color': '#007aff'}, {'id': 2, 'value': 18, 'label': 'Firefox', 'color': '#ff7139'}, {'id': 3, 'value': 12, 'label': 'Edge', 'color': '#0078d7'}, {'id': 4, 'value': 10, 'label': 'Other', 'color': '#9e9e9e'}, ] sales_data = [ {'id': i, 'value': random.randint(15, 50), 'label': cat} for i, cat in enumerate(['Electronics', 'Clothing', 'Food', 'Books', 'Toys']) ] inner_data = [ {'id': 0, 'value': 60, 'label': 'Desktop', 'color': '#1565c0'}, {'id': 1, 'value': 35, 'label': 'Mobile', 'color': '#2e7d32'}, {'id': 2, 'value': 5, 'label': 'Tablet', 'color': '#e65100'}, ] outer_data = [ {'id': 0, 'value': 30, 'label': 'Windows', 'color': '#42a5f5'}, {'id': 1, 'value': 20, 'label': 'macOS', 'color': '#66bb6a'}, {'id': 2, 'value': 10, 'label': 'Linux', 'color': '#ef5350'}, {'id': 3, 'value': 20, 'label': 'iOS', 'color': '#ab47bc'}, {'id': 4, 'value': 15, 'label': 'Android', 'color': '#ffa726'}, {'id': 5, 'value': 5, 'label': 'iPadOS', 'color': '#26c6da'}, ] component = dmc.Stack([ dmc.Text("Pie Charts", fw=700, size="xl"), dmc.Text("Pie, donut, nested, and gauge-arc variations.", size="sm", c="dimmed"), dmc.SimpleGrid(cols={"base": 1, "md": 2}, children=[ dmc.Paper( dmc.Stack([ dmc.Text("Pie Chart", fw=600), dmc.Text("Browser market share with arc labels.", size="sm", c="dimmed"), PieChart(id="mc-pie-basic", data=market_data, arcLabel='formattedValue', arcLabelMinAngle=25, colors=PALETTE, height=280), ], gap="sm"), p="lg", radius="md", style=GLASS, ), dmc.Paper( dmc.Stack([ dmc.Text("Donut Chart", fw=600), dmc.Text("Sales by category with inner radius cutout.", size="sm", c="dimmed"), PieChart(id="mc-pie-donut", data=sales_data, innerRadius=60, cornerRadius=4, paddingAngle=2, colors=PALETTE, height=280), ], gap="sm"), p="lg", radius="md", style=GLASS, ), ]), dmc.Paper( dmc.Stack([ dmc.Text("Nested Concentric Pie", fw=600), dmc.Text("Inner ring: device type. Outer ring: OS breakdown.", size="sm", c="dimmed"), PieChart( id="mc-pie-nested", series=[ {'data': inner_data, 'innerRadius': 0, 'outerRadius': 70, 'highlightScope': {'fade': 'global', 'highlight': 'item'}}, {'data': outer_data, 'innerRadius': 80, 'outerRadius': 110, 'highlightScope': {'fade': 'global', 'highlight': 'item'}}, ], height=300, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), dmc.Paper( dmc.Stack([ dmc.Text("Gauge-Style Arc", fw=600), dmc.Text("Half-circle gauge using startAngle/endAngle.", size="sm", c="dimmed"), dmc.SimpleGrid(cols=2, children=[ PieChart( id=f"mc-pie-gauge-{i}", data=[ {'id': 0, 'value': val, 'label': label, 'color': color}, {'id': 1, 'value': 100 - val, 'color': 'light-dark(#e0e0e0, #424242)'}, ], startAngle=-90, endAngle=90, innerRadius=50, outerRadius=80, arcLabel='value', height=160, ) for i, (val, label, color) in enumerate([ (72, 'CPU', '#1976d2'), (88, 'Disk', '#f57c00'), ]) ]), ], gap="sm"), p="lg", radius="md", style=GLASS, ), ], gap="lg") ``` --- ## Scatter Charts .. exec::docs.dash_mui_charts.scatter_charts :code: false ```python # File: docs/dash_mui_charts/scatter_charts.py import random import dash_mantine_components as dmc from dash_mui_charts import ScatterChart random.seed(55) GLASS = { "background": "light-dark(rgba(255,255,255,0.55), rgba(30,30,30,0.55))", "backdropFilter": "blur(16px) saturate(1.8)", "WebkitBackdropFilter": "blur(16px) saturate(1.8)", "border": "1px solid light-dark(rgba(255,255,255,0.5), rgba(255,255,255,0.08))", } def make_cluster(cx, cy, n=30, spread=15): return [{'x': round(cx + random.gauss(0, spread), 1), 'y': round(cy + random.gauss(0, spread), 1), 'id': i} for i in range(n)] cluster_a = make_cluster(150, 200, 40) cluster_b = make_cluster(300, 150, 35) cluster_c = make_cluster(220, 350, 30) z_data = [{'x': round(random.uniform(0, 100), 1), 'y': round(random.uniform(0, 100), 1), 'z': round(random.uniform(0, 100), 1), 'id': i} for i in range(60)] component = dmc.Stack([ dmc.Text("Scatter Charts", fw=700, size="xl"), dmc.Text("Multi-series scatter plots with clustering, z-axis coloring, and voronoi interaction.", size="sm", c="dimmed"), dmc.Paper( dmc.Stack([ dmc.Text("Multi-Series Clusters", fw=600), dmc.Text("Three distinct clusters with voronoi hover detection.", size="sm", c="dimmed"), ScatterChart( id="mc-scatter-clusters", series=[ {'id': 'cluster-a', 'label': 'Group A', 'data': cluster_a, 'color': '#1976d2', 'markerSize': 5}, {'id': 'cluster-b', 'label': 'Group B', 'data': cluster_b, 'color': '#388e3c', 'markerSize': 5}, {'id': 'cluster-c', 'label': 'Group C', 'data': cluster_c, 'color': '#f57c00', 'markerSize': 5}, ], xAxis=[{'label': 'Feature X', 'min': 50, 'max': 400}], yAxis=[{'label': 'Feature Y', 'min': 50, 'max': 450}], voronoiMaxRadius=40, grid={'horizontal': True, 'vertical': True}, height=380, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), dmc.Paper( dmc.Stack([ dmc.Text("Z-Axis Color Mapping", fw=600), dmc.Text("Third dimension mapped to a continuous color scale.", size="sm", c="dimmed"), ScatterChart( id="mc-scatter-zaxis", series=[ {'id': 'z-series', 'label': 'Intensity', 'data': z_data, 'markerSize': 7, 'highlightScope': {'highlight': 'item', 'fade': 'global'}}, ], zAxis=[{'colorMap': {'type': 'continuous', 'min': 0, 'max': 100, 'color': ['#e3f2fd', '#1565c0']}}], xAxis=[{'label': 'X', 'min': -5, 'max': 105}], yAxis=[{'label': 'Y', 'min': -5, 'max': 105}], voronoiMaxRadius=25, grid={'horizontal': True, 'vertical': True}, height=380, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), ], gap="lg") ``` --- ## Composite Charts .. exec::docs.dash_mui_charts.composite_charts :code: false ```python # File: docs/dash_mui_charts/composite_charts.py import os import random import math import dash_mantine_components as dmc from dash_mui_charts import CompositeChart MUI_KEY = os.getenv('MUI_PRO_API_KEY', '') random.seed(33) GLASS = { "background": "light-dark(rgba(255,255,255,0.55), rgba(30,30,30,0.55))", "backdropFilter": "blur(16px) saturate(1.8)", "WebkitBackdropFilter": "blur(16px) saturate(1.8)", "border": "1px solid light-dark(rgba(255,255,255,0.5), rgba(255,255,255,0.08))", } n = 50 scatter_data = [{'x': i, 'y': round(20 + 0.4 * i + random.gauss(0, 4), 1), 'id': i} for i in range(n)] trend_line = [round(20 + 0.4 * i, 1) for i in range(n)] component = dmc.Stack([ dmc.Text("Composite Charts", fw=700, size="xl"), dmc.Text("Layer scatter points and line series on a single chart surface.", size="sm", c="dimmed"), dmc.Paper( dmc.Stack([ dmc.Text("Scatter + Trend Line", fw=600), dmc.Text("Sensor readings with a linear regression overlay and reference limits.", size="sm", c="dimmed"), CompositeChart( id="mc-composite-trend", licenseKey=MUI_KEY, series=[ {'type': 'scatter', 'id': 'readings', 'label': 'Readings', 'data': scatter_data, 'markerSize': 4, 'color': '#1976d2'}, {'type': 'line', 'id': 'trend', 'label': 'Trend', 'data': trend_line, 'curve': 'linear', 'showMark': False, 'color': '#ff7043'}, ], xAxis=[{'id': 'x', 'data': list(range(n)), 'scaleType': 'linear', 'label': 'Sample', 'zoom': {'minSpan': 10, 'panning': True}}], yAxis=[{'label': 'Value'}], referenceLines=[ {'y': 35, 'label': 'Upper limit', 'lineStyle': {'stroke': '#d32f2f', 'strokeDasharray': '6 3'}}, {'y': 15, 'label': 'Lower limit', 'lineStyle': {'stroke': '#1565c0', 'strokeDasharray': '6 3'}}, ], initialZoom=[{'axisId': 'x', 'start': 0, 'end': 60}], showSlider=True, voronoiMaxRadius=20, grid={'horizontal': True}, height=400, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), dmc.Paper( dmc.Stack([ dmc.Text("Biaxial Composite", fw=600), dmc.Text("Temperature scatter on left axis, humidity line on right axis.", size="sm", c="dimmed"), CompositeChart( id="mc-composite-biaxial", licenseKey=MUI_KEY, series=[ {'type': 'scatter', 'id': 'temp', 'label': 'Temperature (°C)', 'data': [{'x': i, 'y': round(22 + random.gauss(0, 3), 1), 'id': i} for i in range(24)], 'markerSize': 5, 'color': '#ef5350', 'yAxisId': 'left'}, {'type': 'line', 'id': 'humidity', 'label': 'Humidity (%)', 'data': [round(60 + 15 * math.sin(2 * math.pi * i / 24) + random.uniform(-3, 3), 1) for i in range(24)], 'curve': 'natural', 'showMark': False, 'color': '#42a5f5', 'area': True, 'yAxisId': 'right'}, ], xAxis=[{'data': list(range(24)), 'scaleType': 'linear', 'label': 'Hour'}], yAxis=[{'id': 'left', 'label': '°C', 'position': 'left'}, {'id': 'right', 'label': '%', 'position': 'right'}], grid={'horizontal': True}, height=350, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), ], gap="lg") ``` --- ## Heatmap Charts .. exec::docs.dash_mui_charts.heatmap_charts :code: false ```python # File: docs/dash_mui_charts/heatmap_charts.py import os import random import dash_mantine_components as dmc from dash_mui_charts import Heatmap MUI_KEY = os.getenv('MUI_PRO_API_KEY', '') random.seed(88) GLASS = { "background": "light-dark(rgba(255,255,255,0.55), rgba(30,30,30,0.55))", "backdropFilter": "blur(16px) saturate(1.8)", "WebkitBackdropFilter": "blur(16px) saturate(1.8)", "border": "1px solid light-dark(rgba(255,255,255,0.5), rgba(255,255,255,0.08))", } days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] hours = [f'{h}:00' for h in range(6, 22)] activity_data = [] for xi, day in enumerate(days): for yi, hour in enumerate(hours): base = 30 if xi < 5 and 3 <= yi <= 10 else 10 val = max(0, min(100, base + random.randint(-10, 40))) activity_data.append([xi, yi, val]) labels = ['Revenue', 'Traffic', 'Conversions', 'Ad Spend', 'Satisfaction'] corr_data = [] for i in range(len(labels)): for j in range(len(labels)): val = 1.0 if i == j else round(random.uniform(-0.3, 0.95), 2) corr_data.append([i, j, val]) component = dmc.Stack([ dmc.Text("Heatmap Charts", fw=700, size="xl"), dmc.Group([ dmc.Text("Matrix visualization with continuous and piecewise color scales.", size="sm", c="dimmed"), dmc.Badge("Pro Feature", color="violet", variant="light", size="sm"), ]), dmc.Paper( dmc.Stack([ dmc.Text("Website Activity Heatmap", fw=600), dmc.Text("Visitor activity by day and hour. Darker = more active.", size="sm", c="dimmed"), Heatmap( id="mc-heatmap-activity", licenseKey=MUI_KEY, data=activity_data, xAxis={'data': days, 'label': 'Day'}, yAxis={'data': hours, 'label': 'Hour'}, colorScale={'type': 'continuous', 'min': 0, 'max': 100, 'colors': ['#e3f2fd', '#1565c0']}, height=400, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), dmc.Paper( dmc.Stack([ dmc.Text("Correlation Matrix", fw=600), dmc.Text("Business metric correlations with diverging color scale.", size="sm", c="dimmed"), Heatmap( id="mc-heatmap-corr", licenseKey=MUI_KEY, data=corr_data, xAxis={'data': labels}, yAxis={'data': labels}, colorScale={'type': 'piecewise', 'thresholds': [-0.5, 0, 0.5], 'colors': ['#d32f2f', '#ffcdd2', '#c8e6c9', '#2e7d32']}, height=350, ), ], gap="sm"), p="lg", radius="md", style=GLASS, ), ], gap="lg") ``` --- ## Sparkline Charts .. exec::docs.dash_mui_charts.sparkline_charts :code: false ```python # File: docs/dash_mui_charts/sparkline_charts.py import random import dash_mantine_components as dmc from dash_mui_charts import SparklineChart random.seed(66) GLASS = { "background": "light-dark(rgba(255,255,255,0.55), rgba(30,30,30,0.55))", "backdropFilter": "blur(16px) saturate(1.8)", "WebkitBackdropFilter": "blur(16px) saturate(1.8)", "border": "1px solid light-dark(rgba(255,255,255,0.5), rgba(255,255,255,0.08))", } def spark_data(n=12, base=50, spread=20): return [max(0, round(base + random.uniform(-spread, spread), 1)) for _ in range(n)] revenue_spark = spark_data(12, 60, 15) users_spark = spark_data(12, 200, 50) errors_spark = [random.randint(0, 8) for _ in range(12)] cpu_spark = spark_data(20, 45, 25) component = dmc.Stack([ dmc.Text("Sparkline Charts", fw=700, size="xl"), dmc.Text("Compact inline charts for dashboards, tables, and KPI cards.", size="sm", c="dimmed"), dmc.SimpleGrid(cols={"base": 1, "sm": 2, "md": 4}, children=[ dmc.Paper( dmc.Stack([ dmc.Text("Revenue", size="sm", c="dimmed"), dmc.Group([dmc.Text(f"${sum(revenue_spark):.0f}k", fw=700, size="xl"), dmc.Badge("+12%", color="green", variant="light", size="sm")], justify="space-between"), SparklineChart(id="mc-spark-revenue", data=revenue_spark, plotType='line', color='#1976d2', area=True, curve='monotoneX', height=40, showTooltip=True), ], gap="xs"), p="md", radius="md", style=GLASS, ), dmc.Paper( dmc.Stack([ dmc.Text("Active Users", size="sm", c="dimmed"), dmc.Group([dmc.Text(f"{users_spark[-1]:.0f}", fw=700, size="xl"), dmc.Badge("+8%", color="green", variant="light", size="sm")], justify="space-between"), SparklineChart(id="mc-spark-users", data=users_spark, plotType='line', color='#388e3c', area=True, curve='monotoneX', height=40, showTooltip=True), ], gap="xs"), p="md", radius="md", style=GLASS, ), dmc.Paper( dmc.Stack([ dmc.Text("Errors", size="sm", c="dimmed"), dmc.Group([dmc.Text(f"{errors_spark[-1]}", fw=700, size="xl"), dmc.Badge("-3%", color="red", variant="light", size="sm")], justify="space-between"), SparklineChart(id="mc-spark-errors", data=errors_spark, plotType='bar', color='#ef5350', height=40, showTooltip=True), ], gap="xs"), p="md", radius="md", style=GLASS, ), dmc.Paper( dmc.Stack([ dmc.Text("CPU Load", size="sm", c="dimmed"), dmc.Group([dmc.Text(f"{cpu_spark[-1]:.0f}%", fw=700, size="xl"), dmc.Badge("stable", color="gray", variant="light", size="sm")], justify="space-between"), SparklineChart(id="mc-spark-cpu", data=cpu_spark, plotType='line', color='#f57c00', curve='linear', height=40, showTooltip=True), ], gap="xs"), p="md", radius="md", style=GLASS, ), ]), dmc.Paper( dmc.Stack([ dmc.Text("Sparkline Variations", fw=600), dmc.Text("Different plot types, curves, and configurations.", size="sm", c="dimmed"), dmc.SimpleGrid(cols=3, children=[ dmc.Stack([ dmc.Text("Line (monotoneX)", size="xs", c="dimmed", ta="center"), SparklineChart(id="mc-spark-v1", data=spark_data(), plotType='line', color='#1976d2', curve='monotoneX', height=60, area=True, showTooltip=True), ], gap="xs"), dmc.Stack([ dmc.Text("Line (step)", size="xs", c="dimmed", ta="center"), SparklineChart(id="mc-spark-v2", data=spark_data(), plotType='line', color='#7b1fa2', curve='step', height=60, showTooltip=True), ], gap="xs"), dmc.Stack([ dmc.Text("Bar", size="xs", c="dimmed", ta="center"), SparklineChart(id="mc-spark-v3", data=spark_data(8, 30, 20), plotType='bar', color='#388e3c', height=60, showTooltip=True), ], gap="xs"), ]), ], gap="sm"), p="lg", radius="md", style=GLASS, ), ], gap="lg") ``` --- ## Live Trading Chart Real-time OHLCV candlestick streaming with volume bars, a forecast line with uncertainty bands, and automatic swing-point alert labels. All simulation parameters are controllable at runtime. | Feature | Description | |:--------|:------------| | **Candlesticks** | OHLCV bars with green/red coloring | | **Volume** | Optional volume histogram (bottom panel) | | **Forecast** | Forward projection with uncertainty shading | | **Alerts** | Configurable via `alertProbability` (chance per tick) and `alertThresholdPct` (minimum % move) | | **Alert colors** | `alertUpColor` / `alertDownColor` for label styling | | **Zoom / Slider** | Pro — range slider preview | .. exec::docs.dash_mui_charts.live_trading :code: false ```python # File: docs/dash_mui_charts/live_trading.py """Live Trading Chart — real-time OHLCV candlestick simulation with swing-point alerts.""" import os import dash_mantine_components as dmc from dash import html, callback, Input, Output, State, ctx from dash_mui_charts import LiveTradingChart MUI_KEY = os.getenv('MUI_PRO_API_KEY', '') GLASS = { "background": "light-dark(rgba(255,255,255,0.55), rgba(30,30,30,0.55))", "backdropFilter": "blur(16px) saturate(1.8)", "WebkitBackdropFilter": "blur(16px) saturate(1.8)", "border": "1px solid light-dark(rgba(255,255,255,0.5), rgba(255,255,255,0.08))", } component = dmc.Stack([ dmc.Text("Live Trading Chart", fw=700, size="xl"), dmc.Text( "Real-time candlestick simulation with OHLCV data, volume bars, " "forecast line with uncertainty bands, and swing-point alert labels. " "Alerts only fire at confirmed local highs and lows — not on every candle.", size="sm", c="dimmed", ), dmc.Paper(dmc.Stack([ # ── Controls Row 1: Buttons + Toggles ───────────────────────────── dmc.Group([ dmc.Group([ dmc.Button("Start", id="mc-lt-start", color="green", size="sm"), dmc.Button("Stop", id="mc-lt-stop", color="yellow", size="sm", variant="outline"), dmc.Button("Reset", id="mc-lt-reset", color="red", size="sm", variant="outline"), ], gap="xs"), dmc.Group([ dmc.Switch(id="mc-lt-volume", label="Volume", checked=True, size="sm"), dmc.Switch(id="mc-lt-labels", label="Price Labels", checked=False, size="sm"), dmc.Switch(id="mc-lt-slider", label="Zoom Preview", checked=True, size="sm"), ], gap="md"), ], justify="space-between"), # ── Controls Row 2: Sliders ──────────────────────────────────────── dmc.SimpleGrid(cols={"base": 1, "sm": 2, "lg": 4}, children=[ dmc.Stack([ dmc.Text("Speed (ms/tick)", size="xs", fw=500), dmc.Slider( id="mc-lt-speed", value=200, min=50, max=1000, step=50, marks=[ {"value": 50, "label": "50"}, {"value": 200, "label": "200"}, {"value": 500, "label": "500"}, {"value": 1000, "label": "1s"}, ], ), ], gap=4), dmc.Stack([ dmc.Text("Volatility", size="xs", fw=500), dmc.Slider( id="mc-lt-volatility", value=2.0, min=0.5, max=8.0, step=0.5, marks=[ {"value": 0.5, "label": "0.5"}, {"value": 2.0, "label": "2.0"}, {"value": 8.0, "label": "8.0"}, ], ), ], gap=4), dmc.Stack([ dmc.Text("Drift", size="xs", fw=500), dmc.Slider( id="mc-lt-drift", value=0.1, min=-0.5, max=0.5, step=0.05, marks=[ {"value": -0.5, "label": "-0.5"}, {"value": 0, "label": "0"}, {"value": 0.5, "label": "+0.5"}, ], ), ], gap=4), dmc.Stack([ dmc.Text("Window", size="xs", fw=500), dmc.Slider( id="mc-lt-window", value=80, min=30, max=200, step=10, marks=[ {"value": 30, "label": "30"}, {"value": 80, "label": "80"}, {"value": 200, "label": "200"}, ], ), ], gap=4), ]), # ── Stats Row ────────────────────────────────────────────────────── dmc.Group([ dmc.Stack([ dmc.Text("Price", size="xs", c="dimmed"), dmc.Text(id="mc-lt-price", children="$100.00", fw=700, size="lg"), ], gap=0, align="center"), dmc.Stack([ dmc.Text("Ticks", size="xs", c="dimmed"), dmc.Text(id="mc-lt-ticks", children="0", fw=700, size="lg"), ], gap=0, align="center"), dmc.Stack([ dmc.Text("Alerts", size="xs", c="dimmed"), dmc.Text(id="mc-lt-alerts", children="0", fw=700, size="lg"), ], gap=0, align="center"), dmc.Stack([ dmc.Text("Status", size="xs", c="dimmed"), dmc.Text(id="mc-lt-status", children="Stopped", fw=700, size="lg", c="dimmed"), ], gap=0, align="center"), ], gap="xl"), # ── Chart ────────────────────────────────────────────────────────── LiveTradingChart( id="mc-lt-chart", licenseKey=MUI_KEY, height=520, running=False, intervalMs=200, seed=42, windowSize=80, forecastSize=20, initialPrice=100, volatility=0.02, drift=0.001, forecastVolatility=1.5, # Alert tuning — low probability + high threshold keeps labels sparse alertProbability=0.03, # 3% chance per tick (vs default 8%) alertThresholdPct=3.0, # minimum 3% move to qualify alertUpColor="#4caf50", alertDownColor="#f44336", showVolume=True, showLabels=False, showSlider=True, volumeHeightPct=20, margin={"left": 75, "right": 30, "top": 20, "bottom": 50}, ), # ── Alert History ────────────────────────────────────────────────── dmc.Text("Recent Alerts", fw=600, size="sm"), html.Pre( id="mc-lt-log", children="Alerts will appear here once running...", style={ "fontSize": "11px", "maxHeight": "130px", "overflow": "auto", "margin": 0, "padding": "8px 12px", "borderRadius": "6px", "background": "light-dark(#f8f9fa, #1a1b1e)", "border": "1px solid light-dark(#dee2e6, #373a40)", }, ), ], gap="md"), p="lg", radius="md", style=GLASS), ], gap="md") # ── Callbacks ───────────────────────────────────────────────────────────────── @callback( Output("mc-lt-chart", "running"), Input("mc-lt-start", "n_clicks"), Input("mc-lt-stop", "n_clicks"), prevent_initial_call=True, ) def toggle_running(_start, _stop): return ctx.triggered_id == "mc-lt-start" @callback( Output("mc-lt-chart", "resetTrigger"), Input("mc-lt-reset", "n_clicks"), prevent_initial_call=True, ) def reset_chart(n): return n or 0 @callback(Output("mc-lt-chart", "intervalMs"), Input("mc-lt-speed", "value")) def set_speed(val): return val or 200 @callback(Output("mc-lt-chart", "volatility"), Input("mc-lt-volatility", "value")) def set_volatility(val): return (val or 2.0) / 100 @callback(Output("mc-lt-chart", "drift"), Input("mc-lt-drift", "value")) def set_drift(val): return (val or 0) / 100 @callback(Output("mc-lt-chart", "windowSize"), Input("mc-lt-window", "value")) def set_window(val): return val or 80 @callback(Output("mc-lt-chart", "showVolume"), Input("mc-lt-volume", "checked")) def set_volume(v): return v if v is not None else True @callback(Output("mc-lt-chart", "showLabels"), Input("mc-lt-labels", "checked")) def set_labels(v): return v if v is not None else False @callback(Output("mc-lt-chart", "showSlider"), Input("mc-lt-slider", "checked")) def set_slider(v): return v if v is not None else True @callback( Output("mc-lt-price", "children"), Output("mc-lt-price", "c"), Output("mc-lt-ticks", "children"), Output("mc-lt-status", "children"), Output("mc-lt-status", "c"), Input("mc-lt-chart", "currentPrice"), Input("mc-lt-chart", "tickCount"), State("mc-lt-chart", "running"), ) def update_stats(price, ticks, running): p = price if price is not None else 100.0 return ( f"${p:,.2f}", "green" if p >= 100 else "red", str(ticks or 0), "Running" if running else "Stopped", "green" if running else "dimmed", ) @callback( Output("mc-lt-alerts", "children"), Output("mc-lt-log", "children"), Input("mc-lt-chart", "alertHistory"), ) def update_alerts(alerts): if not alerts: return "0", "Alerts will appear here once running..." recent = list(reversed(alerts[-15:])) lines = [ f"[Tick {a.get('tick', '?'):>5}] " f"{'UP' if a.get('type') == 'up' else 'DN'} " f"${a.get('price', 0):>8.2f} ({a.get('message', '')})" for a in recent ] return str(len(alerts)), "\n".join(lines) ``` --- ## LineChart Properties | Property | Type | Default | Description | |:---------|:-----|:--------|:------------| | `series` | list | Required | Array of series objects with `data`, `label`, `color`, `curve`, `area`, `stack` | | `xAxis` | list | `None` | X-axis config: `data`, `scaleType`, `label`, `zoom` (Pro) | | `yAxis` | list | `None` | Y-axis config: `label`, `position`, `min`, `max` | | `referenceLines` | list | `None` | Horizontal/vertical reference lines | | `licenseKey` | string | `""` | MUI Pro license key (for zoom, brush, slider) | | `initialZoom` | list | `None` | Initial zoom state (Pro) | | `showSlider` | bool | `False` | Show zoom range slider (Pro) | | `showToolbar` | bool | `False` | Show zoom/export toolbar (Pro) | | `brushConfig` | dict | `None` | Brush selection config (Pro) | | `grid` | dict | `None` | Grid lines: `{horizontal: bool, vertical: bool}` | | `height` | int | `300` | Chart height in pixels | | `colors` | list | `None` | Custom color palette | | `axisHighlight` | dict | `None` | `{x: 'none'/'line'/'band', y: 'none'/'line'}` | | `tooltip` | dict | `None` | `{trigger: 'axis'/'item'/'none'}` | | `clickData` | dict | Output | Click event data | | `highlightedItem` | dict | `None` | Controlled highlight state | | `dateFormat` | string | `None` | **1.1.0** — Tooltip date format for `scaleType: 'time'` (e.g. `"MMM d, YYYY"`) | | `dateTickFormat` | string | `None` | **1.1.0** — Axis tick date format for `scaleType: 'time'` (e.g. `"M/d"`) | --- ## PieChart Properties | Property | Type | Default | Description | |:---------|:-----|:--------|:------------| | `data` | list | `None` | Array of `{id, value, label, color}` objects | | `series` | list | `None` | Multi-series for nested pies | | `innerRadius` | int | `0` | Donut hole radius (>0 = donut) | | `outerRadius` | int | `None` | Outer radius | | `cornerRadius` | int | `0` | Rounded slice corners | | `paddingAngle` | int | `0` | Gap between slices (degrees) | | `startAngle` | int | `0` | Arc start angle | | `endAngle` | int | `360` | Arc end angle | | `arcLabel` | string | `None` | `'value'`, `'label'`, `'formattedValue'` | | `arcLabelMinAngle` | int | `0` | Min angle to show label | | `height` | int | `300` | Chart height | --- ## ScatterChart Properties | Property | Type | Default | Description | |:---------|:-----|:--------|:------------| | `series` | list | Required | Array of series with `data: [{x, y, z?, id}]` | | `zAxis` | list | `None` | Z-axis color mapping config | | `voronoiMaxRadius` | int | `None` | Proximity hover radius | | `xAxis` | list | `None` | X-axis config | | `yAxis` | list | `None` | Y-axis config | | `height` | int | `300` | Chart height | --- ## Heatmap Properties (Pro) | Property | Type | Default | Description | |:---------|:-----|:--------|:------------| | `data` | list | Required | Array of `[x_index, y_index, value]` | | `xAxis` | dict | Required | `{data: [...], label: "..."}` | | `yAxis` | dict | Required | `{data: [...], label: "..."}` | | `colorScale` | dict | Required | `{type, min, max, colors}` or `{type, thresholds, colors}` | | `licenseKey` | string | Required | MUI Pro license key | | `height` | int | `300` | Chart height | --- ## LiveTradingChart Properties | Property | Type | Default | Description | |:---------|:-----|:--------|:------------| | `running` | bool | `False` | Start / stop the simulation tick | | `intervalMs` | int | `200` | Milliseconds between ticks | | `windowSize` | int | `80` | Number of visible candles | | `forecastSize` | int | `20` | Candles projected ahead | | `initialPrice` | float | `100` | Starting price | | `volatility` | float | `0.02` | Per-tick price volatility (e.g. `0.02` = 2%) | | `drift` | float | `0.001` | Per-tick price drift (positive = upward trend) | | `forecastVolatility` | float | `1.5` | Uncertainty band width multiplier | | `seed` | int | `None` | Random seed for reproducibility | | `showVolume` | bool | `True` | Show volume histogram | | `showLabels` | bool | `False` | Show price labels on candles | | `showSlider` | bool | `False` | Show zoom range slider (Pro) | | `volumeHeightPct` | int | `20` | Volume panel height as % of chart height | | `alertProbability` | float | `0.08` | Probability of an alert firing per tick (lower = fewer labels) | | `alertThresholdPct` | float | `2.0` | Minimum % price change required to trigger an alert | | `alertUpColor` | string | `"#4caf50"` | Label color for upward alert moves | | `alertDownColor` | string | `"#f44336"` | Label color for downward alert moves | | `margin` | dict | `None` | Chart margins `{left, right, top, bottom}` | | `licenseKey` | string | `""` | MUI Pro license key | | `resetTrigger` | int | `None` | Increment to reset simulation | | `currentPrice` | float | Output | Current simulated price | | `tickCount` | int | Output | Number of ticks elapsed | | `alertHistory` | list | Output | Array of `{type, tick, price, message}` alert objects | --- ## Contributing Contributions welcome! Visit the [GitHub repo](https://github.com/pip-install-python/dash-mui-charts/issues). ## License MIT License (component). MUI X Pro license required for Pro features. --- *Source: /pip/dash_mui_charts* *Generated with dash-improve-my-llms*