Guides

/

DataFrames and Real Data

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

Expand

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 pyarrow separately 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() and frame["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.

Built with Reflex