Interactive Heatmap props playground (MUI X Pro): live controls for color scale, dimensions, cell style, interactions and margins on a 5x5 grid.

Heatmap Props

Interactive Heatmap props playground (MUI X Pro): live controls for color scale, dimensions, cell style, interactions and margins on a 5x5 grid.


Overview

An interactive control panel for exploring and customizing Heatmap props on a 5×5 grid — changes reflect in real time, and the generated code panel writes the exact Heatmap(...) call for the current settings.

Heatmap is a MUI X Pro component. These demos read the license key from the MUI_PRO_API_KEY environment variable; without it the chart renders with the unlicensed watermark and the playground shows a warning banner.


Playground

# File: docs/heatmap-props/playground.py

"""Heatmap props playground — MUI X Pro, live controls on a 5x5 grid.

Rendered on /heatmap-props via `.. exec::`; ported verbatim from the
pre-migration pages/heatmap_props.py (same ids, same callbacks).
"""
import json
import os

from dash import html, callback, Input, Output, dcc

import dash_mantine_components as dmc
from dash_mui_charts import Heatmap

# Get license key from environment
MUI_LICENSE_KEY = os.environ.get('MUI_PRO_API_KEY', '')

# Sample data - 5x5 grid
SAMPLE_DATA = [
    [0, 0, 2], [1, 0, 5], [2, 0, 8], [3, 0, 4], [4, 0, 6],
    [0, 1, 7], [1, 1, 3], [2, 1, 9], [3, 1, 1], [4, 1, 5],
    [0, 2, 4], [1, 2, 8], [2, 2, 2], [3, 2, 7], [4, 2, 3],
    [0, 3, 6], [1, 3, 1], [2, 3, 5], [3, 3, 9], [4, 3, 8],
    [0, 4, 3], [1, 4, 6], [2, 4, 4], [3, 4, 2], [4, 4, 7],
]
X_LABELS = ['A', 'B', 'C', 'D', 'E']
Y_LABELS = ['Row 1', 'Row 2', 'Row 3', 'Row 4', 'Row 5']

# Color swatches
COLOR_SWATCHES = [
    '#e3f2fd', '#bbdefb', '#90caf9', '#64b5f6', '#42a5f5',
    '#1976d2', '#1565c0', '#0d47a1', '#4fc3f7', '#00bcd4',
]
WARM_SWATCHES = [
    '#fff3e0', '#ffe0b2', '#ffcc80', '#ffb74d', '#ffa726',
    '#ff9800', '#f57c00', '#ef6c00', '#e65100', '#ff5722',
]
COOL_SWATCHES = [
    '#e8f5e9', '#c8e6c9', '#a5d6a7', '#81c784', '#66bb6a',
    '#4caf50', '#43a047', '#388e3c', '#2e7d32', '#1b5e20',
]


def create_control_card(title, children):
    """Helper to create a styled control card."""
    return dmc.Paper(
        shadow='sm',
        radius='md',
        p='md',
        children=[
            dmc.Text(title, fw=600, size='lg', mb='md'),
            dmc.Stack(gap='sm', children=children),
        ],
    )


