seaborn: a brief introduction

Author

Marie-Hélène Burle

seaborn, at its core, is a statistical visualization library for tabular data[1]. It is based on matplotlib, but its higher-level, declarative, and easy interface makes it ideal for exploratory data analysis (EDA). It comes with demo datasets and statistical tools.

Getting data

seaborn comes with a number of datasets used in its documentation. They are convenient to play with the library. In this section however, we use snow survey data for the province of British Columbia (Canada). I am interested in assessing whether global warming is causing a decrease in the snowpack height in this part of the world.

The data is tabular and stored in a CSV file. We read it into a Polars DataFrame:

import polars as pl

file_path = "/project/def-sponsor00/data/allmss_archive.csv"

Troubleshooting data reading

As we saw earlier, you read tabular data in a Polars DataFrame with:

df = pl.read_csv(file_path)

However, here, we get the following error:

ComputeError: could not parse `35.0` as dtype `i64` at column ' Snow Depth cm' (column number 5)

With, conveniently, the following suggestions:

You might want to try:
- increasing `infer_schema_length` (e.g. `infer_schema_length=10000`),
- specifying correct dtype with the `schema_overrides` argument
- setting `ignore_errors` to `True`,
- adding `35.0` to the `null_values` list.n

If you want to be sure to read the data without error, you can use ignore_errors=True, but this will drop the problematic rows and you will loose data. This is the solution of last resort.

A better solution here is to set the schema for the problematic variable manually:

df = pl.read_csv(file_path, schema_overrides={" Snow Depth cm": pl.Float64})

But oops. We now get the following error:

ComputeError: could not parse `760.0` as dtype `i64` at column ' Water Equiv. mm' (column number 6)

Your turn:

Fix the new problem to read in the data.

Data exploration and transformation

Here is our DataFrame:

print(df)
shape: (60_265, 10)
┌──────────────┬─────────┬────────┬─────────────┬───┬─────────┬─────────────┬─────────────┬────────┐
│ Snow Course  ┆  Number ┆ Elev.  ┆ Date of     ┆ … ┆ Survey  ┆ Snow Line   ┆  Density %  ┆ Survey │
│ Name         ┆ ---     ┆ metres ┆ Survey      ┆   ┆ Code    ┆ Elev. m     ┆ ---         ┆ Period │
│ ---          ┆ str     ┆ ---    ┆ ---         ┆   ┆ ---     ┆ ---         ┆ i64         ┆ ---    │
│ str          ┆         ┆ i64    ┆ str         ┆   ┆ str     ┆ str         ┆             ┆ str    │
╞══════════════╪═════════╪════════╪═════════════╪═══╪═════════╪═════════════╪═════════════╪════════╡
│ YELLOWHEAD   ┆ 1A01    ┆ 1860   ┆ 1951/03/30  ┆ … ┆ null    ┆ null        ┆ 31          ┆ 01-Apr │
│ YELLOWHEAD   ┆ 1A01    ┆ 1860   ┆ 1951/04/30  ┆ … ┆ null    ┆ null        ┆ 33          ┆ 01-May │
│ YELLOWHEAD   ┆ 1A01    ┆ 1860   ┆ 1951/05/19  ┆ … ┆ null    ┆ null        ┆ 36          ┆ 15-May │
│ YELLOWHEAD   ┆ 1A01    ┆ 1860   ┆ 1952/04/30  ┆ … ┆ null    ┆ null        ┆ 33          ┆ 01-May │
│ YELLOWHEAD   ┆ 1A01    ┆ 1860   ┆ 1952/05/19  ┆ … ┆ null    ┆ null        ┆ 33          ┆ 15-May │
│ …            ┆ …       ┆ …      ┆ …           ┆ … ┆ …       ┆ …           ┆ …           ┆ …      │
│ STANLEY      ┆ 4E03    ┆ 930    ┆ 1985/05/16  ┆ … ┆ null    ┆ null        ┆ 37          ┆ 15-May │
│ CREEK        ┆         ┆        ┆             ┆   ┆         ┆             ┆             ┆        │
│ STANLEY      ┆ 4E03    ┆ 930    ┆ 1986/03/02  ┆ … ┆ null    ┆ null        ┆ 23          ┆ 01-Mar │
│ CREEK        ┆         ┆        ┆             ┆   ┆         ┆             ┆             ┆        │
│ STANLEY      ┆ 4E03    ┆ 930    ┆ 1986/04/01  ┆ … ┆ PROBLEM ┆ null        ┆ 27          ┆ 01-Apr │
│ CREEK        ┆         ┆        ┆             ┆   ┆         ┆             ┆             ┆        │
│ STANLEY      ┆ 4E03    ┆ 930    ┆ 1986/05/01  ┆ … ┆ PROBLEM ┆ null        ┆ 33          ┆ 01-May │
│ CREEK        ┆         ┆        ┆             ┆   ┆         ┆             ┆             ┆        │
│ STANLEY      ┆ 4E03    ┆ 930    ┆ 1986/05/15  ┆ … ┆ null    ┆ null        ┆ 34          ┆ 15-May │
│ CREEK        ┆         ┆        ┆             ┆   ┆         ┆             ┆             ┆        │
└──────────────┴─────────┴────────┴─────────────┴───┴─────────┴─────────────┴─────────────┴────────┘

First cleaning

Let’s create a cleaned DataFrame with relevant columns, the date into a proper format, etc.:

snow_data = df.select(
    pl.col("Snow Course Name").str.to_titlecase().alias("station"),
    pl.col(" Elev. metres").alias("elevation"),
    pl.col(" Date of Survey").str.to_date("%Y/%m/%d").alias("date"),
    pl.col(" Snow Depth cm").alias("snow"),
    pl.col(" Water Equiv. mm").alias("water")
)

print(snow_data)
shape: (60_265, 5)
┌───────────────┬───────────┬────────────┬───────┬───────┐
│ station       ┆ elevation ┆ date       ┆ snow  ┆ water │
│ ---           ┆ ---       ┆ ---        ┆ ---   ┆ ---   │
│ str           ┆ i64       ┆ date       ┆ f64   ┆ f64   │
╞═══════════════╪═══════════╪════════════╪═══════╪═══════╡
│ Yellowhead    ┆ 1860      ┆ 1951-03-30 ┆ 168.0 ┆ 528.0 │
│ Yellowhead    ┆ 1860      ┆ 1951-04-30 ┆ 147.0 ┆ 485.0 │
│ Yellowhead    ┆ 1860      ┆ 1951-05-19 ┆ 89.0  ┆ 320.0 │
│ Yellowhead    ┆ 1860      ┆ 1952-04-30 ┆ 157.0 ┆ 523.0 │
│ Yellowhead    ┆ 1860      ┆ 1952-05-19 ┆ 79.0  ┆ 264.0 │
│ …             ┆ …         ┆ …          ┆ …     ┆ …     │
│ Stanley Creek ┆ 930       ┆ 1985-05-16 ┆ 83.0  ┆ 307.0 │
│ Stanley Creek ┆ 930       ┆ 1986-03-02 ┆ 142.0 ┆ 320.0 │
│ Stanley Creek ┆ 930       ┆ 1986-04-01 ┆ 135.0 ┆ 365.0 │
│ Stanley Creek ┆ 930       ┆ 1986-05-01 ┆ 121.0 ┆ 400.0 │
│ Stanley Creek ┆ 930       ┆ 1986-05-15 ┆ 83.0  ┆ 285.0 │
└───────────────┴───────────┴────────────┴───────┴───────┘

We can explore the data a bit:

print(snow_data.columns)
['station', 'elevation', 'date', 'snow', 'water']
snow_data.glimpse()
Rows: 60265
Columns: 5
$ station    <str> 'Yellowhead', 'Yellowhead', 'Yellowhead', 'Yellowhead', 'Yellowhead', 'Yellowhead', 'Yellowhead', 'Yellowhead', 'Yellowhead', 'Yellowhead'
$ elevation  <i64> 1860, 1860, 1860, 1860, 1860, 1860, 1860, 1860, 1860, 1860
$ date      <date> 1951-03-30, 1951-04-30, 1951-05-19, 1952-04-30, 1952-05-19, 1953-04-01, 1953-05-01, 1953-05-15, 1954-04-05, 1954-04-29
$ snow       <f64> 168.0, 147.0, 89.0, 157.0, 79.0, 140.0, 130.0, 91.0, 193.0, 198.0
$ water      <f64> 528.0, 485.0, 320.0, 523.0, 264.0, 404.0, 455.0, 297.0, 564.0, 577.0
print(snow_data.describe())
shape: (9, 6)
┌────────────┬───────────────┬────────────┬────────────────────────────┬────────────┬────────────┐
│ statistic  ┆ station       ┆ elevation  ┆ date                       ┆ snow       ┆ water      │
│ ---        ┆ ---           ┆ ---        ┆ ---                        ┆ ---        ┆ ---        │
│ str        ┆ str           ┆ f64        ┆ str                        ┆ f64        ┆ f64        │
╞════════════╪═══════════════╪════════════╪════════════════════════════╪════════════╪════════════╡
│ count      ┆ 60265         ┆ 60265.0    ┆ 60265                      ┆ 59806.0    ┆ 59801.0    │
│ null_count ┆ 0             ┆ 0.0        ┆ 0                          ┆ 459.0      ┆ 464.0      │
│ mean       ┆ null          ┆ 1363.41369 ┆ 1989-10-21 01:30:49.371940 ┆ 118.480019 ┆ 428.141503 │
│ std        ┆ null          ┆ 402.853802 ┆ null                       ┆ 94.081751  ┆ 415.776042 │
│ min        ┆ Aberdeen Lake ┆ 0.0        ┆ 1935-03-22                 ┆ 0.0        ┆ 0.0        │
│ 25%        ┆ null          ┆ 1100.0     ┆ 1976-04-28                 ┆ 52.0       ┆ 136.0      │
│ 50%        ┆ null          ┆ 1400.0     ┆ 1989-01-01                 ┆ 98.0       ┆ 300.0      │
│ 75%        ┆ null          ┆ 1660.0     ┆ 2004-02-25                 ┆ 165.0      ┆ 599.0      │
│ max        ┆ Yellowhead    ┆ 2230.0     ┆ 2026-02-04                 ┆ 806.0      ┆ 3845.0     │
└────────────┴───────────────┴────────────┴────────────────────────────┴────────────┴────────────┘
n_stations = snow_data.select(pl.col("station")).n_unique()
print(f"There are {n_stations} stations.")
There are 364 stations.
list_stations = snow_data.get_column("station").unique().to_list()
print(list_stations)
['Sinclair Pass', 'Trout Creek West', 'Fort St. John Airport', 'Eaglenest Creek', 'Fish Lake No. 2', 'Mckendrick Creek', 'Mount Assiniboine', 'Dickson Lake', 'Cook Forks', 'Ottomite', 'Watam Lake', 'Burns Lake', 'Bralorne', 'Trapping Creek (Lower)', 'Bluff Creek', 'Toba River', 'Fidelity Mountain', 'Duncan Lake', 'Bouleau Creek', 'Forbidden Plateau', 'Snippaker Creek', 'Cassiar', 'Whistler Mountain', 'Deadwood River', 'Esperon Creek Middle', 'Elk River', 'Beatton River', 'Forrest Kerr Creek', 'Bear Creek Reservoir', 'Whiterocks Mountain', 'Boundary', 'Marble Canyon', 'Brookmere', 'Coquitlam Lake', 'Nechako', 'Bralorne (Upper)', 'Kinaskan Lake', 'Mount Timothy', 'Puntzi Mountain', 'Koch Creek', 'Palisade Lake', 'Carmi', 'Carrs Landing (Upper)', 'Dome Mountain', 'Whatshan Lower', 'Missezula Mountain', 'Sullivan Mine', 'Portage Mountain', 'Esperon Creek Lower', 'Whatshan Upper', 'Kimberley (Upper) Vor', 'Mackenzie Airport', 'Old Glory Mountain', 'Mount Sheba', 'Vermilion River No.1', 'Wolf River Middle', 'Nahatlatch River', 'Big White Mountain', 'Wolf River Upper', 'French Snowshoe', 'Knouff Lake', 'Canoe River', 'New Glacier', 'Duffey Lake', 'Revolution Creek', 'East Creek', 'Germansen Upper', 'Alouette Lake', 'Thunder Creek', 'Nazko', 'Azure River', 'Red Chris Mine Lower', 'Pulpit Lake', 'Boston Bar Creek (Lower)', 'Tutizzi Lake', 'Mount Copeland', 'Islaht Lake', 'Grayling River', 'Shovelnose Mountain', 'Adams River', 'Hollyburn', 'Blackwater Lookout', 'Sandon', 'Tiedemann Glacier', 'Glacier', 'Conant Lake', 'Kostal Lake', 'Mount Revelstoke', 'Ferguson', 'Klesilkwa', 'Great Bear', 'Forfar Creek (Upper)', 'Kimberley', 'Heather Mountain', 'Nickel Plate', 'Terrace Airport', 'Chapman Creek', 'Holmes River', 'Porcupine Ridge', 'Pearson Creek', 'Kimberley (Middle)Vor', 'Mcbride Lower', 'Upper Stave River', 'Sproat Lake', 'Lu Lake', 'Sunbeam Lake', 'Dease Lake', 'Purcell', 'Chapman Lake', 'Tatlayoko Lake', 'Morrissey Ridge', 'Vermilion River No.4', 'Kaza Lake', 'Upper Thelwood Lake', 'Missinka River', 'Kemess Creek Lower', 'Aberdeen Lake', 'Mount Wells', 'Mount Abbot', 'Newcastle Ridge', 'Pavilion', 'St. Leon Creek', 'Park Mountain', 'Invermere', 'Postill Lake Upper', 'Memory Lake', 'New Tashme', 'Bugaboo Creek', 'Shalalth', 'Pink Mountain', 'Germansen Lower', 'Downton Lake Upper', 'Hamilton Hill', 'Nelson', 'Esperon Creek Upper', 'Trapping Creek', 'Bluejoint Mountain', 'Wolf River Lower', 'Smithers', 'Tahtsa Lake', 'Postill Lake', 'Skins Lake', 'Beaverfoot', 'Gerrard', 'Upper Quinsam', 'Cypress Lake', 'Blue River', 'Bigmouth Creek', 'Mcqueen Lake', 'Pacific Lake', 'Bouleau Lake', 'Margaret Lake', 'Nutli Lake', 'Philip Lake', 'Hourglass', 'Red Chris Mine Upper', 'Deadman River', 'June Lake', 'Mount Cronin', 'Kwadacha River', 'Hansard', 'Gray Creek Upper', 'Horsefly Mountain', 'Penfold Creek', 'Vermilion River No.5', 'Stanley Creek', 'Blue River Town', 'Pondosy Lake', 'Pass Lake', 'Lost Ledge', 'Sumallo River West', 'Lost Horse Mountain', 'Sukunka River', 'Ware (Lower)', 'Wolverine Creek', 'Mount Kobau', 'Powell River Upper', 'Bush River', 'Mcleod Lake', 'Pavilion Mtn.', 'Mica Creek', 'Alligator Meadows', 'Wonowon', 'Morfee Mountain', 'Whitesail Lake', 'Frog River', 'Trout Creek', 'Blackwater Creek', 'Fish Lake', 'Vermilion River No. 3', 'Wahleach Lake', 'Sno-Bird Lake', 'Tumeka Creek', 'Pennask Creek', 'Macdonald Lake', 'Brenda Mine', 'Knudsen Lake', 'Farron', 'Fredrickson Lake', 'Kidprice Lake', 'Schaft Creek', 'Ningunsaw Pass', 'Mount Roosevelt', 'Mount Cokely', 'Sikanni Lake', 'Keystone Creek', 'Longworth Lower', 'Loch Lomond', 'Edwards Lake', 'Bowron Lake', 'Black Mountain', 'Anglemont', 'Longworth Upper', 'Mount Albreda', 'Tennent Lake', 'Tahltan Lake', 'Labour Day Lake', 'Mount Penrose', 'Fernie East', 'Johanson Lake', 'Kimberley (Lower) Vor', 'Bullhead Mountain', 'Summerland Reservoir', 'Wedeene River South', 'Orchid Lake', 'Mount Cook', 'Precipice', 'Grouse Mountain', 'Granduc Mine', 'Hedrick Lake', 'Mount Stearns', 'Isintok Lake', 'Tenquille Lake', 'Tachek Creek', 'Log Cabin', 'Silver Star Mountain', 'Trophy Mountain', 'Kicking Horse', 'Downie Slide Lower', 'Duncan Lake No. 2', 'Burman Lake', 'Fernie', 'Cornwall Hills', 'Trapping Creek (Upper)', 'Trygve Lake', 'Dog Mountain', 'Revelstoke', 'Trout River', 'Vermont Creek', 'Highland Valley', 'Callaghan Creek', 'Bonaparte Lake', 'Tsaydaychi Lake', 'Humamilt Lake', 'Braden River', 'Powell River', 'Equity Mine', 'Moyie Mountain', 'Rabbit River', 'Blackhawk', 'Kinbasket Lake', 'Oyama Lake', 'Blackwall Peak', 'Sumallo River', 'Tranquille Lake', 'Powell River Lower', 'Gray Creek Lower', 'Jade City', 'Wade Lake', 'Ware (Upper)', 'Atlin Lake', 'Mcgillivray Pass', 'Burwell Lake', 'Kluachesi Lake', 'Torpy River', 'Lac Le Jeune Lower', 'Upper Stikine', 'Mission Creek', 'Tripp Meadows', 'Monkman Creek', 'Gnawed Mountain', 'Bird Creek', 'Bridge Glacier Lower', 'Fort Nelson Airport', 'Field', 'Mount Joffre', 'Mount Swannell', 'Garibaldi Lake', 'Arrow Creek', 'Haddo Lake', 'North Clemina Creek', 'Lac Le Jeune Upper', 'Fort St. James', 'Ipec Lake', 'Prince George Airport', 'Spahomin', 'Downie Site 8', 'Goldstream', 'Telegraph Creek', 'Mount Seymour', 'Vaseux Creek', 'Vermilion River No.2', 'Char Creek', 'Kirbyville Lake', 'Kemess Creek Upper', 'Fernie Ridge', 'Yanks Peak', 'Graystoke Lake', 'Monashee Pass', 'Diamond Head', 'Hope', 'Greyback Reservoir', 'Bear Pass', 'Heather Mountain Upper', 'Link Lake', 'Mount Templeman', 'Boston Bar Creek (Upper)', 'Boss Mountain Mine', 'Summit Lake', 'Iskut', 'Lytton', 'Tashme', 'Steelhead', 'Floe Lake', 'Lady Laurier Lake', 'Meadow Mountain', 'Toad River', 'Hudson Bay Mountain', 'Narrow Lake', 'Bella Coola', 'Fernie (Ne)', 'Machmell River', 'Mackenzie Airport Manual Snow Course (2003)', 'Triumph Creek', 'Mount Saint Anne', 'Middle River', 'Mcbride Upper', 'Lyford Mountain', 'Tyaughton Creek (North)', 'Barkerville', 'Barnes Creek', 'Carrs Landing (Lower)', 'Pine Pass', 'Mcculloch', 'Yellowhead', 'Harry Lake', 'Disappointment Lake', 'Bullmoose Creek', 'Green Mountain', 'Big Creek', 'Harlow Creek', 'Enderby', 'Stave Lake', 'Downie Slide Upper', 'Lightning Lake', 'Copper Mountain', 'Nostetuko River', 'Mcbride Middle', 'Granite Mountain', 'Caverhill Lake New', 'Record Mountain', 'Upper Elk River', 'Wedeene River', 'Sunday Summit']

