seaborn: a brief introduction

Author

Marie-Hélène Burle

seaborn, at its core, is a statistical visualization library for tabular data[]. 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("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)
['Powell River Upper', 'Copper Mountain', 'Germansen Lower', 'Tsaydaychi Lake', 'Lost Horse Mountain', 'Pass Lake', 'Pacific Lake', 'Bluejoint Mountain', 'Isintok Lake', 'Mount Seymour', 'Sproat Lake', 'Mount Penrose', 'Mount Abbot', 'Bear Creek Reservoir', 'Jade City', 'Heather Mountain Upper', 'Margaret Lake', 'Dease Lake', 'Fort Nelson Airport', 'Portage Mountain', 'Fort St. James', 'Nahatlatch River', 'Tranquille Lake', 'Tachek Creek', 'Esperon Creek Lower', 'Wolf River Lower', 'Pavilion Mtn.', 'Vermont Creek', 'Upper Elk River', 'Lady Laurier Lake', 'Trapping Creek (Upper)', 'Canoe River', 'Dog Mountain', 'Bugaboo Creek', 'Mount Albreda', 'Tennent Lake', 'Machmell River', 'Big Creek', 'Tumeka Creek', 'Upper Stikine', 'Trophy Mountain', 'Duncan Lake', 'Lost Ledge', 'Tiedemann Glacier', 'Nostetuko River', 'Fort St. John Airport', 'Cassiar', 'Powell River Lower', 'Log Cabin', 'Meadow Mountain', 'Mount Cronin', 'Burman Lake', 'Bear Pass', 'Tahtsa Lake', 'Mount Sheba', 'Mount Wells', 'Toba River', 'Porcupine Ridge', 'Nutli Lake', 'June Lake', 'Stave Lake', 'Downie Slide Upper', 'Great Bear', 'Terrace Airport', 'Vermilion River No.2', 'Record Mountain', 'Deadman River', 'Labour Day Lake', 'Lyford Mountain', 'Bouleau Creek', 'Kostal Lake', 'Snippaker Creek', 'Blackwater Lookout', 'Ottomite', 'Ware (Lower)', 'Sandon', 'Harlow Creek', 'Koch Creek', 'Forbidden Plateau', 'Mackenzie Airport Manual Snow Course (2003)', 'Conant Lake', 'Fernie Ridge', 'Eaglenest Creek', 'Kaza Lake', 'Wedeene River South', 'Green Mountain', 'Schaft Creek', 'Granite Mountain', 'Nelson', 'Bella Coola', 'Wade Lake', 'Knudsen Lake', 'Morrissey Ridge', 'Trapping Creek (Lower)', 'Mcbride Upper', 'Mount Kobau', 'Bridge Glacier Lower', 'Missinka River', 'Boston Bar Creek (Lower)', 'Middle River', 'Greyback Reservoir', 'Heather Mountain', 'Red Chris Mine Lower', 'Fidelity Mountain', 'Upper Quinsam', 'Blue River Town', 'Tripp Meadows', 'Hollyburn', 'Equity Mine', 'Cook Forks', 'Garibaldi Lake', 'Wonowon', 'Sunbeam Lake', 'Kimberley (Middle)Vor', 'Bullmoose Creek', 'Wolf River Upper', 'Granduc Mine', 'Shalalth', 'Pondosy Lake', 'Philip Lake', 'Nazko', 'Mount Saint Anne', 'Bigmouth Creek', 'Wedeene River', 'Kinaskan Lake', 'Beatton River', 'Barnes Creek', 'Downton Lake Upper', 'Silver Star Mountain', 'Mount Revelstoke', 'Old Glory Mountain', 'Bullhead Mountain', 'Pearson Creek', 'Duffey Lake', 'Holmes River', 'Missezula Mountain', 'Bralorne (Upper)', 'Wolverine Creek', 'Lac Le Jeune Upper', 'Johanson Lake', 'Mount Joffre', 'Brookmere', 'Vermilion River No.5', 'Burns Lake', 'Mission Creek', 'Mckendrick Creek', 'Spahomin', 'Graystoke Lake', 'Toad River', 'Kicking Horse', 'Smithers', 'Mount Copeland', 'Lac Le Jeune Lower', 'North Clemina Creek', 'Skins Lake', 'Sumallo River', 'Mount Cook', 'Disappointment Lake', 'Mount Swannell', 'Vaseux Creek', 'Mount Cokely', 'Nickel Plate', 'Tashme', 'Carmi', 'Bralorne', 'Keystone Creek', 'Kemess Creek Lower', 'Downie Slide Lower', 'Ware (Upper)', 'Haddo Lake', 'Sukunka River', 'Lightning Lake', 'Nechako', 'Summit Lake', 'Vermilion River No. 3', 'Invermere', 'Park Mountain', 'Aberdeen Lake', 'Mount Stearns', 'Whitesail Lake', 'Black Mountain', 'Kidprice Lake', 'Link Lake', 'Klesilkwa', 'Gray Creek Lower', 'Hansard', 'Grayling River', 'Bluff Creek', 'Macdonald Lake', 'Bonaparte Lake', 'Sullivan Mine', 'Mcleod Lake', 'Cornwall Hills', 'Esperon Creek Upper', 'Thunder Creek', 'Goldstream', 'Hourglass', 'Edwards Lake', 'Memory Lake', 'Torpy River', 'St. Leon Creek', 'Kimberley (Upper) Vor', 'Longworth Upper', 'Mcqueen Lake', 'New Glacier', 'Mount Assiniboine', 'Boss Mountain Mine', 'Grouse Mountain', 'Harry Lake', 'Knouff Lake', 'Mcbride Lower', 'Farron', 'Blackwater Creek', 'Deadwood River', 'Monkman Creek', 'Prince George Airport', 'Postill Lake', 'Ningunsaw Pass', 'Sumallo River West', 'Telegraph Creek', 'Kimberley', 'Mica Creek', 'Gray Creek Upper', 'Elk River', 'Kluachesi Lake', 'Hedrick Lake', 'Dome Mountain', 'Bird Creek', 'Yanks Peak', 'Trout Creek West', 'Callaghan Creek', 'Orchid Lake', 'Blackhawk', 'Anglemont', 'Whatshan Lower', 'Boston Bar Creek (Upper)', 'Frog River', 'Bush River', 'Brenda Mine', 'Postill Lake Upper', 'Powell River', 'Upper Thelwood Lake', 'Downie Site 8', 'Kwadacha River', 'Mcbride Middle', 'Burwell Lake', 'Germansen Upper', 'Glacier', 'Palisade Lake', 'Morfee Mountain', 'Adams River', 'Highland Valley', 'Azure River', 'Revelstoke', 'Purcell', 'Field', 'Beaverfoot', 'Longworth Lower', 'Sikanni Lake', 'Atlin Lake', 'Lu Lake', 'Pine Pass', 'Tyaughton Creek (North)', 'Fernie East', 'Whatshan Upper', 'Puntzi Mountain', 'Trout River', 'Mcculloch', 'Whiterocks Mountain', 'Fredrickson Lake', 'Fish Lake No. 2', 'Duncan Lake No. 2', 'Mount Timothy', 'Mount Roosevelt', 'Ipec Lake', 'Alouette Lake', 'Esperon Creek Middle', 'Floe Lake', 'Fernie (Ne)', 'Bouleau Lake', 'East Creek', 'Triumph Creek', 'Blackwall Peak', 'Boundary', 'Iskut', 'Yellowhead', 'Fish Lake', 'Kirbyville Lake', 'Sinclair Pass', 'Watam Lake', 'Hope', 'Loch Lomond', 'Upper Stave River', 'Gnawed Mountain', 'Ferguson', 'Hudson Bay Mountain', 'Horsefly Mountain', 'Alligator Meadows', 'Red Chris Mine Upper', 'Chapman Lake', 'Trapping Creek', 'Tahltan Lake', 'Monashee Pass', 'Mcgillivray Pass', 'Kemess Creek Upper', 'Blue River', 'Barkerville', 'Kinbasket Lake', 'Bowron Lake', 'Arrow Creek', 'Cypress Lake', 'Precipice', 'Pink Mountain', 'Enderby', 'Carrs Landing (Lower)', 'Caverhill Lake New', 'Marble Canyon', 'Fernie', 'Vermilion River No.1', 'Tenquille Lake', 'Summerland Reservoir', 'French Snowshoe', 'Newcastle Ridge', 'Whistler Mountain', 'Stanley Creek', 'Shovelnose Mountain', 'Forfar Creek (Upper)', 'Pennask Creek', 'Steelhead', 'Tutizzi Lake', 'Rabbit River', 'Revolution Creek', 'Penfold Creek', 'Vermilion River No.4', 'Oyama Lake', 'Islaht Lake', 'Diamond Head', 'Trout Creek', 'Chapman Creek', 'Kimberley (Lower) Vor', 'Trygve Lake', 'Mackenzie Airport', 'Mount Templeman', 'Dickson Lake', 'Braden River', 'Gerrard', 'Hamilton Hill', 'New Tashme', 'Big White Mountain', 'Carrs Landing (Upper)', 'Lytton', 'Narrow Lake', 'Sunday Summit', 'Pavilion', 'Wahleach Lake', 'Wolf River Middle', 'Tatlayoko Lake', 'Forrest Kerr Creek', 'Moyie Mountain', 'Char Creek', 'Coquitlam Lake', 'Pulpit Lake', 'Humamilt Lake', 'Sno-Bird Lake']

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("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
['Forbidden Plateau', 'Klesilkwa', 'Upper Thelwood Lake', 'Nahatlatch River', 'Mount Wells', 'Grouse Mountain', 'Duffey Lake', 'Wolf River Lower']

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

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(7, 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(7, 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(7, 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.regplot plots the data and a linear regression model fit:

sns.regplot(
    data=subset_enso,
    x="season",
    y="snow"
).figure.set_size_inches(7, 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(7, 4)

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

seaborn.lmplot

sns.lmplot(
    data=subset_enso,
    x="season",
    y="snow",
    hue="enso"
).figure.set_size_inches(7, 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 scatterplots

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

Boxplots

Boxplots are a good way to display differences between groups. They can be draw in seaborn with seaborn.boxplot:

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

Violin plots

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

Distributions

seaborn.displot allows to display distribution plots.

Histograms

seaborn.histplot

sns.displot(
    data=subset_enso,
    x="snow",
    hue="enso"
)

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.

seaborn.kdeplot

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
)

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"
)

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