Skip to main content

PhenoPhyto

PhenoPhyto is a Python package for detecting and visualizing phytoplankton bloom phenology from chlorophyll data. It supports three common workflows:

  • spatial daily climatology bloom detection
  • spatial weekly climatology bloom detection
  • non-spatial time-series bloom detection and visualization

The package also includes helper functions for regional comparison plots and spatial mapping of phenology metrics.

What the package does

PhenoPhyto can help you:

  • detect bloom initiation, peak, termination, and duration from chlorophyll climatologies
  • detect multiple bloom events in a single non-spatial time series
  • highlight bloom periods on time-series plots
  • create quick spatial maps from point results
  • interpolate phenology variables to a grid with inverse distance weighting (IDW)
  • build regional boxplots with Tukey HSD compact letter displays

Installation

Use Python 3.

pip install PhenoPhyto

Optional geospatial overlays and masking in the mapping functions work best if you also install:

pip install geopandas shapely

Imports

These functions are available from the package root:

from PhenoPhyto import (
    detect_phyto_pheno_1,
    detect_phyto_pheno_2,
    detect_phyto_pheno_3,
    plot_bloom_events,
)

Additional plotting helpers live in PhenoPhyto.plotting:

from PhenoPhyto.plotting import (
    apply_idw_interpolation,
    plot_bloom_map,
    map_phenology_variable,
    regional_bloom_days_boxplot,
    regional_number_of_bloom_boxplot,
)

Quick start: non-spatial time series

Use detect_phyto_pheno_3() when you have a single chlorophyll time series without latitude and longitude columns.

import numpy as np
import pandas as pd

from PhenoPhyto import detect_phyto_pheno_3, plot_bloom_events

df = pd.DataFrame({
    "day_of_year": np.arange(1, 366),
    "CHL": 1 + 0.3 * np.sin(np.linspace(0, 8 * np.pi, 365)) + np.random.rand(365) * 0.4,
})

bloom_data = detect_phyto_pheno_3(
    df,
    time_col="day_of_year",
    chl_col="CHL",
    threshold_percent=10,
    min_gap=2,
    min_duration=3,
)

print("Threshold:", bloom_data["threshold"])
print(bloom_data["bloom_events"])

plot_bloom_events(
    df,
    bloom_data,
    region_name="Sample Region",
    time_col="day_of_year",
    chl_col="CHL",
)

detect_phyto_pheno_3() returns a dictionary with:

  • median_chl
  • threshold
  • threshold_percent
  • bloom_events

The bloom_events value is a pandas DataFrame with these columns:

  • bloom_id
  • bloom_start_day
  • bloom_start_value
  • bloom_end_day
  • bloom_end_value
  • bloom_peak_day
  • bloom_peak_value
  • bloom_duration

Spatial daily climatology

Use detect_phyto_pheno_1() when your data contain latitude, longitude, daily time steps, and chlorophyll values.

import pandas as pd

from PhenoPhyto import detect_phyto_pheno_1

df_daily = pd.DataFrame({
    "latitude": [21.0, 21.0, 21.0, 21.5, 21.5, 21.5],
    "longitude": [91.0, 91.0, 91.0, 91.5, 91.5, 91.5],
    "day": [40, 80, 120, 40, 80, 120],
    "CHL": [0.8, 2.3, 1.1, 0.9, 2.8, 1.2],
})

daily_result = detect_phyto_pheno_1(
    df_daily,
    lat_col="latitude",
    lon_col="longitude",
    time_col="day",
    chl_col="CHL",
    threshold_percent=10,
    min_duration=0,
)

print(daily_result.head())

The output is a DataFrame with one row per location and columns such as:

  • latitude, longitude
  • bloom_initiation, bloom_initiation_chl
  • bloom_peak, bloom_peak_chl
  • bloom_termination, bloom_termination_chl
  • bloom_duration
  • bloom_initiation_month, bloom_peak_month, bloom_termination_month

Spatial weekly climatology

Use detect_phyto_pheno_2() when the time column is weekly instead of daily.

from PhenoPhyto import detect_phyto_pheno_2

weekly_result = detect_phyto_pheno_2(
    df_weekly,
    lat_col="latitude",
    lon_col="longitude",
    time_col="week",
    chl_col="CHL",
    threshold_percent=10,
    min_duration=0,
)

The returned columns match the daily workflow, but the timing is interpreted in weeks.

Quick spatial map

If you already have spatial point results from detect_phyto_pheno_1() or detect_phyto_pheno_2(), you can map any phenology variable directly.

from PhenoPhyto.plotting import map_phenology_variable

fig = map_phenology_variable(
    daily_result,
    var_col="bloom_peak",
    title="Bloom Peak Day",
    legend_label="Day of Year",
    color_palette="viridis",
)

Expected input columns:

  • longitude
  • latitude
  • the variable you want to plot

Interpolated phenology map