Stations selection

Let’s select subsets of snow pillow stations located in the Southern Coastal Mountains of British Columbia. They exclude stations in the Interior (Okanagan, Kamloops, Kootenays, Cariboo, Rockies, Columbias) and Northern BC. This is where a decrease in snowpack due to global warming is the most likely to be detectable since the temperatures are not very cold and a few degrees of warming is enough to go from snow to rain.

I used Gemini 3 to split the list of stations into mountain ranges. This was very convenient since the data doesn’t include coordinates (that would have allowed to filter by latitude and longitude) nor information about the location of the stations.

# Vancouver Island Ranges:
island_stations = [
    "Burman Lake", "Dickson Lake", "East Creek", "Forbidden Plateau", "Green Mountain",
    "Heather Mountain", "Heather Mountain Upper", "June Lake", "Labour Day Lake",
    "Loch Lomond", "Lyford Mountain", "Mount Cokely", "Mount Wells", "Newcastle Ridge",
    "Sproat Lake", "Tennent Lake", "Upper Quinsam", "Upper Thelwood Lake",
    "Wolf River Lower", "Wolf River Middle", "Wolf River Upper"
]

# Lower Mainland & Fraser Valley:
vancouver_stations = [
    "Alouette Lake", "Black Mountain (Cypress Provincial Park)", "Burwell Lake (North Shore)",
    "Coquitlam Lake", "Dog Mountain (Mount Seymour)", "Grouse Mountain", "Hollyburn", "Hope",
    "Mount Saint Anne (Sunshine Coast/Sechelt)", "Mount Seymour",
    "Orchid Lake (Stave/Lower Mainland)", "Palisade Lake (Capilano Watershed)",
    "Stave Lake", "Steelhead", "Upper Stave River", "Wahleach Lake"
]

# Sea-to-Sky, Garibaldi & Bridge River:
s2s_stations = [
    "Bralorne", "Bralorne (Upper)", "Bridge Glacier Lower", "Callaghan Creek", "Diamond Head",
    "Downton Lake Upper", "Duffey Lake", "Garibaldi Lake", "McGillivray Pass", "Mount Cook",
    "Mount Penrose", "Mount Sheba", "Powell River", "Powell River Lower", "Powell River Upper",
    "Shalalth", "Shovelnose Mountain", "Tenquille Lake", "Toba River",
    "Tyaughton Creek (North)", "Whistler Mountain"
]

# Cascades & Coquihalla (Southern Border Ranges):
cascades_stations = [
    "Blackwall Peak", "Boston Bar Creek (Lower)", "Boston Bar Creek (Upper)", "Great Bear",
    "Klesilkwa", "Lightning Lake", "Nahatlatch River", "New Tashme", "Sumallo River",
    "Sumallo River West", "Sunday Summit", "Tashme"
]

Now we can filter the data for all these stations:

selected_data = snow_data.filter(
    pl.col("station").is_in(
        island_stations + vancouver_stations + s2s_stations + cascades_stations
    )
).with_columns(
    pl.when(pl.col("station").is_in(island_stations)).then(pl.lit("Vancouver Island"))
    .when(pl.col("station").is_in(vancouver_stations)).then(pl.lit("Lower Mainland"))
    .when(pl.col("station").is_in(s2s_stations)).then(pl.lit("Sea to Sky"))
    .otherwise(pl.lit("Cascades"))
    .alias("range")
)

Convert to seasons

Snow pillow data go from October 1st of one year to September 30th of the following year. Let’s add a season column:

season_data = selected_data.with_columns(
    pl.col("date").dt.offset_by("3mo").dt.year().alias("season")
)

print(season_data)
shape: (8_867, 7)
┌─────────────┬───────────┬────────────┬───────┬───────┬──────────────────┬────────┐
│ station     ┆ elevation ┆ date       ┆ snow  ┆ water ┆ range            ┆ season │
│ ---         ┆ ---       ┆ ---        ┆ ---   ┆ ---   ┆ ---              ┆ ---    │
│ str         ┆ i64       ┆ date       ┆ f64   ┆ f64   ┆ str              ┆ i32    │
╞═════════════╪═══════════╪════════════╪═══════╪═══════╪══════════════════╪════════╡
│ Mount Wells ┆ 1490      ┆ 1952-02-29 ┆ 127.0 ┆ 358.0 ┆ Vancouver Island ┆ 1952   │
│ Mount Wells ┆ 1490      ┆ 1953-02-26 ┆ 127.0 ┆ 371.0 ┆ Vancouver Island ┆ 1953   │
│ Mount Wells ┆ 1490      ┆ 1953-04-02 ┆ 117.0 ┆ 376.0 ┆ Vancouver Island ┆ 1953   │
│ Mount Wells ┆ 1490      ┆ 1953-05-06 ┆ 122.0 ┆ 411.0 ┆ Vancouver Island ┆ 1953   │
│ Mount Wells ┆ 1490      ┆ 1954-03-02 ┆ 185.0 ┆ 577.0 ┆ Vancouver Island ┆ 1954   │
│ …           ┆ …         ┆ …          ┆ …     ┆ …     ┆ …                ┆ …      │
│ Mount Sheba ┆ 1490      ┆ 2022-12-30 ┆ 112.0 ┆ 301.0 ┆ Sea to Sky       ┆ 2023   │
│ Mount Sheba ┆ 1490      ┆ 2023-02-01 ┆ null  ┆ null  ┆ Sea to Sky       ┆ 2023   │
│ Mount Sheba ┆ 1490      ┆ 2023-02-28 ┆ 225.0 ┆ 715.0 ┆ Sea to Sky       ┆ 2023   │
│ Mount Sheba ┆ 1490      ┆ 2023-03-30 ┆ 206.0 ┆ 794.0 ┆ Sea to Sky       ┆ 2023   │
│ Mount Sheba ┆ 1490      ┆ 2023-04-28 ┆ 208.0 ┆ 853.0 ┆ Sea to Sky       ┆ 2023   │
└─────────────┴───────────┴────────────┴───────┴───────┴──────────────────┴────────┘

Select balanced panel

Our data is in long format. It is the format we want for plotting and analyses. The wide format has use cases too. For instance, it allows to easily see whether data was collected for all stations at all times.

polars.DataFrame.pivot turns a long-format DataFrame to a wide-format one:

stations_years = season_data.pivot(
    "season",
    index="station",
    values="snow",
    sort_columns=True,
    aggregate_function="mean"
)

print(stations_years)
shape: (63, 93)
┌────────────────────┬──────┬──────┬──────┬───┬───────────┬───────────┬───────────┬───────┐
│ station            ┆ 1935 ┆ 1936 ┆ 1937 ┆ … ┆ 2023      ┆ 2024      ┆ 2025      ┆ 2026  │
│ ---                ┆ ---  ┆ ---  ┆ ---  ┆   ┆ ---       ┆ ---       ┆ ---       ┆ ---   │
│ str                ┆ f64  ┆ f64  ┆ f64  ┆   ┆ f64       ┆ f64       ┆ f64       ┆ f64   │
╞════════════════════╪══════╪══════╪══════╪═══╪═══════════╪═══════════╪═══════════╪═══════╡
│ Mount Wells        ┆ null ┆ null ┆ null ┆ … ┆ 107.0     ┆ 84.0      ┆ 78.8      ┆ 123.0 │
│ Mount Penrose      ┆ null ┆ null ┆ null ┆ … ┆ null      ┆ null      ┆ null      ┆ null  │
│ Green Mountain     ┆ null ┆ null ┆ null ┆ … ┆ null      ┆ null      ┆ null      ┆ null  │
│ Bralorne           ┆ null ┆ null ┆ null ┆ … ┆ 45.0      ┆ 34.0      ┆ null      ┆ null  │
│ Shalalth           ┆ null ┆ null ┆ null ┆ … ┆ null      ┆ null      ┆ null      ┆ null  │
│ …                  ┆ …    ┆ …    ┆ …    ┆ … ┆ …         ┆ …         ┆ …         ┆ …     │
│ Sumallo River      ┆ null ┆ null ┆ null ┆ … ┆ null      ┆ null      ┆ null      ┆ null  │
│ Sumallo River West ┆ null ┆ null ┆ null ┆ … ┆ 30.25     ┆ 4.25      ┆ 0.0       ┆ 28.0  │
│ Lightning Lake     ┆ null ┆ null ┆ null ┆ … ┆ 71.333333 ┆ 51.666667 ┆ 33.333333 ┆ null  │
│ Klesilkwa          ┆ null ┆ null ┆ null ┆ … ┆ 31.0      ┆ 5.6       ┆ 9.2       ┆ 35.0  │
│ Mount Sheba        ┆ null ┆ null ┆ null ┆ … ┆ 187.75    ┆ null      ┆ null      ┆ null  │
└────────────────────┴──────┴──────┴──────┴───┴───────────┴───────────┴───────────┴───────┘

