Package Overview

terndata.ecoplots is a Python client for the TERN EcoPlots platform. It helps you discover, filter, preview, and download ecological plot data in a workflow that feels familiar to ecologists.

The package is designed so you can:

  • Start with simple filters (for example site, dataset, region)

  • Preview results before full download

  • Retrieve data as pandas/geopandas tables for analysis

  • Save your current setup and reuse it later

If you are new to Python, the most important thing to know is: you usually only need to set filters with methods like select(). Most internal variables are managed by the library.

Client Types: Sync vs Async

The library provides two clients. They behave almost the same, except for how get_data() is called.

Client

Best for

When to use

get_data() call

EcoPlots

Beginners, notebooks, simple scripts

You want the simplest workflow and do not need await.

df = ec.get_data()

AsyncEcoPlots

Larger fetches, apps/services, advanced users

You are already using async code and want non-blocking downloads.

df = await ec.get_data()

Important:

  • Methods such as select(), summary(), and preview() are used in the same way for both clients.

  • The practical difference is mainly the final data fetch step (get_data()).

Constructor Parameters (__init__)

Both classes share the same constructor:

EcoPlots(filterset=None, query_filters=None, mode="observations")
AsyncEcoPlots(filterset=None, query_filters=None, mode="observations")

Parameter guide

Parameter

Type

What it sets

Should you set it manually?

filterset

dict or None

Human-readable filters loaded at startup.

Usually leave as None and use select() in normal use.

query_filters

dict or None

Internal API-ready filter values (typically resolved URIs).

No. This is internal state and should usually not be edited.

mode

str

Data domain: "observations" (default) or "samples".

Yes, if you intentionally want samples workflows.

What mode changes

  • mode="observations":

    Standard ecological observation workflows.

  • mode="samples":

    Enables sample-focused workflows and methods (for example material sample type, IGSN, soil/sample utilities).

In samples mode, the library enforces a required dataset selection (TERN Ecosystem Surveillance) internally so the query stays valid. Do not manually remove this from internal state.

Variables You Should Not Change Manually

For most users, avoid editing internal attributes directly. In particular, do not manually modify:

  • _query_filters (internal API filter representation)

  • _filters (managed by helper methods such as select() and remove())

  • _mode after initialization (set mode=... when creating the client)

  • _base_url (managed by package configuration)

Recommended practice is:

  1. Create a client.

  2. Apply filters via public methods.

  3. Preview/summary.

  4. Call get_data().

Beginner-Friendly Example

from terndata.ecoplots import EcoPlots

# Start simple with default mode="observations"
ec = EcoPlots()

# Add filters using public API (recommended)
ec.select(site_id="TCFTNS0002", dataset="TERN Ecosystem Surveillance")

# Check a small preview first
preview_df = ec.preview(dformat="pd")

# Fetch full data
data_gdf = ec.get_data()

Magic Methods & Pythonic API

Both EcoPlots and AsyncEcoPlots support intuitive Pythonic operations through magic methods:

from terndata.ecoplots import EcoPlots

ec = EcoPlots()

# Dict-like access
ec["site_id"] = "TCFTNS0002"
ec["dataset"] = "TERN Ecosystem Surveillance"

# Check filters
if "site_id" in ec:
    print(f"Site ID: {ec['site_id']}")

# Count filters
print(f"Active filters: {len(ec)}")

# Boolean check
if ec:  # True if any filters are set
    print("Filters are configured")

# Beautiful display
print(ec)  # Shows professional box-formatted output

# Comparison
ec2 = EcoPlots()
ec2["site_id"] = "TCFTNS0002"
print(ec == ec2)  # False (different datasets)

# Copying
import copy
ec_copy = copy.deepcopy(ec)

See the EcoPlots and AsyncEcoPlots class documentation for detailed method descriptions.

EcoPlots: Python clients for TERN’s EcoPlots REST API.

This package provides high-level clients that abstract data discovery and access from the EcoPlots Portal into a small, Pythonic API. Use it to discover datasets, apply filters, preview results, and retrieve tidy data structures for analysis.

Operational Modes:

EcoPlots supports two modes via the mode argument on client construction:

  • observations (default): access observation workflows including feature

    types, observed properties, and GeoJSON-oriented retrieval.

  • samples: access material-sample workflows (for example,

    material_sample_type and used_procedure) with samples-specific discovery and retrieval semantics.

