# Filter exposure layer by raster extents

**URL:** <https://community.riskscape.org.nz/t/filter-exposure-layer-by-raster-extents/182>\
**Category:** Community\
**Created:** [13 August 2024 23:30 UTC](https://community.riskscape.org.nz/t/filter-exposure-layer-by-raster-extents/182 "2024-08-13T23:30:16Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![luisa](https://avatars.discourse-cdn.com/v4/letter/l/76d3ee/32.png) [@luisa](https://community.riskscape.org.nz/u/luisa)\
**Post date:** [13 August 2024 23:30 UTC](https://community.riskscape.org.nz/t/filter-exposure-layer-by-raster-extents/182/1 "2024-08-13T23:30:16Z")

</div>

Hi,

I want to filter a large, national exposure dataset by the extents of regional hazard rasters, so that RiskScape doesn’t check the exposure layer on one side of the country when the hazard is at the other end. What would be the most efficient way to do that?

Thank you!  
Luisa

---

<div class="post-metadata">

**Author:** ![timbeale](https://avatars.discourse-cdn.com/v4/letter/t/57b2e6/32.png) [@timbeale](https://community.riskscape.org.nz/u/timbeale)\
**Post date:** [14 August 2024 01:46 UTC](https://community.riskscape.org.nz/t/filter-exposure-layer-by-raster-extents/182/2 "2024-08-14T01:46:40Z")

</div>

Hi Luisa,

It depends somewhat on what your model is doing. RiskScape is generally pretty quick at checking if a given point is within a GeoTIFF’s bounds or not. However, if you’re dealing with large exposure features like linestring or polygon geometry, it becomes a lot more work.

Generally you’ll want to take the bounds of the GeoTIFF and check the exposure falls within those bounds. You can get the bounds with:

```auto
bounds(bookmark('region-specific.tif'))

```

If both features are in the same CRS, you can check for an intersection (true/false) with:

```auto
intersects(exposure, bounds(bookmark('region-specific.tif')))

```

This works best as the ‘on’ condition in a join step. However, if the layers are in different CRSs then you’ll have to reproject the geometry first.

If you have a large CSV full of GeoTIFFs then you can turn the bounds of all the GeoTIFFs into a coverage lookup, and then sample that to find matching regions/GeoTIFFs.

Hope that helps.

Tim

---

<div class="post-metadata">

**Author:** ![JPowell](https://avatars.discourse-cdn.com/v4/letter/j/bbce88/32.png) [@JPowell](https://community.riskscape.org.nz/u/JPowell)\
**Post date:** [3 October 2024 22:27 UTC](https://community.riskscape.org.nz/t/filter-exposure-layer-by-raster-extents/182/3 "2024-10-03T22:27:27Z")

</div>

Hi Tim,  
Do you mean something more or less like this?

project.ini

```auto
[project]
description = Clips an input geopackage down to the extent of a raster

[model clipInputGpkg]
framework = pipeline
location = clipInputGpkg.txt

[bookmark inputGpkg]
location = input.gpkg
format = geopackage

[bookmark clipRaster]
location = raster.tif
format = geotiff

```

clipInputGpkg.txt

```auto
input(relation: 'inputGpkg') as exposure
-> select({*, intersects(geom, bounds(bookmark('clipRaster')))})
-> filter("intersects")
-> save(name: 'output', format: 'geopackage')

```

What would be the advantage of doing it in a join step rather than filter?

---

<div class="post-metadata">

**Author:** ![timbeale](https://avatars.discourse-cdn.com/v4/letter/t/57b2e6/32.png) [@timbeale](https://community.riskscape.org.nz/u/timbeale)\
**Post date:** [3 October 2024 22:52 UTC](https://community.riskscape.org.nz/t/filter-exposure-layer-by-raster-extents/182/4 "2024-10-03T22:52:32Z")

</div>

Yes, that looks about right.

You technically don’t need the bookmarks in this case - you could just use the .gpkg/.tif files directly in the pipeline (or as model parameters).

You wouldn’t need a join step in your example. Luisa’s original question made it sound like she was processing multiple raster files in a single model, in which case it would probably already have a join step where the exposure-layer is joined to multiple hazard-layers (i.e. like a [probabilistic model](https://riskscape.org.nz/docs/advanced/probabilistic/multi-file-hazard.html#multiple-geotiffs-example)). It’s probably a _tiny_ bit more efficient to do the bounds check in the join step, but there wouldn’t be a huge difference compared to using a filter step.

---

<div class="post-metadata">

**Author:** ![JPowell](https://avatars.discourse-cdn.com/v4/letter/j/bbce88/32.png) [@JPowell](https://community.riskscape.org.nz/u/JPowell)\
**Post date:** [3 October 2024 23:09 UTC](https://community.riskscape.org.nz/t/filter-exposure-layer-by-raster-extents/182/5 "2024-10-03T23:09:58Z")

</div>

So if the clipRaster bookmark was a csv of raster files how would that change my pipeline? Is there any way I can check against just one of the rasters if I know that they all have the same extent?

---

<div class="post-metadata">

**Author:** ![timbeale](https://avatars.discourse-cdn.com/v4/letter/t/57b2e6/32.png) [@timbeale](https://community.riskscape.org.nz/u/timbeale)\
**Post date:** [4 October 2024 00:30 UTC](https://community.riskscape.org.nz/t/filter-exposure-layer-by-raster-extents/182/6 "2024-10-04T00:30:26Z")

</div>

Actually there’s a limitation there currently where the `bounds()` function won’t work with a dynamic coverage (i.e. raster data loaded from a CSV file).

It’s a bit fiddly, but as a work-around you could do something like this:

1. Run this pipeline, which will take your CSV of rasters and turn it into pipeline code (but as a CSV output).

```auto
riskscape pipeline eval -o . "
  input('ABunchOfRasters.csv')
  -> select({ 'input(value: { bounds(bookmark(\'' + file + '\')) as bounds, }) -> union' as pipeline }) as pipeline
"

```

1. Take the pipeline.csv that got generated and copy-paste the contents into a new-pipeline.txt file. Skip the first line and use find/replace to delete the `"` characters. If you’re a Linux user, you could just do:

```auto
tail -n +2 pipeline.csv | sed s/\"//g > new-pipeline.txt

```

1. Add the following to the end of new-pipeline.txt:

```auto
union()
-> group(by: bounds, select: { * })
-> save('hazard-extent', format: 'geopackage')

```

1. Run the pipeline, e.g. `riskscape pipeline eval new-pipeline.txt`. It should produce a `hazard-extent.gpkg` result.

The `hazard-extent.gpkg` should contain polygons that represent the extent of _all_ your hazard maps. You can use this in your regular pipeline (instead of ‘clipRaster’) to check which exposures intersect a hazard-layer, e.g.

```auto
filter(is_not_null(sample_one(exposure, to_coverage(bookmark('hazard-extent.gpkg')))))

```

Hope that makes sense.

---

<div class="post-metadata">

**Author:** ![JPowell](https://avatars.discourse-cdn.com/v4/letter/j/bbce88/32.png) [@JPowell](https://community.riskscape.org.nz/u/JPowell)\
**Post date:** [4 October 2024 02:43 UTC](https://community.riskscape.org.nz/t/filter-exposure-layer-by-raster-extents/182/7 "2024-10-04T02:43:25Z")

</div>

hey Tim

As all my rasters have the same extent I am getting the filename of the first one (from the first column of my csv) and using that as the clipping layer

```auto
[bookmark clipRaster]
location = changeme

```

```auto
input(relation: 'inputGpkg') as exposure
-> select({*, intersects(geom, bounds(bookmark('clipRaster', {location: $clipRasterLocation})))})
-> filter("intersects")
-> save(name: 'output', format: 'geopackage')

```

to run

```auto
clipRaster=`awk -F"," 'NR==2 { print $1 }' data/Westport.csv`
riskscape model run clipInputGpkg -p"clipRasterLocation='"$clipRaster"'"

```

Would be cool to have the functionality to create an extent from a csv of rasters though…

Thanks for your help!