This clearly shows that the data was not collected on all stations for all years. If we want to see trends over time, this is not good, particularly since not all stations are at the same elevation (if early years mostly had low elevations stations and recent years have more stations in the alpine, we would get a totally fake signal).

We need to select a period and a set of stations that are monitored throughout that period. This is called a balanced panel.

Let’s define a function that returns the number of stations that have data collected for each season between 2 particular seasons:

def n_valid_in_period(df, period_start, period_end):
    test_seasons = range(period_start, period_end + 1)

    # Filter data for the test seasons
    test_seasons_subset = df.filter(pl.col("season").is_in(test_seasons))

    # Count seasons per station
    station_counts = test_seasons_subset.group_by("station").agg(
        pl.col("season").n_unique().alias("n_seasons")
    )

    # Filter stations with data for all test seasons
    valid_stations = station_counts.filter(pl.col("n_seasons") == len(test_seasons))

    n_valid = len(valid_stations)

    return n_valid, period_start, period_end

We can test our function:

print(n_valid_in_period(season_data, 1998, 2001))
(29, 1998, 2001)

This means that 29 stations have data collected every season between 1998 and 2001.

Now we need to know the earliest and latest seasons in our dataset:

seasons = season_data.select(pl.col("season"))
min_season = seasons.min().item()
max_season = seasons.max().item()
print(f"Seasons range: {min_season} to {max_season}")
Seasons range: 1935 to 2026

We can create a list the number of stations present in the whole period for each period spanning at least 10 seasons:

list_n_valid = []

for i in range(min_season, max_season + 1):
    for j in range(min_season, max_season + 1):
        if j - i > 9:         # we want a period of at least 10 seasons
            list_n_valid.append(n_valid_in_period(season_data, i, j))

We want at least 5 stations, so let’s clean the list from all n_valid < 5:

selected_list_n_valid = [i for i in list_n_valid if i[0] >= 5]

