Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: raster_reduce for raster operations that don't produce a raster #285

Closed
emlys opened this issue Dec 6, 2022 · 4 comments
Closed
Assignees
Labels
enhancement New feature or request in progress Working on it! proposal Proposals requiring team feedback

Comments

@emlys
Copy link
Member

emlys commented Dec 6, 2022

It could be useful to have an equivalent of raster_calculator for operations that don't produce a raster output. If raster_calculator is like map over the blocks of a raster, then this would be like functools.reduce over the blocks of a raster.

Aggregations are probably the most common use case. For the Morgan Stanley project I needed to produce histogram data for a raster. raster_calculator seems like the easiest approach, but it requires writing to a target raster which was totally irrelevant for my use case. I ended up with:

def raster_histogram(raster_path, bins=10):
    """Return histogram data for the given raster divided into bins."""

    histogram = numpy.zeros(bins)

    def add_to_histogram(array):
        nonlocal histogram
        histogram += numpy.histogram(array, bins=bins)[0]
        return array

    pygeoprocessing.raster_calculator(
        [(raster_path, 1)],
        add_to_histogram,
        'foo.tif',
        gdal.GDT_Int32,
        TARGET_NODATA
    )
    return histogram

Given a proposed new function raster_reduce(raster_path, function, initializer) that behaves like functools.reduce, that could be rewritten as

def raster_histogram(raster_path, bins=10):
    """Return histogram data for the given raster divided into bins."""

    def add_to_histogram(array, histogram):
        return histogram + numpy.histogram(array, bins=bins)[0]

    return pygeoprocessing.raster_reduce(
        [(raster_path, 1)],
        add_to_histogram,
        numpy.zeros(bins))

I'm not sure if there are any use cases for this function in invest, but I imagine it would be useful for data analysis.

@emlys
Copy link
Member Author

emlys commented Dec 6, 2022

This would be easy to implement with iterblocks too, like

def raster_reduce(raster_path, function, initializer):
    aggregator = initializer
    for (_, block) in iterblocks(raster_path):
        aggregator = function(aggregator, block)
    return aggregator

The main value of this wrapper function would be so we don't have to think about blocks at all. And I wonder if there's some boilerplate code in raster_calculator that would be useful here too.

@phargogh
Copy link
Member

phargogh commented Dec 6, 2022

👍 Great idea!

As for other use cases, a few come to mind:

  • pygeoprocessing.zonal_statistics seems like it could be rewritten in terms of a reduce function
  • There are places in InVEST where we're doing some kind of iterblocks-based accumulation, for example:
    • Crop production (example, another, and another), returning float numbers
    • Scenic Quality, returning a dict of viewpoint coordinates that are over valid DEM pixel values
    • Carbon, for accumulating carbon totals

@emlys emlys added the enhancement New feature or request label Dec 6, 2022
@emlys
Copy link
Member Author

emlys commented Dec 19, 2022

In our meeting on 12/9 we approved this without a design doc.

@emlys emlys self-assigned this Dec 19, 2022
@emlys emlys added the in progress Working on it! label Dec 19, 2022
@dcdenu4 dcdenu4 added the proposal Proposals requiring team feedback label Apr 27, 2023
@emlys
Copy link
Member Author

emlys commented Jun 2, 2023

This was implemented in #292

@emlys emlys closed this as completed Jun 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request in progress Working on it! proposal Proposals requiring team feedback
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants