{"record":{"id":"c644b1653fdaf75c","repo":"pola-rs/polars","slug":"sparkline-data-range-cols-must-all-be-adjacent","errorCode":null,"errorMessage":"sparkline data range/cols must all be adjacent","messagePattern":"sparkline data range/cols must all be adjacent","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/io/spreadsheet/_write_utils.py","lineNumber":305,"sourceCode":"    ws: Worksheet,\n    df: DataFrame,\n    table_start: tuple[int, int],\n    col: str,\n    *,\n    include_header: bool,\n    params: Sequence[str] | dict[str, Any],\n) -> None:\n    \"\"\"Inject sparklines into (previously-created) empty table columns.\"\"\"\n    from xlsxwriter.utility import xl_rowcol_to_cell\n\n    m: dict[str, Any] = {}\n    data_cols = params.get(\"columns\") if isinstance(params, dict) else params\n    if not data_cols:\n        msg = \"supplying 'columns' param value is mandatory for sparklines\"\n        raise ValueError(msg)\n    elif not _adjacent_cols(df, data_cols, min_max=m):\n        msg = \"sparkline data range/cols must all be adjacent\"\n        raise RuntimeError(msg)\n\n    spk_row, spk_col, _, _ = _xl_column_range(\n        df, table_start, col, include_header=include_header, as_range=False\n    )\n    data_start_col = table_start[1] + m[\"min\"][\"idx\"]\n    data_end_col = table_start[1] + m[\"max\"][\"idx\"]\n\n    if not isinstance(params, dict):\n        options = {}\n    else:\n        # strip polars-specific params before passing to xlsxwriter\n        options = {\n            name: val\n            for name, val in params.items()\n            if name not in (\"columns\", \"insert_after\", \"insert_before\")\n        }\n        if \"negative_points\" not in options:\n            options[\"negative_points\"] = options.get(\"type\") in (\"column\", \"win_loss\")","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/io/spreadsheet/_write_utils.py#L287-L323","documentation":"RuntimeError raised by _inject_sparklines during write_excel: a sparkline's data columns must be adjacent in the worksheet, because an Excel sparkline charts one contiguous cell range. _adjacent_cols verifies the referenced columns form a consecutive block in the frame; if other columns sit between them, the range cannot be built.","triggerScenarios":"pl.write_excel(df, sparklines={'trend': ['a', 'c']}) when df columns are ordered a, b, c — 'b' sits inside the range. Also triggered by dict form with a non-contiguous 'columns' list.","commonSituations":"Pointing a sparkline at summary columns scattered across a wide export (e.g. monthly totals with metric-label columns interleaved); frames reordered by a group_by/with_columns pipeline so previously adjacent columns no longer are.","solutions":["Reorder the frame so the sparkline's data columns are consecutive: df.select(['a', 'c', 'b', ...]) or sparklines over ['a','b','c'] instead.","Or narrow the sparkline to a contiguous subset of the columns you care about.","Or split into multiple sparklines, one per contiguous block."],"exampleFix":"# before\npl.write_excel(df, sparklines={'trend': ['a', 'c']})  # df order: a, b, c\n\n# after\npl.write_excel(df.select('a', 'c', 'b'), sparklines={'trend': ['a', 'c']})","handlingStrategy":"validation","validationCode":"def adjacent(df, cols):\n    idx = [df.columns.index(c) for c in cols]\n    return max(idx) - min(idx) == len(idx) - 1\n\nfor name, spec in sparklines.items():\n    cols = spec.get('columns') if isinstance(spec, dict) else spec\n    if not adjacent(df, cols):\n        df = df.select(*[c for c in df.columns if c not in cols], *cols)  # group them\npl.write_excel(df, sparklines=sparklines)","typeGuard":null,"tryCatchPattern":"try:\n    pl.write_excel(df, sparklines=sparklines)\nexcept RuntimeError as e:\n    if 'adjacent' in str(e):\n        cols = next(iter(sparklines.values()))\n        cols = cols.get('columns') if isinstance(cols, dict) else cols\n        ordered = [c for c in df.columns if c not in cols] + list(cols)\n        pl.write_excel(df.select(ordered), sparklines=sparklines)\n    else:\n        raise","preventionTips":["Design exports so each sparkline's data columns are written consecutively.","Pin column order explicitly with df.select(...) instead of relying on pipeline order.","Check adjacency (index span equals count) before calling write_excel."],"tags":["excel","spreadsheet","write-excel","sparklines","column-order"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}