print(selected_list_n_valid)
[(5, 1947, 1957), (5, 1947, 1958), (5, 1947, 1959), (5, 1947, 1960), (5, 1947, 1961), (5, 1947, 1962), (5, 1947, 1963), (5, 1947, 1964), (5, 1947, 1965), (5, 1947, 1966), (5, 1947, 1967), (5, 1947, 1968), (5, 1947, 1969), (5, 1947, 1970), (5, 1947, 1971), (5, 1947, 1972), (5, 1947, 1973), (5, 1947, 1974), (5, 1947, 1975), (5, 1947, 1976), (5, 1947, 1977), (5, 1947, 1978), (5, 1947, 1979), (5, 1947, 1980), (5, 1947, 1981), (5, 1947, 1982), (5, 1947, 1983), (5, 1947, 1984), (5, 1948, 1958), (5, 1948, 1959), (5, 1948, 1960), (5, 1948, 1961), (5, 1948, 1962), (5, 1948, 1963), (5, 1948, 1964), (5, 1948, 1965), (5, 1948, 1966), (5, 1948, 1967), (5, 1948, 1968), (5, 1948, 1969), (5, 1948, 1970), (5, 1948, 1971), (5, 1948, 1972), (5, 1948, 1973), (5, 1948, 1974), (5, 1948, 1975), (5, 1948, 1976), (5, 1948, 1977), (5, 1948, 1978), (5, 1948, 1979), (5, 1948, 1980), (5, 1948, 1981), (5, 1948, 1982), (5, 1948, 1983), (5, 1948, 1984), (5, 1949, 1959), (5, 1949, 1960), (5, 1949, 1961), (5, 1949, 1962), (5, 1949, 1963), (5, 1949, 1964), (5, 1949, 1965), (5, 1949, 1966), (5, 1949, 1967), (5, 1949, 1968), (5, 1949, 1969), (5, 1949, 1970), (5, 1949, 1971), (5, 1949, 1972), (5, 1949, 1973), (5, 1949, 1974), (5, 1949, 1975), (5, 1949, 1976), (5, 1949, 1977), (5, 1949, 1978), (5, 1949, 1979), (5, 1949, 1980), (5, 1949, 1981), (5, 1949, 1982), (5, 1949, 1983), (5, 1949, 1984), (6, 1950, 1960), (6, 1950, 1961), (6, 1950, 1962), (6, 1950, 1963), (6, 1950, 1964), (6, 1950, 1965), (6, 1950, 1966), (6, 1950, 1967), (6, 1950, 1968), (6, 1950, 1969), (6, 1950, 1970), (6, 1950, 1971), (6, 1950, 1972), (5, 1950, 1973), (5, 1950, 1974), (5, 1950, 1975), (5, 1950, 1976), (5, 1950, 1977), (5, 1950, 1978), (5, 1950, 1979), (5, 1950, 1980), (5, 1950, 1981), (5, 1950, 1982), (5, 1950, 1983), (5, 1950, 1984), (6, 1951, 1961), (6, 1951, 1962), (6, 1951, 1963), (6, 1951, 1964), (6, 1951, 1965), (6, 1951, 1966), (6, 1951, 1967), (6, 1951, 1968), (6, 1951, 1969), (6, 1951, 1970), (6, 1951, 1971), (6, 1951, 1972), (5, 1951, 1973), (5, 1951, 1974), (5, 1951, 1975), (5, 1951, 1976), (5, 1951, 1977), (5, 1951, 1978), (5, 1951, 1979), (5, 1951, 1980), (5, 1951, 1981), (5, 1951, 1982), (5, 1951, 1983), (5, 1951, 1984), (7, 1952, 1962), (7, 1952, 1963), (7, 1952, 1964), (7, 1952, 1965), (7, 1952, 1966), (7, 1952, 1967), (7, 1952, 1968), (7, 1952, 1969), (7, 1952, 1970), (7, 1952, 1971), (7, 1952, 1972), (6, 1952, 1973), (6, 1952, 1974), (6, 1952, 1975), (6, 1952, 1976), (6, 1952, 1977), (6, 1952, 1978), (6, 1952, 1979), (6, 1952, 1980), (6, 1952, 1981), (6, 1952, 1982), (6, 1952, 1983), (6, 1952, 1984), (5, 1952, 1985), (5, 1952, 1986), (5, 1952, 1987), (9, 1953, 1963), (9, 1953, 1964), (8, 1953, 1965), (8, 1953, 1966), (8, 1953, 1967), (8, 1953, 1968), (8, 1953, 1969), (8, 1953, 1970), (8, 1953, 1971), (8, 1953, 1972), (7, 1953, 1973), (7, 1953, 1974), (7, 1953, 1975), (7, 1953, 1976), (7, 1953, 1977), (7, 1953, 1978), (7, 1953, 1979), (7, 1953, 1980), (7, 1953, 1981), (7, 1953, 1982), (7, 1953, 1983), (7, 1953, 1984), (6, 1953, 1985), (6, 1953, 1986), (6, 1953, 1987), (5, 1953, 1988), (5, 1953, 1989), (5, 1953, 1990), (5, 1953, 1991), (5, 1953, 1992), (5, 1953, 1993), (5, 1953, 1994), (5, 1953, 1995), (5, 1953, 1996), (5, 1953, 1997), (5, 1953, 1998), (5, 1953, 1999), (5, 1953, 2000), (5, 1953, 2001), (5, 1953, 2002), (5, 1953, 2003), (5, 1953, 2004), (5, 1953, 2005), (11, 1954, 1964), (10, 1954, 1965), (10, 1954, 1966), (9, 1954, 1967), (9, 1954, 1968), (9, 1954, 1969), (9, 1954, 1970), (9, 1954, 1971), (9, 1954, 1972), (8, 1954, 1973), (8, 1954, 1974), (8, 1954, 1975), (8, 1954, 1976), (8, 1954, 1977), (8, 1954, 1978), (8, 1954, 1979), (8, 1954, 1980), (8, 1954, 1981), (8, 1954, 1982), (8, 1954, 1983), (8, 1954, 1984), (7, 1954, 1985), (7, 1954, 1986), (7, 1954, 1987), (6, 1954, 1988), (6, 1954, 1989), (6, 1954, 1990), (6, 1954, 1991), (6, 1954, 1992), (6, 1954, 1993), (6, 1954, 1994), (6, 1954, 1995), (6, 1954, 1996), (6, 1954, 1997), (6, 1954, 1998), (6, 1954, 1999), (6, 1954, 2000), (6, 1954, 2001), (6, 1954, 2002), (6, 1954, 2003), (6, 1954, 2004), (6, 1954, 2005), (5, 1954, 2006), (5, 1954, 2007), (5, 1954, 2008), (5, 1954, 2009), (5, 1954, 2010), (5, 1954, 2011), (5, 1954, 2012), (5, 1954, 2013), (5, 1954, 2014), (5, 1954, 2015), (5, 1954, 2016), (5, 1954, 2017), (5, 1954, 2018), (5, 1954, 2019), (5, 1954, 2020), (5, 1954, 2021), (5, 1954, 2022), (5, 1954, 2023), (5, 1954, 2024), (5, 1954, 2025), (10, 1955, 1965), (10, 1955, 1966), (9, 1955, 1967), (9, 1955, 1968), (9, 1955, 1969), (9, 1955, 1970), (9, 1955, 1971), (9, 1955, 1972), (8, 1955, 1973), (8, 1955, 1974), (8, 1955, 1975), (8, 1955, 1976), (8, 1955, 1977), (8, 1955, 1978), (8, 1955, 1979), (8, 1955, 1980), (8, 1955, 1981), (8, 1955, 1982), (8, 1955, 1983), (8, 1955, 1984), (7, 1955, 1985), (7, 1955, 1986), (7, 1955, 1987), (6, 1955, 1988), (6, 1955, 1989), (6, 1955, 1990), (6, 1955, 1991), (6, 1955, 1992), (6, 1955, 1993), (6, 1955, 1994), (6, 1955, 1995), (6, 1955, 1996), (6, 1955, 1997), (6, 1955, 1998), (6, 1955, 1999), (6, 1955, 2000), (6, 1955, 2001), (6, 1955, 2002), (6, 1955, 2003), (6, 1955, 2004), (6, 1955, 2005), (5, 1955, 2006), (5, 1955, 2007), (5, 1955, 2008), (5, 1955, 2009), (5, 1955, 2010), (5, 1955, 2011), (5, 1955, 2012), (5, 1955, 2013), (5, 1955, 2014), (5, 1955, 2015), (5, 1955, 2016), (5, 1955, 2017), (5, 1955, 2018), (5, 1955, 2019), (5, 1955, 2020), (5, 1955, 2021), (5, 1955, 2022), (5, 1955, 2023), (5, 1955, 2024), (5, 1955, 2025), (10, 1956, 1966), (9, 1956, 1967), (9, 1956, 1968), (9, 1956, 1969), (9, 1956, 1970), (9, 1956, 1971), (9, 1956, 1972), (8, 1956, 1973), (8, 1956, 1974), (8, 1956, 1975), (8, 1956, 1976), (8, 1956, 1977), (8, 1956, 1978), (8, 1956, 1979), (8, 1956, 1980), (8, 1956, 1981), (8, 1956, 1982), (8, 1956, 1983), (8, 1956, 1984), (7, 1956, 1985), (7, 1956, 1986), (7, 1956, 1987), (6, 1956, 1988), (6, 1956, 1989), (6, 1956, 1990), (6, 1956, 1991), (6, 1956, 1992), (6, 1956, 1993), (6, 1956, 1994), (6, 1956, 1995), (6, 1956, 1996), (6, 1956, 1997), (6, 1956, 1998), (6, 1956, 1999), (6, 1956, 2000), (6, 1956, 2001), (6, 1956, 2002), (6, 1956, 2003), (6, 1956, 2004), (6, 1956, 2005), (5, 1956, 2006), (5, 1956, 2007), (5, 1956, 2008), (5, 1956, 2009), (5, 1956, 2010), (5, 1956, 2011), (5, 1956, 2012), (5, 1956, 2013), (5, 1956, 2014), (5, 1956, 2015), (5, 1956, 2016), (5, 1956, 2017), (5, 1956, 2018), (5, 1956, 2019), (5, 1956, 2020), (5, 1956, 2021), (5, 1956, 2022), (5, 1956, 2023), (5, 1956, 2024), (5, 1956, 2025), (9, 1957, 1967), (9, 1957, 1968), (9, 1957, 1969), (9, 1957, 1970), (9, 1957, 1971), (9, 1957, 1972), (8, 1957, 1973), (8, 1957, 1974), (8, 1957, 1975), (8, 1957, 1976), (8, 1957, 1977), (8, 1957, 1978), (8, 1957, 1979), (8, 1957, 1980), (8, 1957, 1981), (8, 1957, 1982), (8, 1957, 1983), (8, 1957, 1984), (7, 1957, 1985), (7, 1957, 1986), (7, 1957, 1987), (6, 1957, 1988), (6, 1957, 1989), (6, 1957, 1990), (6, 1957, 1991), (6, 1957, 1992), (6, 1957, 1993), (6, 1957, 1994), (6, 1957, 1995), (6, 1957, 1996), (6, 1957, 1997), (6, 1957, 1998), (6, 1957, 1999), (6, 1957, 2000), (6, 1957, 2001), (6, 1957, 2002), (6, 1957, 2003), (6, 1957, 2004), (6, 1957, 2005), (5, 1957, 2006), (5, 1957, 2007), (5, 1957, 2008), (5, 1957, 2009), (5, 1957, 2010), (5, 1957, 2011), (5, 1957, 2012), (5, 1957, 2013), (5, 1957, 2014), (5, 1957, 2015), (5, 1957, 2016), (5, 1957, 2017), (5, 1957, 2018), (5, 1957, 2019), (5, 1957, 2020), (5, 1957, 2021), (5, 1957, 2022), (5, 1957, 2023), (5, 1957, 2024), (5, 1957, 2025), (11, 1958, 1968), (11, 1958, 1969), (11, 1958, 1970), (11, 1958, 1971), (11, 1958, 1972), (10, 1958, 1973), (10, 1958, 1974), (10, 1958, 1975), (9, 1958, 1976), (9, 1958, 1977), (9, 1958, 1978), (9, 1958, 1979), (9, 1958, 1980), (9, 1958, 1981), (9, 1958, 1982), (9, 1958, 1983), (9, 1958, 1984), (8, 1958, 1985), (8, 1958, 1986), (8, 1958, 1987), (7, 1958, 1988), (7, 1958, 1989), (7, 1958, 1990), (7, 1958, 1991), (7, 1958, 1992), (7, 1958, 1993), (7, 1958, 1994), (7, 1958, 1995), (7, 1958, 1996), (7, 1958, 1997), (7, 1958, 1998), (7, 1958, 1999), (7, 1958, 2000), (7, 1958, 2001), (7, 1958, 2002), (7, 1958, 2003), (7, 1958, 2004), (7, 1958, 2005), (6, 1958, 2006), (6, 1958, 2007), (6, 1958, 2008), (6, 1958, 2009), (6, 1958, 2010), (6, 1958, 2011), (6, 1958, 2012), (6, 1958, 2013), (6, 1958, 2014), (6, 1958, 2015), (6, 1958, 2016), (6, 1958, 2017), (6, 1958, 2018), (6, 1958, 2019), (6, 1958, 2020), (6, 1958, 2021), (6, 1958, 2022), (6, 1958, 2023), (6, 1958, 2024), (6, 1958, 2025), (5, 1958, 2026), (13, 1959, 1969), (13, 1959, 1970), (13, 1959, 1971), (13, 1959, 1972), (12, 1959, 1973), (12, 1959, 1974), (12, 1959, 1975), (11, 1959, 1976), (11, 1959, 1977), (11, 1959, 1978), (11, 1959, 1979), (11, 1959, 1980), (11, 1959, 1981), (11, 1959, 1982), (11, 1959, 1983), (11, 1959, 1984), (10, 1959, 1985), (10, 1959, 1986), (10, 1959, 1987), (9, 1959, 1988), (9, 1959, 1989), (9, 1959, 1990), (9, 1959, 1991), (9, 1959, 1992), (9, 1959, 1993), (9, 1959, 1994), (8, 1959, 1995), (8, 1959, 1996), (7, 1959, 1997), (7, 1959, 1998), (7, 1959, 1999), (7, 1959, 2000), (7, 1959, 2001), (7, 1959, 2002), (7, 1959, 2003), (7, 1959, 2004), (7, 1959, 2005), (6, 1959, 2006), (6, 1959, 2007), (6, 1959, 2008), (6, 1959, 2009), (6, 1959, 2010), (6, 1959, 2011), (6, 1959, 2012), (6, 1959, 2013), (6, 1959, 2014), (6, 1959, 2015), (6, 1959, 2016), (6, 1959, 2017), (6, 1959, 2018), (6, 1959, 2019), (6, 1959, 2020), (6, 1959, 2021), (6, 1959, 2022), (6, 1959, 2023), (6, 1959, 2024), (6, 1959, 2025), (5, 1959, 2026), (15, 1960, 1970), (15, 1960, 1971), (15, 1960, 1972), (14, 1960, 1973), (14, 1960, 1974), (14, 1960, 1975), (13, 1960, 1976), (13, 1960, 1977), (13, 1960, 1978), (13, 1960, 1979), (13, 1960, 1980), (13, 1960, 1981), (13, 1960, 1982), (13, 1960, 1983), (13, 1960, 1984), (12, 1960, 1985), (12, 1960, 1986), (12, 1960, 1987), (11, 1960, 1988), (11, 1960, 1989), (10, 1960, 1990), (10, 1960, 1991), (10, 1960, 1992), (10, 1960, 1993), (10, 1960, 1994), (9, 1960, 1995), (9, 1960, 1996), (8, 1960, 1997), (7, 1960, 1998), (7, 1960, 1999), (7, 1960, 2000), (7, 1960, 2001), (7, 1960, 2002), (7, 1960, 2003), (7, 1960, 2004), (7, 1960, 2005), (6, 1960, 2006), (6, 1960, 2007), (6, 1960, 2008), (6, 1960, 2009), (6, 1960, 2010), (6, 1960, 2011), (6, 1960, 2012), (6, 1960, 2013), (6, 1960, 2014), (6, 1960, 2015), (6, 1960, 2016), (6, 1960, 2017), (6, 1960, 2018), (6, 1960, 2019), (6, 1960, 2020), (6, 1960, 2021), (6, 1960, 2022), (6, 1960, 2023), (6, 1960, 2024), (6, 1960, 2025), (5, 1960, 2026), (16, 1961, 1971), (16, 1961, 1972), (15, 1961, 1973), (15, 1961, 1974), (15, 1961, 1975), (14, 1961, 1976), (14, 1961, 1977), (14, 1961, 1978), (14, 1961, 1979), (14, 1961, 1980), (14, 1961, 1981), (14, 1961, 1982), (14, 1961, 1983), (14, 1961, 1984), (13, 1961, 1985), (13, 1961, 1986), (13, 1961, 1987), (12, 1961, 1988), (12, 1961, 1989), (11, 1961, 1990), (11, 1961, 1991), (11, 1961, 1992), (11, 1961, 1993), (11, 1961, 1994), (10, 1961, 1995), (10, 1961, 1996), (8, 1961, 1997), (7, 1961, 1998), (7, 1961, 1999), (7, 1961, 2000), (7, 1961, 2001), (7, 1961, 2002), (7, 1961, 2003), (7, 1961, 2004), (7, 1961, 2005), (6, 1961, 2006), (6, 1961, 2007), (6, 1961, 2008), (6, 1961, 2009), (6, 1961, 2010), (6, 1961, 2011), (6, 1961, 2012), (6, 1961, 2013), (6, 1961, 2014), (6, 1961, 2015), (6, 1961, 2016), (6, 1961, 2017), (6, 1961, 2018), (6, 1961, 2019), (6, 1961, 2020), (6, 1961, 2021), (6, 1961, 2022), (6, 1961, 2023), (6, 1961, 2024), (6, 1961, 2025), (5, 1961, 2026), (16, 1962, 1972), (15, 1962, 1973), (15, 1962, 1974), (15, 1962, 1975), (14, 1962, 1976), (14, 1962, 1977), (14, 1962, 1978), (14, 1962, 1979), (14, 1962, 1980), (14, 1962, 1981), (14, 1962, 1982), (14, 1962, 1983), (14, 1962, 1984), (13, 1962, 1985), (13, 1962, 1986), (13, 1962, 1987), (12, 1962, 1988), (12, 1962, 1989), (11, 1962, 1990), (11, 1962, 1991), (11, 1962, 1992), (11, 1962, 1993), (11, 1962, 1994), (10, 1962, 1995), (10, 1962, 1996), (8, 1962, 1997), (7, 1962, 1998), (7, 1962, 1999), (7, 1962, 2000), (7, 1962, 2001), (7, 1962, 2002), (7, 1962, 2003), (7, 1962, 2004), (7, 1962, 2005), (6, 1962, 2006), (6, 1962, 2007), (6, 1962, 2008), (6, 1962, 2009), (6, 1962, 2010), (6, 1962, 2011), (6, 1962, 2012), (6, 1962, 2013), (6, 1962, 2014), (6, 1962, 2015), (6, 1962, 2016), (6, 1962, 2017), (6, 1962, 2018), (6, 1962, 2019), (6, 1962, 2020), (6, 1962, 2021), (6, 1962, 2022), (6, 1962, 2023), (6, 1962, 2024), (6, 1962, 2025), (5, 1962, 2026), (16, 1963, 1973), (16, 1963, 1974), (16, 1963, 1975), (15, 1963, 1976), (15, 1963, 1977), (15, 1963, 1978), (15, 1963, 1979), (15, 1963, 1980), (15, 1963, 1981), (15, 1963, 1982), (15, 1963, 1983), (15, 1963, 1984), (14, 1963, 1985), (14, 1963, 1986), (14, 1963, 1987), (13, 1963, 1988), (13, 1963, 1989), (12, 1963, 1990), (12, 1963, 1991), (12, 1963, 1992), (12, 1963, 1993), (12, 1963, 1994), (11, 1963, 1995), (11, 1963, 1996), (9, 1963, 1997), (8, 1963, 1998), (8, 1963, 1999), (8, 1963, 2000), (8, 1963, 2001), (8, 1963, 2002), (8, 1963, 2003), (8, 1963, 2004), (8, 1963, 2005), (7, 1963, 2006), (7, 1963, 2007), (7, 1963, 2008), (7, 1963, 2009), (7, 1963, 2010), (7, 1963, 2011), (7, 1963, 2012), (7, 1963, 2013), (7, 1963, 2014), (7, 1963, 2015), (7, 1963, 2016), (7, 1963, 2017), (7, 1963, 2018), (7, 1963, 2019), (7, 1963, 2020), (7, 1963, 2021), (7, 1963, 2022), (7, 1963, 2023), (7, 1963, 2024), (6, 1963, 2025), (5, 1963, 2026), (16, 1964, 1974), (16, 1964, 1975), (15, 1964, 1976), (15, 1964, 1977), (15, 1964, 1978), (15, 1964, 1979), (15, 1964, 1980), (15, 1964, 1981), (15, 1964, 1982), (15, 1964, 1983), (15, 1964, 1984), (14, 1964, 1985), (14, 1964, 1986), (14, 1964, 1987), (13, 1964, 1988), (13, 1964, 1989), (12, 1964, 1990), (12, 1964, 1991), (12, 1964, 1992), (12, 1964, 1993), (12, 1964, 1994), (11, 1964, 1995), (11, 1964, 1996), (9, 1964, 1997), (8, 1964, 1998), (8, 1964, 1999), (8, 1964, 2000), (8, 1964, 2001), (8, 1964, 2002), (8, 1964, 2003), (8, 1964, 2004), (8, 1964, 2005), (7, 1964, 2006), (7, 1964, 2007), (7, 1964, 2008), (7, 1964, 2009), (7, 1964, 2010), (7, 1964, 2011), (7, 1964, 2012), (7, 1964, 2013), (7, 1964, 2014), (7, 1964, 2015), (7, 1964, 2016), (7, 1964, 2017), (7, 1964, 2018), (7, 1964, 2019), (7, 1964, 2020), (7, 1964, 2021), (7, 1964, 2022), (7, 1964, 2023), (7, 1964, 2024), (6, 1964, 2025), (5, 1964, 2026), (17, 1965, 1975), (16, 1965, 1976), (16, 1965, 1977), (16, 1965, 1978), (16, 1965, 1979), (16, 1965, 1980), (16, 1965, 1981), (15, 1965, 1982), (15, 1965, 1983), (15, 1965, 1984), (14, 1965, 1985), (14, 1965, 1986), (14, 1965, 1987), (13, 1965, 1988), (13, 1965, 1989), (12, 1965, 1990), (12, 1965, 1991), (12, 1965, 1992), (12, 1965, 1993), (12, 1965, 1994), (11, 1965, 1995), (11, 1965, 1996), (9, 1965, 1997), (8, 1965, 1998), (8, 1965, 1999), (8, 1965, 2000), (8, 1965, 2001), (8, 1965, 2002), (8, 1965, 2003), (8, 1965, 2004), (8, 1965, 2005), (7, 1965, 2006), (7, 1965, 2007), (7, 1965, 2008), (7, 1965, 2009), (7, 1965, 2010), (7, 1965, 2011), (7, 1965, 2012), (7, 1965, 2013), (7, 1965, 2014), (7, 1965, 2015), (7, 1965, 2016), (7, 1965, 2017), (7, 1965, 2018), (7, 1965, 2019), (7, 1965, 2020), (7, 1965, 2021), (7, 1965, 2022), (7, 1965, 2023), (7, 1965, 2024), (6, 1965, 2025), (5, 1965, 2026), (17, 1966, 1976), (17, 1966, 1977), (17, 1966, 1978), (17, 1966, 1979), (17, 1966, 1980), (17, 1966, 1981), (16, 1966, 1982), (16, 1966, 1983), (16, 1966, 1984), (14, 1966, 1985), (14, 1966, 1986), (14, 1966, 1987), (13, 1966, 1988), (13, 1966, 1989), (12, 1966, 1990), (12, 1966, 1991), (12, 1966, 1992), (12, 1966, 1993), (12, 1966, 1994), (11, 1966, 1995), (11, 1966, 1996), (9, 1966, 1997), (8, 1966, 1998), (8, 1966, 1999), (8, 1966, 2000), (8, 1966, 2001), (8, 1966, 2002), (8, 1966, 2003), (8, 1966, 2004), (8, 1966, 2005), (7, 1966, 2006), (7, 1966, 2007), (7, 1966, 2008), (7, 1966, 2009), (7, 1966, 2010), (7, 1966, 2011), (7, 1966, 2012), (7, 1966, 2013), (7, 1966, 2014), (7, 1966, 2015), (7, 1966, 2016), (7, 1966, 2017), (7, 1966, 2018), (7, 1966, 2019), (7, 1966, 2020), (7, 1966, 2021), (7, 1966, 2022), (7, 1966, 2023), (7, 1966, 2024), (6, 1966, 2025), (5, 1966, 2026), (20, 1967, 1977), (20, 1967, 1978), (20, 1967, 1979), (20, 1967, 1980), (20, 1967, 1981), (19, 1967, 1982), (19, 1967, 1983), (19, 1967, 1984), (17, 1967, 1985), (17, 1967, 1986), (17, 1967, 1987), (16, 1967, 1988), (16, 1967, 1989), (15, 1967, 1990), (15, 1967, 1991), (15, 1967, 1992), (15, 1967, 1993), (15, 1967, 1994), (14, 1967, 1995), (14, 1967, 1996), (11, 1967, 1997), (10, 1967, 1998), (10, 1967, 1999), (10, 1967, 2000), (10, 1967, 2001), (10, 1967, 2002), (10, 1967, 2003), (10, 1967, 2004), (10, 1967, 2005), (9, 1967, 2006), (9, 1967, 2007), (9, 1967, 2008), (9, 1967, 2009), (9, 1967, 2010), (9, 1967, 2011), (9, 1967, 2012), (9, 1967, 2013), (9, 1967, 2014), (9, 1967, 2015), (9, 1967, 2016), (9, 1967, 2017), (9, 1967, 2018), (9, 1967, 2019), (9, 1967, 2020), (9, 1967, 2021), (8, 1967, 2022), (8, 1967, 2023), (8, 1967, 2024), (6, 1967, 2025), (5, 1967, 2026), (21, 1968, 1978), (21, 1968, 1979), (21, 1968, 1980), (21, 1968, 1981), (20, 1968, 1982), (20, 1968, 1983), (20, 1968, 1984), (18, 1968, 1985), (18, 1968, 1986), (18, 1968, 1987), (17, 1968, 1988), (17, 1968, 1989), (16, 1968, 1990), (16, 1968, 1991), (16, 1968, 1992), (16, 1968, 1993), (16, 1968, 1994), (15, 1968, 1995), (15, 1968, 1996), (12, 1968, 1997), (11, 1968, 1998), (11, 1968, 1999), (11, 1968, 2000), (11, 1968, 2001), (11, 1968, 2002), (11, 1968, 2003), (11, 1968, 2004), (11, 1968, 2005), (10, 1968, 2006), (10, 1968, 2007), (10, 1968, 2008), (10, 1968, 2009), (10, 1968, 2010), (10, 1968, 2011), (10, 1968, 2012), (10, 1968, 2013), (10, 1968, 2014), (10, 1968, 2015), (10, 1968, 2016), (10, 1968, 2017), (10, 1968, 2018), (10, 1968, 2019), (10, 1968, 2020), (10, 1968, 2021), (9, 1968, 2022), (9, 1968, 2023), (9, 1968, 2024), (7, 1968, 2025), (6, 1968, 2026), (22, 1969, 1979), (22, 1969, 1980), (22, 1969, 1981), (21, 1969, 1982), (21, 1969, 1983), (21, 1969, 1984), (19, 1969, 1985), (19, 1969, 1986), (19, 1969, 1987), (18, 1969, 1988), (18, 1969, 1989), (17, 1969, 1990), (17, 1969, 1991), (17, 1969, 1992), (17, 1969, 1993), (17, 1969, 1994), (16, 1969, 1995), (16, 1969, 1996), (13, 1969, 1997), (12, 1969, 1998), (12, 1969, 1999), (12, 1969, 2000), (12, 1969, 2001), (12, 1969, 2002), (12, 1969, 2003), (12, 1969, 2004), (12, 1969, 2005), (11, 1969, 2006), (11, 1969, 2007), (11, 1969, 2008), (11, 1969, 2009), (11, 1969, 2010), (11, 1969, 2011), (11, 1969, 2012), (11, 1969, 2013), (11, 1969, 2014), (11, 1969, 2015), (11, 1969, 2016), (11, 1969, 2017), (11, 1969, 2018), (11, 1969, 2019), (11, 1969, 2020), (11, 1969, 2021), (10, 1969, 2022), (10, 1969, 2023), (9, 1969, 2024), (7, 1969, 2025), (6, 1969, 2026), (26, 1970, 1980), (26, 1970, 1981), (25, 1970, 1982), (25, 1970, 1983), (25, 1970, 1984), (23, 1970, 1985), (23, 1970, 1986), (23, 1970, 1987), (22, 1970, 1988), (22, 1970, 1989), (21, 1970, 1990), (20, 1970, 1991), (20, 1970, 1992), (20, 1970, 1993), (20, 1970, 1994), (19, 1970, 1995), (18, 1970, 1996), (15, 1970, 1997), (14, 1970, 1998), (14, 1970, 1999), (14, 1970, 2000), (14, 1970, 2001), (14, 1970, 2002), (14, 1970, 2003), (14, 1970, 2004), (14, 1970, 2005), (13, 1970, 2006), (13, 1970, 2007), (13, 1970, 2008), (13, 1970, 2009), (13, 1970, 2010), (13, 1970, 2011), (13, 1970, 2012), (13, 1970, 2013), (13, 1970, 2014), (13, 1970, 2015), (13, 1970, 2016), (13, 1970, 2017), (13, 1970, 2018), (13, 1970, 2019), (13, 1970, 2020), (13, 1970, 2021), (12, 1970, 2022), (12, 1970, 2023), (11, 1970, 2024), (9, 1970, 2025), (7, 1970, 2026), (26, 1971, 1981), (25, 1971, 1982), (25, 1971, 1983), (25, 1971, 1984), (23, 1971, 1985), (23, 1971, 1986), (23, 1971, 1987), (22, 1971, 1988), (22, 1971, 1989), (21, 1971, 1990), (20, 1971, 1991), (20, 1971, 1992), (20, 1971, 1993), (20, 1971, 1994), (19, 1971, 1995), (18, 1971, 1996), (15, 1971, 1997), (14, 1971, 1998), (14, 1971, 1999), (14, 1971, 2000), (14, 1971, 2001), (14, 1971, 2002), (14, 1971, 2003), (14, 1971, 2004), (14, 1971, 2005), (13, 1971, 2006), (13, 1971, 2007), (13, 1971, 2008), (13, 1971, 2009), (13, 1971, 2010), (13, 1971, 2011), (13, 1971, 2012), (13, 1971, 2013), (13, 1971, 2014), (13, 1971, 2015), (13, 1971, 2016), (13, 1971, 2017), (13, 1971, 2018), (13, 1971, 2019), (13, 1971, 2020), (13, 1971, 2021), (12, 1971, 2022), (12, 1971, 2023), (11, 1971, 2024), (9, 1971, 2025), (7, 1971, 2026), (26, 1972, 1982), (26, 1972, 1983), (26, 1972, 1984), (24, 1972, 1985), (24, 1972, 1986), (24, 1972, 1987), (23, 1972, 1988), (23, 1972, 1989), (22, 1972, 1990), (21, 1972, 1991), (21, 1972, 1992), (21, 1972, 1993), (21, 1972, 1994), (20, 1972, 1995), (19, 1972, 1996), (16, 1972, 1997), (15, 1972, 1998), (15, 1972, 1999), (15, 1972, 2000), (15, 1972, 2001), (15, 1972, 2002), (15, 1972, 2003), (15, 1972, 2004), (15, 1972, 2005), (14, 1972, 2006), (14, 1972, 2007), (14, 1972, 2008), (14, 1972, 2009), (13, 1972, 2010), (13, 1972, 2011), (13, 1972, 2012), (13, 1972, 2013), (13, 1972, 2014), (13, 1972, 2015), (13, 1972, 2016), (13, 1972, 2017), (13, 1972, 2018), (13, 1972, 2019), (13, 1972, 2020), (13, 1972, 2021), (12, 1972, 2022), (12, 1972, 2023), (11, 1972, 2024), (9, 1972, 2025), (7, 1972, 2026), (26, 1973, 1983), (26, 1973, 1984), (24, 1973, 1985), (24, 1973, 1986), (24, 1973, 1987), (23, 1973, 1988), (23, 1973, 1989), (22, 1973, 1990), (21, 1973, 1991), (21, 1973, 1992), (21, 1973, 1993), (21, 1973, 1994), (20, 1973, 1995), (19, 1973, 1996), (16, 1973, 1997), (15, 1973, 1998), (15, 1973, 1999), (15, 1973, 2000), (15, 1973, 2001), (15, 1973, 2002), (15, 1973, 2003), (15, 1973, 2004), (15, 1973, 2005), (14, 1973, 2006), (14, 1973, 2007), (14, 1973, 2008), (14, 1973, 2009), (13, 1973, 2010), (13, 1973, 2011), (13, 1973, 2012), (13, 1973, 2013), (13, 1973, 2014), (13, 1973, 2015), (13, 1973, 2016), (13, 1973, 2017), (13, 1973, 2018), (13, 1973, 2019), (13, 1973, 2020), (13, 1973, 2021), (12, 1973, 2022), (12, 1973, 2023), (11, 1973, 2024), (9, 1973, 2025), (7, 1973, 2026), (29, 1974, 1984), (27, 1974, 1985), (26, 1974, 1986), (25, 1974, 1987), (24, 1974, 1988), (24, 1974, 1989), (23, 1974, 1990), (22, 1974, 1991), (22, 1974, 1992), (22, 1974, 1993), (22, 1974, 1994), (21, 1974, 1995), (20, 1974, 1996), (17, 1974, 1997), (16, 1974, 1998), (16, 1974, 1999), (16, 1974, 2000), (16, 1974, 2001), (16, 1974, 2002), (16, 1974, 2003), (16, 1974, 2004), (15, 1974, 2005), (14, 1974, 2006), (14, 1974, 2007), (14, 1974, 2008), (14, 1974, 2009), (13, 1974, 2010), (13, 1974, 2011), (13, 1974, 2012), (13, 1974, 2013), (13, 1974, 2014), (13, 1974, 2015), (13, 1974, 2016), (13, 1974, 2017), (13, 1974, 2018), (13, 1974, 2019), (13, 1974, 2020), (13, 1974, 2021), (12, 1974, 2022), (12, 1974, 2023), (11, 1974, 2024), (9, 1974, 2025), (7, 1974, 2026), (28, 1975, 1985), (27, 1975, 1986), (26, 1975, 1987), (25, 1975, 1988), (25, 1975, 1989), (24, 1975, 1990), (23, 1975, 1991), (22, 1975, 1992), (22, 1975, 1993), (22, 1975, 1994), (21, 1975, 1995), (20, 1975, 1996), (17, 1975, 1997), (16, 1975, 1998), (16, 1975, 1999), (16, 1975, 2000), (16, 1975, 2001), (16, 1975, 2002), (16, 1975, 2003), (16, 1975, 2004), (15, 1975, 2005), (14, 1975, 2006), (14, 1975, 2007), (14, 1975, 2008), (14, 1975, 2009), (13, 1975, 2010), (13, 1975, 2011), (13, 1975, 2012), (13, 1975, 2013), (13, 1975, 2014), (13, 1975, 2015), (13, 1975, 2016), (13, 1975, 2017), (13, 1975, 2018), (13, 1975, 2019), (13, 1975, 2020), (13, 1975, 2021), (12, 1975, 2022), (12, 1975, 2023), (11, 1975, 2024), (9, 1975, 2025), (7, 1975, 2026), (29, 1976, 1986), (28, 1976, 1987), (27, 1976, 1988), (27, 1976, 1989), (25, 1976, 1990), (24, 1976, 1991), (23, 1976, 1992), (23, 1976, 1993), (23, 1976, 1994), (22, 1976, 1995), (21, 1976, 1996), (18, 1976, 1997), (17, 1976, 1998), (17, 1976, 1999), (17, 1976, 2000), (17, 1976, 2001), (17, 1976, 2002), (17, 1976, 2003), (16, 1976, 2004), (15, 1976, 2005), (14, 1976, 2006), (14, 1976, 2007), (14, 1976, 2008), (14, 1976, 2009), (13, 1976, 2010), (13, 1976, 2011), (13, 1976, 2012), (13, 1976, 2013), (13, 1976, 2014), (13, 1976, 2015), (13, 1976, 2016), (13, 1976, 2017), (13, 1976, 2018), (13, 1976, 2019), (13, 1976, 2020), (13, 1976, 2021), (12, 1976, 2022), (12, 1976, 2023), (11, 1976, 2024), (9, 1976, 2025), (7, 1976, 2026), (29, 1977, 1987), (28, 1977, 1988), (28, 1977, 1989), (26, 1977, 1990), (25, 1977, 1991), (24, 1977, 1992), (24, 1977, 1993), (24, 1977, 1994), (23, 1977, 1995), (22, 1977, 1996), (19, 1977, 1997), (18, 1977, 1998), (17, 1977, 1999), (17, 1977, 2000), (17, 1977, 2001), (17, 1977, 2002), (17, 1977, 2003), (16, 1977, 2004), (15, 1977, 2005), (14, 1977, 2006), (14, 1977, 2007), (14, 1977, 2008), (14, 1977, 2009), (13, 1977, 2010), (13, 1977, 2011), (13, 1977, 2012), (13, 1977, 2013), (13, 1977, 2014), (13, 1977, 2015), (13, 1977, 2016), (13, 1977, 2017), (13, 1977, 2018), (13, 1977, 2019), (13, 1977, 2020), (13, 1977, 2021), (12, 1977, 2022), (12, 1977, 2023), (11, 1977, 2024), (9, 1977, 2025), (7, 1977, 2026), (29, 1978, 1988), (29, 1978, 1989), (27, 1978, 1990), (26, 1978, 1991), (25, 1978, 1992), (25, 1978, 1993), (25, 1978, 1994), (24, 1978, 1995), (23, 1978, 1996), (20, 1978, 1997), (19, 1978, 1998), (18, 1978, 1999), (18, 1978, 2000), (18, 1978, 2001), (18, 1978, 2002), (18, 1978, 2003), (17, 1978, 2004), (16, 1978, 2005), (15, 1978, 2006), (15, 1978, 2007), (15, 1978, 2008), (15, 1978, 2009), (14, 1978, 2010), (14, 1978, 2011), (14, 1978, 2012), (14, 1978, 2013), (14, 1978, 2014), (14, 1978, 2015), (14, 1978, 2016), (14, 1978, 2017), (14, 1978, 2018), (14, 1978, 2019), (14, 1978, 2020), (14, 1978, 2021), (13, 1978, 2022), (13, 1978, 2023), (12, 1978, 2024), (10, 1978, 2025), (8, 1978, 2026), (31, 1979, 1989), (29, 1979, 1990), (28, 1979, 1991), (27, 1979, 1992), (27, 1979, 1993), (27, 1979, 1994), (26, 1979, 1995), (24, 1979, 1996), (21, 1979, 1997), (20, 1979, 1998), (19, 1979, 1999), (19, 1979, 2000), (19, 1979, 2001), (19, 1979, 2002), (19, 1979, 2003), (18, 1979, 2004), (17, 1979, 2005), (16, 1979, 2006), (16, 1979, 2007), (16, 1979, 2008), (16, 1979, 2009), (15, 1979, 2010), (15, 1979, 2011), (15, 1979, 2012), (15, 1979, 2013), (15, 1979, 2014), (15, 1979, 2015), (15, 1979, 2016), (15, 1979, 2017), (15, 1979, 2018), (15, 1979, 2019), (15, 1979, 2020), (15, 1979, 2021), (14, 1979, 2022), (14, 1979, 2023), (13, 1979, 2024), (10, 1979, 2025), (8, 1979, 2026), (29, 1980, 1990), (28, 1980, 1991), (27, 1980, 1992), (27, 1980, 1993), (27, 1980, 1994), (26, 1980, 1995), (24, 1980, 1996), (21, 1980, 1997), (20, 1980, 1998), (19, 1980, 1999), (19, 1980, 2000), (19, 1980, 2001), (19, 1980, 2002), (19, 1980, 2003), (18, 1980, 2004), (17, 1980, 2005), (16, 1980, 2006), (16, 1980, 2007), (16, 1980, 2008), (16, 1980, 2009), (15, 1980, 2010), (15, 1980, 2011), (15, 1980, 2012), (15, 1980, 2013), (15, 1980, 2014), (15, 1980, 2015), (15, 1980, 2016), (15, 1980, 2017), (15, 1980, 2018), (15, 1980, 2019), (15, 1980, 2020), (15, 1980, 2021), (14, 1980, 2022), (14, 1980, 2023), (13, 1980, 2024), (10, 1980, 2025), (8, 1980, 2026), (28, 1981, 1991), (27, 1981, 1992), (27, 1981, 1993), (27, 1981, 1994), (26, 1981, 1995), (24, 1981, 1996), (21, 1981, 1997), (20, 1981, 1998), (19, 1981, 1999), (19, 1981, 2000), (19, 1981, 2001), (19, 1981, 2002), (19, 1981, 2003), (18, 1981, 2004), (17, 1981, 2005), (16, 1981, 2006), (16, 1981, 2007), (16, 1981, 2008), (16, 1981, 2009), (15, 1981, 2010), (15, 1981, 2011), (15, 1981, 2012), (15, 1981, 2013), (15, 1981, 2014), (15, 1981, 2015), (15, 1981, 2016), (15, 1981, 2017), (15, 1981, 2018), (15, 1981, 2019), (15, 1981, 2020), (15, 1981, 2021), (14, 1981, 2022), (14, 1981, 2023), (13, 1981, 2024), (10, 1981, 2025), (8, 1981, 2026), (27, 1982, 1992), (27, 1982, 1993), (27, 1982, 1994), (26, 1982, 1995), (24, 1982, 1996), (21, 1982, 1997), (20, 1982, 1998), (19, 1982, 1999), (19, 1982, 2000), (19, 1982, 2001), (19, 1982, 2002), (19, 1982, 2003), (18, 1982, 2004), (17, 1982, 2005), (16, 1982, 2006), (16, 1982, 2007), (16, 1982, 2008), (16, 1982, 2009), (15, 1982, 2010), (15, 1982, 2011), (15, 1982, 2012), (15, 1982, 2013), (15, 1982, 2014), (15, 1982, 2015), (15, 1982, 2016), (15, 1982, 2017), (15, 1982, 2018), (15, 1982, 2019), (15, 1982, 2020), (15, 1982, 2021), (14, 1982, 2022), (14, 1982, 2023), (13, 1982, 2024), (10, 1982, 2025), (8, 1982, 2026), (27, 1983, 1993), (27, 1983, 1994), (26, 1983, 1995), (24, 1983, 1996), (21, 1983, 1997), (20, 1983, 1998), (19, 1983, 1999), (19, 1983, 2000), (19, 1983, 2001), (19, 1983, 2002), (19, 1983, 2003), (18, 1983, 2004), (17, 1983, 2005), (16, 1983, 2006), (16, 1983, 2007), (16, 1983, 2008), (16, 1983, 2009), (15, 1983, 2010), (15, 1983, 2011), (15, 1983, 2012), (15, 1983, 2013), (15, 1983, 2014), (15, 1983, 2015), (15, 1983, 2016), (15, 1983, 2017), (15, 1983, 2018), (15, 1983, 2019), (15, 1983, 2020), (15, 1983, 2021), (14, 1983, 2022), (14, 1983, 2023), (13, 1983, 2024), (10, 1983, 2025), (8, 1983, 2026), (30, 1984, 1994), (29, 1984, 1995), (27, 1984, 1996), (24, 1984, 1997), (23, 1984, 1998), (22, 1984, 1999), (22, 1984, 2000), (22, 1984, 2001), (22, 1984, 2002), (22, 1984, 2003), (21, 1984, 2004), (20, 1984, 2005), (18, 1984, 2006), (18, 1984, 2007), (18, 1984, 2008), (18, 1984, 2009), (17, 1984, 2010), (17, 1984, 2011), (15, 1984, 2012), (15, 1984, 2013), (15, 1984, 2014), (15, 1984, 2015), (15, 1984, 2016), (15, 1984, 2017), (15, 1984, 2018), (15, 1984, 2019), (15, 1984, 2020), (15, 1984, 2021), (14, 1984, 2022), (14, 1984, 2023), (13, 1984, 2024), (10, 1984, 2025), (8, 1984, 2026), (30, 1985, 1995), (28, 1985, 1996), (25, 1985, 1997), (24, 1985, 1998), (23, 1985, 1999), (23, 1985, 2000), (23, 1985, 2001), (23, 1985, 2002), (23, 1985, 2003), (22, 1985, 2004), (21, 1985, 2005), (19, 1985, 2006), (19, 1985, 2007), (19, 1985, 2008), (19, 1985, 2009), (18, 1985, 2010), (18, 1985, 2011), (16, 1985, 2012), (16, 1985, 2013), (16, 1985, 2014), (16, 1985, 2015), (16, 1985, 2016), (16, 1985, 2017), (16, 1985, 2018), (16, 1985, 2019), (16, 1985, 2020), (16, 1985, 2021), (15, 1985, 2022), (15, 1985, 2023), (13, 1985, 2024), (10, 1985, 2025), (8, 1985, 2026), (29, 1986, 1996), (25, 1986, 1997), (24, 1986, 1998), (23, 1986, 1999), (23, 1986, 2000), (23, 1986, 2001), (23, 1986, 2002), (23, 1986, 2003), (22, 1986, 2004), (21, 1986, 2005), (19, 1986, 2006), (19, 1986, 2007), (19, 1986, 2008), (19, 1986, 2009), (18, 1986, 2010), (18, 1986, 2011), (16, 1986, 2012), (16, 1986, 2013), (16, 1986, 2014), (16, 1986, 2015), (16, 1986, 2016), (16, 1986, 2017), (16, 1986, 2018), (16, 1986, 2019), (16, 1986, 2020), (16, 1986, 2021), (15, 1986, 2022), (15, 1986, 2023), (13, 1986, 2024), (10, 1986, 2025), (8, 1986, 2026), (25, 1987, 1997), (24, 1987, 1998), (23, 1987, 1999), (23, 1987, 2000), (23, 1987, 2001), (23, 1987, 2002), (23, 1987, 2003), (22, 1987, 2004), (21, 1987, 2005), (19, 1987, 2006), (19, 1987, 2007), (19, 1987, 2008), (19, 1987, 2009), (18, 1987, 2010), (18, 1987, 2011), (16, 1987, 2012), (16, 1987, 2013), (16, 1987, 2014), (16, 1987, 2015), (16, 1987, 2016), (16, 1987, 2017), (16, 1987, 2018), (16, 1987, 2019), (16, 1987, 2020), (16, 1987, 2021), (15, 1987, 2022), (15, 1987, 2023), (13, 1987, 2024), (10, 1987, 2025), (8, 1987, 2026), (24, 1988, 1998), (23, 1988, 1999), (23, 1988, 2000), (23, 1988, 2001), (23, 1988, 2002), (23, 1988, 2003), (22, 1988, 2004), (21, 1988, 2005), (19, 1988, 2006), (19, 1988, 2007), (19, 1988, 2008), (19, 1988, 2009), (18, 1988, 2010), (18, 1988, 2011), (16, 1988, 2012), (16, 1988, 2013), (16, 1988, 2014), (16, 1988, 2015), (16, 1988, 2016), (16, 1988, 2017), (16, 1988, 2018), (16, 1988, 2019), (16, 1988, 2020), (16, 1988, 2021), (15, 1988, 2022), (15, 1988, 2023), (13, 1988, 2024), (10, 1988, 2025), (8, 1988, 2026), (23, 1989, 1999), (23, 1989, 2000), (23, 1989, 2001), (23, 1989, 2002), (23, 1989, 2003), (22, 1989, 2004), (21, 1989, 2005), (19, 1989, 2006), (19, 1989, 2007), (19, 1989, 2008), (19, 1989, 2009), (18, 1989, 2010), (18, 1989, 2011), (16, 1989, 2012), (16, 1989, 2013), (16, 1989, 2014), (16, 1989, 2015), (16, 1989, 2016), (16, 1989, 2017), (16, 1989, 2018), (16, 1989, 2019), (16, 1989, 2020), (16, 1989, 2021), (15, 1989, 2022), (15, 1989, 2023), (13, 1989, 2024), (10, 1989, 2025), (8, 1989, 2026), (23, 1990, 2000), (23, 1990, 2001), (23, 1990, 2002), (23, 1990, 2003), (22, 1990, 2004), (21, 1990, 2005), (19, 1990, 2006), (19, 1990, 2007), (19, 1990, 2008), (19, 1990, 2009), (18, 1990, 2010), (18, 1990, 2011), (16, 1990, 2012), (16, 1990, 2013), (16, 1990, 2014), (16, 1990, 2015), (16, 1990, 2016), (16, 1990, 2017), (16, 1990, 2018), (16, 1990, 2019), (16, 1990, 2020), (16, 1990, 2021), (15, 1990, 2022), (15, 1990, 2023), (13, 1990, 2024), (10, 1990, 2025), (8, 1990, 2026), (24, 1991, 2001), (24, 1991, 2002), (24, 1991, 2003), (23, 1991, 2004), (22, 1991, 2005), (20, 1991, 2006), (20, 1991, 2007), (20, 1991, 2008), (20, 1991, 2009), (19, 1991, 2010), (19, 1991, 2011), (17, 1991, 2012), (17, 1991, 2013), (17, 1991, 2014), (17, 1991, 2015), (17, 1991, 2016), (17, 1991, 2017), (17, 1991, 2018), (17, 1991, 2019), (17, 1991, 2020), (17, 1991, 2021), (16, 1991, 2022), (16, 1991, 2023), (14, 1991, 2024), (11, 1991, 2025), (9, 1991, 2026), (25, 1992, 2002), (25, 1992, 2003), (24, 1992, 2004), (23, 1992, 2005), (21, 1992, 2006), (21, 1992, 2007), (21, 1992, 2008), (21, 1992, 2009), (20, 1992, 2010), (20, 1992, 2011), (18, 1992, 2012), (18, 1992, 2013), (18, 1992, 2014), (18, 1992, 2015), (18, 1992, 2016), (18, 1992, 2017), (18, 1992, 2018), (18, 1992, 2019), (18, 1992, 2020), (18, 1992, 2021), (17, 1992, 2022), (17, 1992, 2023), (15, 1992, 2024), (12, 1992, 2025), (10, 1992, 2026), (25, 1993, 2003), (24, 1993, 2004), (23, 1993, 2005), (21, 1993, 2006), (21, 1993, 2007), (21, 1993, 2008), (21, 1993, 2009), (20, 1993, 2010), (20, 1993, 2011), (18, 1993, 2012), (18, 1993, 2013), (18, 1993, 2014), (18, 1993, 2015), (18, 1993, 2016), (18, 1993, 2017), (18, 1993, 2018), (18, 1993, 2019), (18, 1993, 2020), (18, 1993, 2021), (17, 1993, 2022), (17, 1993, 2023), (15, 1993, 2024), (12, 1993, 2025), (10, 1993, 2026), (24, 1994, 2004), (23, 1994, 2005), (21, 1994, 2006), (21, 1994, 2007), (21, 1994, 2008), (21, 1994, 2009), (20, 1994, 2010), (20, 1994, 2011), (18, 1994, 2012), (18, 1994, 2013), (18, 1994, 2014), (18, 1994, 2015), (18, 1994, 2016), (18, 1994, 2017), (18, 1994, 2018), (18, 1994, 2019), (18, 1994, 2020), (18, 1994, 2021), (17, 1994, 2022), (17, 1994, 2023), (15, 1994, 2024), (12, 1994, 2025), (10, 1994, 2026), (27, 1995, 2005), (25, 1995, 2006), (25, 1995, 2007), (25, 1995, 2008), (25, 1995, 2009), (24, 1995, 2010), (24, 1995, 2011), (22, 1995, 2012), (22, 1995, 2013), (22, 1995, 2014), (22, 1995, 2015), (22, 1995, 2016), (22, 1995, 2017), (22, 1995, 2018), (22, 1995, 2019), (22, 1995, 2020), (22, 1995, 2021), (21, 1995, 2022), (21, 1995, 2023), (18, 1995, 2024), (14, 1995, 2025), (10, 1995, 2026), (25, 1996, 2006), (25, 1996, 2007), (25, 1996, 2008), (25, 1996, 2009), (24, 1996, 2010), (24, 1996, 2011), (22, 1996, 2012), (22, 1996, 2013), (22, 1996, 2014), (22, 1996, 2015), (22, 1996, 2016), (22, 1996, 2017), (22, 1996, 2018), (22, 1996, 2019), (22, 1996, 2020), (22, 1996, 2021), (21, 1996, 2022), (21, 1996, 2023), (18, 1996, 2024), (14, 1996, 2025), (10, 1996, 2026), (25, 1997, 2007), (25, 1997, 2008), (25, 1997, 2009), (24, 1997, 2010), (24, 1997, 2011), (22, 1997, 2012), (22, 1997, 2013), (22, 1997, 2014), (22, 1997, 2015), (22, 1997, 2016), (22, 1997, 2017), (22, 1997, 2018), (22, 1997, 2019), (22, 1997, 2020), (22, 1997, 2021), (21, 1997, 2022), (21, 1997, 2023), (18, 1997, 2024), (14, 1997, 2025), (10, 1997, 2026), (25, 1998, 2008), (25, 1998, 2009), (24, 1998, 2010), (24, 1998, 2011), (22, 1998, 2012), (22, 1998, 2013), (22, 1998, 2014), (22, 1998, 2015), (22, 1998, 2016), (22, 1998, 2017), (22, 1998, 2018), (22, 1998, 2019), (22, 1998, 2020), (22, 1998, 2021), (21, 1998, 2022), (21, 1998, 2023), (18, 1998, 2024), (14, 1998, 2025), (10, 1998, 2026), (25, 1999, 2009), (24, 1999, 2010), (24, 1999, 2011), (22, 1999, 2012), (22, 1999, 2013), (22, 1999, 2014), (22, 1999, 2015), (22, 1999, 2016), (22, 1999, 2017), (22, 1999, 2018), (22, 1999, 2019), (22, 1999, 2020), (22, 1999, 2021), (21, 1999, 2022), (21, 1999, 2023), (18, 1999, 2024), (14, 1999, 2025), (10, 1999, 2026), (24, 2000, 2010), (24, 2000, 2011), (22, 2000, 2012), (22, 2000, 2013), (22, 2000, 2014), (22, 2000, 2015), (22, 2000, 2016), (22, 2000, 2017), (22, 2000, 2018), (22, 2000, 2019), (22, 2000, 2020), (22, 2000, 2021), (21, 2000, 2022), (21, 2000, 2023), (18, 2000, 2024), (14, 2000, 2025), (10, 2000, 2026), (24, 2001, 2011), (22, 2001, 2012), (22, 2001, 2013), (22, 2001, 2014), (22, 2001, 2015), (22, 2001, 2016), (22, 2001, 2017), (22, 2001, 2018), (22, 2001, 2019), (22, 2001, 2020), (22, 2001, 2021), (21, 2001, 2022), (21, 2001, 2023), (18, 2001, 2024), (14, 2001, 2025), (10, 2001, 2026), (22, 2002, 2012), (22, 2002, 2013), (22, 2002, 2014), (22, 2002, 2015), (22, 2002, 2016), (22, 2002, 2017), (22, 2002, 2018), (22, 2002, 2019), (22, 2002, 2020), (22, 2002, 2021), (21, 2002, 2022), (21, 2002, 2023), (18, 2002, 2024), (14, 2002, 2025), (10, 2002, 2026), (22, 2003, 2013), (22, 2003, 2014), (22, 2003, 2015), (22, 2003, 2016), (22, 2003, 2017), (22, 2003, 2018), (22, 2003, 2019), (22, 2003, 2020), (22, 2003, 2021), (21, 2003, 2022), (21, 2003, 2023), (18, 2003, 2024), (14, 2003, 2025), (10, 2003, 2026), (22, 2004, 2014), (22, 2004, 2015), (22, 2004, 2016), (22, 2004, 2017), (22, 2004, 2018), (22, 2004, 2019), (22, 2004, 2020), (22, 2004, 2021), (21, 2004, 2022), (21, 2004, 2023), (18, 2004, 2024), (14, 2004, 2025), (10, 2004, 2026), (22, 2005, 2015), (22, 2005, 2016), (22, 2005, 2017), (22, 2005, 2018), (22, 2005, 2019), (22, 2005, 2020), (22, 2005, 2021), (21, 2005, 2022), (21, 2005, 2023), (18, 2005, 2024), (14, 2005, 2025), (10, 2005, 2026), (22, 2006, 2016), (22, 2006, 2017), (22, 2006, 2018), (22, 2006, 2019), (22, 2006, 2020), (22, 2006, 2021), (21, 2006, 2022), (21, 2006, 2023), (18, 2006, 2024), (14, 2006, 2025), (10, 2006, 2026), (22, 2007, 2017), (22, 2007, 2018), (22, 2007, 2019), (22, 2007, 2020), (22, 2007, 2021), (21, 2007, 2022), (21, 2007, 2023), (18, 2007, 2024), (14, 2007, 2025), (10, 2007, 2026), (22, 2008, 2018), (22, 2008, 2019), (22, 2008, 2020), (22, 2008, 2021), (21, 2008, 2022), (21, 2008, 2023), (18, 2008, 2024), (14, 2008, 2025), (10, 2008, 2026), (22, 2009, 2019), (22, 2009, 2020), (22, 2009, 2021), (21, 2009, 2022), (21, 2009, 2023), (18, 2009, 2024), (14, 2009, 2025), (10, 2009, 2026), (22, 2010, 2020), (22, 2010, 2021), (21, 2010, 2022), (21, 2010, 2023), (18, 2010, 2024), (14, 2010, 2025), (10, 2010, 2026), (23, 2011, 2021), (22, 2011, 2022), (22, 2011, 2023), (19, 2011, 2024), (15, 2011, 2025), (10, 2011, 2026), (22, 2012, 2022), (22, 2012, 2023), (19, 2012, 2024), (15, 2012, 2025), (10, 2012, 2026), (22, 2013, 2023), (19, 2013, 2024), (15, 2013, 2025), (10, 2013, 2026), (19, 2014, 2024), (15, 2014, 2025), (10, 2014, 2026), (15, 2015, 2025), (10, 2015, 2026), (10, 2016, 2026)]

