Metadata-Version: 2.4
Name: shoreline
Version: 0.3.0
Summary: NATURESCAPES shoreline analysis
Author-email: Stephan Hügel <shugel@tcd.ie>
License-Expression: BlueOak-1.0.0
Project-URL: Repository, https://github.com/urschrei/naturescapes
Project-URL: Tracker, https://github.com/urschrei/naturescapes/issues
Keywords: gis,shoreline,analysis,DSAS
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.md
Requires-Dist: fastparquet>=2024.11.0
Requires-Dist: geojson>=3.2.0
Requires-Dist: geopandas>=1.0.1
Requires-Dist: matplotlib>=3.10.0
Requires-Dist: matplotlib-scalebar>=0.9.0
Requires-Dist: numpy>=2.2.2
Requires-Dist: scipy>=1.15.1
Requires-Dist: shapely>=2.0.6
Provides-Extra: test
Requires-Dist: pytest>=8.3.4; extra == "test"
Dynamic: license-file

# NATURESCAPES `shoreline` Package
![PyPI - Format](https://img.shields.io/pypi/format/shoreline?link=https%3A%2F%2Fpypi.org%2Fproject%2Fshoreline%2F)

This is the repo for the Naturescapes `shoreline` package and research notebooks.

Utilities for ray casting, working with LineString resolution, and clipping rays have been organized as a Python package in the `src` directory. The main interface is provided by the `ShorelineAnalyzer` class.

The design rationale for the ray-casting mechanism (back-projection from the LAT line, wave shadow detection, the derived refractive ratio, and the snell/transect mode split) is documented in [`docs/ray_casting.md`](docs/ray_casting.md).

**The minimum supported Python version is Python 3.10**.

## Usage (see `shoreline.ipynb` for example)
```python
from shoreline import ShorelineAnalyzer

# Create a new analyzer
analyzer = ShorelineAnalyzer()
sa = ShorelineAnalyzer(
    crs="EPSG:25829",
    shoreline="geodata/ireland/gadm36_IRL_shp/gadm36_IRL_0.shp",
    tideline="geodata/cleanup/Calculated Contours Backup/vorf_lat_simplified.gpkg",
    hat=2.09,
    lat=-2.44,
    wave_period=3.0,
    wave_height=2.0,
    ray_resolution=10,
    wave_bearing=295, # compass bearing waves travel towards (0 north, 90 east); defaults to shore-normal swell
    origin_distance=1500, # distance in m from the LAT line at which wave rays originate
    mode="snell", # "snell" (default): wave rays for impact analysis; "transect": shore-normal transects for slope statistics
    smoothing_window=500 # optional, transect-mode angle smoothing; defaults to 250
)
analysis = sa.evaluate()
# we now have a result object containing analysis metadata (.metadata), as well as geometries
# and summary stats
# call help(analysis) for more

# we can plot results if we're using a notebook. pl is a tuple of Matplotlib figures
pl = analysis.visualise_coastal_slopes()
# this gives us a (map, stats) tuple. Each figure can be saved
pl[0].savefig("dublin.png", dpi=300, bbox_inches="tight")
# you can also call the analysis.summary_stats property
# the computed ray and slope DataFrame is available as analysis.ray_data
```

## AnalysisResult Object Fields

The `AnalysisResult` object returned by `sa.evaluate()` contains the following fields:

### Metadata
- `metadata`: Dictionary containing analysis parameters including:
  - `timestamp`: ISO format timestamp of analysis
  - `analysis_crs`: The coordinate reference system used
  - `lat`/`hat`: Lowest/Highest Astronomical Tide values
  - `lat_crs`/`hat_crs`: Original CRS of LAT/HAT data
  - `wave_period`/`wave_height`: Wave parameters
  - `ray_resolution`: Resolution of ray casting in metres
  - `smoothing_window`: Window size used for transect-mode angle smoothing
  - `mode`: "snell" or "transect"
  - `wave_bearing`: Compass bearing waves travel towards
  - `refractive_index_ratio`: Resolved Snell ratio at the LAT line
  - `shadowed_vertices`: Number of LAT vertices shadowed from the swell direction

### Geometry Data
- `lat_line`: GeoDataFrame containing the LAT (Lowest Astronomical Tide) line
- `shore_line`: GeoDataFrame containing the HAT (Highest Astronomical Tide) shoreline
- `origin_rays`: GeoDataFrame containing the original rays before intersection
- `slopes`: GeoDataFrame containing the trimmed rays with calculated metrics (see below)
- `shoaling`: GeoDataFrame containing the line where waves begin shoaling
- `breaking`: GeoDataFrame containing the line where waves break
- `intertidal`: GeoDataFrame containing the intertidal zone polygon
- `score`: GeoDataFrame containing a LineString with impact intensity scores
- `shadowed`: GeoDataFrame of LAT vertices shadowed from the swell direction (snell mode)
- `intersections`: List of any ray intersections that were removed

### The `slopes` DataFrame
This is the main analysis output containing trimmed rays with the following columns:
- `geometry`: LineString geometries of rays from LAT to HAT
- `length`: Length of each ray in metres
- `start_depth`/`end_depth`: Depths at LAT and HAT
- `slope`: Gradient (rise/run)
- `slope_degrees`: Slope angle in degrees
- `slope_radians`: Slope angle in radians
- `slope_degrees_normalised`: Normalised slope values (0-1)
- `distance_to_breaking`: Distance from HAT to breaking line
- `distance_to_shoaling`: Distance from HAT to shoaling line
- `shoal_break_width`: Width between shoaling and breaking lines
- `shoal_extrapolated`/`break_extrapolated`: True where the shoaling or breaking point lies seaward of the LAT line and was placed by extrapolating the intertidal slope. Real subtidal profiles are typically flatter, so these offshore distances are lower bounds
- `convergence`: Shoreward convergence of the local ray bundle, the ratio of inter-ray spacing at the LAT line to the spacing at the HAT endpoints, averaged over each ray's neighbours. Values above 1 mean rays converge shoreward (wave-energy focusing, typical of bays under oblique swell); below 1, divergence. Its square root is the refraction coefficient K_r of classical wave-ray theory, so it can be used to scale local wave height (see `docs/ray_casting.md`)
- `impact_intensity`: The min-max normalised slope angle (0-1, higher = more intense wave impact). With a constant rise (HAT minus LAT) across all rays, the intertidal slope is the only independent geometric variable per ray, and steeper slopes deliver wave energy closer to the shoreline. The distance columns above are deliberately not combined into this score: under min-max normalisation they collapse to identical values and the wave parameters cancel out. Scores are relative within a single analysis and not comparable across analyses

### Summary Statistics
- `metrics`: Array of calculated gradient metrics
- `friendly_metrics`: Dictionary version of metrics with descriptive names
- `pcbreaks`: Percentile breakpoints used for visualisation [10, 25, 50, 75, 90, 95]

### Methods
- `visualise_coastal_slopes()`: Returns a tuple of (map_figure, stats_figure) for visualisation
- `summary_stats`: Property that returns formatted summary statistics

## Sample output from [`shoreline.ipynb`](isobath_to_onshore.ipynb) (Dublin Bay)
![Dublin Bay](standard.png "Dublin Bay, with smoothed rays cast offshore to onshore")

## Sample output of a ray intersecting isobaths [`ray_slope.ipynb`](ray_slope.ipynb)
![Ray / Slope](ray_slope.png "Using a divergent colour scheme to visualise slope orientation")

# Installation
`uv add shoreline` or `pip install shoreline`

## Installing for local development
This project is developed using [`uv`](https://docs.astral.sh/uv/),  but should work with just pip. The use of a virtualenv is advised.

```shell
uv venv
source .venv/bin/activate
uv sync --all-extras

uv add --dev ipykernel
uv run ipython kernel install --user --env VIRTUAL_ENV $(pwd)/.venv --name=shoreline
uv run --with jupyter jupyter lab
```
When creating a notebook, select the **`shoreline`** kernel from the dropdown. Then use e.g. `!uv add pydantic` to add pydantic to the project's dependencies, or `!uv pip install pydantic` to install pydantic into the project's virtual environment without persisting the change to the project `pyproject.toml` or `uv.lock files`. Either command will make import pydantic work within the notebook

### Anaconda
For Anaconda users: you will probably have to pull the requirements out of `pyproject.toml`. Sorry!

## Testing
The smoothing algorithm is relatively well covered by tests (see `tests/test_utils.py`). Run `pytest` in the root dir in order to test if you'd like to tinker with it.

## Data
Are in the [`geodata`](geodata) folder.

## Copyright
Stephan Hügel / Naturescapes, 2025

## Funding
The NATURESCAPES project is funded by the European Union under Grant Agreement No 10108434
