nautechsystems/nautilus_trader · error · ValueError

Grid has {rows * cols} cells but {len(charts)} charts were c

Error message

Grid has {rows * cols} cells but {len(charts)} charts were configured; provide a larger GridLayout via TearsheetConfig.layout

What it means

_calculate_grid_layout checks that the chosen subplot grid can hold every configured chart: len(charts) must be <= rows*cols. With a custom TearsheetConfig.layout (a plotly GridLayout) the grid dimensions are user-supplied, so an under-sized layout is rejected instead of silently dropping charts.

Source

Thrown at python/nautilus_trader/analysis/tearsheet.py:2526

        if num_charts <= 2:
            rows, cols = 1, num_charts
            heights = [1.0 / rows] * rows
        elif num_charts <= 4:
            rows, cols = 2, 2
            heights = [1.0 / rows] * rows
        elif num_charts <= 6:
            rows, cols = 3, 2
            heights = [1.0 / rows] * rows
        else:
            cols = 2
            rows = max(4, (num_charts + cols - 1) // cols)
            heights = [0.50, 0.22, 0.16, 0.12] if rows == 4 else [1.0 / rows] * rows

        v_spacing = 0.10
        h_spacing = 0.10

    if len(charts) > rows * cols:
        raise ValueError(
            f"Grid has {rows * cols} cells but {len(charts)} charts were configured; "
            f"provide a larger GridLayout via TearsheetConfig.layout",
        )

    specs = []
    titles = []
    chart_idx = 0

    for _ in range(rows):
        row_specs: list[dict[str, Any] | None] = []

        for _ in range(cols):
            if chart_idx < len(charts):
                chart = charts[chart_idx]
                chart_name = chart.name
                spec = _TEARSHEET_CHART_SPECS.get(chart_name, {})
                subplot_type = spec.get("type", "scatter")
                default_title = spec.get("title", chart_name.replace("_", " ").title())

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Enlarge the custom layout (more rows/cols) so rows*cols >= len(config.charts)
  2. Or remove charts from TearsheetConfig.charts until they fit
  3. Or drop the custom layout (layout=None) to let the function auto-size rows/cols for any chart count

Example fix

# before
layout = GridLayout(grid=[[{'colspan': 2}, None], [{}, {}]])  # 4 cells
config = TearsheetConfig(charts=[c1, c2, c3, c4, c5], layout=layout)
# ValueError: Grid has 4 cells but 5 charts were configured

# after
layout = GridLayout(grid=[[{'colspan': 2}, None], [{}, {}], [{}, {}]])  # 6 cells
config = TearsheetConfig(charts=[c1, c2, c3, c4, c5], layout=layout)
Defensive patterns

Strategy: validation

Validate before calling

if config.layout is not None:
    cells = config.layout.rows * config.layout.cols  # adapt to your GridLayout accessor
    assert len(config.charts) <= cells, (
        f'{len(config.charts)} charts > {cells} grid cells; enlarge layout or trim charts'
    )
create_tearsheet(returns=result, config=config)

Try / catch

try:
    create_tearsheet(returns=result, config=config)
except ValueError as e:
    if 'Grid has' in str(e):
        config = TearsheetConfig(charts=config.charts, layout=None)  # auto-size
        create_tearsheet(returns=result, config=config)
    else:
        raise

Prevention

When it happens

Trigger: Passing TearsheetConfig(layout=GridLayout with e.g. 2x2=4 cells) together with 5+ charts in config.charts; or a custom layout whose row/col product is smaller than the charts list even when auto-layout would have sufficed.

Common situations: Hand-tuning a tearsheet layout then adding more charts later; copying a layout sized for the default chart set into a config that appends custom charts.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/f3367b2a5d02fa12. Report an issue: GitHub.