Now we can turn this new list of tuples into a DataFrame, add a column with the length of the period, and sort it by decreasing period length:

balanced_panels = pl.DataFrame(
    selected_list_n_valid,
    orient="row",
    schema=["n_valid", "period_start", "period_end"]
).with_columns(
    (pl.col("period_end") - pl.col("period_start")).alias("period_length")
).sort(
    "period_length", "n_valid", descending=True
)

print(balanced_panels)
shape: (2_211, 4)
┌─────────┬──────────────┬────────────┬───────────────┐
│ n_valid ┆ period_start ┆ period_end ┆ period_length │
│ ---     ┆ ---          ┆ ---        ┆ ---           │
│ i64     ┆ i64          ┆ i64        ┆ i64           │
╞═════════╪══════════════╪════════════╪═══════════════╡
│ 5       ┆ 1954         ┆ 2025       ┆ 71            │
│ 5       ┆ 1954         ┆ 2024       ┆ 70            │
│ 5       ┆ 1955         ┆ 2025       ┆ 70            │
│ 5       ┆ 1954         ┆ 2023       ┆ 69            │
│ 5       ┆ 1955         ┆ 2024       ┆ 69            │
│ …       ┆ …            ┆ …          ┆ …             │
│ 6       ┆ 1950         ┆ 1960       ┆ 10            │
│ 6       ┆ 1951         ┆ 1961       ┆ 10            │
│ 5       ┆ 1948         ┆ 1958       ┆ 10            │
│ 5       ┆ 1947         ┆ 1957       ┆ 10            │
│ 5       ┆ 1949         ┆ 1959       ┆ 10            │
└─────────┴──────────────┴────────────┴───────────────┘