Public API

  • EcoPlots — synchronous client for scripts and notebooks

  • AsyncEcoPlots — async counterpart for ASGI apps or

    parallel I/O in notebooks

Returned results integrate naturally with analysis tools (e.g., pandas.DataFrame, geopandas.GeoDataFrame) or can be consumed as raw GeoJSON.

Side Effects

On import, EcoPlots may start a best-effort, background cache preloader to warm up lightweight metadata used for discovery and validation. This is deliberately minimal; if the loader is unavailable (e.g., no network), the import still succeeds and normal client operations continue without caching.

Quick Start

Synchronous:

from terndata.ecoplots import EcoPlots

ec = EcoPlots()
ec.select(site_id="TCFTNS0002")        # add filters
preview = ec.preview().head()           # quick look
gdf = ec.get_data()                     # full pull (GeoDataFrame)

Synchronous (samples mode):

from terndata.ecoplots import EcoPlots

ec = EcoPlots(mode="samples")
ec.select(material_sample_type="Plant Tissue Sample")
gdf = ec.get_data(dformat="gpd")
df = ec.get_data(dformat="pd")

Asynchronous:

import asyncio
from terndata.ecoplots import AsyncEcoPlots

async def main():
    ec = AsyncEcoPlots()
    ec.select(site_id="TCFTNS0002")
    gdf = await ec.get_data()
    return gdf

# asyncio.run(main())

Asynchronous (samples mode):

import asyncio
from terndata.ecoplots import AsyncEcoPlots

async def main_samples():
    ec = AsyncEcoPlots(mode="samples")
    ec.select(material_sample_type="Plant Tissue Sample")
    gdf = await ec.get_data(dformat="gpd")
    df = await ec.get_data(dformat="pd")
    return gdf, df

# asyncio.run(main_samples())

Notes

  • The package surface is intentionally small; modules and names prefixed with _ are

    internal and may change without notice.

  • Projects can be saved/loaded via .ecoproj files for reproducible workflows.

  • In samples mode, exactly one material_sample_type must be selected

    before data retrieval.

class terndata.ecoplots.EcoPlots(filterset=None, query_filters=None, mode='observations')[source]

Bases: EcoPlotsBase

High-level Python client for the EcoPlots REST API.

Provides a small, Pythonic surface for discovering, filtering, previewing, and retrieving ecological plot data. Returns tidy structures for analysis (pandas.DataFrame, geopandas.GeoDataFrame) or raw GeoJSON.

The class mirrors the async runtime (AsyncEcoPlots) but is synchronous for notebook and script workflows. Projects can be serialised and reloaded via .ecoproj files to make analyses reproducible.

Examples

Basic usage:

from terndata.ecoplots import EcoPlots

ecoplots = EcoPlots()
ecoplots.get_datasources().head()         # discover datasets
ecoplots.select(site_id="TCFTNS0002")     # add filters (validated & fuzzy-resolved)
ecoplots.preview().head()                 # quick look (first page)
df = ecoplots.get_data()                  # full pull as GeoDataFrame

Save / load a project:

path = ecoplots.save("myproject.ecoproj")
ecoplots2 = EcoPlots.load(path)
ecoplots2.get_filter("site_id")           # ['TCFTNS0002']

See also

AsyncEcoPlots: Async counterpart with the same surface area.

Parameters:
  • filterset (dict | None)

  • query_filters (dict | None)

  • mode (str | None)

summary(dformat=None)[source]

Summarize the EcoPlots data.

Parameters:

dformat (str | None) – The desired format for the summary. If "json", returns the raw summary dict from the API. Defaults to None, which returns a pandas.DataFrame.

Returns:

When dformat is "json", returns the raw summary dict from the API. Otherwise, returns a pandas.DataFrame with columns metric and count summarising the current selection (e.g. total observations, unique sites, datasets).

Return type:

DataFrame | str

preview(dformat=None)[source]

Fetch a small preview of EcoPlots data. # noqa: DAR401, D415

Mirrors get_data() but limits results to 10 records for a quick look.

In observations mode, fetches CSV from up to 2 feature types (5 rows each). In samples mode, calls the samples endpoint and returns the first 10 rows; "geojson"/"json" formats are not supported in this mode.

