stride Data API¶
This page displays the data API methods available in stride for computing energy demand calculations.
Data API¶
- class stride.api.APIClient(project: Project | None = None)¶
Singleton API client for querying STRIDE electricity load and demand data.
This class provides a thread-safe singleton interface to a DuckDB database containing electricity consumption, demand, and related metrics data. It ensures only one database connection exists throughout the application lifecycle while providing convenient methods for common data queries used in dashboard visualizations.
The client supports various data retrieval patterns including: - Annual consumption and peak demand metrics with optional breakdowns - Load duration curves for capacity planning analysis - Time series data with flexible resampling and grouping - Seasonal load pattern analysis - Secondary metrics integration (economic, demographic, weather data)
- db¶
The underlying DuckDB database connection
- Type:
duckdb.DuckDBPyConnection
- project_config¶
The project configuration if provided
- Type:
ProjectConfig, optional
- energy_proj_table¶
Name of the energy projection table
- Type:
str
- project_country¶
Country identifier for the project
- Type:
str
Examples
>>> # Initialize with database path >>> client = APIClient("/path/to/database.db") >>> >>> # Initialize with ProjectConfig >>> client = APIClient(project_config=config, db_connection=conn) >>> >>> # Query annual consumption by sector >>> consumption = client.get_annual_electricity_consumption( ... scenarios=["baseline", "high_growth"], group_by="Sector" ... )
- property years: list[int]¶
Get cached list of valid model years.
- Returns:
A list of valid model years from the database.
- Return type:
list[int]
- property scenarios: list[str]¶
Get cached list of valid scenarios.
- Returns:
A list of valid scenarios from the database.
- Return type:
list[str]
- refresh_metadata() None¶
Refresh cached years and scenarios by re-reading from database. Call this if the database content has changed.
- get_unique_sectors() list[str]¶
Get unique sectors from the energy projection table.
- Returns:
Sorted list of unique sectors from the database
- Return type:
list[str]
- get_unique_end_uses() list[str]¶
Get unique end uses (metrics) from the energy projection table.
- Returns:
Sorted list of unique end uses/metrics from the database
- Return type:
list[str]
- get_years() list[int]¶
- Returns:
A list of valid model years. Used for validating inputs into api query functions.
- Return type:
list[int]
Examples
>>> client = APIClient(path_or_conn) >>> years = client.get_years() >>> print(years) [2025, 2030, 2035, 2040, 2045, 2050]
- get_annual_electricity_consumption(scenarios: list[str] | None = None, years: list[int] | None = None, group_by: Literal['End Use', 'Sector'] | None = None) DataFrame¶
Queries the Total Annual Consumption for each scenario.
- Parameters:
years (list[int], optional) – Valid projection years for the opened project. If None, uses all projection years.
group_by (ConsumptionBreakdown, optional) – Optionally breakdown by Sector and end Use. If None, uses total.
scenarios (list[str], optional) – Optional list of scenarios to filter by. If None, uses all scenarios available.
- Returns:
DataFrame with consumption values in tall format.
Columns: - scenario: str, scenario name - year: int, projection year - sector/end_use: str, breakdown category (if group_by specified) - value: float, consumption value in MWh
- Return type:
pd.DataFrame
Examples
>>> client = APIClient(path_or_conn) >>> # Get total consumption for all scenarios and years >>> df = client.get_annual_electricity_consumption()
|-------------|------|-------------|-------| | scenario | year | value | |-------------|------|-------| | baseline | 2025 | 5500 | | baseline | 2030 | 5900 | | high_growth | 2025 | 6000 | | high_growth | 2030 | 6500 | |-------------|------|-------------|-------|
>>> # Get consumption by sector for specific scenarios >>> df = client.get_annual_electricity_consumption( ... scenarios=["baseline", "high_growth"], group_by="Sector" ... )
|-------------|------|-------------|-------| | scenario | year | sector | value | |-------------|------|-------------|-------| | baseline | 2025 | Commercial | 1500 | | baseline | 2025 | Industrial | 2200 | | baseline | 2025 | Residential | 1800 | | baseline | 2030 | Commercial | 1650 | | high_growth | 2025 | Commercial | 1600 | |-------------|------|-------------|-------|
- get_annual_peak_demand(scenarios: list[str] | None = None, years: list[int] | None = None, group_by: Literal['End Use', 'Sector'] | None = None) DataFrame¶
Queries the peak annual consumption for each scenario. If group_by is specified, uses the peak timestamp to look up corresponding End Use or Sector values.
- Parameters:
years (list[int], optional) – Valid projection years for the opened project. If None, uses all projection years.
group_by (ConsumptionBreakdown, optional) – Optionally breakdown by Sector and end Use. If None, uses total.
scenarios (list[str], optional) – Optional list of scenarios to filter by. If None, uses all scenarios available.
- Returns:
DataFrame with peak demand values in tall format.
Columns: - scenario: str, scenario name - year: int, projection year - sector/end_use: str, breakdown category (if group_by specified) - value: float, peak demand value in MW
- Return type:
pd.DataFrame
Examples
>>> client = APIClient(path_or_conn) >>> # Get peak demand for all scenarios and years (no breakdown) >>> df = client.get_annual_peak_demand()
|-------------|------|-------| | scenario | year | value | |-------------|------|-------| | baseline | 2025 | 5500 | | baseline | 2030 | 5900 | | high_growth | 2025 | 6000 | | high_growth | 2030 | 6500 | |-------------|------|-------|
>>> # Get peak demand by sector for specific scenarios >>> df = client.get_annual_peak_demand( ... scenarios=["baseline", "high_growth"], group_by="Sector" ... )
|-------------|------|-------------|-------| | scenario | year | sector | value | |-------------|------|-------------|-------| | baseline | 2025 | Commercial | 1500 | | baseline | 2025 | Industrial | 2200 | | baseline | 2025 | Residential | 1800 | | baseline | 2030 | Commercial | 1650 | | high_growth | 2025 | Commercial | 1600 | |-------------|------|-------------|-------|
- get_secondary_metric(scenario: str, metric: Literal['GDP', 'GDP Per Capita', 'Human Development Index', 'Population'], years: list[int] | None = None) DataFrame¶
Queries the database for the secondary metric to overlay against a particular plot on the secondary axis
!!!Must be able to handle multiple overrides of a particular metric to differentiate between scenarios!!!
- Parameters:
scenario (str) – A valid scenario for the project.
metric (SecondaryMetric) – The secondary metric to query.
years (list[int], optional) – A list of valid model years to filter by. Uses all model years if None specified.
- Returns:
DataFrame with secondary metric values.
Columns: - year: int, model year - value: float, metric value for the specified scenario and metric type
- Return type:
pd.DataFrame
Examples
>>> client = APIClient(path_or_conn) >>> df = client.get_secondary_metric("baseline", "GDP", [2025, 2030, 2035])
|------|-------| | year | value | |------|-------| | 2025 | 1250.5| | 2030 | 1380.2| | 2035 | 1520.8| |------|-------|
- get_load_duration_curve(years: int | list[int] | None = None, scenarios: list[str] | None = None) DataFrame¶
Gets the load duration curve for each scenario or year
- Parameters:
years (int | list[int], optional) – A valid year or list of years for the given project. If None, uses first year.
scenarios (list[str], optional) – List of scenarios to filter by. If None, uses all scenarios.
- Returns:
DataFrame with load duration curve data.
- Columns:
{scenario_name} or {year}: float, demand values sorted from highest to lowest for each scenario (if multiple scenarios) or year (if multiple years)
Index: row number (0 to 8759 for hourly data)
- Return type:
pd.DataFrame
- Raises:
ValueError – If both years and scenarios are lists with more than one item
Examples
>>> client = APIClient(path_or_conn) >>> # Single year, multiple scenarios >>> df = client.get_load_duration_curve(2030, ["baseline", "high_growth"]) >>> # Multiple years, single scenario >>> df = client.get_load_duration_curve([2025, 2030], ["baseline"]) >>> # Single year, single scenario >>> df = client.get_load_duration_curve(2030, ["baseline"])
- get_scenario_summary(scenario: str, year: int) dict[str, float]¶
- Parameters:
scenario (str) – A valid scenario from the project.
year (int) – The projection year to get the summary.
- Returns:
Dictionary of KPI metrics with metric names as keys and values as floats.
Keys: - TOTAL_CONSUMPTION: float, total electricity consumption (MWh) - PERCENT_GROWTH: float, percentage growth from base year - PEAK_DEMAND: float, peak demand (MW) - Additional KPIs to be defined
- Return type:
dict[str, float]
Examples
>>> client = APIClient(path_or_conn) >>> summary = client.get_scenario_summary("baseline", 2030) >>> print(summary) { 'TOTAL_CONSUMPTION': 45.2, 'PERCENT_GROWTH': 12.5, 'PEAK_DEMAND': 5500.0 }
- get_weather_metric(scenario: str, year: int, wvar: Literal['BAIT', 'HDD', 'CDD', 'Temperature', 'Solar_Radiation', 'Wind_Speed', 'Dew_Point', 'Humidity'], resample: Literal['Hourly', 'Daily Mean', 'Weekly Mean'], timegroup: Literal['Seasonal', 'Seasonal and Weekday/Weekend', 'Weekday/Weekend'] | None = None) DataFrame¶
Gets the weather time series data to use as a secondary axis. Optionally Resample to Daily or weekly mean
- Parameters:
scenario (str) – The scenario specific weather source data
year (int) – The valid model year to choose for the weather metric
wvar (WeatherVar) – The weather variable to choose (currently only “BAIT” is supported)
resample (ResampleOptions, optional) – Resampling option for the data
timegroup (TimeGroup, optional) – Time grouping option
- Returns:
Pandas DataFrame with weather values
- Columns:
datetime: Datetime64, datetime or time period depending on resample option
value: float, BAIT (Balance Point Adjusted Integrated Temperature) values
- Return type:
pd.DataFrame
Examples
>>> client = APIClient(path_or_conn) >>> weather = client.get_weather_metric("baseline", 2030, "BAIT", "Daily Mean") >>> print(weather.head())
|------------|-------| | datetime | value | |------------|-------| | 2030-01-01 | 5.2 | | 2030-01-02 | 6.1 | | 2030-01-03 | 4.8 | | 2030-01-04 | 7.3 | | 2030-01-05 | 8.9 | |------------|-------|
- get_time_series_comparison(scenario: str, years: int | list[int], group_by: Literal['End Use', 'Sector'] | None = None, resample: Literal['Hourly', 'Daily Mean', 'Weekly Mean'] = 'Daily Mean') DataFrame¶
User selects 1 or more than model years. Returns tall format data with time period information.
- Parameters:
scenario (str) – A valid scenario for the project.
years (Union[int, list[int]]) – 1 or 2 model years to view on the same chart.
group_by (ConsumptionBreakdown) – The load broken down by sector or end use.
resample (ResampleOptions, optional) – Resampling option for the data. Use None for raw hourly data.
- Returns:
DataFrame with electricity consumption time series data in tall format.
Columns: - scenario: str, scenario name - year: int, projection year - time_period: int, time period (hour of year for raw data, day/week for resampled) - sector/end_use: str, breakdown category (if group_by specified) - value: float, consumption value
- Return type:
pd.DataFrame
Examples
>>> client = APIClient(path_or_conn) >>> # Raw hourly data with group_by >>> df = client.get_time_series_comparison( ... "baseline", [2025, 2030], "Sector", resample=None ... )
|----------|------|-------------|-------------|--------| | scenario | year | time_period | sector | value | |----------|------|-------------|-------------|--------| | baseline | 2025 | 1 | Commercial | 125.5 | | baseline | 2025 | 1 | Industrial | 210.3 | | baseline | 2025 | 1 | Residential | 180.7 | | baseline | 2025 | 2 | Commercial | 124.8 | |----------|------|-------------|-------------|--------|
>>> # Resampled data with group_by specified >>> df = client.get_time_series_comparison("baseline", [2025, 2030], "Sector")
|----------|------|-------------|-------------|--------| | scenario | year | time_period | sector | value | |----------|------|-------------|-------------|--------| | baseline | 2025 | 1 | Commercial | 1250.5 | | baseline | 2025 | 1 | Industrial | 2100.3 | | baseline | 2025 | 1 | Residential | 1800.7 | | baseline | 2025 | 2 | Commercial | 1245.8 | | baseline | 2030 | 1 | Commercial | 1380.2 | |----------|------|-------------|-------------|--------|
>>> # Raw hourly data without group_by >>> df = client.get_time_series_comparison("baseline", [2025, 2030], resample=None)
|----------|------|-------------|--------| | scenario | year | time_period | value | |----------|------|-------------|--------| | baseline | 2025 | 1 | 5150.5 | | baseline | 2025 | 2 | 5136.2 | | baseline | 2030 | 1 | 5675.4 | | baseline | 2030 | 2 | 5666.5 | |----------|------|-------------|--------|
- get_seasonal_load_lines(scenario: str, years: int | list[int] | None = None, group_by: Literal['Seasonal', 'Seasonal and Weekday/Weekend', 'Weekday/Weekend'] = 'Seasonal', agg: Literal['Average Day', 'Peak Day', 'Minimum Day', 'Median Day'] = 'Average Day') DataFrame¶
- Parameters:
scenario (str) – A valid scenario within the project.
group_by (TimeGroup) – Seasonal, Weekday/Weekend, or Both.
agg (TimeGroupAgg) – How to aggregate each hour of the day.
years (int | list[int]] | None) – A single or list of valid model years.
- Returns:
DataFrame with seasonal load line data in tall format.
Columns: - scenario: str, scenario name - year: int, projection year - season: str, season name (Winter, Spring, Summer, Fall) - if group_by includes “Seasonal” - day_type: str, day type (Weekday, Weekend) - if group_by includes “Weekday/Weekend” - hour_of_day: int, hour of day (0-23) - value: float, aggregated load value
- Return type:
pd.DataFrame
Examples
>>> client = APIClient(path_or_conn) >>> # Seasonal grouping only >>> df = client.get_seasonal_load_lines( ... "baseline", [2025, 2030], "Seasonal", "Average Day" ... )
|----------|------|--------|-------------|--------| | scenario | year | season | hour_of_day | value | |----------|------|--------|-------------|--------| | baseline | 2025 | Winter | 0 | 3200.5 | | baseline | 2025 | Winter | 1 | 3100.2 | | baseline | 2025 | Winter | 2 | 3050.8 | | baseline | 2025 | Spring | 0 | 2800.3 | | baseline | 2030 | Winter | 0 | 3450.2 | |----------|------|--------|-------------|--------|
>>> # Both seasonal and weekday/weekend grouping >>> df = client.get_seasonal_load_lines( ... "baseline", [2025], "Seasonal and Weekday/Weekend", "Average Day" ... )
|----------|------|--------|----------|-------------|--------| | scenario | year | season | day_type | hour_of_day | value | |----------|------|--------|----------|-------------|--------| | baseline | 2025 | Winter | Weekday | 0 | 3400.5 | | baseline | 2025 | Winter | Weekday | 1 | 3350.2 | | baseline | 2025 | Winter | Weekend | 0 | 3000.3 | | baseline | 2025 | Spring | Weekday | 0 | 2900.7 | |----------|------|--------|----------|-------------|--------|
- get_seasonal_load_area(scenario: str, year: int, group_by: Literal['Seasonal', 'Seasonal and Weekday/Weekend', 'Weekday/Weekend'] = 'Seasonal', agg: Literal['Average Day', 'Peak Day', 'Minimum Day', 'Median Day'] = 'Average Day', breakdown: Literal['End Use', 'Sector'] | None = None) DataFrame¶
Get seasonal load area data for a single year with optional breakdown by sector/end_use.
- Parameters:
scenario (str) – A valid scenario within the project.
year (int) – A single valid model year.
group_by (TimeGroup) – Seasonal, Weekday/Weekend, or Both.
agg (TimeGroupAgg) – How to aggregate each hour of the day.
breakdown (ConsumptionBreakdown, optional) – Optional breakdown by Sector or End Use.
- Returns:
DataFrame with seasonal load area data in tall format.
Columns: - scenario: str, scenario name - year: int, projection year - season: str, season name (Winter, Spring, Summer, Fall) - if group_by includes “Seasonal” - day_type: str, day type (Weekday, Weekend) - if group_by includes “Weekday/Weekend” - hour_of_day: int, hour of day (0-23) - sector/end_use: str, breakdown category (if breakdown specified) - value: float, aggregated load value
- Return type:
pd.DataFrame
Examples
>>> client = APIClient(path_or_conn) >>> df = client.get_seasonal_load_area("baseline", 2030)
|-------------|------|--------|-------------|-------| | scenario | year | season | hour_of_day | value | |-------------|------|--------|-------------|-------| | baseline | 2030 | Winter | 0 | 3400.5| | baseline | 2030 | Winter | 1 | 3350.2| | baseline | 2030 | Spring | 0 | 2900.7| | baseline | 2030 | Spring | 1 | 2850.3| |-------------|------|--------|-------------|-------|
>>> df = client.get_seasonal_load_area("baseline", 2030, breakdown="Sector")
|-------------|------|--------|-------------|-------------|-------| | scenario | year | season | hour_of_day | sector | value | |-------------|------|--------|-------------|-------------|-------| | baseline | 2030 | Winter | 0 | Commercial | 1200.5| | baseline | 2030 | Winter | 0 | Industrial | 1500.2| | baseline | 2030 | Winter | 0 | Residential | 1700.8| | baseline | 2030 | Spring | 0 | Commercial | 1300.7| | baseline | 2030 | Spring | 0 | Industrial | 1600.3| |-------------|------|--------|-------------|-------------|-------|