component = html.Div([
        # Pro License Warning (if no key)
        html.Div([
            dmc.Paper(
                shadow='xs',
                radius='md',
                p='md',
                style={'backgroundColor': 'var(--mantine-color-orange-0)', 'borderLeft': '4px solid #ff9800'},
                children=[
                    dmc.Text(
                        'This feature requires an MUI X Pro license key. '
                        'Set MUI_PRO_API_KEY environment variable.',
                        size='sm',
                        c='orange',
                    ),
                ],
            ),
        ], style={'marginBottom': '20px'}) if not MUI_LICENSE_KEY else None,

        # Live Preview Section
        dmc.Paper(
            shadow='sm',
            radius='md',
            p='lg',
            mb='lg',
            children=[
                dmc.Text('Live Preview', fw=600, size='lg', mb='md'),
                html.Div(
                    id='heatmap-preview-container',
                    style={
                        'display': 'flex',
                        'justifyContent': 'center',
                        'alignItems': 'center',
                        'minHeight': '350px',
                        'backgroundColor': 'var(--mantine-color-default)',
                        'borderRadius': '8px',
                        'padding': '20px',
                        'transition': 'background-color 0.3s ease',
                    },
                    children=[
                        html.Div(id='heatmap-preview'),
                    ],
                ),
                # Interaction Info
                dmc.SimpleGrid(
                    cols=2,
                    spacing='md',
                    mt='md',
                    children=[
                        dmc.Paper(
                            p='sm',
                            radius='sm',
                            withBorder=True,
                            children=[
                                dmc.Text('Hover Info', size='xs', c='dimmed', mb='xs'),
                                html.Div(
                                    id='heatmap-hover-info',
                                    children='Hover over a cell',
                                    style={'fontFamily': 'monospace', 'fontSize': '13px'},
                                ),
                            ],
                        ),
                        dmc.Paper(
                            p='sm',
                            radius='sm',
                            withBorder=True,
                            children=[
                                dmc.Text('Click Data', size='xs', c='dimmed', mb='xs'),
                                html.Div(
                                    id='heatmap-click-info',
                                    children='Click on a cell',
                                    style={'fontFamily': 'monospace', 'fontSize': '13px'},
                                ),
                            ],
                        ),
                    ],
                ),
            ],
        ),

        # Control Panel Grid
        dmc.SimpleGrid(
            cols={'base': 1, 'sm': 2, 'lg': 3},
            spacing='lg',
            mb='lg',
            children=[
                # Color Scale Card
                create_control_card('Color Scale', [
                    dmc.Text('Scale Type', size='sm', fw=500, mb='xs'),
                    dmc.SegmentedControl(
                        id='ctrl-scale-type',
                        data=[
                            {'value': 'continuous', 'label': 'Continuous'},
                            {'value': 'piecewise', 'label': 'Piecewise'},
                        ],
                        value='continuous',
                        fullWidth=True,
                        mb='md',
                    ),
                    dmc.ColorInput(
                        id='ctrl-min-color',
                        label='Min Color',
                        value='#e3f2fd',
                        format='hex',
                        swatches=COLOR_SWATCHES,
                        mb='sm',
                    ),
                    dmc.ColorInput(
                        id='ctrl-max-color',
                        label='Max Color',
                        value='#1565c0',
                        format='hex',
                        swatches=COLOR_SWATCHES,
                        mb='sm',
                    ),
                    dmc.NumberInput(
                        id='ctrl-min-value',
                        label='Min Value',
                        value=0,
                        min=-100,
                        max=100,
                        mb='sm',
                    ),
                    dmc.NumberInput(
                        id='ctrl-max-value',
                        label='Max Value',
                        value=10,
                        min=-100,
                        max=100,
                    ),
                ]),

                # Dimensions Card
                create_control_card('Dimensions', [
                    dmc.Text('Width', size='sm', fw=500, mb='xs'),
                    dmc.Slider(
                        id='ctrl-width',
                        value=400,
                        min=200,
                        max=600,
                        step=10,
                        marks=[
                            {'value': 200, 'label': '200'},
                            {'value': 400, 'label': '400'},
                            {'value': 600, 'label': '600'},
                        ],
                        mb='lg',
                    ),
                    dmc.Text('Height', size='sm', fw=500, mb='xs'),
                    dmc.Slider(
                        id='ctrl-height',
                        value=300,
                        min=200,
                        max=500,
                        step=10,
                        marks=[
                            {'value': 200, 'label': '200'},
                            {'value': 350, 'label': '350'},
                            {'value': 500, 'label': '500'},
                        ],
                        mb='md',
                    ),
                ]),

                # Cell Style Card
                create_control_card('Cell Style', [
                    dmc.Text('Style', size='sm', fw=500, mb='xs'),
                    dmc.SegmentedControl(
                        id='ctrl-cell-style',
                        data=[
                            {'value': 'default', 'label': 'Default'},
                            {'value': 'rounded', 'label': 'Rounded'},
                        ],
                        value='default',
                        fullWidth=True,
                        mb='md',
                    ),
                    dmc.Text('Gap (px)', size='sm', fw=500, mb='xs'),
                    dmc.Slider(
                        id='ctrl-gap',
                        value=4,
                        min=0,
                        max=10,
                        step=1,
                        marks=[
                            {'value': 0, 'label': '0'},
                            {'value': 5, 'label': '5'},
                            {'value': 10, 'label': '10'},
                        ],
                        mb='lg',
                    ),
                    dmc.Text('Border Radius (px)', size='sm', fw=500, mb='xs'),
                    dmc.Slider(
                        id='ctrl-border-radius',
                        value=10,
                        min=0,
                        max=20,
                        step=1,
                        marks=[
                            {'value': 0, 'label': '0'},
                            {'value': 10, 'label': '10'},
                            {'value': 20, 'label': '20'},
                        ],
                        mb='lg',
                    ),
                    dmc.Switch(
                        id='ctrl-show-values',
                        label='Show Values in Cells',
                        checked=True,
                        mb='sm',
                    ),
                    dmc.Text('Font Size (px)', size='sm', fw=500, mb='xs'),
                    dmc.Slider(
                        id='ctrl-font-size',
                        value=12,
                        min=8,
                        max=18,
                        step=1,
                        marks=[
                            {'value': 8, 'label': '8'},
                            {'value': 12, 'label': '12'},
                            {'value': 18, 'label': '18'},
                        ],
                        mb='lg',
                    ),
                    dmc.ColorInput(
                        id='ctrl-text-color',
                        label='Text Color',
                        value='#ffffff',
                        format='hex',
                        swatches=['#ffffff', '#000000', '#333333', '#666666'],
                    ),
                ]),

                # Interactions Card
                create_control_card('Interactions', [
                    dmc.Switch(
                        id='ctrl-highlight',
                        label='Highlight on Hover',
                        checked=True,
                        mb='sm',
                    ),
                    dmc.Switch(
                        id='ctrl-hide-legend',
                        label='Hide Legend',
                        checked=False,
                        mb='sm',
                    ),
                ]),

                # Margins Card
                create_control_card('Margins', [
                    dmc.SimpleGrid(
                        cols=2,
                        spacing='sm',
                        children=[
                            dmc.NumberInput(
                                id='ctrl-margin-top',
                                label='Top',
                                value=20,
                                min=0,
                                max=100,
                            ),
                            dmc.NumberInput(
                                id='ctrl-margin-right',
                                label='Right',
                                value=20,
                                min=0,
                                max=100,
                            ),
                            dmc.NumberInput(
                                id='ctrl-margin-bottom',
                                label='Bottom',
                                value=50,
                                min=0,
                                max=100,
                            ),
                            dmc.NumberInput(
                                id='ctrl-margin-left',
                                label='Left',
                                value=80,
                                min=0,
                                max=100,
                            ),
                        ],
                    ),
                ]),
            ],
        ),

        # Generated Code Section
        dmc.Paper(
            shadow='sm',
            radius='md',
            p='lg',
            children=[
                dmc.Group(
                    justify='space-between',
                    mb='md',
                    children=[
                        dmc.Text('Generated Code', fw=600, size='lg'),
                        dmc.Group(
                            gap='sm',
                            children=[
                                dmc.Button(
                                    'Reset to Defaults',
                                    id='reset-heatmap-btn',
                                    variant='outline',
                                    size='sm',
                                ),
                                dcc.Clipboard(
                                    target_id='generated-heatmap-code',
                                    style={
                                        'display': 'inline-block',
                                        'backgroundColor': 'var(--mantine-color-blue-6)',
                                        'color': 'white',
                                        'padding': '6px 12px',
                                        'borderRadius': '4px',
                                        'cursor': 'pointer',
                                        'fontSize': '14px',
                                    },
                                ),
                            ],
                        ),
                    ],
                ),
                html.Pre(
                    id='generated-heatmap-code',
                    style={
                        'backgroundColor': 'var(--mantine-color-dark-8)',
                        'color': '#d4d4d4',
                        'padding': '20px',
                        'borderRadius': '8px',
                        'fontSize': '13px',
                        'lineHeight': '1.5',
                        'overflowX': 'auto',
                        'margin': 0,
                    },
                ),
            ],
        ),

    ], style={'maxWidth': '1200px', 'margin': '0 auto', 'padding': '20px'})