Parameters:

dformat (str | None) – Output format. - "geojson" or "json": returns a GeoJSON dict (observations only). - "pandas" (or "pd"): returns a pandas.DataFrame. - "geopandas" (or "gpd") (default): returns a GeoDataFrame.

Returns:

Preview data in the requested format.

Raises:
  • EcoPlotsError – If an invalid dformat is provided.

  • RuntimeError – If no feature types found (observations mode).

Return type:

geopandas.GeoDataFrame | dict | str

get_datasources()[source]

Get the data sources available for applied filters.

Returns:

A DataFrame containing the data sources.

Return type:

DataFrame

get_datasources_attributes()[source]

Get the attributes of data sources from the applied filters.

Returns:

A DataFrame containing the attributes of the data sources.

Return type:

DataFrame

get_sites()[source]

Get the sites from the applied filters.

Returns:

A DataFrame containing the sites.

Return type:

DataFrame

get_sites_attributes()[source]

Get the attributes of sites from the applied filters.

Returns:

A DataFrame containing the attributes of the sites.

Return type:

DataFrame

get_site_visit_attributes()[source]

Get the attributes of site visits from the applied filters.

Returns:

A DataFrame containing the attributes of the site visits.

Return type:

DataFrame

get_region_types()[source]

Get the available region types from the applied filters.

Returns:

A DataFrame containing the region types.

Return type:

DataFrame

get_regions(region_type)[source]

Get the available regions for a specific region type from the applied filters.

Parameters:

region_type (str) – The region type to retrieve regions for.

Returns:

A DataFrame containing the regions for the specified region type.

Return type:

DataFrame

get_feature_types()[source]

Get the feature types from the applied filters.

Returns:

A DataFrame containing the feature types.

Return type:

DataFrame

get_observed_properties()[source]

Get the observed properties from the applied filters.

Returns:

A DataFrame containing the observed properties.

Return type:

DataFrame

get_used_procedures()[source]

Get the used procedures available for the current filters.

Available in both observations and samples modes.

Returns:

A DataFrame containing the used procedures.

Return type:

DataFrame

get_observation_attributes()[source]

Get the attributes of observations from the applied filters. Available only in “observations” mode.

Returns:

A DataFrame containing the attributes of the observations.

Raises:

EcoPlotsError – If called in a mode other than “observations”.

Return type:

DataFrame

get_material_sample_types()[source]

Get the material sample types from the applied filters. Available only in “samples” mode.

Returns:

A DataFrame containing the material sample types.

Raises:

EcoPlotsError – If called in a mode other than “samples”.

Return type:

DataFrame

get_sample_igsn()[source]

Get sample names and derived IGSN values.

Available only in samples mode. This method discovers sample_name values using the current query filters, then returns a DataFrame with: - sample_name: sample name with alphabetic characters capitalized. - igsn: derived as 10.60792/{sample_name_raw}.

Returns:

A DataFrame with columns sample_name and igsn.

Raises:

EcoPlotsError – If called in a mode other than samples.

Return type:

DataFrame

view_sample_igsn(igsn=None)[source]

Open an interactive notebook viewer for sample IGSN DOI pages.

Available only in samples mode. This method discovers sample names, builds IGSN values, and displays either: - a dropdown + iframe widget (default), or - a single iframe for a provided IGSN/DOI value.

Parameters:

igsn (str | None) – Optional IGSN value or DOI URL. Accepted inputs include 10.60792/..., doi.org/10.60792/..., and https://doi.org/10.60792/....

Returns:

ipywidgets.VBox – Interactive IGSN viewer widget.

Raises:
get_soil_depth_range()[source]

Get the soil depth range for the current filters.

Available only in “samples” mode.

Returns:

A GeoDataFrame containing aggregated soil depth range values.

Raises:
  • EcoPlotsError – If called in a mode other than “samples”.

  • EcoPlotsError – If none of the required material sample types are selected.

Return type:

geopandas.GeoDataFrame

get_soilpit()[source]

Get soil pit distribution for the current filters.

Available only in “samples” mode.

Returns:

A DataFrame with two columnssoilpit and counts.

Raises:
  • EcoPlotsError – If called in a mode other than “samples”.

  • EcoPlotsError – If none of the required material sample types are selected.

