Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
913c1b3
Fix outbounds line burn (#951)
rafaqz Apr 23, 2025
7574a8f
bump patch version to 0.14.4
rafaqz Apr 23, 2025
f1c4b75
use the correct `@example` label
tiemvanderdeure Apr 24, 2025
7e9240d
Merge pull request #953 from tiemvanderdeure/bonus_spatialmean
tiemvanderdeure Apr 24, 2025
a99c800
start cdm read overhaul
rafaqz May 3, 2025
6ac1b33
Fix multilinestring load
asinghvi17 May 3, 2025
87944b0
Fix everything for CDM geom lookup + add tests
asinghvi17 May 3, 2025
57b0a64
more cf read / write
rafaqz May 4, 2025
768685d
namespace coord names in geometry lookup, but only if necessary
asinghvi17 May 4, 2025
0b7e7e6
read geom working
rafaqz May 4, 2025
ee68ede
round trip geometrylookup
rafaqz May 4, 2025
a798c72
working Raster
rafaqz May 4, 2025
ed7ca3b
add cf test files
rafaqz May 4, 2025
41ce164
add more cf examples
rafaqz May 6, 2025
173eaa2
Update make.jl
asinghvi17 May 14, 2025
014a2a5
add my DV branch for now
asinghvi17 May 14, 2025
f25285c
REMOVE BEFORE MERGING: draft=true for faster iteration
asinghvi17 May 14, 2025
fcc6e13
Update make.jl
asinghvi17 May 14, 2025
63c088c
Update docs/Project.toml
asinghvi17 May 14, 2025
43622e9
more cf
rafaqz May 17, 2025
e21dbea
warnonly=false and import packages (#954)
tiemvanderdeure May 17, 2025
41e7436
move logo to top right
alex-s-gardner May 22, 2025
030e3e4
add new aqua logo
alex-s-gardner May 22, 2025
fddd0eb
remove broken downloads
alex-s-gardner May 22, 2025
64e4044
modify text
alex-s-gardner May 22, 2025
eb7b5ac
fix Downloads badge
alex-s-gardner May 23, 2025
2cbda6d
fix downloads badge request
alex-s-gardner May 23, 2025
95437ed
Merge pull request #977 from alex-s-gardner/update-ReadMe
lazarusA May 23, 2025
2ff1087
Update docs/make.jl
asinghvi17 May 23, 2025
abc3d02
Update config.mts
asinghvi17 May 23, 2025
c715dc8
Merge branch 'main' into asinghvi17-patch-7
asinghvi17 May 23, 2025
5a609f7
Merge pull request #974 from rafaqz/asinghvi17-patch-7
lazarusA May 23, 2025
febbc76
fix lazy in create without filename (#979)
rafaqz Jun 2, 2025
815bf5a
bump patch version to 0.14.5
rafaqz Jun 2, 2025
06ae9f4
remove unnecessary `replace_missing` (#982)
tiemvanderdeure Jun 18, 2025
c11690e
check if dimtree exists (#985)
rafaqz Jun 23, 2025
284022e
bump patch version to 0.14.6
rafaqz Jun 23, 2025
c704e71
Merge branch 'main' into cdm_overhaul
rafaqz Jun 28, 2025
92b95c1
more passing cf
rafaqz Jul 4, 2025
1fce5ad
add UGRID mesh
rafaqz Jul 5, 2025
e7d86b5
refactor cf
rafaqz Jul 6, 2025
9cddb02
mostly working climatology bounds
rafaqz Jul 7, 2025
ec80d6c
unaligned
rafaqz Jul 12, 2025
abd10bf
better rotated lookups
rafaqz Jul 14, 2025
d207a43
Merge remote-tracking branch 'origin/main' into cdm_overhaul (#996)
asinghvi17 Jul 19, 2025
12596d9
fix sources for dev branches
asinghvi17 Jul 19, 2025
bd89244
domains working
rafaqz Aug 24, 2025
59d3669
fix lazy Char string reading and other minor things
rafaqz Sep 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Rasters"
uuid = "a3a2b9e3-a471-40c9-b274-f788e487c689"
authors = ["Rafael Schouten <rafaelschouten@gmail.com>"]
version = "0.14.3"
version = "0.14.6"

[deps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
Expand All @@ -22,6 +22,7 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Missings = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
Mmap = "a63ad114-7e13-5084-954f-fe012c677804"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Expand Down Expand Up @@ -61,7 +62,7 @@ CommonDataModel = "0.2.3, 0.3"
ConstructionBase = "1"
CoordinateTransformations = "0.6.2"
DataFrames = "1"
DimensionalData = "0.29.4"
DimensionalData = "0.30.0"
DiskArrays = "0.4"
Extents = "0.1"
FillArrays = "0.12, 0.13, 1"
Expand All @@ -71,12 +72,13 @@ GeoDataFrames = "0.3"
GeoFormatTypes = "0.4"
GeoInterface = "1.0"
GeometryBasics = "0.4"
GeometryOps = "0.1.19"
GeometryOpsCore = "0.1.1"
Makie = "0.20, 0.21, 0.22"
GeometryOps = "0.1"
GeometryOpsCore = "0.1"
Makie = "0.20, 0.21, 0.22, 0.23, 0.24"
Missings = "0.4, 1"
NCDatasets = "0.13, 0.14"
OffsetArrays = "1"
OrderedCollections = "1.8"
Plots = "1"
ProgressMeter = "1"
Proj = "1.7.2"
Expand Down Expand Up @@ -119,5 +121,4 @@ test = ["Aqua", "ArchGDAL", "CFTime", "CoordinateTransformations", "DataFrames",


[sources]
DimensionalData = {url = "https://github.com/rafaqz/DimensionalData.jl", rev = "as/individualindexing"}
GeometryOps = {url = "https://github.com/JuliaGeo/GeometryOps.jl", rev = "as/extentforwarding_for_predicates"}
DimensionalData = {url = "https://github.com/rafaqz/DimensionalData.jl", rev = "as/multidimtrait"}
38 changes: 21 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
# Rasters

<img src="docs/src/assets/logo.png" align="right" width="30%"></img>
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/rafaqz/Rasters.jl/blob/main/LICENSE)
[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://rafaqz.github.io/Rasters.jl/stable)
[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://rafaqz.github.io/Rasters.jl/dev)
[![CI](https://github.com/rafaqz/Rasters.jl/actions/workflows/ci.yml/badge.svg)](https://github.com/rafaqz/Rasters.jl/actions/workflows/ci.yml)
[![Codecov](https://codecov.io/gh/rafaqz/Rasters.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/rafaqz/Rasters.jl)
[![Aqua.jl Quality Assurance](https://img.shields.io/badge/Aquajl-%F0%9F%8C%A2-aqua.svg)](https://github.com/JuliaTesting/Aqua.jl)
[![Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/Rasters&label=Downloads)](https://pkgs.genieframework.com?packages=Rasters)

<img src="/docs/src/assets/logo.png" align="right" width="30%"></img>
[![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl)
[![Downloads](https://img.shields.io/badge/dynamic/json?url=http%3A%2F%2Fjuliapkgstats.com%2Fapi%2Fv1%2Fmonthly_downloads%2FRasters&query=total_requests&suffix=%2Fmonth&label=Downloads)](https://juliapkgstats.com/pkg/Rasters)

[Rasters.jl](https://rafaqz.github.io/Rasters.jl/dev) defines common types and methods for reading, writing and
manipulating rasterized spatial data.
[Rasters.jl](https://rafaqz.github.io/Rasters.jl/dev) is a powerful Julia package for working with spatial raster data. It provides a unified interface for reading, writing, and manipulating raster data. The package extends [DimensionalData.jl](https://rafaqz.github.io/DimensionalData.jl/dev/) to enable intuitive spatial indexing and manipulation of raster data.

These currently include raster arrays like GeoTIFF and NetCDF, R grd files,
multi-layered stacks, and multi-file series of arrays and stacks.
Key features:
- Support for multiple raster formats (e.g. GeoTIFF, NetCDF, GRD)
- Support for multi-layered stacks and multi-file series of arrays
- Lazy loading of large datasets
- Intuitive spatial indexing with named dimensions (X, Y, Time)
- Efficient handling of multi-layered stacks and time series
- Built-in support for coordinate reference systems (CRS)
- High-performance operations optimized for spatial data

# Quick start

Install the package by typing:

```julia
Expand All @@ -31,7 +35,7 @@ using Rasters

Using `Rasters` to read GeoTiff or NetCDF files will output something similar to the
following toy examples. This is possible because Rasters.jl extends
[DimensionalData.jl](https://github.com/rafaqz/DimensionalData.jl) so that
[DimensionalData.jl](https://rafaqz.github.io/DimensionalData.jl/dev/) so that
spatial data can be indexed using named dimensions like `X`, `Y` and `Ti` (time)
and e.g. spatial coordinates.

Expand All @@ -41,7 +45,7 @@ lon, lat = X(25:1:30), Y(25:1:30)
ti = Ti(DateTime(2001):Month(1):DateTime(2002))
ras = Raster(rand(lon, lat, ti)) # this generates random numbers with the dimensions given
```
```
```julia
6×6×13 Raster{Float64,3} with dimensions:
X Sampled{Int64} 25:1:30 ForwardOrdered Regular Points,
Y Sampled{Int64} 25:1:30 ForwardOrdered Regular Points,
Expand All @@ -64,7 +68,7 @@ Rasters reduces its dependencies to keep the `using` time low.
But, it means you have to manually load packages you need for each
backend or additional functionality.

For example, to use the GDAL backend, and download RasterDataSources files, you now need to do:
For example, to use the GDAL backend, and download RasterDataSources files, you need to do:

```julia
using Rasters, ArchGDAL, RasterDataSources
Expand All @@ -80,7 +84,7 @@ Sources and packages needed:
Other functionality in extensions:
- Raster data downloads, like `Worldclim{Climate}`: `using RasterDataSources`
- Makie plots: `using GLMakie` (opengl interactive) or `using CairoMakie` (print) etc.
- Coordinate transformations for gdal rasters: `using CoordinateTransformations`
- Coordinate transformations for GDAL rasters: `using CoordinateTransformations`

## Getting the `lookup` array from dimensions

Expand All @@ -100,7 +104,7 @@ Selecting a time slice by `index` is done via
```julia
ras[Ti(1)]
```
```
```julia
6×6 Raster{Float64,2} with dimensions:
X Sampled{Int64} 25:1:30 ForwardOrdered Regular Points,
Y Sampled{Int64} 25:1:30 ForwardOrdered Regular Points
Expand All @@ -120,7 +124,7 @@ values: 25 26 27 28 29 30
```julia
ras[Ti=1]
```
```
```julia
6×6 Raster{Float64,2} with dimensions:
X Sampled{Int64} 25:1:30 ForwardOrdered Regular Points,
Y Sampled{Int64} 25:1:30 ForwardOrdered Regular Points
Expand All @@ -142,7 +146,7 @@ or and interval of indices using the syntax `=a:b` or `(a:b)`
```julia
ras[Ti(1:10)]
```
```
```julia
6×6×10 Raster{Float64,3} with dimensions:
X Sampled{Int64} 25:1:30 ForwardOrdered Regular Points,
Y Sampled{Int64} 25:1:30 ForwardOrdered Regular Points,
Expand All @@ -165,7 +169,7 @@ values: [:, :, 1]
```julia
ras[Ti=At(DateTime(2001))]
```
```
```julia
6×6 Raster{Float64,2} with dimensions:
X Sampled{Int64} 25:1:30 ForwardOrdered Regular Points,
Y Sampled{Int64} 25:1:30 ForwardOrdered Regular Points
Expand Down
7 changes: 3 additions & 4 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ using Documenter, Rasters, Plots, Logging, Statistics, Dates,
import Makie, CairoMakie
using DocumenterVitepress
using Rasters.LookupArrays, Rasters.Dimensions
import Shapefile, DataFrames, NaturalEarth # to avoid precompilation in doctests

# Don't output huge svgs for Makie plots
CairoMakie.activate!(type = "png")
Expand Down Expand Up @@ -43,17 +44,15 @@ makedocs(
devbranch = "main",
devurl = "dev";
),
draft = false,
source = "src",
build = "build",
warnonly=true,
warnonly=false,
)

# Enable logging to console again
Logging.disable_logging(Logging.BelowMinLevel)

deploydocs(; repo="github.com/rafaqz/Rasters.jl",
target = "build", # this is where Vitepress stores its output
DocumenterVitepress.deploydocs(; repo="github.com/rafaqz/Rasters.jl",
branch = "gh-pages",
devbranch = "main",
push_preview = true
Expand Down
3 changes: 3 additions & 0 deletions docs/src/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ export default defineConfig({
],
ignoreDeadLinks: false,
vite: {
define: {
__DEPLOY_ABSPATH__: JSON.stringify('REPLACE_ME_DOCUMENTER_VITEPRESS_DEPLOY_ABSPATH'),
},
resolve: {
alias: {
'@': path.resolve(__dirname, '../components')
Expand Down
5 changes: 2 additions & 3 deletions docs/src/tutorials/spatial_mean.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ As a next step, we would like to know how precipitation will change in Chile unt

To start, we define a simple function that takes an SSP (socioeconomic scenario) and a GCM (climate model) as input, and return the appropriate climate data.

````@example zonal
````@example cellarea
using Dates
getfutureprec(ssp, gcm) = Raster(WorldClim{Future{Climate, CMIP6, gcm, ssp}}, :prec, date = Date(2090))
````
Expand All @@ -163,11 +163,10 @@ GCMs = Dim{:gcm}([GFDL_ESM4, IPSL_CM6A_LR]) # These are different general circul
precip_future = (@d getfutureprec.(SSPs, GCMs)) |> RasterSeries |> Rasters.combine
````

Since the format of WorldClim's datasets for future climate is slightly different from the dataset for the historical period, this actually returned a 5-dimensional raster, with a `Band` dimension that represents months. Here we'll just select the 6th month, matching the selection above (but note that the analysis would also work for all Bands simultaneously). We will also replace the `NaN` missing value by the more standard `missing` using [`replace_missing`](@ref).
Since the format of WorldClim's datasets for future climate is slightly different from the dataset for the historical period, this actually returned a 5-dimensional raster, with a `Band` dimension that represents months. Here we'll just select the 6th month, matching the selection above (but note that the analysis would also work for all Bands simultaneously).

````@example cellarea
precip_future = precip_future[Band = 6]
precip_future = replace_missing(precip_future)
````

On our 4-dimensional raster, functions like `crop` and `mask`, as well as broadcasting, will still work.
Expand Down
5 changes: 2 additions & 3 deletions ext/RastersGRIBDatasetsExt/gribdatasets_source.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ Base.close(os::RA.OpenStack{GRIBsource}) = nothing
RA.missingval(var::GDS.Variable, ::RA.Metadata{<:RA.CDMsource}) = _missingval(var)
RA.missingval(var::GDS.Variable, args...) = _missingval(var)

function _missingval(var::GDS.Variable{T}) where T
function _missingval(var::GDS.Variable)
mv = GDS.missing_value(var)
T1 = promote_type(typeof(mv), T)
return T1(mv)
RA._fix_missingval(var, mv)
end
10 changes: 2 additions & 8 deletions src/Rasters.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
module Rasters

# Use the README as the module docs
@doc let
# path = joinpath(dirname(@__DIR__), "README.md")
# include_dependency(path)
# read(path, String)
end Rasters

using Dates

# Load first to fix StaticArrays invalidations
Expand All @@ -24,6 +17,7 @@ import Adapt,
GeometryOps,
GeometryOpsCore,
OffsetArrays,
OrderedCollections,
ProgressMeter,
Missings,
Mmap,
Expand All @@ -44,6 +38,7 @@ using DimensionalData: Name, NoName
using .Dimensions: StandardIndices, DimTuple
using .Lookups: LookupTuple

using OrderedCollections: OrderedDict
using Statistics: mean
using RecipesBase: @recipe, @series
using Base: tail, @propagate_inbounds
Expand Down Expand Up @@ -123,7 +118,6 @@ include("utils.jl")
include("skipmissing.jl")

include("geometry_lookup/geometry_lookup.jl")
include("geometry_lookup/lookups.jl")
include("geometry_lookup/methods.jl")
include("geometry_lookup/io.jl")

Expand Down
4 changes: 2 additions & 2 deletions src/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ function Raster(filename::AbstractString; source=nokw, kw...)
end::Raster
end
# Load a Raster from an opened Dataset
# We need the inner method for AbstractArray ambiguit
# We need the inner method for AbstractArray ambiguity
Raster(ds; kw...) = _raster(ds; kw...)
function _raster(ds;
dims=nokw,
Expand Down Expand Up @@ -401,4 +401,4 @@ filekey(filename::String) = Symbol(splitext(basename(filename))[1])

# Add a `dimconstructor` method so `AbstractProjected` lookups create a Raster
# TODO this should be unwrapped to `DD.lookupconstructor` to avoid future ambiguities
DD.dimconstructor(::Tuple{<:Dimension{<:AbstractProjected},Vararg{Dimension}}) = Raster
DD.dimconstructor(::Tuple{<:Dimension{<:AbstractProjected},Vararg{Dimension}}) = Raster
4 changes: 3 additions & 1 deletion src/create.jl
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,10 @@ function create(filename::Nothing, types::NamedTuple, dims::Tuple;
layerdims=nokw,
layermetadata=nokw,
f=identity,
lazy=false,
kw...
)
lazy && throw(ArgumentError("`lazy` cannot be `true` without passing a `filename` keyword"))
layerdims = isnokw(layerdims) ? map(_ -> basedims(dims), types) : layerdims
layermetadata = layermetadata isa NamedTuple ? layermetadata : map(_ -> layermetadata, types)
layerfill = fill isa NamedTuple ? fill : map(_ -> fill, types)
Expand Down Expand Up @@ -355,4 +357,4 @@ end

_warn_keyword_not_used(label, obj) = @warn "`$label` of `$obj` found. But `chunks` are not used for in-memory rasters"
_missingval_pair(missingval::Pair) = missingval
_missingval_pair(missingval) = missingval => missingval
_missingval_pair(missingval) = missingval => missingval
24 changes: 23 additions & 1 deletion src/dimensions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,28 @@ mean(A; dims=Band)
"""
@dim Band

"""
Lat <: Dimension

Lat(val=:)

Used for holding degrees north lookups.

Will error on lookup construction if metadata of `units="degrees_north"` does not exist.
"""
@dim Lat

"""
Lon <: Dimension

Lon(val=:)

Used for holding degrees east lookups.

Will error on lookup construction if metadata of `units="degrees_east"` does not exist.
"""
@dim Lon

"""
Geometry <: Dimension

Expand All @@ -37,4 +59,4 @@ val = A[Geometry(Touches(other_geom))] # this is automatically accelerated by sp
mean(A; dims=Geometry)
```
"""
@dim Geometry
@dim Geometry
25 changes: 23 additions & 2 deletions src/filearray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ function FileArray{S}(
T = _mod_eltype(var, mod)
return FileArray{S,T,N}(filename, size(var); eachchunk, haschunks, mod, kw...)
end
function FileArray{S}(
var::AbstractArray{Char,N}, filename; mod, kw...
) where {S<:CDMsource,N}
eachchunk = DA.eachchunk(var)
haschunks = DA.haschunks(var)
if Missings.nonmissingtype(eltype(mod)) isa AbstractString
return FileArray{S,eltype(mod),N-1}(filename, size(var); eachchunk, haschunks, mod, kw...)
else
T = _mod_eltype(var, mod)
return FileArray{S,T,N}(filename, size(var); eachchunk, haschunks, mod, kw...)
end
end

# FileArray has S, T and N parameters not recoverable from fields
ConstructionBase.constructorof(::Type{<:FileArray{S,T,N}}) where {S,T,N} = FileArray{S,T,N}
Expand All @@ -68,7 +80,12 @@ end
function DA.readblock!(A::FileArray, dst, r::AbstractUnitRange...)
open(A) do O
if isdisk(O)
DA.readblock!(O, dst, r...)
# Handle CF 2d Char arrays that are really 1d strings
if eltype(O) <: Char && eltype(A) <: String
DA.readblock!(DiskCharToString(O), dst, r...)
else
DA.readblock!(O, dst, r...)
end
else
dest[r...] .= view(parent(O), r...)
end
Expand All @@ -77,7 +94,11 @@ end
function DA.writeblock!(A::FileArray, src, r::AbstractUnitRange...)
open(A; write=A.write) do O
if isdisk(A)
DA.writeblock!(O, src, r...)
if eltype(O) <: Char && eltype(A) <: String
DA.writeblock!(DiskCharToString(O), src, r...)
else
DA.writeblock!(O, src, r...)
end
else
parent(O)[r...] .= src
end
Expand Down
Loading
Loading