diff --git a/docs/cli/_category_.json b/docs/cli/_category_.json new file mode 100644 index 0000000..2f799da --- /dev/null +++ b/docs/cli/_category_.json @@ -0,0 +1,10 @@ +{ + "position": 3, + "label": "Meteostat CLI", + "collapsible": true, + "collapsed": true, + "link": { + "type": "generated-index", + "title": "Meteostat CLI" + } +} diff --git a/docs/cli/configuration.md b/docs/cli/configuration.md new file mode 100644 index 0000000..2a1c460 --- /dev/null +++ b/docs/cli/configuration.md @@ -0,0 +1,29 @@ +--- +title: Configuration | Meteostat CLI +sidebar_label: Configuration +sidebar_position: 4 +--- + +# Configuration + +Manage the Meteostat CLI configuration. Settings are stored in a `cli.yml` file in the platform-specific app directory (e.g. `~/.config/meteostat/cli.yml` on Linux). + +## Usage + +```bash +meteo config [KEY VALUE] [OPTIONS] +``` + +## Examples + +```bash +meteo config --list # Show all current settings +meteo config cache_enable false # Disable caching +meteo config interpolation_radius 25000 # Set interpolation radius to 25 km +``` + +## Options + +| Option | Description | +| -------- | -------------------------- | +| `--list` | Print all current settings | diff --git a/docs/cli/overview.md b/docs/cli/overview.md new file mode 100644 index 0000000..24ffd4d --- /dev/null +++ b/docs/cli/overview.md @@ -0,0 +1,55 @@ +--- +title: Meteostat CLI +sidebar_label: Overview +id: cli-overview +slug: /cli +sidebar_position: 1 +--- + +import DocCardList from '@theme/DocCardList'; + +# Meteostat CLI + +The Meteostat CLI gives you direct access to weather and climate data from the terminal. It is built on top of the [Meteostat Python library](/python) and lets you query historical observations, browse weather stations, and export data in a variety of formats — all without writing a single line of code. + +## 📚 Installation + +Install the CLI via [PyPI](https://pypi.org/project/meteostat-cli/): + +```bash +pip install --user meteostat-cli +``` + +For plotting support (`png`/`svg` output), install the `plot` extra: + +```bash +pip install --user meteostat-cli[plot] +``` + +## 🚀 Usage + +Want to know the hottest temperature of 2024 at Frankfurt Airport (station `10637`)? Run the following command: + +```bash +meteo d 10637 -s 2024-01-01 -e 2024-12-31 -p tmax --agg max +``` + +This will yield the following output: + +``` + tmax +station +10637 35.9 +``` + +## ⚡ Shell Completion + +To enable shell completion (Bash, Zsh, Fish, PowerShell), run the following command: + +```bash +meteo --install-completion +``` + +## 👀 Learn More + + diff --git a/docs/cli/stations/_category_.json b/docs/cli/stations/_category_.json new file mode 100644 index 0000000..7b9fb9d --- /dev/null +++ b/docs/cli/stations/_category_.json @@ -0,0 +1,10 @@ +{ + "position": 2, + "label": "Weather Stations", + "collapsible": true, + "collapsed": true, + "link": { + "type": "doc", + "id": "cli-stations-overview" + } +} diff --git a/docs/cli/stations/inventory.md b/docs/cli/stations/inventory.md new file mode 100644 index 0000000..8211d21 --- /dev/null +++ b/docs/cli/stations/inventory.md @@ -0,0 +1,37 @@ +--- +title: Inventory | Meteostat CLI +sidebar_label: Inventory +sidebar_position: 4 +--- + +# Inventory + +Check what data is available for a weather station. You can filter by granularity and specific parameters to see exactly which records exist. + +## Usage + +```bash +meteo inventory STATION_ID [OPTIONS] +``` + +Alias: `meteo i` + +## Examples + +```bash +meteo inventory 10637 +meteo inventory 10637 --granularity daily +meteo inventory 10637 --granularity daily --parameters tavg,tmin,tmax +``` + +## Options + +| Option | Short | Description | +| --------------- | ----- | --------------------------------------------------------------- | +| `--granularity` | `-g` | Filter by granularity: `hourly`/`h`, `daily`/`d`, `monthly`/`m` | +| `--parameters` | `-p` | Comma-separated parameters (e.g. `tavg,tmin,tmax`) | +| `--providers` | `-P` | Comma-separated data providers | +| `--format` | `-f` | Output format: `csv`, `json`, `xlsx`, `parquet` | +| `--output` | `-o` | Output file path (defaults to stdout) | +| `--no-header` | | Omit CSV header row | +| `--all` | `-A` | Print full table without truncation | diff --git a/docs/cli/stations/nearby.md b/docs/cli/stations/nearby.md new file mode 100644 index 0000000..8a758b9 --- /dev/null +++ b/docs/cli/stations/nearby.md @@ -0,0 +1,37 @@ +--- +title: Nearby Stations | Meteostat CLI +sidebar_label: Nearby Stations +sidebar_position: 3 +--- + +# Nearby Stations + +Find weather stations near a geographic location. Provide a latitude and longitude and the command returns the closest stations within the specified radius. + +## Usage + +```bash +meteo nearby LAT LON [OPTIONS] +``` + +Alias: `meteo n` + +## Examples + +```bash +meteo nearby 50.1109 8.6821 # Nearest stations (default: 5 within 5 km) +meteo nearby 50.1109 8.6821 --limit 10 # Return up to 10 stations +meteo nearby 50.1109 8.6821 --radius 20000 # Search within 20 km +meteo nearby 50.1109 8.6821 --format json # JSON output +``` + +## Options + +| Option | Short | Description | +| ------------- | ----- | ----------------------------------------------- | +| `--limit` | `-l` | Maximum number of stations (default: 5) | +| `--radius` | `-r` | Search radius in meters (default: 5000) | +| `--format` | `-f` | Output format: `csv`, `json`, `xlsx`, `parquet` | +| `--output` | `-o` | Output file path (defaults to stdout) | +| `--no-header` | | Omit CSV header row | +| `--all` | `-A` | Print full table without truncation | diff --git a/docs/cli/stations/overview.md b/docs/cli/stations/overview.md new file mode 100644 index 0000000..6522b5d --- /dev/null +++ b/docs/cli/stations/overview.md @@ -0,0 +1,49 @@ +--- +title: Weather Stations | Meteostat CLI +sidebar_label: Overview +id: cli-stations-overview +slug: /cli/stations +sidebar_position: 1 +--- + +import DocCardList from '@theme/DocCardList'; + +# Weather Stations + +The Meteostat CLI provides several commands to browse and look up weather stations. You can search by location, country, name, or various station identifiers, and inspect the availability of data for any station. + +## 🚀 Example + +Look up the metadata for Frankfurt Airport: + +```bash +meteo station 10637 +``` + +Find stations in Germany: + +```bash +meteo station --country DE +``` + +Search for stations by name: + +```bash +meteo station --name "Frankfurt" +``` + +Find the nearest stations to a location: + +```bash +meteo nearby 50.1109 8.6821 +``` + +Check what data is available for a station: + +```bash +meteo inventory 10637 +``` + +## 👀 Learn More + + diff --git a/docs/cli/stations/station.md b/docs/cli/stations/station.md new file mode 100644 index 0000000..841d21f --- /dev/null +++ b/docs/cli/stations/station.md @@ -0,0 +1,46 @@ +--- +title: Station Lookup | Meteostat CLI +sidebar_label: Station Lookup +sidebar_position: 2 +--- + +# Station Lookup + +Browse and search weather stations in the Meteostat network. You can look up a specific station by ID or filter stations by country, region, name, or various identifiers. + +## Usage + +```bash +meteo station [ID] [OPTIONS] +``` + +Alias: `meteo s` + +## Examples + +```bash +meteo station 10637 # Metadata for a specific station +meteo station --country DE # List stations by country +meteo station --country DE --state HE # Filter by country and state +meteo station --name "Frankfurt" # Search by name +meteo station --wmo 10637 # Look up by WMO ID +meteo station --bbox 8.0,50.0,9.0,51.0 # Stations within a bounding box +``` + +## Options + +| Option | Short | Description | +| ------------- | ----- | ------------------------------------------------ | +| `--country` | `-c` | ISO 3166-1 alpha-2 country code | +| `--state` | | State or region code | +| `--name` | `-n` | Station name (partial match) | +| `--wmo` | `-w` | WMO station ID | +| `--icao` | `-i` | ICAO station ID | +| `--iata` | | IATA station ID | +| `--national` | `-N` | National station ID | +| `--bbox` | | Bounding box (`lon_min,lat_min,lon_max,lat_max`) | +| `--sql` | | Arbitrary SQL query | +| `--format` | `-f` | Output format: `csv`, `json`, `xlsx`, `parquet` | +| `--output` | `-o` | Output file path (defaults to stdout) | +| `--no-header` | | Omit CSV header row | +| `--all` | `-A` | Print full table without truncation | diff --git a/docs/cli/timeseries/_category_.json b/docs/cli/timeseries/_category_.json new file mode 100644 index 0000000..6dc9650 --- /dev/null +++ b/docs/cli/timeseries/_category_.json @@ -0,0 +1,10 @@ +{ + "position": 3, + "label": "Time Series", + "collapsible": true, + "collapsed": true, + "link": { + "type": "doc", + "id": "cli-ts-overview" + } +} diff --git a/docs/cli/timeseries/daily.md b/docs/cli/timeseries/daily.md new file mode 100644 index 0000000..7736408 --- /dev/null +++ b/docs/cli/timeseries/daily.md @@ -0,0 +1,34 @@ +--- +title: Daily Data | Meteostat CLI +sidebar_label: Daily Data +sidebar_position: 3 +--- + +# Daily Data + +Fetch daily weather observations for one or more weather stations. Supports coordinate-based input for interpolated data. + +## Usage + +```bash +meteo daily STATIONS... [OPTIONS] +``` + +Alias: `meteo d` + +## Examples + +```bash +meteo daily 10637 --start 2024-01-01 --end 2024-12-31 +meteo d 10637 -s 2024-01-01 -e 2024-12-31 # Short form +meteo daily 10637 10635 -s 2024-01-01 -e 2024-12-31 # Multiple stations +meteo daily 50.1109,8.6821 -s 2024-01-01 -e 2024-12-31 # Coordinates (interpolation) +meteo daily 10637 -s 2024-01-01 -e 2024-12-31 --parameters tavg,tmin,tmax,prcp +meteo daily 10637 -s 2024-01-01 -e 2024-12-31 --agg max +meteo daily 10637 -s 2024-01-01 -e 2024-12-31 --output data.json +meteo daily 10637 -s 2024-01-01 -e 2024-12-31 --output chart.png +``` + +## Options + +See [common time series options](/cli/timeseries#common-options). diff --git a/docs/cli/timeseries/hourly.md b/docs/cli/timeseries/hourly.md new file mode 100644 index 0000000..93bcee8 --- /dev/null +++ b/docs/cli/timeseries/hourly.md @@ -0,0 +1,38 @@ +--- +title: Hourly Data | Meteostat CLI +sidebar_label: Hourly Data +sidebar_position: 2 +--- + +# Hourly Data + +Fetch hourly weather observations for one or more weather stations. Supports coordinate-based input for interpolated data. + +## Usage + +```bash +meteo hourly STATIONS... [OPTIONS] +``` + +Alias: `meteo h` + +## Examples + +```bash +meteo hourly 10637 --start 2024-01-01 --end 2024-01-31 +meteo h 10637 -s 2024-01-01 -e 2024-01-31 # Short form +meteo hourly 10637 10635 -s 2024-01-01 -e 2024-01-31 # Multiple stations +meteo hourly 50.1109,8.6821 -s 2024-01-01 -e 2024-01-07 # Coordinates (interpolation) +meteo hourly 10637 -s 2024-01-01 -e 2024-01-31 --timezone Europe/Berlin +meteo hourly 10637 -s 2024-01-01 -e 2024-01-31 --parameters tavg,prcp +meteo hourly 10637 -s 2024-01-01 -e 2024-01-31 --output data.csv +meteo hourly 10637 -s 2024-01-01 -e 2024-01-31 --output chart.png +``` + +## Options + +Hourly data supports all [common time series options](/cli/timeseries#common-options) plus: + +| Option | Short | Description | +| ------------ | ----- | ---------------------------------------------- | +| `--timezone` | `-t` | Timezone for timestamps (e.g. `Europe/Berlin`) | diff --git a/docs/cli/timeseries/monthly.md b/docs/cli/timeseries/monthly.md new file mode 100644 index 0000000..b7ee817 --- /dev/null +++ b/docs/cli/timeseries/monthly.md @@ -0,0 +1,31 @@ +--- +title: Monthly Data | Meteostat CLI +sidebar_label: Monthly Data +sidebar_position: 4 +--- + +# Monthly Data + +Fetch monthly weather summaries for one or more weather stations. + +## Usage + +```bash +meteo monthly STATIONS... [OPTIONS] +``` + +Alias: `meteo m` + +## Examples + +```bash +meteo monthly 10637 --start 2020 --end 2024 +meteo m 10637 -s 2020 -e 2024 # Short form +meteo monthly 10637 10635 -s 2020 -e 2024 # Multiple stations +meteo monthly 10637 -s 2020 -e 2024 --parameters tavg,prcp +meteo monthly 10637 -s 2020 -e 2024 --output data.xlsx +``` + +## Options + +See [common time series options](/cli/timeseries#common-options). diff --git a/docs/cli/timeseries/normals.md b/docs/cli/timeseries/normals.md new file mode 100644 index 0000000..69fe1e4 --- /dev/null +++ b/docs/cli/timeseries/normals.md @@ -0,0 +1,31 @@ +--- +title: Climate Normals | Meteostat CLI +sidebar_label: Climate Normals +sidebar_position: 5 +--- + +# Climate Normals + +Fetch climate normals for one or more weather stations. Climate normals are long-term averages (typically 30 years) used as a baseline for comparing current conditions. + +## Usage + +```bash +meteo normals STATIONS... [OPTIONS] +``` + +Alias: `meteo n` + +## Examples + +```bash +meteo normals 10637 --start 1991 --end 2020 +meteo n 10637 -s 1991 -e 2020 # Short form +meteo normals 10637 10635 -s 1991 -e 2020 # Multiple stations +meteo normals 10637 -s 1991 -e 2020 --parameters tavg,prcp +meteo normals 10637 -s 1991 -e 2020 --output normals.csv +``` + +## Options + +See [common time series options](/cli/timeseries#common-options). diff --git a/docs/cli/timeseries/overview.md b/docs/cli/timeseries/overview.md new file mode 100644 index 0000000..4fa3425 --- /dev/null +++ b/docs/cli/timeseries/overview.md @@ -0,0 +1,79 @@ +--- +title: Time Series | Meteostat CLI +sidebar_label: Overview +id: cli-ts-overview +slug: /cli/timeseries +sidebar_position: 1 +--- + +import DocCardList from '@theme/DocCardList'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Time Series + +The Meteostat CLI provides commands for fetching historical time series data at hourly, daily, monthly, and climate normal granularities. All commands accept one or more station IDs (or coordinates for interpolation) and a date range. + +## 🚀 Example + + + + + Fetch hourly data for Frankfurt Airport in January 2024: + + ```bash + meteo hourly 10637 --start 2024-01-01 --end 2024-01-31 + ``` + + + + + Fetch daily data for Frankfurt Airport for the full year 2024: + + ```bash + meteo daily 10637 --start 2024-01-01 --end 2024-12-31 + ``` + + + + + Fetch monthly data for Frankfurt Airport from 2020 to 2024: + + ```bash + meteo monthly 10637 --start 2020 --end 2024 + ``` + + + + + Fetch the 30-year climate normals for Frankfurt Airport: + + ```bash + meteo normals 10637 --start 1991 --end 2020 + ``` + + + + +## 🎯 Common Options {#common-options} + +All time series commands share the following options: + +| Option | Short | Description | +| ---------------- | ----- | ------------------------------------------------------------- | +| `--start` | `-s` | Start date (`YYYY-MM-DD`, `YYYY-MM`, `YYYY`) | +| `--end` | `-e` | End date (same formats) | +| `--parameters` | `-p` | Comma-separated parameters (e.g. `tavg,tmin,tmax,prcp`) | +| `--providers` | `-P` | Comma-separated data providers | +| `--format` | `-f` | Output format: `csv`, `json`, `xlsx`, `parquet`, `png`, `svg` | +| `--output` | `-o` | Output file path (defaults to stdout) | +| `--with-sources` | `-S` | Include data source column in output | +| `--no-models` | | Exclude model data (e.g. MOSMIX) | +| `--no-header` | | Omit CSV header row | +| `--no-cache` | | Disable result caching | +| `--all` | `-A` | Print full table without truncation | +| `--agg` | | Aggregation function: `mean`, `sum`, `min`, `max` | + +## 👀 Learn More + + diff --git a/docs/cookbook/overview.md b/docs/cookbook/overview.md new file mode 100644 index 0000000..4529749 --- /dev/null +++ b/docs/cookbook/overview.md @@ -0,0 +1,27 @@ +--- +title: Cookbook +sidebar_label: Overview +sidebar_position: 1 +slug: /cookbook +custom_edit_url: null +pagination_next: null +--- + +import DocCardList from "@theme/DocCardList"; +import CookbookIndex from "@site/src/components/CookbookIndex"; + +
+ +# Cookbook + +A collection of recipes and examples for working with Meteostat weather and climate data. + +## Collections + + + +## Recipes + + + +
diff --git a/docs/cookbook/python/_category_.json b/docs/cookbook/python/_category_.json new file mode 100644 index 0000000..e1ad155 --- /dev/null +++ b/docs/cookbook/python/_category_.json @@ -0,0 +1,10 @@ +{ + "position": 2, + "label": "Python", + "collapsible": true, + "collapsed": true, + "link": { + "type": "doc", + "id": "cookbook-python-overview" + } +} diff --git a/docs/cookbook/python/location-input.md b/docs/cookbook/python/location-input.md new file mode 100644 index 0000000..2f8bdd7 --- /dev/null +++ b/docs/cookbook/python/location-input.md @@ -0,0 +1,76 @@ +--- +title: Location Input +description: Learn how to specify a location for fetching weather data using the Meteostat Python library. +tags: + - Python + - Time Series +--- + +# Location Input + +When working with time series data in Meteostat, you can specify weather stations and geographical points as location input. We are using the [`hourly`](/python/timeseries/hourly.md) function as an example, but the same options apply to other time series functions. + +:::tip[Performance Tip] +When working with the default providers, you may specify a new [`Station`](/python/api/meteostat.Station.md) object with just the station ID. That will improve performance by avoiding unnecessary metadata lookups. Example: `ms.Station(id='10637')`. +::: + +## Station ID + +You can access time series data by specifying a weather station using its Meteostat ID: + +```python +ts = ms.hourly('10637', START, END) +``` + +You can also provide a list of station IDs to access data from multiple stations simultaneously: + +```python +ts = ms.hourly(['10637', '10635'], START, END) +``` + +## Station + +You can pass a [`Station`](/python/api/meteostat.Station.md) object to specify a weather station. This could also be a list of [`Station`](/python/api/meteostat.Station.md) objects. Passing a [`Station`](/python/api/meteostat.Station.md) object allows you to specify a station's metadata yourself. This is useful if you want to include stations that are not (yet) part of the Meteostat database. + +```python +STATION = ms.Station( + id='10637', + name='Frankfurt Airport', + country='DE', + region='HE', + lat=50.05, + lon=8.6842, + elevation=100 +) + +ts = ms.hourly(STATION, START, END) +``` + +## DataFrame + +You can pass a Pandas [`DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html) with an index named `id`. This is mainly used for accessing data for a list of nearby weather stations obtained from the [`meteostat.stations.nearby`](/python/api/meteostat.stations.nearby.md) function. + +```python +# Specify location and time range +POINT = ms.Point(50.1155, 8.6842, 113) + +# Get nearby weather stations as Pandas DataFrame +stations = ms.stations.nearby(POINT, limit=4) + +# Get hourly data +ts = ms.hourly(stations, START, END) +``` + +## Point + +You can pass a [`Point`](/python/api/meteostat.Point.md) object to specify a geographical point. This could also be a list of [`Point`](/python/api/meteostat.Point.md) objects. Passing a [`Point`](/python/api/meteostat.Point.md) object allows you to specify a location's metadata yourself. This is useful if you want to access data for a geographical point, not a specific weather station. + +:::warning +Note that when using a [`Point`](/python/api/meteostat.Point.md) object, only providers that support accessing data by geographical point can be used. +::: + +```python +POINT = ms.Point(50.05, 8.6842, 100) + +ts = ms.hourly(POINT, START, END, providers=[ms.Provider.METNO_FORECAST]) +``` diff --git a/docs/cookbook/python/merging-time-series.md b/docs/cookbook/python/merging-time-series.md new file mode 100644 index 0000000..d4c2448 --- /dev/null +++ b/docs/cookbook/python/merging-time-series.md @@ -0,0 +1,41 @@ +--- +title: Merging Time Series +description: Learn how to merge multiple time series objects into a single one using the Meteostat Python library. +tags: + - Python + - Time Series +--- + +# Merging Time Series + +Meteostat allows you to merge multiple time series objects into a single object using the [`merge`](/python/api/meteostat.merge.md) function. This is useful when you want to combine data from different sources or time periods into one cohesive dataset. The [`merge`](/python/api/meteostat.merge.md) function can handle various types of time series data, including hourly, daily, and monthly data. However, it is important to ensure that the time series being merged are compatible in terms of their structure and parameters. + +## Requirements {#merging-requirements} + +- All time series objects to be merged must have the same granularity (e.g., all hourly, all daily, or all monthly). +- In case of hourly data, the time zones of the time series objects must match. + +## Example {#merging-example} + +```python +from datetime import date +import meteostat as ms + +# Specify time range +START1 = date(2020, 1, 1) +END1 = date(2020, 1, 10) +START2 = date(2020, 1, 11) +END2 = date(2020, 1, 20) + +# Get daily data for two different periods +ts1 = ms.daily('72503', START1, END1) +ts2 = ms.daily('72503', START2, END2) + +# Merge time series +ts = ms.merge([ts1, ts2]) + +# Fetch combined data as Pandas DataFrame +df = ts.fetch() + +print(df) +``` diff --git a/docs/cookbook/python/overview.md b/docs/cookbook/python/overview.md new file mode 100644 index 0000000..fc0b032 --- /dev/null +++ b/docs/cookbook/python/overview.md @@ -0,0 +1,15 @@ +--- +title: Python | Cookbook +sidebar_label: Overview +id: cookbook-python-overview +slug: /cookbook/python +sidebar_position: 1 +--- + +import DocCardList from '@theme/DocCardList'; + +# Python Cookbook + +A collection of recipes and examples for working with Meteostat weather and climate data using the Python library. + + diff --git a/docs/python/timeseries/overview.md b/docs/python/timeseries/overview.md index 10d015e..f028d3f 100644 --- a/docs/python/timeseries/overview.md +++ b/docs/python/timeseries/overview.md @@ -84,106 +84,11 @@ Meteostat provides access to time series data for thousands of weather stations ## 🎯 Location Input {#location-input} -When working with time series data in Meteostat, you can specify weather stations and geographical points as location input. We are using the [`hourly`](/python/timeseries/hourly.md) function as an example, but the same options apply to other time series functions. - -:::tip[Performance Tip] -When working with the default providers, you may specify a new [`Station`](../api/meteostat.Station.md) object with just the station ID. That will improve performance by avoiding unnecessary metadata lookups. Example: `ms.Station(id='10637')`. -::: - -### Station ID - -You can access time series data by specifying a weather station using its Meteostat ID: - -```python -ts = ms.hourly('10637', START, END) -``` - -You can also provide a list of station IDs to access data from multiple stations simultaneously: - -```python -ts = ms.hourly(['10637', '10635'], START, END) -``` - -### Station - -You can pass a [`Station`](../api/meteostat.Station.md) object to specify a weather station. This could also be a list of [`Station`](../api/meteostat.Station.md) objects. Passing a [`Station`](../api/meteostat.Station.md) object allows you to specify a station's metadata yourself. This is useful if you want to include stations that are not (yet) part of the Meteostat database. - -```python -STATION = ms.Station( - id='10637', - name='Frankfurt Airport', - country='DE', - region='HE', - lat=50.05, - lon=8.6842, - elevation=100 -) - -ts = ms.hourly(STATION, START, END) -``` - -### DataFrame - -You can pass a Pandas [`DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html) with an index named `id`. This is mainly used for accessing data for a list of nearby weather stations obtained from the [`meteostat.stations.nearby`](../api/meteostat.stations.nearby.md) function. - -```python -# Specify location and time range -POINT = ms.Point(50.1155, 8.6842, 113) - -# Get nearby weather stations as Pandas DataFrame -stations = ms.stations.nearby(POINT, limit=4) - -# Get hourly data -ts = ms.hourly(stations, START, END) -``` - -### Point - -You can pass a [`Point`](../api/meteostat.Point.md) object to specify a geographical point. This could also be a list of [`Point`](../api/meteostat.Point.md) objects. Passing a [`Point`](../api/meteostat.Point.md) object allows you to specify a location's metadata yourself. This is useful if you want to access data for a geographical point, not a specific weather station. - -:::warning -Note that when using a [`Point`](../api/meteostat.Point.md) object, only providers that support accessing data by geographical point can be used. -::: - -```python -POINT = ms.Point(50.05, 8.6842, 100) - -ts = ms.hourly(POINT, START, END, providers=[ms.Provider.METNO_FORECAST]) -``` +Please refer to the [Location Input](/cookbook/python/location-input.md) recipe for details on how to specify a location for fetching time series data. ## 🔀 Merging Time Series {#merging} -Meteostat allows you to merge multiple time series objects into a single object using the [`merge`](../api/meteostat.merge.md) function. This is useful when you want to combine data from different sources or time periods into one cohesive dataset. The [`merge`](../api/meteostat.merge.md) function can handle various types of time series data, including hourly, daily, and monthly data. However, it is important to ensure that the time series being merged are compatible in terms of their structure and parameters. - -### Requirements {#merging-requirements} - -- All time series objects to be merged must have the same granularity (e.g., all hourly, all daily, or all monthly). -- In case of hourly data, the time zones of the time series objects must match. - -### Example {#merging-example} - -```python -from datetime import date -import meteostat as ms - -# Specify time range -START1 = date(2020, 1, 1) -END1 = date(2020, 1, 10) -START2 = date(2020, 1, 11) -END2 = date(2020, 1, 20) - -# Get daily data for two different periods -ts1 = ms.daily('72503', START1, END1) -ts2 = ms.daily('72503', START2, END2) - -# Merge time series -ts = ms.merge([ts1, ts2]) - -# Fetch combined data as Pandas DataFrame -df = ts.fetch() - -print(df) -``` +Please refer to the [Merging Time Series](/cookbook/python/merging-time-series.md) recipe for details on how to merge multiple time series objects into a single one. ## 👀 Learn More {#learn-more} diff --git a/docusaurus.config.ts b/docusaurus.config.ts index a2ff281..1849901 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -72,7 +72,7 @@ const config: Config = { ], ], - plugins: ["docusaurus-plugin-matomo"], + plugins: ["docusaurus-plugin-matomo", "./src/plugins/docTagsPlugin.ts"], themeConfig: { // Replace with your project's social card @@ -112,6 +112,12 @@ const config: Config = { position: "left", label: "Python", }, + { + type: "docSidebar", + sidebarId: "cliSidebar", + position: "left", + label: "CLI", + }, { type: "docSidebar", sidebarId: "dataSidebar", @@ -124,6 +130,11 @@ const config: Config = { position: "left", label: "API", }, + { + to: "/cookbook", + position: "left", + label: "Cookbook", + }, { href: "https://meteostat.net", label: "Meteostat", @@ -150,6 +161,10 @@ const config: Config = { label: "Python Library", to: "/python", }, + { + label: "CLI", + to: "/cli", + }, { label: "Bulk Data", to: "/data", diff --git a/sidebars.ts b/sidebars.ts index f6533da..d428cce 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -70,6 +70,8 @@ const sidebars: SidebarsConfig = { href: "https://rapidapi.com/meteostat/api/meteostat/", }, ], + cliSidebar: [{ type: "autogenerated", dirName: "cli" }], + cookbookSidebar: [{ type: "autogenerated", dirName: "cookbook" }], }; export default sidebars; diff --git a/src/components/CookbookIndex/index.tsx b/src/components/CookbookIndex/index.tsx new file mode 100644 index 0000000..f4b482a --- /dev/null +++ b/src/components/CookbookIndex/index.tsx @@ -0,0 +1,133 @@ +import React, { useMemo, useState } from 'react'; +import Link from '@docusaurus/Link'; +import { useLocation } from '@docusaurus/router'; +import { usePluginData } from '@docusaurus/useGlobalData'; +import { + useDocsSidebar, +} from '@docusaurus/plugin-content-docs/client'; +import type { + PropSidebarItem, + PropSidebarItemLink, +} from '@docusaurus/plugin-content-docs'; +import type { DocTagsMap } from '@site/src/plugins/docTagsPlugin'; +import styles from './styles.module.css'; + +function collectDocLinks(items: PropSidebarItem[]): PropSidebarItemLink[] { + const links: PropSidebarItemLink[] = []; + for (const item of items) { + if (item.type === 'link' && item.docId) { + links.push(item); + } else if (item.type === 'category') { + links.push(...collectDocLinks(item.items)); + } + } + return links; +} + +function RecipeItem({ + link, + tagsMap, +}: { + link: PropSidebarItemLink; + tagsMap: DocTagsMap; +}) { + const tags = (link.docId && tagsMap[link.docId]) ?? []; + + return ( + +
{link.label}
+ {tags.length > 0 && ( +
+ {tags.map((tag) => ( + + {tag} + + ))} +
+ )} + + ); +} + +const CookbookIndex: React.FC = () => { + const sidebar = useDocsSidebar(); + const { pathname } = useLocation(); + const tagsMap = usePluginData('doc-tags') as DocTagsMap; + + const docLinks = useMemo( + () => + sidebar + ? collectDocLinks(sidebar.items).filter( + (link) => link.href !== pathname, + ) + : [], + [sidebar, pathname], + ); + + const tagCounts = useMemo(() => { + const map = new Map(); + docLinks.forEach((link) => { + const tags = (link.docId && tagsMap[link.docId]) ?? []; + tags.forEach((t) => map.set(t, (map.get(t) || 0) + 1)); + }); + return Array.from(map.entries()).sort( + (a, b) => b[1] - a[1] || a[0].localeCompare(b[0]), + ); + }, [docLinks, tagsMap]); + + const [selectedTags, setSelectedTags] = useState>(new Set()); + + const toggleTag = (tag: string) => { + setSelectedTags((prev) => { + const next = new Set(prev); + if (next.has(tag)) { + next.delete(tag); + } else { + next.add(tag); + } + return next; + }); + }; + + const filtered = useMemo(() => { + if (selectedTags.size === 0) return docLinks; + return docLinks.filter((link) => { + const tags = (link.docId && tagsMap[link.docId]) ?? []; + return Array.from(selectedTags).every((tag) => tags.includes(tag)); + }); + }, [docLinks, selectedTags, tagsMap]); + + return ( +
+ {tagCounts.length > 0 && ( +
+ {tagCounts.map(([tag, count]) => ( + + ))} +
+ )} + +
+ {filtered.map((link) => ( + + ))} +
+ + {filtered.length === 0 && ( +

+ No recipes match the selected filters. +

+ )} +
+ ); +}; + +export default CookbookIndex; diff --git a/src/components/CookbookIndex/styles.module.css b/src/components/CookbookIndex/styles.module.css new file mode 100644 index 0000000..def7687 --- /dev/null +++ b/src/components/CookbookIndex/styles.module.css @@ -0,0 +1,124 @@ +/* ── Filter bar ── */ +.filterBar { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-bottom: 1.5rem; +} + +.filterTag { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0 0.75rem; + height: 2rem; + border-radius: 9999px; + border: none; + background: var(--ifm-color-emphasis-200, #ebebeb); + color: var(--ifm-color-emphasis-900, #171717); + font-size: 0.875rem; + font-weight: 500; + font-family: var(--ifm-font-family-base); + cursor: pointer; + transition: background 150ms ease, color 150ms ease; + line-height: 1; + text-transform: capitalize; +} + +.filterTag:hover { + background: var(--ifm-color-emphasis-300, #d4d4d4); +} + +.filterTagActive { + background: var(--ifm-color-primary, #0678be); + color: #fff; +} + +.filterTagActive:hover { + background: var(--ifm-color-primary-dark, #066caa); + color: #fff; +} + +.filterCount { + font-size: 0.75rem; + opacity: 0.65; +} + +/* ── Recipe list ── */ +.recipeList { + display: flex; + flex-direction: column; +} + +.recipeRow { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 0.5rem 0; + border-bottom: 1px solid var(--ifm-color-emphasis-200, #ebebeb); + text-decoration: none; + color: var(--ifm-color-emphasis-900, #171717); + transition: color 150ms ease; +} + +.recipeRow:hover { + text-decoration: none; + color: var(--ifm-color-emphasis-900, #171717); +} + +.recipeRow:hover .recipeTitle { + text-decoration: underline; +} + +.recipeTitle { + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + flex: 1; + min-width: 0; +} + +.recipeTags { + display: flex; + flex-direction: row; + gap: 0.5rem; + flex-shrink: 0; + margin-left: 1rem; +} + +.recipeBadge { + display: inline-flex; + align-items: center; + padding: 0 0.625rem; + height: 1.5rem; + border-radius: 9999px; + background: var(--ifm-color-emphasis-200, #ebebeb); + color: var(--ifm-color-emphasis-900, #171717); + font-size: 0.75rem; + font-weight: 500; + line-height: 1; + text-transform: capitalize; + white-space: nowrap; +} + +/* ── Empty state ── */ +.empty { + text-align: center; + padding: 3rem 1rem; + color: var(--ifm-color-emphasis-500, #9ca3af); + font-size: 0.9rem; +} + +/* ── Responsive ── */ +@media (max-width: 767px) { + .recipeRow { + flex-direction: column; + align-items: flex-start; + gap: 0.375rem; + } + + .recipeTags { + margin-left: 0; + } +} diff --git a/src/plugins/docTagsPlugin.ts b/src/plugins/docTagsPlugin.ts new file mode 100644 index 0000000..d4b244e --- /dev/null +++ b/src/plugins/docTagsPlugin.ts @@ -0,0 +1,30 @@ +import type { LoadContext, Plugin, AllContent } from '@docusaurus/types'; +import type { LoadedContent } from '@docusaurus/plugin-content-docs'; + +export type DocTagsMap = { [docId: string]: string[] }; + +export default function docTagsPlugin(_context: LoadContext): Plugin { + return { + name: 'doc-tags', + async allContentLoaded({ allContent, actions }) { + const docsContent = ( + allContent['docusaurus-plugin-content-docs'] as + | { [id: string]: LoadedContent } + | undefined + )?.default; + + if (!docsContent) return; + + const map: DocTagsMap = {}; + for (const version of docsContent.loadedVersions) { + for (const doc of version.docs) { + if (doc.tags.length > 0) { + map[doc.id] = doc.tags.map((t) => t.label); + } + } + } + + actions.setGlobalData(map); + }, + }; +} diff --git a/src/theme/DocBreadcrumbs/useSidebarBreadcrumbsWithContext.ts b/src/theme/DocBreadcrumbs/useSidebarBreadcrumbsWithContext.ts index 8ac8db0..8e00fa3 100644 --- a/src/theme/DocBreadcrumbs/useSidebarBreadcrumbsWithContext.ts +++ b/src/theme/DocBreadcrumbs/useSidebarBreadcrumbsWithContext.ts @@ -15,6 +15,10 @@ const CONTEXT_MAP = { label: "JSON API", href: "/api", }, + cookbook: { + label: "Cookbook", + href: "/cookbook", + }, }; export function useSidebarBreadcrumbsWithContext(): diff --git a/src/theme/DocCardList/index.tsx b/src/theme/DocCardList/index.tsx new file mode 100644 index 0000000..92fb2c2 --- /dev/null +++ b/src/theme/DocCardList/index.tsx @@ -0,0 +1,43 @@ +import React, { type ComponentProps, type ReactNode } from "react"; +import DocCardList from "@theme-original/DocCardList"; +import { + useCurrentSidebarSiblings, + filterDocCardListItems, +} from "@docusaurus/plugin-content-docs/client"; +import { useLocation } from "@docusaurus/router"; +import type { PropSidebarItem } from "@docusaurus/plugin-content-docs"; + +type Props = ComponentProps & { + readonly skipCurrentPage?: boolean; +}; + +function useFilteredItems( + items: PropSidebarItem[] | undefined, + skipCurrentPage: boolean +): PropSidebarItem[] | undefined { + const sidebarItems = useCurrentSidebarSiblings(); + const { pathname } = useLocation(); + + if (!skipCurrentPage) { + return items; + } + + const sourceItems = items ?? sidebarItems; + const filtered = filterDocCardListItems(sourceItems); + + return filtered.filter((item) => { + if (item.type === "link") { + const itemPath = item.href.replace(/\/+$/, ""); + const currentPath = pathname.replace(/\/+$/, ""); + return itemPath !== currentPath; + } + return true; + }); +} + +export default function DocCardListWrapper(props: Props): ReactNode { + const { skipCurrentPage = false, ...rest } = props; + const filteredItems = useFilteredItems(rest.items, skipCurrentPage); + + return ; +}