diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml
new file mode 100644
index 0000000..c388afd
--- /dev/null
+++ b/.github/workflows/Documentation.yml
@@ -0,0 +1,80 @@
+name: Documentation
+
+on:
+ push:
+ branches:
+ - main
+ tags: '*'
+ pull_request:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ build-docs:
+ name: Build
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: julia-actions/setup-julia@v2
+ with:
+ version: '1'
+
+ - uses: julia-actions/cache@v2
+
+ - name: Install dependencies
+ run: |
+ julia --project=docs -e '
+ using Pkg
+ Pkg.develop(PackageSpec(path=pwd()))
+ Pkg.instantiate()'
+
+ - name: Build documentation
+ run: julia --project=docs docs/make.jl
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Upload build artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: documentation-build
+ path: docs/build/
+ retention-days: 7
+
+ deploy-docs:
+ name: Deploy
+ needs: build-docs
+ runs-on: ubuntu-latest
+ # Deploy on pushes to main or tags, and PRs from the same repo (not forks)
+ if: github.event_name == 'push' || (github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork)
+ permissions:
+ contents: write
+ pull-requests: read
+ statuses: write
+ concurrency:
+ group: docs-deploy
+ cancel-in-progress: false
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: julia-actions/setup-julia@v2
+ with:
+ version: '1'
+
+ - uses: actions/download-artifact@v4
+ with:
+ name: documentation-build
+ path: docs/build/
+
+ - name: Install Documenter
+ run: julia -e 'using Pkg; Pkg.add("Documenter")'
+
+ - name: Deploy documentation
+ run: julia docs/deploy.jl
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
diff --git a/.gitignore b/.gitignore
index c178bd0..09f0117 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,11 @@ Manifest.toml
*.png
*.mp4
+*.js
+*.html
+*.css
+
+docs/build/
+docs/literated/
+
+
diff --git a/README.md b/README.md
index 7291ece..95b4701 100644
--- a/README.md
+++ b/README.md
@@ -1,98 +1,100 @@
-# CopernicusClimateDataStore.jl
+
+
+ CopernicusClimateDataStore.jl
+
-Julia wrapper around the [Copernicus Climate Data Store (CDS)](https://cds.climate.copernicus.eu/)
-for downloading ERA5 reanalysis data.
+
+
+ 🌍 Julia interface to the Copernicus Climate Data Store for downloading ERA5 reanalysis data
+
-## Installation
+
+
+
+
+
+
+CopernicusClimateDataStore.jl wraps the [`era5cli`](https://era5cli.readthedocs.io/) command-line tool,
+providing a convenient Julia interface for downloading ERA5 hourly and monthly data to NetCDF or GRIB.
+
+### Installation
```julia
using Pkg
-Pkg.add(url="https://github.com/YOUR_USERNAME/CopernicusClimateDataStore.jl")
+Pkg.add(url="https://github.com/NumericalEarth/CopernicusClimateDataStore.jl")
```
-## CDS Account Setup
+### Before you start
-Before downloading data, you must:
+You need a Copernicus Climate Data Store account:
-1. **Create a CDS account** at https://cds.climate.copernicus.eu/
-2. **Accept the Terms of Use** for the ERA5 dataset at
- https://cds.climate.copernicus.eu/datasets/reanalysis-era5-single-levels?tab=download#manage-licences
-3. **Configure your API key** by running:
+1. **Create an account** at https://cds.climate.copernicus.eu/
+2. **Accept the ERA5 Terms of Use** at https://cds.climate.copernicus.eu/datasets/reanalysis-era5-single-levels
+3. **Configure your API key**:
```bash
era5cli config --key YOUR_PERSONAL_ACCESS_TOKEN
```
-Your personal access token can be found on your CDS profile page after logging in.
+Your personal access token is on your [CDS profile page](https://cds.climate.copernicus.eu/).
-## Quick Start
+### Quick start
+
+Download and visualize 2-metre temperature over Europe:
```julia
using CopernicusClimateDataStore
using NCDatasets
using CairoMakie
-# Download 2m temperature for Europe, Jan 1, 2020 at 12:00 UTC
-files = hourly(
- variables = "2m_temperature",
- startyear = 2020,
- months = 1,
- days = 1,
- hours = 12,
- area = (lat = (35, 60), lon = (-10, 25)),
- format = "netcdf",
- outputprefix = "europe"
-)
-
-# Load the downloaded file
-filename = first(files)
-ds = NCDataset(filename)
-
-lon = ds["longitude"][:]
-lat = ds["latitude"][:]
-temp_C = ds["t2m"][:, :, 1] .- 273.15
+files = hourly(variables = "2m_temperature",
+ startyear = 2020,
+ months = 6,
+ days = 21,
+ hours = 12,
+ area = (lat = (35, 70), lon = (-15, 40)),
+ outputprefix = "europe")
+
+# Load the data
+ds = NCDataset(first(files))
+λ = ds["longitude"][:] # degrees East
+φ = ds["latitude"][:] # degrees North
+T = ds["t2m"][:, :, 1] .- 273.15 # K → °C
close(ds)
# Plot
-fig = Figure(size = (800, 600))
-ax = Axis(fig[1, 1], xlabel = "Longitude", ylabel = "Latitude")
-hm = heatmap!(ax, lon, lat, temp_C', colormap = :thermal)
-Colorbar(fig[1, 2], hm, label = "Temperature (°C)")
+fig, ax, hm = heatmap(λ, φ, T'; colormap = :thermal)
+Colorbar(fig[1, 2], hm; label = "Temperature (°C)")
+ax.xlabel = "λ (°E)"
+ax.ylabel = "φ (°N)"
save("temperature.png", fig)
```
-## API
-
-### `hourly(; variables, startyear, ...)`
+
-Download ERA5 hourly data.
+### Key arguments
-**Key arguments:**
-- `variables`: Variable name(s), e.g. `"2m_temperature"`
-- `startyear`, `endyear`: Year range
-- `months`, `days`, `hours`: Time filters
-- `area`: Bounding box `(lat = (south, north), lon = (west, east))`
-- `format`: `"netcdf"` (default) or `"grib"`
-- `outputprefix`: Prefix for output filename
-- `dryrun`: If `true`, print command without downloading
-- `splitmonths`: Split output by month (default: `true`)
-- `merge`: Merge all output into a single file (default: `false`)
+| Argument | Description |
+|:---------|:------------|
+| `variables` | Variable name, e.g. `"2m_temperature"`, `"total_precipitation"` |
+| `startyear` | Year to download (required) |
+| `months` | Month or months (1–12) |
+| `days` | Day or days (1–31) |
+| `hours` | Hour or hours (0–23) |
+| `area` | Bounding box: `(lat = (south, north), lon = (west, east))` |
+| `format` | `"netcdf"` (default) or `"grib"` |
+| `outputprefix` | Prefix for output filename |
+| `merge` | Merge all data into a single file (default: `false`) |
-**Note:** By default, one file is created per month. Use `merge=true` for a single file.
+By default, one file is created per month. Use `merge = true` for a single file.
### Common variables
| Request name | NetCDF name | Description |
-|-------------|-------------|-------------|
-| `2m_temperature` | `t2m` | 2 metre temperature (K) |
-| `10m_u_component_of_wind` | `u10` | 10 metre U wind (m/s) |
-| `10m_v_component_of_wind` | `v10` | 10 metre V wind (m/s) |
+|:-------------|:------------|:------------|
+| `2m_temperature` | `t2m` | 2-metre temperature (K) |
+| `10m_u_component_of_wind` | `u10` | 10-metre zonal wind (m/s) |
+| `10m_v_component_of_wind` | `v10` | 10-metre meridional wind (m/s) |
| `total_precipitation` | `tp` | Total precipitation (m) |
+| `mean_sea_level_pressure` | `msl` | Mean sea level pressure (Pa) |
-## Examples
-
-See the `examples/` directory for Literate-style examples including an animation
-of European temperature evolution.
-
-## License
-
-Apache License 2.0
+See the [CDS ERA5 documentation](https://cds.climate.copernicus.eu/datasets/reanalysis-era5-single-levels) for a complete list.
diff --git a/docs/Project.toml b/docs/Project.toml
index c4a0f05..df691b8 100644
--- a/docs/Project.toml
+++ b/docs/Project.toml
@@ -5,6 +5,9 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab"
+[sources]
+CopernicusClimateDataStore = {path = ".."}
+
[compat]
CairoMakie = "0.12, 0.13"
Documenter = "1"
diff --git a/docs/deploy.jl b/docs/deploy.jl
new file mode 100644
index 0000000..e7f2b12
--- /dev/null
+++ b/docs/deploy.jl
@@ -0,0 +1,20 @@
+using Documenter
+
+@info "Cleaning up temporary .jld2 and .nc output created by doctests or literated examples..."
+
+for (root, _, filenames) in walkdir(@__DIR__)
+ for file in filenames
+ if any(occursin(file), (r"\.jld2$", r"\.nc$", r"\.grib$"))
+ rm(joinpath(root, file); force=true)
+ end
+ end
+end
+
+deploydocs(;
+ repo = "github.com/NumericalEarth/CopernicusClimateDataStore.jl",
+ devbranch = "main",
+ # Only push previews if all the relevant environment variables are non-empty. This is an
+ # attempt to work around https://github.com/JuliaDocs/Documenter.jl/issues/2048.
+ push_preview = all(!isempty, (get(ENV, "GITHUB_TOKEN", ""), get(ENV, "DOCUMENTER_KEY", ""))),
+ forcepush = true,
+)
diff --git a/docs/make.jl b/docs/make.jl
index 882c3a8..d696e7c 100644
--- a/docs/make.jl
+++ b/docs/make.jl
@@ -13,6 +13,7 @@ examples = [
("European temperature evolution", "european_temperature_evolution"),
]
+#=
for (title, basename) in examples
script_path = joinpath(examples_src_dir, basename * ".jl")
@info "Building example: $title"
@@ -20,6 +21,7 @@ for (title, basename) in examples
end
example_pages = [title => joinpath("literated", basename * ".md") for (title, basename) in examples]
+=#
makedocs(
sitename = "CopernicusClimateDataStore.jl",
@@ -30,7 +32,9 @@ makedocs(
),
pages = [
"Home" => "index.md",
- "Examples" => example_pages,
+ # "Examples" => example_pages,
+ "API Reference" => "api.md",
],
)
+
diff --git a/docs/src/api.md b/docs/src/api.md
new file mode 100644
index 0000000..30acbfa
--- /dev/null
+++ b/docs/src/api.md
@@ -0,0 +1,24 @@
+# API Reference
+
+## Main Functions
+
+```@docs
+hourly
+info
+```
+
+## Installation and CLI
+
+```@docs
+install_era5cli
+era5cli_cmd
+```
+
+## Internal Functions
+
+```@docs
+CopernicusClimateDataStore.build_hourly_cmd
+CopernicusClimateDataStore.format_area
+CopernicusClimateDataStore.monthly
+```
+
diff --git a/docs/src/index.md b/docs/src/index.md
index aa1cd4c..968a048 100644
--- a/docs/src/index.md
+++ b/docs/src/index.md
@@ -10,7 +10,7 @@ providing a convenient Julia interface for downloading ERA5 and ERA5-Land data.
```julia
using Pkg
-Pkg.add(url="https://github.com/YOUR_USERNAME/CopernicusClimateDataStore.jl")
+Pkg.add(url="https://github.com/NumericalEarth/CopernicusClimateDataStore.jl")
```
## CDS Account Setup
diff --git a/examples/Project.toml b/examples/Project.toml
index 7d6a47c..9537122 100644
--- a/examples/Project.toml
+++ b/examples/Project.toml
@@ -3,6 +3,9 @@ CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
CopernicusClimateDataStore = "bce3f73f-acea-4481-bd86-df89ecc2cb46"
NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab"
+[sources]
+CopernicusClimateDataStore = {path = ".."}
+
[compat]
CairoMakie = "0.12, 0.13"
NCDatasets = "0.14, 0.15"