Online Polars Compiler

Run Polars code in your browser. Filter and add columns, group and aggregate, join DataFrames and build lazy queries.

Python
import polars as pl
import requests
import io

url = "https://raw.githubusercontent.com/mwaskom/seaborn-data/master/mpg.csv"
response = requests.get(url)
df = pl.read_csv(io.StringIO(response.text))

df.head()

Polars is a DataFrame library for Python, written in Rust. It covers the same ground as pandas: reading CSV files, filtering rows, adding columns, grouping and joining. Steps are written as expressions such as pl.col("price") * 2, and a lazy query lets Polars plan every step before it runs any of them. People use it to clean, reshape and summarize tables of data. This page is an online Polars compiler: the code runs in your browser, so you can try it without installing anything. Run the example first, then paste any snippet below into a new cell to try it.

What the example does

requests.get() downloads mpg.csv, a table of cars from the seaborn-data repository on GitHub, and response.text holds the file as one string. io.StringIO() wraps that string so pl.read_csv() can read it like a file. The result is a DataFrame of 398 cars and 9 columns. df.head() returns the first five rows, which appear below the code as a table. Under each column name, Polars shows the type it detected: f64 for decimals, i64 for whole numbers and str for text.

Select, filter and add columns

pl.col("name") refers to a column inside an expression. filter() keeps the rows where an expression is true, with_columns() adds or replaces columns, and select() keeps the columns you name:

import polars as pl

df = pl.DataFrame({
    "city": ["Oslo", "Lima", "Pune", "Oslo", "Lima", "Pune"],
    "month": ["Jan", "Jan", "Jan", "Jul", "Jul", "Jul"],
    "temp_c": [-4.3, 22.8, 20.9, 16.8, 16.4, 26.6],
    "rain_mm": [49, 1, 2, 81, 1, 180],
})

warm = (
    df.filter(pl.col("temp_c") > 20)
    .with_columns((pl.col("temp_c") * 9 / 5 + 32).round(1).alias("temp_f"))
    .select("city", "month", "temp_c", "temp_f")
    .sort("temp_c", descending=True)
)
print(warm)

Group and aggregate

group_by() splits the rows by the values in a column, and agg() returns one row per group with a result for each expression you pass. pl.len() counts the rows in each group, and an expression can combine columns before it sums them:

import polars as pl

sales = pl.DataFrame({
    "region": ["North", "South", "North", "East", "South", "North"],
    "units": [12, 7, 3, 9, 14, 5],
    "price": [2.5, 2.5, 4.0, 4.0, 4.0, 2.5],
})

summary = (
    sales.group_by("region")
    .agg(
        pl.len().alias("orders"),
        pl.col("units").sum(),
        (pl.col("units") * pl.col("price")).sum().alias("revenue"),
    )
    .sort("revenue", descending=True)
)
print(summary)

Join two DataFrames

join() matches rows on key columns. With how="left", every order is kept, and one with no matching customer gets a null name. how="anti" keeps only the rows that have no match:

import polars as pl

customers = pl.DataFrame({"id": [1, 2, 3], "name": ["Ana", "Ben", "Chloe"]})
orders = pl.DataFrame({
    "order_id": [10, 11, 12, 13],
    "customer_id": [1, 1, 3, 4],
    "total": [25.0, 12.5, 40.0, 8.0],
})

# Every order, with the customer's name where there is one
print(orders.join(customers, left_on="customer_id", right_on="id", how="left"))

# Customers who have no orders
print(customers.join(orders, left_on="id", right_on="customer_id", how="anti"))

Build a lazy query

.lazy() turns a DataFrame into a LazyFrame. Each method after it adds a step to a query plan instead of running it, and collect() runs the whole plan and returns a DataFrame:

import polars as pl

pl.DataFrame({
    "day": ["Mon", "Tue", "Wed", "Thu", "Fri"],
    "visits": [120, 95, 143, 110, 160],
    "signups": [6, 3, 9, 4, 11],
}).write_csv("visits.csv")

query = (
    pl.read_csv("visits.csv")
    .lazy()
    .with_columns((pl.col("signups") / pl.col("visits") * 100).round(1).alias("rate_pct"))
    .filter(pl.col("visits") > 100)
    .select("day", "rate_pct")
    .sort("rate_pct", descending=True)
)
print(query.explain())   # the optimized plan, read from the bottom up
print(query.collect())

The code filters after with_columns(), but the plan applies the filter first (SELECTION on the bottom line), so Polars drops Tuesday before it computes rate_pct.

Good to know

  • group_by() does not keep the groups in the order they first appear, and the order can change from one run to the next. Sort the result, as the snippet above does, or pass maintain_order=True.
  • In this build (Polars 1.18), read_parquet() and write_parquet() raise AttributeError, and pl.scan_csv(...).collect() stops with a PanicException. Use pl.read_csv() followed by .lazy(), as above, and DuckDB for Parquet files.
  • to_pandas() needs pandas and pyarrow, and Polars looks for them only when it is first imported. After the example has run, importing them still leaves to_pandas() raising ModuleNotFoundError. Reload the page and import pandas, pyarrow and then polars in your first cell.