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

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