@callback(
    Output('heatmap-preview', 'children'),
    Output('generated-heatmap-code', 'children'),
    Input('ctrl-scale-type', 'value'),
    Input('ctrl-min-color', 'value'),
    Input('ctrl-max-color', 'value'),
    Input('ctrl-min-value', 'value'),
    Input('ctrl-max-value', 'value'),
    Input('ctrl-width', 'value'),
    Input('ctrl-height', 'value'),
    Input('ctrl-cell-style', 'value'),
    Input('ctrl-gap', 'value'),
    Input('ctrl-border-radius', 'value'),
    Input('ctrl-show-values', 'checked'),
    Input('ctrl-font-size', 'value'),
    Input('ctrl-text-color', 'value'),
    Input('ctrl-highlight', 'checked'),
    Input('ctrl-hide-legend', 'checked'),
    Input('ctrl-margin-top', 'value'),
    Input('ctrl-margin-right', 'value'),
    Input('ctrl-margin-bottom', 'value'),
    Input('ctrl-margin-left', 'value'),
)
def update_heatmap(
    scale_type, min_color, max_color, min_value, max_value,
    width, height, cell_style, gap, border_radius,
    show_values, font_size, text_color, highlight, hide_legend,
    margin_top, margin_right, margin_bottom, margin_left,
):
    """Update heatmap preview and generated code."""

    # Build color scale
    color_scale = {
        'type': scale_type,
        'min': min_value or 0,
        'max': max_value or 10,
        'colors': [min_color, max_color],
    }

    # Build cell style (only for rounded)
    cell_style_prop = None
    if cell_style == 'rounded':
        cell_style_prop = {
            'gap': gap,
            'borderRadius': border_radius,
            'showValue': show_values,
            'fontSize': font_size,
            'textColor': text_color,
        }

    # Build highlight scope
    highlight_scope = {'highlight': 'item'} if highlight else None

    # Build margin
    margin = {
        'top': margin_top or 20,
        'right': margin_right or 20,
        'bottom': margin_bottom or 50,
        'left': margin_left or 80,
    }

    # Create heatmap component
    heatmap = Heatmap(
        id='preview-heatmap',
        licenseKey=MUI_LICENSE_KEY,
        data=SAMPLE_DATA,
        xAxis={'data': X_LABELS},
        yAxis={'data': Y_LABELS},
        width=width,
        height=height,
        colorScale=color_scale,
        cellStyle=cell_style_prop,
        highlightScope=highlight_scope,
        hideLegend=hide_legend,
        margin=margin,
    )

    # Generate code string
    code_lines = ['Heatmap(']
    code_lines.append('    data=data,')
    code_lines.append(f"    xAxis={{'data': {X_LABELS}}},")
    code_lines.append(f"    yAxis={{'data': {Y_LABELS}}},")
    code_lines.append(f'    width={width},')
    code_lines.append(f'    height={height},')
    code_lines.append('    colorScale={')
    code_lines.append(f"        'type': '{scale_type}',")
    code_lines.append(f"        'min': {min_value},")
    code_lines.append(f"        'max': {max_value},")
    code_lines.append(f"        'colors': ['{min_color}', '{max_color}'],")
    code_lines.append('    },')

    if cell_style_prop:
        code_lines.append('    cellStyle={')
        code_lines.append(f"        'gap': {gap},")
        code_lines.append(f"        'borderRadius': {border_radius},")
        code_lines.append(f"        'showValue': {show_values},")
        code_lines.append(f"        'fontSize': {font_size},")
        code_lines.append(f"        'textColor': '{text_color}',")
        code_lines.append('    },')

    if highlight_scope:
        code_lines.append("    highlightScope={'highlight': 'item'},")

    if hide_legend:
        code_lines.append('    hideLegend=True,')

    code_lines.append('    margin={')
    code_lines.append(f"        'top': {margin_top}, 'right': {margin_right},")
    code_lines.append(f"        'bottom': {margin_bottom}, 'left': {margin_left},")
    code_lines.append('    },')
    code_lines.append(')')

    code = '\n'.join(code_lines)

    return heatmap, code


