PhenoPhyto: A python package for detecting and visualizing phytoplankton bloom phenology events
Project description
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_chlthresholdthreshold_percentbloom_events
The bloom_events value is a pandas DataFrame with these columns:
bloom_idbloom_start_daybloom_start_valuebloom_end_daybloom_end_valuebloom_peak_daybloom_peak_valuebloom_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,longitudebloom_initiation,bloom_initiation_chlbloom_peak,bloom_peak_chlbloom_termination,bloom_termination_chlbloom_durationbloom_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:
longitudelatitude- 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()expectslongitude,latitude, and the variable to displayapply_idw_interpolation()expectslatitude,longitude, and the variable to interpolateplot_bloom_map()expects the interpolated output columnsx,y, and the variable to plot
For regional boxplots
regional_bloom_days_boxplot()expects a region column plus one or more bloom timing variablesregional_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_durationis interpreted in the same units as the supplied time column.geopandasandshapelyare only needed for shapefile masking and land or boundary overlays.
License
This project is released under the MIT License. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file phenophyto-0.3.1.tar.gz.
File metadata
- Download URL: phenophyto-0.3.1.tar.gz
- Upload date:
- Size: 26.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1fdea416693c7cdb3d2f0d586ca2b44f676ec0f8847408dde92a0e5467f17a1
|
|
| MD5 |
b13bf1553b6f92a0a180ad245bf59ef3
|
|
| BLAKE2b-256 |
5c3a2b0be85fd2b57944afd8d4c39f1bb9365d5e3fe5e9aff8cbc0f5c0c537c1
|
File details
Details for the file phenophyto-0.3.1-py3-none-any.whl.
File metadata
- Download URL: phenophyto-0.3.1-py3-none-any.whl
- Upload date:
- Size: 24.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
753580f338dff5472468dbae701ea284590ec3a619ed4bfcf543234faa29d161
|
|
| MD5 |
a8605ce19153c30f80660c8747daf1b5
|
|
| BLAKE2b-256 |
7bfd3194c68c12cc15d2834b24332fdef85adfaba88575e8458dc1926ce777a3
|