DataFrames and Real Data
XY accepts a pandas DataFrame anywhere its public mark API accepts data=.
Column-name strings then resolve against that table. Keep cleaning, joins,
grouping, and business calculations in the dataframe library; give XY the
finished columns that should become marks.
The workflow below is a complete script. It reads CSV data, validates the
important fields, aggregates duplicate daily rows, builds one line per
channel, and writes both interactive and static output. The embedded CSV keeps
the example copyable; replace StringIO(SAMPLE) with
pd.read_csv("daily_metrics.csv", parse_dates=["day"]) for a real file.
Install pandas beside the released core package first:
End-to-end example
ExpandCollapse
Run it as a script, then open build/daily-revenue.html. In a notebook, leave
chart as the last expression in a cell instead of exporting it.
The example groups explicitly because xy.line(...) draws one ordered series;
it does not silently interpret a categorical column as multiple lines. Doing
the transformation first also makes row ordering, missing-value handling, and
aggregation reviewable outside the renderer.
A single-table encoding
When one mark uses the whole table, pass the DataFrame once and refer to its columns by name:
The color="channel" string is a column mapping because channel is not a
CSS color. A value such as color="#2563eb" is a constant color. Keeping this
distinction explicit prevents a misspelled column from becoming an unintended
style.
Mappings, Arrow, and Polars
You do not need pandas when a simpler boundary is clearer:
- Mappings: A dictionary of aligned one-dimensional columns works with the
same
data=and column-name pattern. It is a useful dependency-free boundary for application code. - PyArrow: Install
pyarrowseparately and pass compatible Arrow Arrays or ChunkedArrays directly. Primitive, null-free float64 layouts have the best chance of avoiding a copy; nulls, chunks, integer or temporal conversion, and unsupported coordinate types can require materialization or rejection. See Data and columns for the exact boundary. - Polars: XY does not currently document a dedicated Polars DataFrame
contract. Extract supported one-dimensional columns explicitly, for example
frame["x"].to_numpy()andframe["y"].to_numpy(), then pass those arrays to a mark. Converting to pandas is also an application-level option when the extra dependency and copy are acceptable. - SQL and DuckDB: Execute filtering and aggregation in the query engine, then materialize only the result columns as pandas, Arrow, or NumPy values. XY does not execute SQL or manage an out-of-core query plan.
Production data checklist
- Sort every ordered series before calling
xy.line. - Make numeric conversion and missing-value policy explicit; do not rely on a renderer to repair business data.
- Keep x, y, color, and size columns aligned after filtering.
- Test category cardinality and datetime precision with production-like data.
- Use
chart.memory_report()when ingest copies or retained source size matter. - Export a representative result in CI so a data-schema change fails before deployment.
Continue with Large data and performance, Display and export, or Troubleshooting.