@callback(
    Output('heatmap-hover-info', 'children'),
    Input('preview-heatmap', 'highlightedItem'),
    prevent_initial_call=True
)
def update_hover_info(highlighted_item):
    """Display current hover info."""
    if highlighted_item:
        return json.dumps(highlighted_item, indent=2)
    return 'Hover over a cell'


@callback(
    Output('heatmap-click-info', 'children'),
    Input('preview-heatmap', 'clickData'),
    prevent_initial_call=True
)
def update_click_info(click_data):
    """Display click data."""
    if click_data:
        return f"Cell ({click_data.get('x')}, {click_data.get('y')}) = {click_data.get('value')}"
    return 'Click on a cell'


@callback(
    Output('ctrl-scale-type', 'value'),
    Output('ctrl-min-color', 'value'),
    Output('ctrl-max-color', 'value'),
    Output('ctrl-min-value', 'value'),
    Output('ctrl-max-value', 'value'),
    Output('ctrl-width', 'value'),
    Output('ctrl-height', 'value'),
    Output('ctrl-cell-style', 'value'),
    Output('ctrl-gap', 'value'),
    Output('ctrl-border-radius', 'value'),
    Output('ctrl-show-values', 'checked'),
    Output('ctrl-font-size', 'value'),
    Output('ctrl-text-color', 'value'),
    Output('ctrl-highlight', 'checked'),
    Output('ctrl-hide-legend', 'checked'),
    Output('ctrl-margin-top', 'value'),
    Output('ctrl-margin-right', 'value'),
    Output('ctrl-margin-bottom', 'value'),
    Output('ctrl-margin-left', 'value'),
    Input('reset-heatmap-btn', 'n_clicks'),
    prevent_initial_call=True
)
def reset_controls(n_clicks):
    """Reset all controls to defaults."""
    return (
        'continuous',  # scale type
        '#e3f2fd',     # min color
        '#1565c0',     # max color
        0,             # min value
        10,            # max value
        400,           # width
        300,           # height
        'default',     # cell style
        4,             # gap
        10,            # border radius
        True,          # show values
        12,            # font size
        '#ffffff',     # text color
        True,          # highlight
        False,         # hide legend
        20,            # margin top
        20,            # margin right
        50,            # margin bottom
        80,            # margin left
    )

:defaultExpanded: false :withExpandedButton: true


Related pages


Source: /heatmap-props

Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs: