Create your first Python project with pixi
This tutorial builds a weather data analysis tool that reads CSV data, computes statistics with pandas, and produces a chart with matplotlib. Every dependency comes from conda-forge and is managed by pixi.
Prerequisites
Install pixi following the official installation instructions. No separate Python install is required.
Create the project
pixi init weather_analysis
cd weather_analysisThis creates a directory with a pixi.toml file that stores project metadata, dependencies, and task definitions:
[workspace]
name = "weather_analysis"
channels = ["conda-forge"]
platforms = ["osx-arm64"]The channels field tells pixi where to fetch packages. conda-forge is a community-maintained, openly licensed package repository with thousands of scientific Python packages.
The platforms value reflects your current machine. Pixi sets this automatically.
Note
You may also see a pixi.lock file. This lockfile pins the exact version of every package pixi installs. Commit it to version control so collaborators reproduce the same environment.
Add dependencies
pixi add python pandas matplotlibThis does three things:
- Resolves compatible versions of Python, pandas, matplotlib, and all their transitive dependencies from conda-forge.
- Installs everything into a
.pixi/directory inside the project (a project-local environment, not a global one). - Updates
pixi.lockwith the exact versions.
The pixi.toml now includes:
[dependencies]
python = ">=3.13.3,<4"
pandas = ">=2.2.3,<3"
matplotlib = ">=3.10.1,<4"The version bounds reflect whichever releases are current when you run the command.
Tip
The .pixi/ directory contains the full environment (Python interpreter, all packages). It can be large. Add .pixi/ to .gitignore and let collaborators recreate it with pixi install.
Create sample data
Create a data directory and add a CSV file:
mkdir dataCreate data/weather.csv with this content:
date,city,temp_high,temp_low,precipitation_mm,humidity_pct
2025-01-01,Portland,8,2,12.5,82
2025-01-02,Portland,7,1,0.0,65
2025-01-03,Portland,9,3,8.3,78
2025-01-04,Portland,6,-1,15.2,88
2025-01-05,Portland,10,4,0.0,60
2025-01-01,Phoenix,18,5,0.0,25
2025-01-02,Phoenix,20,7,0.0,22
2025-01-03,Phoenix,22,8,0.0,20
2025-01-04,Phoenix,19,6,2.1,35
2025-01-05,Phoenix,21,7,0.0,23Write the analysis script
Create analyze.py:
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from pathlib import Path
matplotlib.use("Agg")
def load_weather_data(path):
df = pd.read_csv(path, parse_dates=["date"])
df["temp_range"] = df["temp_high"] - df["temp_low"]
return df
def summarize_by_city(df):
return df.groupby("city").agg(
avg_high=("temp_high", "mean"),
avg_low=("temp_low", "mean"),
total_precip=("precipitation_mm", "sum"),
avg_humidity=("humidity_pct", "mean"),
).round(1)
def plot_temperature_comparison(df, output_path):
fig, ax = plt.subplots(figsize=(8, 4))
for city, group in df.groupby("city"):
ax.plot(group["date"], group["temp_high"], marker="o", label=f"{city} high")
ax.plot(group["date"], group["temp_low"], marker="s", label=f"{city} low",
linestyle="--", alpha=0.6)
ax.set_ylabel("Temperature (°C)")
ax.set_title("Daily Temperatures by City")
ax.legend()
fig.tight_layout()
fig.savefig(output_path, dpi=150)
print(f"Chart saved to {output_path}")
plt.close(fig)
def main():
data_dir = Path(__file__).parent / "data"
df = load_weather_data(data_dir / "weather.csv")
summary = summarize_by_city(df)
print("Weather Summary by City:")
print(summary)
print()
plot_temperature_comparison(df, data_dir / "temperatures.png")
if __name__ == "__main__":
main()Run the script
pixi run python analyze.pyExpected output:
Weather Summary by City:
avg_high avg_low total_precip avg_humidity
city
Phoenix 20.0 6.6 2.1 25.0
Portland 8.0 1.8 36.0 74.6
Chart saved to data/temperatures.pngpixi run activates the project environment and executes the command. You never need to activate or deactivate environments manually.
Add a named task
Instead of typing pixi run python analyze.py every time, define a task in pixi.toml:
[tasks]
analyze = "python analyze.py"Now run the analysis with:
pixi run analyzeTasks are useful for longer commands, pipelines, and giving collaborators discoverable entry points into the project.
Add a dev dependency and write a test
Add pytest as a dependency:
pixi add pytestCreate test_analyze.py:
import pandas as pd
from analyze import load_weather_data, summarize_by_city
from pathlib import Path
def test_load_weather_data():
path = Path(__file__).parent / "data" / "weather.csv"
df = load_weather_data(path)
assert "temp_range" in df.columns
assert len(df) == 10
def test_summarize_by_city():
df = pd.DataFrame({
"city": ["A", "A", "B"],
"temp_high": [20, 22, 10],
"temp_low": [10, 12, 5],
"precipitation_mm": [0.0, 5.0, 10.0],
"humidity_pct": [50, 60, 70],
})
summary = summarize_by_city(df)
assert summary.loc["A", "avg_high"] == 21.0
assert summary.loc["B", "total_precip"] == 10.0Add a test task and run it:
[tasks]
analyze = "python analyze.py"
test = "pytest"pixi run testFinal project structure
-
- pixi.toml
- pixi.lock
- analyze.py
- test_analyze.py
- .gitignore
-
- weather.csv
-
Commit pixi.toml, pixi.lock, your source files, and data. The .pixi/ directory is local and should stay in .gitignore.
Next steps
- Take Over an Existing Conda Environment to learn how conda works when you inherit a project
- pixi reference for a full overview of pixi’s features
- When Should I Choose pixi Over uv? for guidance on picking the right tool
- uv vs pixi vs conda for Scientific Python for a detailed comparison