If there is any trend such as a decrease in the snow pack height due to global warming, we want to include data up to the present.

Your turn:

Create a DataFrame of balanced panels similar to balanced_panels but in which all periods include the present.

Call it current.

To print more rows than the default, you can use polars.Config.set_tbl_rows:

with pl.Config(tbl_rows=100):
    print(balanced_current)
shape: (59, 4)
┌─────────┬──────────────┬────────────┬───────────────┐
│ n_valid ┆ period_start ┆ period_end ┆ period_length │
│ ---     ┆ ---          ┆ ---        ┆ ---           │
│ i64     ┆ i64          ┆ i64        ┆ i64           │
╞═════════╪══════════════╪════════════╪═══════════════╡
│ 5       ┆ 1958         ┆ 2026       ┆ 68            │
│ 5       ┆ 1959         ┆ 2026       ┆ 67            │
│ 5       ┆ 1960         ┆ 2026       ┆ 66            │
│ 5       ┆ 1961         ┆ 2026       ┆ 65            │
│ 5       ┆ 1962         ┆ 2026       ┆ 64            │
│ 5       ┆ 1963         ┆ 2026       ┆ 63            │
│ 5       ┆ 1964         ┆ 2026       ┆ 62            │
│ 5       ┆ 1965         ┆ 2026       ┆ 61            │
│ 5       ┆ 1966         ┆ 2026       ┆ 60            │
│ 5       ┆ 1967         ┆ 2026       ┆ 59            │
│ 6       ┆ 1968         ┆ 2026       ┆ 58            │
│ 6       ┆ 1969         ┆ 2026       ┆ 57            │
│ 7       ┆ 1970         ┆ 2026       ┆ 56            │
│ 7       ┆ 1971         ┆ 2026       ┆ 55            │
│ 7       ┆ 1972         ┆ 2026       ┆ 54            │
│ 7       ┆ 1973         ┆ 2026       ┆ 53            │
│ 7       ┆ 1974         ┆ 2026       ┆ 52            │
│ 7       ┆ 1975         ┆ 2026       ┆ 51            │
│ 7       ┆ 1976         ┆ 2026       ┆ 50            │
│ 7       ┆ 1977         ┆ 2026       ┆ 49            │
│ 8       ┆ 1978         ┆ 2026       ┆ 48            │
│ 8       ┆ 1979         ┆ 2026       ┆ 47            │
│ 8       ┆ 1980         ┆ 2026       ┆ 46            │
│ 8       ┆ 1981         ┆ 2026       ┆ 45            │
│ 8       ┆ 1982         ┆ 2026       ┆ 44            │
│ 8       ┆ 1983         ┆ 2026       ┆ 43            │
│ 8       ┆ 1984         ┆ 2026       ┆ 42            │
│ 8       ┆ 1985         ┆ 2026       ┆ 41            │
│ 8       ┆ 1986         ┆ 2026       ┆ 40            │
│ 8       ┆ 1987         ┆ 2026       ┆ 39            │
│ 8       ┆ 1988         ┆ 2026       ┆ 38            │
│ 8       ┆ 1989         ┆ 2026       ┆ 37            │
│ 8       ┆ 1990         ┆ 2026       ┆ 36            │
│ 9       ┆ 1991         ┆ 2026       ┆ 35            │
│ 10      ┆ 1992         ┆ 2026       ┆ 34            │
│ 10      ┆ 1993         ┆ 2026       ┆ 33            │
│ 10      ┆ 1994         ┆ 2026       ┆ 32            │
│ 10      ┆ 1995         ┆ 2026       ┆ 31            │
│ 10      ┆ 1996         ┆ 2026       ┆ 30            │
│ 10      ┆ 1997         ┆ 2026       ┆ 29            │
│ 10      ┆ 1998         ┆ 2026       ┆ 28            │
│ 10      ┆ 1999         ┆ 2026       ┆ 27            │
│ 10      ┆ 2000         ┆ 2026       ┆ 26            │
│ 10      ┆ 2001         ┆ 2026       ┆ 25            │
│ 10      ┆ 2002         ┆ 2026       ┆ 24            │
│ 10      ┆ 2003         ┆ 2026       ┆ 23            │
│ 10      ┆ 2004         ┆ 2026       ┆ 22            │
│ 10      ┆ 2005         ┆ 2026       ┆ 21            │
│ 10      ┆ 2006         ┆ 2026       ┆ 20            │
│ 10      ┆ 2007         ┆ 2026       ┆ 19            │
│ 10      ┆ 2008         ┆ 2026       ┆ 18            │
│ 10      ┆ 2009         ┆ 2026       ┆ 17            │
│ 10      ┆ 2010         ┆ 2026       ┆ 16            │
│ 10      ┆ 2011         ┆ 2026       ┆ 15            │
│ 10      ┆ 2012         ┆ 2026       ┆ 14            │
│ 10      ┆ 2013         ┆ 2026       ┆ 13            │
│ 10      ┆ 2014         ┆ 2026       ┆ 12            │
│ 10      ┆ 2015         ┆ 2026       ┆ 11            │
│ 10      ┆ 2016         ┆ 2026       ┆ 10            │
└─────────┴──────────────┴────────────┴───────────────┘