For a smoother map, interpolate a phenology variable to a grid with IDW and then plot the result.

from PhenoPhyto.plotting import apply_idw_interpolation, plot_bloom_map

interp = apply_idw_interpolation(
    daily_result,
    var_column="bloom_initiation",
    grid_resolution=0.05,
    idp_value=2.0,
)

fig = plot_bloom_map(
    data=interp,
    x_col="x",
    y_col="y",
    fill_col="bloom_initiation",
    title="Bloom Initiation Day",
    fill_name="Day of Year",
    fill_palette="RdYlBu_r",
)

If you pass GeoDataFrames to the shapefile arguments, plot_bloom_map() can also overlay region boundaries and land layers.

Regional comparison boxplots

regional_bloom_days_boxplot() is designed for comparing bloom timing variables across regions.

from PhenoPhyto.plotting import regional_bloom_days_boxplot

fig = regional_bloom_days_boxplot(
    data=regional_df,
    region_var="region",
    y_vars=["bloom_initiation", "bloom_peak", "bloom_termination"],
    y_labels=["Bloom Start Day", "Bloom Peak Day", "Bloom Termination Day"],
    ncol=3,
)

regional_number_of_bloom_boxplot() is designed for long-format bloom-count data.

from PhenoPhyto.plotting import regional_number_of_bloom_boxplot

fig = regional_number_of_bloom_boxplot(
    data=count_df,
    x_var="Zone",
    y_var="Count",
    x_label="Regions",
    y_label="Number of Blooms",
)

Both functions use Tukey HSD compact letter displays when the statistical calculation succeeds.

Function overview

Function Purpose
find_peaks_from_chl_data() Helper for identifying peaks above a threshold in a time series
detect_phyto_pheno_1() Detect bloom phenology from daily spatial climatology data
detect_phyto_pheno_2() Detect bloom phenology from weekly spatial climatology data
detect_phyto_pheno_3() Detect bloom events from a non-spatial chlorophyll time series
plot_bloom_events() Plot a chlorophyll time series and shade bloom periods
map_phenology_variable() Create a quick spatial map from point phenology data
apply_idw_interpolation() Interpolate a phenology variable to a regular grid
plot_bloom_map() Plot an interpolated phenology surface with optional overlays
regional_bloom_days_boxplot() Compare bloom timing metrics across regions
regional_number_of_bloom_boxplot() Compare bloom counts across regions

Data requirements

For detect_phyto_pheno_1()

  • a pandas DataFrame
  • latitude and longitude columns
  • a daily time column such as day
  • a numeric chlorophyll column such as CHL

For detect_phyto_pheno_2()

  • a pandas DataFrame
  • latitude and longitude columns
  • a weekly time column such as week
  • a numeric chlorophyll column such as CHL

For detect_phyto_pheno_3()

  • a pandas DataFrame
  • a time column such as day_of_year
  • a numeric chlorophyll column such as CHL

For mapping functions

  • map_phenology_variable() expects longitude, latitude, and the variable to display
  • apply_idw_interpolation() expects latitude, longitude, and the variable to interpolate
  • plot_bloom_map() expects the interpolated output columns x, y, and the variable to plot

For regional boxplots

  • regional_bloom_days_boxplot() expects a region column plus one or more bloom timing variables
  • regional_number_of_bloom_boxplot() expects long-format data with a grouping column and a numeric count column

Notes

  • Chlorophyll values must be numeric.
  • In the spatial detection functions, duplicate observations at the same time step within a location are averaged before analysis.
  • min_duration is interpreted in the same units as the supplied time column.
  • geopandas and shapely are only needed for shapefile masking and land or boundary overlays.

License

This project is released under the MIT License. See LICENSE.

Metadata

Release files for PhenoPhyto 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for PhenoPhyto 0.3.1
File Size Uploaded
phenophyto-0.3.1.tar.gz 26.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for PhenoPhyto 0.3.1
File Interpreter ABI Platform
phenophyto-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 50.6 kB

Release files / phenophyto-0.3.1.tar.gz

Download URL phenophyto-0.3.1.tar.gz
Size 26.3 kB
Tags Source
SHA-256 checksum
How to use checksums
c1fdea416693c7cdb3d2f0d586ca2b44f676ec0f8847408dde92a0e5467f17a1
BLAKE2b-256 checksum
How to use checksums
5c3a2b0be85fd2b57944afd8d4c39f1bb9365d5e3fe5e9aff8cbc0f5c0c537c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.1

Release files / phenophyto-0.3.1-py3-none-any.whl

Download URL phenophyto-0.3.1-py3-none-any.whl
Size 24.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
753580f338dff5472468dbae701ea284590ec3a619ed4bfcf543234faa29d161
BLAKE2b-256 checksum
How to use checksums
7bfd3194c68c12cc15d2834b24332fdef85adfaba88575e8458dc1926ce777a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.1

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2

2 release files

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page