Return type:

DataFrame

get_speciesname()[source]

Get species name distribution for the current filters.

Available only in “samples” mode.

This method preserves all current query filters, including has_image.

Returns:

A DataFrame with two columnsspeciesname and count.

Raises:
  • EcoPlotsError – If called in a mode other than “samples”.

  • EcoPlotsError – If none of the required material sample types are selected.

Return type:

DataFrame

get_data(allow_full_download=False, dformat='gpd')[source]

Retrieve EcoPlots data based on the current filters.

Parameters:
  • allow_full_download (bool | None) – If True, allows downloading the full dataset without filters. Defaults to False.

  • dformat (str | None) –

    Output format. - “geojson” or “json”: returns a pretty-printed GeoJSON string. - “pandas” (or ‘pd’): returns a pandas DataFrame. - “geopandas” (or ‘gpd’) (default): returns a GeoDataFrame.

    In “samples” mode, only “pandas”/”pd” and “geopandas”/”gpd” are supported (no “geojson”/”json”).

    In “samples” mode, exactly one material_sample_type must be selected at a time.

Raises:
  • RuntimeError – If no filters are set and allow_full_download is False.

  • EcoPlotsError – If an invalid dformat is provided.

Returns:

Data in the requested format.

Return type:

geopandas.GeoDataFrame

select_spatial(**kwargs)[source]

Open the spatial selection widget.

A minimal map based spatial selector, similar to spatial selection tool in EcoPlots Portal.

Parameters:

**kwargs – Additional keyword arguments to pass to the widget.

Returns:

ipywidgets.VBox – The widget. Use it in a notebook cell to display.

view_sample_images(data=None, image_column='sample_images', sample_id_column='sample_id', sample_name_column='sample_name', scientific_name_column='scientific_name')[source]

Open an interactive notebook image browser for sample images.

Parameters:
  • data (DataFrame | None) – Optional DataFrame to browse. If omitted, data is fetched in samples mode using current filters.

  • image_column (str) – Name of image column in dataframe.

  • sample_id_column (str) – Name of sample identifier column in dataframe.

  • sample_name_column (str) – Name of sample name column in dataframe.

  • scientific_name_column (str) – Name of scientific name column in dataframe.

Returns:

ipywidgets.VBox – Interactive viewer widget.

class terndata.ecoplots.AsyncEcoPlots(filterset=None, query_filters=None, mode='observations')[source]

Bases: EcoPlots

High-level async client for the EcoPlots REST API.

Provides an awaitable get_data() for large/long-running fetches while reusing the synchronous ergonomics elsewhere. Ideal for web backends (ASGI) or notebooks wanting to parallelise I/O heavy pulls.

Examples

Basic async usage:

from terndata.ecoplots import AsyncEcoPlots

ec = AsyncEcoPlots()
ec.select(site_id="TCFTNS0002")    # selection etc. is sync but cheap
gdf = await ec.get_data()          # await the heavy network call

Notes

  • Only get_data() is async here. Other methods inherited from EcoPlots are synchronous and will block.

  • Safety guard: get_data() raises RuntimeError when no filters are set unless allow_full_download=True.

Parameters:
  • filterset (dict | None)

  • query_filters (dict | None)

  • mode (str | None)

async get_data(allow_full_download=False, dformat='gpd')[source]

Retrieve EcoPlots data asynchronously based on the current filters.

Parameters:
  • allow_full_download (bool | None) – If True, allows downloading the full dataset without filters. Defaults to False.

  • dformat (str | None) –

    Output format. - “geojson” or “json”: returns a pretty-printed GeoJSON string. - “pandas” (or “pd”): returns a pandas DataFrame. - “geopandas” (or “gpd”) (default): returns a GeoDataFrame.

    In “samples” mode, only “pandas”/”pd” and “geopandas”/”gpd” are supported (no “geojson”/”json”).

    In “samples” mode, exactly one material_sample_type must be selected at a time.

Raises:
  • RuntimeError – If no filters are set and allow_full_download is False.

  • EcoPlotsError – If an invalid dformat is provided.

  • BaseException – Propagated from underlying fetch tasks when data retrieval fails. #noqa: DAR402

Returns:

Data in the requested format.

Return type:

geopandas.GeoDataFrame