48 seasons for 8 stations is not bad, so let’s select the period from 1978 to the present and create a new DataFrame called subset_df:

subset_df = season_data.filter(
    pl.col("season").is_between(1978, 2026)
)

print(subset_df)
shape: (6_261, 7)
┌─────────────┬───────────┬────────────┬───────┬───────┬──────────────────┬────────┐
│ station     ┆ elevation ┆ date       ┆ snow  ┆ water ┆ range            ┆ season │
│ ---         ┆ ---       ┆ ---        ┆ ---   ┆ ---   ┆ ---              ┆ ---    │
│ str         ┆ i64       ┆ date       ┆ f64   ┆ f64   ┆ str              ┆ i32    │
╞═════════════╪═══════════╪════════════╪═══════╪═══════╪══════════════════╪════════╡
│ Mount Wells ┆ 1490      ┆ 1978-02-27 ┆ 112.0 ┆ 310.0 ┆ Vancouver Island ┆ 1978   │
│ Mount Wells ┆ 1490      ┆ 1978-03-28 ┆ 127.0 ┆ 358.0 ┆ Vancouver Island ┆ 1978   │
│ Mount Wells ┆ 1490      ┆ 1978-04-26 ┆ 124.0 ┆ 404.0 ┆ Vancouver Island ┆ 1978   │
│ Mount Wells ┆ 1490      ┆ 1978-05-31 ┆ 56.0  ┆ 198.0 ┆ Vancouver Island ┆ 1978   │
│ Mount Wells ┆ 1490      ┆ 1979-02-26 ┆ 160.0 ┆ 495.0 ┆ Vancouver Island ┆ 1979   │
│ …           ┆ …         ┆ …          ┆ …     ┆ …     ┆ …                ┆ …      │
│ Mount Sheba ┆ 1490      ┆ 2022-12-30 ┆ 112.0 ┆ 301.0 ┆ Sea to Sky       ┆ 2023   │
│ Mount Sheba ┆ 1490      ┆ 2023-02-01 ┆ null  ┆ null  ┆ Sea to Sky       ┆ 2023   │
│ Mount Sheba ┆ 1490      ┆ 2023-02-28 ┆ 225.0 ┆ 715.0 ┆ Sea to Sky       ┆ 2023   │
│ Mount Sheba ┆ 1490      ┆ 2023-03-30 ┆ 206.0 ┆ 794.0 ┆ Sea to Sky       ┆ 2023   │
│ Mount Sheba ┆ 1490      ┆ 2023-04-28 ┆ 208.0 ┆ 853.0 ┆ Sea to Sky       ┆ 2023   │
└─────────────┴───────────┴────────────┴───────┴───────┴──────────────────┴────────┘

