🌳 Concepts#

Preferred Import#

You can import SynopticPy either by importing the entire synoptic module

import synoptic

or by importing individual service classes

from synoptic import TimeSeries, Latest # ... etc.

Available Services#

All of Synoptic’s Weather API services are available in SynopticPy (with the exception of qcsegments, which I have never needed).

The names of these service classes are listed in the following table:

Class Description
TimeSeries Get time series data for one or more stations.
Latest Get the most recent data from one or more stations.
NearestTime Get data nearest a specified time for one or more stations.
Precipitation Get derived precipitation total or intervals.
Latency Get station latency.
Metadata Get metadata for one or moe stations.
QCTypes Table of all QC types and names.
Variables Table of all available variables.
Networks Table of all available networks.
NetworkTypes Table of all available network types.

Constructor arguments#

Constructor arguments (class input parameters) are stitched together to create a web query. The parameters used to specify the data you want depends on the API service. Synoptic’s Weather API Documentation and Query Builder can help you determine what parameters can be used for each service.

Tip

I highly recommend you become familiar with Synoptic’s Weather API documentation.

In SynopticPy,

from datetime import datetime
import synoptic

S = synoptic.TimeSeries(
    stid="wbb",
    start=datetime(2024, 1, 1),
    end=datetime(2024, 1, 5),
    vars=["air_temp","wind_speed","wind_direction"],
)

makes the following API request: https://api.synopticdata.com/v2/stations/timeseries?stid=wbb&start=202401010000&end=202401050000&vars=air_temp,wind_speed,wind_direction&token=YourTokenHere

Notice that SynopticPy allows you to use more Pythonic input for these parameters. Pay attention to these extended input conventions used by SynopticPy when requesting data:

  1. Lists and tuples are accepted, and will be converted to comma-separated strings. For example:

    When selecting stations, both are acceptable:

    stid="WBB,KSLC,KMRY"
    
    stid=["WBB", "KSLC", "KMRY"]
    

    When selecting variables, both are acceptable:

    vars="air_temp,wind_speed"
    
    vars=["air_temp","wind_speed"]
    

    When using the radius parameter, both are acceptable:

    radius="wbb,20"
    
    radius=("wbb", 20)
    
  2. Datetime objects are accepted and will be converted to a string required by the Synoptic API. For example:

    While both are acceptable, using datetime objects is preferred to reduce room for errors.

    start=datetime.datetime(2020, 1, 1)
    
    start="202001010000"
    

    The parameter obrange is a special case which can be provided as a tuple of datetimes obrange=(datetime_start, datetime_end).

  3. Timedelta or Polars-style duration strings are accepted and will be converted to a value required by the Synoptic API. For example:

    While Synoptic expects the within and recent arguments to be integer minutes, SynopticPy lets you use a timedelta object or a Polars-style duration string.

    The following are equivalent:

    within=datetime.timedelta(hours=1)
    
    within="1h"
    
    within=60
    
  4. Boolean values are accepted for parameters where Synoptic expects values of 0, 1, "on", or "off". For example:

    showemptystations=False,
    qc=True
    

    can be used in place of

    showemptystations=0,
    qc="on"
    

What if I don’t know a station’s ID?#

Use these two amazing resources:

What is included in a Service Class instance?#

In general, most instances return the following attributes:

  1. Capitalized attributes like .SUMMARY, .STATION, .UNITS, and .QC_SUMMARY are copied dictionaries attached from the returned JSON. These are for convenience.

  2. .df() is the long-format Polars DataFrame of the STATION data.

  3. .endpoint is the URL for the requested API service.

  4. .help_url is the website for the documentation for the service.

  5. .json is the returned JSON from the API request loaded into a Python dictionary.

  6. .params are the user-specified parameters used to make the request.

  7. .response is the object from the requests library, requests.get(...).

  8. .service is the requested Synoptic API service type.

  9. .url is the full URL used to make the API request.

Let’s take a look at the attributes of Metadata service instance…

Data as a Polars DataFrame#

SynopticPy is built with Polars and converts Synoptic’s JSON data to a long-form Polars DataFrame. Use the .df() method on a service class to get the data as a DataFrame.

from synoptic import TimeSeries

df = TimeSeries(stid='wbb', recent=30, vars='air_temp,wind_speed').df()

SynopticPy organizes the Synoptic JSON data in long form Polars DataFrames. A long form DataFrame means that each row in the DataFrame represents a single, unique observations. This makes it easy to archive the data locally (i.e., saving to a Parquet file). This format is flexible, allowing you to manipulate the data (e.g., pivoting or concatenating) as needed.

Why are all Timezones in UTC?#

The date_time column and timezones for other DateTime columns are always returned in UTC, even if you set obtimezone="local". This is because all datetimes in the a date-time column must be in the same time zone.

It is straightforward to convert datetimes to a specific timezone using Polars. I’ve included a helper function to do this for you:

import synoptic
df = synoptic.TimeSeries(stid='wbb', recent=30).df()
df = df.synoptic.with_local_timezone()

Plotting#

Throughout these docs, I use many different plotting tools.

  • Matplotlib

  • Seaborn - Works really well for plotting long-form DataFrames.

  • Cartopy - When I use Cartopy, and I typically use my shortcut EasyMap tool included in Herbie to create those cartopy maps.

  • Altair - Built-in plotting support for Polars.