Now we want to get a list of the stations that have data for all seasons between 1978 and the present:

max_n_seasons = subset_df.group_by("station").agg(
    pl.col("season").n_unique().alias("n_seasons")
).select(pl.col("n_seasons")).max().item()

subset_stations = subset_df.group_by("station").agg(
    pl.col("season").n_unique().alias("n_seasons")
).filter(pl.col("n_seasons") == max_n_seasons).get_column("station").to_list()

print(len(subset_stations))  # should return 8
print(subset_stations)
8
['Grouse Mountain', 'Nahatlatch River', 'Upper Thelwood Lake', 'Wolf River Lower', 'Forbidden Plateau', 'Duffey Lake', 'Klesilkwa', 'Mount Wells']

Finally, we filter data for those stations:

subset_data = subset_df.filter(pl.col("station").is_in(subset_stations))

print(subset_data)
shape: (1_675, 7)
┌─────────────┬───────────┬────────────┬───────┬───────┬──────────────────┬────────┐
│ station     ┆ elevation ┆ date       ┆ snow  ┆ water ┆ range            ┆ season │
│ ---         ┆ ---       ┆ ---        ┆ ---   ┆ ---   ┆ ---              ┆ ---    │
│ str         ┆ i64       ┆ date       ┆ f64   ┆ f64   ┆ str              ┆ i32    │
╞═════════════╪═══════════╪════════════╪═══════╪═══════╪══════════════════╪════════╡
│ Mount Wells ┆ 1490      ┆ 1978-02-27 ┆ 112.0 ┆ 310.0 ┆ Vancouver Island ┆ 1978   │
│ Mount Wells ┆ 1490      ┆ 1978-03-28 ┆ 127.0 ┆ 358.0 ┆ Vancouver Island ┆ 1978   │
│ Mount Wells ┆ 1490      ┆ 1978-04-26 ┆ 124.0 ┆ 404.0 ┆ Vancouver Island ┆ 1978   │
│ Mount Wells ┆ 1490      ┆ 1978-05-31 ┆ 56.0  ┆ 198.0 ┆ Vancouver Island ┆ 1978   │
│ Mount Wells ┆ 1490      ┆ 1979-02-26 ┆ 160.0 ┆ 495.0 ┆ Vancouver Island ┆ 1979   │
│ …           ┆ …         ┆ …          ┆ …     ┆ …     ┆ …                ┆ …      │
│ Klesilkwa   ┆ 1175      ┆ 2025-02-26 ┆ 14.0  ┆ 50.0  ┆ Cascades         ┆ 2025   │
│ Klesilkwa   ┆ 1175      ┆ 2025-03-30 ┆ 5.0   ┆ 18.0  ┆ Cascades         ┆ 2025   │
│ Klesilkwa   ┆ 1175      ┆ 2025-04-29 ┆ 0.0   ┆ 0.0   ┆ Cascades         ┆ 2025   │
│ Klesilkwa   ┆ 1175      ┆ 2025-12-31 ┆ 48.0  ┆ 106.0 ┆ Cascades         ┆ 2026   │
│ Klesilkwa   ┆ 1175      ┆ 2026-01-27 ┆ 22.0  ┆ 71.0  ┆ Cascades         ┆ 2026   │
└─────────────┴───────────┴────────────┴───────┴───────┴──────────────────┴────────┘

subset_data is a balanced panel of 8 stations between 1978 and 2026. That’s the data we will plot and play with.

Add ENSO data

The Pacific coast is strongly affected by El Niño–Southern Oscillation (ENSO)—an unpredictable pseudo-cycle of sea-surface temperature changes that lead to atmospheric oscillations. El Niño years tend to be drier and warmer, so bad for the snowpack (and skiers!) while La Niña tend to be wetter and colder (so great for non-skiers but bad for the snowpack and skiers).

Below a list of El Niño and La Niña years for our period of interest. It comes from the National Oceanic and Atmospheric Administration Oceanic Niño Index (ONI) data. Years that don’t fall under either El Niño or La Niña are considered “neutral”.

This tells a simplified story because not all El Niño or La Niña years are the same: there are strong, moderate, and weak events in which the patterns observed during El Niño or La Niña have different intensities.

el_nino_years = [
    1978, 1980, 1983, 1987, 1988, 1992, 1995, 1998, 2003,
    2005, 2007, 2010, 2015, 2016, 2019, 2020, 2024
]

la_nina_years = [
    1984, 1985, 1989, 1996, 1999, 2000, 2001, 2006, 2008, 2009,
    2011, 2012, 2017, 2018, 2021, 2022, 2023, 2025, 2026
]

We can add a column for ENSO data to our DataFrame (note the use of polars.when, polars.then, polars.otherwise, polars.is_in, and polars.lit in this snippet):

subset_enso = subset_data.with_columns(
    pl.when(pl.col("season").is_in(el_nino_years)).then(pl.lit("El Niño"))
    .when(pl.col("season").is_in(la_nina_years)).then(pl.lit("La Niña"))
    .otherwise(pl.lit("Neutral"))
    .alias("enso")
)

print(subset_enso)
shape: (1_675, 8)
┌─────────────┬───────────┬────────────┬───────┬───────┬──────────────────┬────────┬─────────┐
│ station     ┆ elevation ┆ date       ┆ snow  ┆ water ┆ range            ┆ season ┆ enso    │
│ ---         ┆ ---       ┆ ---        ┆ ---   ┆ ---   ┆ ---              ┆ ---    ┆ ---     │
│ str         ┆ i64       ┆ date       ┆ f64   ┆ f64   ┆ str              ┆ i32    ┆ str     │
╞═════════════╪═══════════╪════════════╪═══════╪═══════╪══════════════════╪════════╪═════════╡
│ Mount Wells ┆ 1490      ┆ 1978-02-27 ┆ 112.0 ┆ 310.0 ┆ Vancouver Island ┆ 1978   ┆ El Niño │
│ Mount Wells ┆ 1490      ┆ 1978-03-28 ┆ 127.0 ┆ 358.0 ┆ Vancouver Island ┆ 1978   ┆ El Niño │
│ Mount Wells ┆ 1490      ┆ 1978-04-26 ┆ 124.0 ┆ 404.0 ┆ Vancouver Island ┆ 1978   ┆ El Niño │
│ Mount Wells ┆ 1490      ┆ 1978-05-31 ┆ 56.0  ┆ 198.0 ┆ Vancouver Island ┆ 1978   ┆ El Niño │
│ Mount Wells ┆ 1490      ┆ 1979-02-26 ┆ 160.0 ┆ 495.0 ┆ Vancouver Island ┆ 1979   ┆ Neutral │
│ …           ┆ …         ┆ …          ┆ …     ┆ …     ┆ …                ┆ …      ┆ …       │
│ Klesilkwa   ┆ 1175      ┆ 2025-02-26 ┆ 14.0  ┆ 50.0  ┆ Cascades         ┆ 2025   ┆ La Niña │
│ Klesilkwa   ┆ 1175      ┆ 2025-03-30 ┆ 5.0   ┆ 18.0  ┆ Cascades         ┆ 2025   ┆ La Niña │
│ Klesilkwa   ┆ 1175      ┆ 2025-04-29 ┆ 0.0   ┆ 0.0   ┆ Cascades         ┆ 2025   ┆ La Niña │
│ Klesilkwa   ┆ 1175      ┆ 2025-12-31 ┆ 48.0  ┆ 106.0 ┆ Cascades         ┆ 2026   ┆ La Niña │
│ Klesilkwa   ┆ 1175      ┆ 2026-01-27 ┆ 22.0  ┆ 71.0  ┆ Cascades         ┆ 2026   ┆ La Niña │
└─────────────┴───────────┴────────────┴───────┴───────┴──────────────────┴────────┴─────────┘

Plotting

Let’s load the seaborn library:

import seaborn as sns

There are several ways to plot in seaborn. In this course, we will use the functions that plot across seaborn.FacedGrid.

Relationship plots

seaborn.relplot displays relationships between dependent and independent variables.

Scatter plots

To display the relationship between the height of snow and the season, you could first calculate the mean height of the snowpack for each season:

season_means = subset_enso.group_by(
    pl.col("season"),
    maintain_order=True
).agg(
    pl.col("snow").mean().alias("mean_snow")
)

Then plot those means against the seasons:

sns.relplot(
    data=season_means,
    x="season",
    y="mean_snow"
).figure.set_size_inches(8, 4)

In Jupyter, the plots will be displayed automatically. Outside Jupyter, you need to import matplotlib.pyplot and run matplotlib.pyplot.show():

import matplotlib.pyplot as plt
plt.show()

Line plots

By default kind is set to scatter and uses under the hood the function season.scatterplot.

You can change it to line and it will use instead the function seaborn.lineplot:

sns.relplot(
    data=season_means,
    kind="line",
    x="season",
    y="mean_snow"
).figure.set_size_inches(8, 4)

But calculating the mean manually as we just did isn’t necessary with seaborn which is a statistically oriented plotting framework. You can directly plot the height of the snowpack against the seasons and seaborn will calculate and plot the mean and 95% confidence interval around the mean:

sns.relplot(
    data=subset_enso,
    kind="line",
    x="season",
    y="snow"
).figure.set_size_inches(8, 4)

We can see that there is a great deal of year to year variation in the snowpack height, but it doesn’t look like there is much of a trend in the height of the snowpack over time.

To assess this further, we can use regression plots.

Regression plots

seaborn.lmplot plots the data and a linear regression model fit:

sns.lmplot(
    data=subset_enso,
    x="season",
    y="snow"
).figure.set_size_inches(8, 4)

Note that you can overlay multiple plots, as long as they share the same axis, by running them in the cell Jupyter cell or, if outside Jupyter, calling them before calling matplotlib.pyplot.show(). In our case, the result is very busy and not great however:

sns.relplot(
    data=subset_enso,
    kind="line",
    x="season",
    y="snow"
).figure.set_size_inches(8, 4)

sns.lmplot(
    data=subset_enso,
    x="season",
    y="snow"
).figure.set_size_inches(8, 4)

You can get the regression lines across various categories by passing a categorical variable to the hue argument:

sns.lmplot(
    data=subset_enso,
    x="season",
    y="snow",
    hue="enso"
).figure.set_size_inches(8, 4)

It looks like there is a downward trend for El Niño years.

Your turn:

Create relationship and regression plots for the El Niño data only.

They should look like the following:

Your turn:

Now make the same regression plot with only the stations below 1100m to see whether climate change is affecting low elevations more strongly.

Does it look like they are?

Categorical data

Categorical data can be displayed thanks to season.catplot.

Categorical scatterplots

By default, catplot displays a cloud of markers for each category:

sns.catplot(
    data=subset_enso,
    x="enso",
    y="snow",
    order=["La Niña", "Neutral", "El Niño"]
).figure.set_size_inches(8, 4)

Boxplots

Boxplots are a good way to display differences between groups. They can be draw in seaborn by passing box to the kind argument (the default is strip):

sns.catplot(
    data=subset_enso,
    x="enso",
    y="snow",
    kind="box",
    order=["La Niña", "Neutral", "El Niño"]
).figure.set_size_inches(8, 4)

Violin plots

For violin plots, pass violin to kind:

sns.catplot(
    data=subset_enso,
    x="enso",
    y="snow",
    kind="violin",
    order=["La Niña", "Neutral", "El Niño"]
).figure.set_size_inches(8, 4)

Distributions

seaborn.displot allows to display distribution plots.

Histograms

By default displot draws histograms (the default for the kind argument is hist and it uses seaborn.histplot under the hood):

sns.displot(
    data=subset_enso,
    x="snow",
    hue="enso"
).figure.set_size_inches(8, 4)

We can see that there is more data in the left bins for El Niño and more in the right bins for La Niña but it is not the best plot to tell our story.

Kernel density estimation

Kernel density estimation (KDE) applies kernel smoothing to the probability density estimation. You can plot them by passing kde to the kind argument (it uses seaborn.kdeplot under the hood).

The value for cut sets how far the evaluation grid extends past the extreme data points. Its default is 3. Setting it to 0 prevents it from drawing negative height of snow by going below zero:

sns.displot(
    data=subset_enso,
    x="snow",
    hue="enso",
    kind="kde",
    cut=0
).figure.set_size_inches(8, 4)

This is even worse than the histogram to show tell our story. It is not a great plot with our data.

eCDF plots

Empirical cumulative distribution functions (eCDF) display the fraction of observations that are smaller or equal to the values on the x axis.

This can be achieved by passing the value ecdf in the kind argument of the displot (which uses seaborn.ecdfplot under the hood):

sns.displot(
    data=subset_enso,
    x="snow",
    hue="enso",
    kind="ecdf"
).figure.set_size_inches(8, 4)

This is a much better way to display this data as it clearly tells the story: we can see that La Niña have a higher snowpack than neutral years which are in turn better than El Niño years.

References

1.
Waskom ML (2021) Seaborn: Statistical data visualization. Journal of Open Source Software 6(60):3021. https://doi.org/10.21105/joss.03021