Again, please keep communication on the maillist, to help others as well.

The R spatial maillist is R-sig-Geo in case you want to continue there.


Here's my solution. I read in your layers, then looped over all polygons. Inside the loop I extract the minimum value of the DEM, then subtract that from the original values, to get the height above minimum. And finally, using extract_exact() I get the sum of all these height pixels within the polygon = volume.


After the loop, rbind to merge the new polygons with volume column.


Here's the code I tried:


# Load packages and Setup directories
pkgs <- c('terra', 'exactextractr', 'dplyr', 'sf')
invisible(lapply(pkgs, require, character.only = TRUE))
GIS_dir <- "./GIS"
dem_file <- file.path(GIS_dir, "Base1.tif")
poly_path <- file.path(GIS_dir, "Sites_Sarch.shp")

# Read the data
dem <- rast(dem_file)
polys <- st_read(poly_path)

# Start a loop over all polygons, and extract data from each
volumes_list <- lapply(1:length(polys$geometry), function(x) {
    poly <- polys$geometry[x] # A single sfc object
    poly <- st_as_sf(poly)    # coerced to an sf object
    poly_id <- polys$Name[x]
    # Get minimum value in this polygon
    dem_crop <- mask(crop(dem, poly), poly)
    dem_min <- min(values(dem_crop), na.rm = TRUE)
    # Make a new cropped raster
    # that is the height above minimum
    dem_height <- dem_crop - dem_min

    # Get the sum of the values in this dem_height
    volume <- exactextractr::exact_extract(dem_height,
                                           poly, 'sum') # in m^3
    # Make a data.frame of all necessary values:
    # minimum and sum for this poly
    # and the id of the poly
    poly_sf <- data.frame("Name" = poly_id,
                          "poly_min" = dem_min,
                          "volume" = volume)
    poly_sf <- st_set_geometry(poly_sf, st_geometry(poly))

    return(poly_sf)
})

# Bind the list output into a merged sf object
result_polys <- do.call(rbind, volumes_list)
print(st_drop_geometry(result_polys))



HTH

On 21/11/2023 10:33, javad bayat wrote:
Micha;
I finally calculated the volumes. But it needs too many codes. Is there any way to reduce the amount of codes? Do you have any idea regarding how to calculate the exact volume under the polygon?


x1 = as.data.frame(x[1])
x2 = as.data.frame(x[2])
x3 = as.data.frame(x[3])
x4 = as.data.frame(x[4])
x5 = as.data.frame(x[5])
x6 = as.data.frame(x[6])
x7 = as.data.frame(x[7])
x8 = as.data.frame(x[8])
x9 = as.data.frame(x[9])
x10 = as.data.frame(x[10])
x11 = as.data.frame(x[11])
x12 = as.data.frame(x[12])

x1$Depth = x1[,1] - min(x1[,1])
x2$Depth = x2[,1] - min(x2[,1])
x3$Depth = x3[,1] - min(x3[,1])
x4$Depth = x4[,1] - min(x4[,1])
x5$Depth = x5[,1] - min(x5[,1])
x6$Depth = x6[,1] - min(x6[,1])
x7$Depth = x7[,1] - min(x7[,1])
x8$Depth = x8[,1] - min(x8[,1])
x9$Depth = x9[,1] - min(x9[,1])
x10$Depth = x10[,1] - min(x10[,1])
x11$Depth = x11[,1] - min(x11[,1])
x12$Depth = x12[,1] - min(x12[,1])


x1$Vol = x1[,2] * x1[,3]
x2$Vol = x2[,2] * x2[,3]
x3$Vol = x3[,2] * x3[,3]
x4$Vol = x4[,2] * x4[,3]
x5$Vol = x5[,2] * x5[,3]
x6$Vol = x6[,2] * x6[,3]
x7$Vol = x7[,2] * x7[,3]
x8$Vol = x8[,2] * x8[,3]
x9$Vol = x9[,2] * x9[,3]
x10$Vol = x10[,2] * x10[,3]
x11$Vol = x11[,2] * x11[,3]
x12$Vol = x12[,2] * x12[,3]

Volume = data.frame(ID = c(1:12), Vol = c(sum(x1$Vol),
                                  sum(x2$Vol),
                                  sum(x3$Vol),
                                  sum(x4$Vol),
                                  sum(x5$Vol),
                                  sum(x6$Vol),
                                  sum(x7$Vol),
                                  sum(x8$Vol),
                                  sum(x9$Vol),
                                  sum(x10$Vol),
                                  sum(x11$Vol),
                                  sum(x12$Vol)))
Volume

On Tue, Nov 21, 2023 at 11:14 AM javad bayat <j.bayat...@gmail.com> wrote:

    Dear Micha, I have sent my question to the R-sig-Geosite too. To
    clarify more, I am trying to calculate the volume of polygons by a
    DEM raster. The shapefile has several polygons (12) and I want to
    calculate the volume of the polygons based on their minimum
    elevations. I tried these codes too, but I don't know how to
    calculate the volumes at the end. The function I wrote uses the
    minimum elevation of all polygons, not each polygon minimum.
    You know I want to calculate the volume of the soil to be removed
    on these sites. Maybe using the minimum elevation is not
    appropriate for this work, maybe calculating the relation between
    elevation and slope of the area under the polygons will act
    better. I dont know how to do it.
    I would be more than happy if you help me.
    The coordinate system is UTM zone 40N.
    I have uploaded the files.

    Sincerely yours

    ################################################################
    library(terra)
    library(exactextractr)
    library(dplyr)
    library(sf)

    # Read the DEM raster file
    r <- rast("E:/Base1.tif")
    # Read the polygon shapefile that contains several polygons from
    different sites
    p <- st_read("E:/Sites.shp")
    crop_r <- crop(r, extent(p))
    mask_r <- mask(crop_r, p)
    # Extract the area of each cell that is contained within each polygon
    x <- exact_extract(r, p, coverage_area = TRUE)
    # Add polygon names that the results will be grouped by
    names(x) <- p$Name
    a = values(mask_r)
    # Bind the list output into a data frame and calculate the
    proportion cover for each category
    result <- bind_rows(x, .id = "Name") %>%
      group_by(Name) %>% summarize(Area = sum(coverage_area)) %>%
      group_by(Name) %>% mutate(Volume = Area * min(na.omit(a)))
    
############################################################################################


    On Tue, Nov 21, 2023 at 10:53 AM Micha Silver <tsvi...@gmail.com>
    wrote:

        (Keeping on the list. And consider my suggestion to move this
        to R-sig-Geo)


        What is the coordinate reference system of the polygon layer?
        Can you
        share these layers?


        On 21/11/2023 4:58, javad bayat wrote:
        > Dear Micha;
        > Thank you for your reply.
        > The R version is 4.3.2, the raster package is
        "raster_3.6-26", the sf
        > package is "sf_1.0-14".
        > The str of the raster and polygon is as follow:
        > > str(r)
        > Formal class 'RasterLayer' [package "raster"] with 13 slots
        >   ..@ file    :Formal class '.RasterFile' [package "raster"]
        with 13 slots
        >   .. .. ..@ name        : chr "E:\Base1.tif"
        >   .. .. ..@ datanotation: chr "INT2S"
        >   .. .. ..@ byteorder   : chr "little"
        >   .. .. ..@ nodatavalue : num -Inf
        >   .. .. ..@ NAchanged   : logi FALSE
        >   .. .. ..@ nbands      : int 1
        >   .. .. ..@ bandorder   : chr "BIL"
        >   .. .. ..@ offset      : int 0
        >   .. .. ..@ toptobottom : logi TRUE
        >   .. .. ..@ blockrows   : Named int 128
        >   .. .. .. ..- attr(*, "names")= chr "rows"
        >   .. .. ..@ blockcols   : Named int 128
        >   .. .. .. ..- attr(*, "names")= chr "cols"
        >   .. .. ..@ driver      : chr "gdal"
        >   .. .. ..@ open        : logi FALSE
        >   ..@ data    :Formal class '.SingleLayerData' [package
        "raster"] with
        > 13 slots
        >   .. .. ..@ values    : logi(0)
        >   .. .. ..@ offset    : num 0
        >   .. .. ..@ gain      : num 1
        >   .. .. ..@ inmemory  : logi FALSE
        >   .. .. ..@ fromdisk  : logi TRUE
        >   .. .. ..@ isfactor  : logi FALSE
        >   .. .. ..@ attributes: list()
        >   .. .. ..@ haveminmax: logi TRUE
        >   .. .. ..@ min       : num 1801
        >   .. .. ..@ max       : num 3289
        >   .. .. ..@ band      : int 1
        >   .. .. ..@ unit      : chr ""
        >   .. .. ..@ names     : chr "Base1"
        >   ..@ legend  :Formal class '.RasterLegend' [package
        "raster"] with 5
        > slots
        >   .. .. ..@ type      : chr(0)
        >   .. .. ..@ values    : logi(0)
        >   .. .. ..@ color     : logi(0)
        >   .. .. ..@ names     : logi(0)
        >   .. .. ..@ colortable: logi(0)
        >   ..@ title   : chr(0)
        >   ..@ extent  :Formal class 'Extent' [package "raster"] with
        4 slots
        >   .. .. ..@ xmin: num 330533
        >   .. .. ..@ xmax: num 402745
        >   .. .. ..@ ymin: num 3307321
        >   .. .. ..@ ymax: num 3345646
        >   ..@ rotated : logi FALSE
        >   ..@ rotation:Formal class '.Rotation' [package "raster"]
        with 2 slots
        >   .. .. ..@ geotrans: num(0)
        >   .. .. ..@ transfun:function ()
        >   ..@ ncols   : int 5777
        >   ..@ nrows   : int 3066
        >   ..@ crs     :Formal class 'CRS' [package "sp"] with 1 slot
        >   .. .. ..@ projargs: chr NA
        >   ..@ srs     : chr "+proj=utm +zone=40 +datum=WGS84
        +units=m +no_defs"
        >   ..@ history : list()
        >   ..@ z       : list()
        >
        > > str(p)
        > sf [12 × 10] (S3: sf/tbl_df/tbl/data.frame)
        >  $ Name      : chr [1:12] "01" "02" "03" "04" ...
        >  $ FolderPath: chr [1:12]  ...
        >  $ SymbolID  : num [1:12] 0 0 0 0 0 0 0 0 0 0 ...
        >  $ AltMode   : int [1:12] 0 0 0 0 0 0 0 0 0 0 ...
        >  $ Base      : num [1:12] 0 0 0 0 0 0 0 0 0 0 ...
        >  $ Clamped   : int [1:12] -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ...
        >  $ Extruded  : int [1:12] 0 0 0 0 0 0 0 0 0 0 ...
        >  $ Shape_Area: num [1:12] 63.51 15.28 9.23 39.19 642.38 ...
        >  $ Area      : num [1:12] 64 15 9 39 642 56 36 16 53 39 ...
        >  $ geometry  :sfc_POLYGON of length 12; first list element:
        List of 1
        >   ..$ : num [1:18, 1:3] 55.6 55.6 55.6 55.6 55.6 ...
        >   ..- attr(*, "class")= chr [1:3] "XYZ" "POLYGON" "sfg"
        >  - attr(*, "sf_column")= chr "geometry"
        >  - attr(*, "agr")= Factor w/ 3 levels
        "constant","aggregate",..: NA NA
        > NA NA NA NA NA NA NA
        >   ..- attr(*, "names")= chr [1:9] "Name" "FolderPath"
        "SymbolID"
        > "AltMode" ...
        > Sincerely
        >
        >
        >
        >
        >
        >
        >
        > On Mon, Nov 20, 2023 at 5:15 PM Micha Silver
        <tsvi...@gmail.com> wrote:
        >
        >     Hi:
        >
        >     Some preliminary comments first
        >
        >     1- You might get a better response posting to R-sig-Geo
        >
        >     2- Probably better to switch to the `terra` package
        instead of the
        >     older
        >     `raster`
        >
        >     3- Furthermore, there is the package `exactextractr`
        that ensures
        >     that
        >     edge pixels are taken into account, weighted by the
        actual, partial
        >     coverage of each pixel by the polygon.
        >
        >     4- Can you post: your R version, and version of the relevant
        >     packages,
        >     and information about the polygons and DEM (i.e.
        `str(p)` and
        >     `str(r)` )
        >
        >
        >     On 20/11/2023 14:30, javad bayat wrote:
        >     > Dear all;
        >     > I am trying to calculate volume under each polygon of a
        >     shapefile according
        >     > to a DEM.
        >     > when I run the code, it gives me an error as follows.
        >     > "
        >     > Error in h(simpleError(msg, call)) :
        >     >    error in evaluating the argument 'x' in selecting a
        method
        >     for function
        >     > 'addAttrToGeom': sp supports Z dimension only for
        POINT and
        >     MULTIPOINT.
        >     > use `st_zm(...)` to coerce to XY dimensions
        >     > "
        >     > I want to have a table that contains one column
        corresponding to the
        >     > polygon rank and another that contains the volume on
        that polyon.
        >     > I would be more than happy if anyone could help me.
        >     > I provided codes at the end of this email.
        >     > Sincerely
        >     >
        >     >
        >     >
        >
         
##########################################################################################
        >     > library(raster);
        >     > library(sf)
        >     > # Load the DEM raster and shapefile
        >     > r <- raster("E:/Base1.tif")
        >     > p <- read_sf(dsn = "E:/Sites.shp", layer = " Sites")
        >
        >
        >     Now to the question:
        >
        >     In `read_sf()`, when the source is a shapefile, you do
        not need the
        >     'layer' option. It doesn't hurt, but in this case I see
        that you
        >     have an
        >     extra space before the layer name. Could that be causing
        the problem?
        >
        >
        >
        >     > # Extract the values of the DEM raster for each polygon
        >     > values <- extract(r, p)
        >     >    Error in h(simpleError(msg, call)) :
        >     >    error in evaluating the argument 'x' in selecting a
        method
        >     for function
        >     > 'addAttrToGeom': sp supports Z dimension only for
        POINT and
        >     MULTIPOINT.
        >     > use `st_zm(...)` to coerce to XY dimensions
        >     >
        >     > # Calculate the volume of each polygon
        >     > volumes <- sapply(values, function(x) rasterVolume(x, r))
        >
        >     What is this "rasterVolume" function that you call here?
        >
        >
        >     > # Print the results
        >     > for (i in 1:length(volumes)) {
        >     >    cat(sprintf("Volume under polygon %d: %f\n", i,
        volumes[i]))
        >     > }
        >     >
        >
         
##########################################################################################
        >     >
        >     >
        >     >
        >     >
        >     >
        >     --
        >     Micha Silver
        >     Ben Gurion Univ.
        >     Sde Boker, Remote Sensing Lab
        >     cell: +972-523-665918
        >
        >
        >
        > --
        > Best Regards
        > Javad Bayat
        > M.Sc. Environment Engineering
        > Alternative Mail: bayat...@yahoo.com

-- Micha Silver
        Ben Gurion Univ.
        Sde Boker, Remote Sensing Lab
        cell: +972-523-665918



-- Best Regards
    Javad Bayat
    M.Sc. Environment Engineering
    Alternative Mail: bayat...@yahoo.com



--
Best Regards
Javad Bayat
M.Sc. Environment Engineering
Alternative Mail: bayat...@yahoo.com

--
Micha Silver
Ben Gurion Univ.
Sde Boker, Remote Sensing Lab
cell: +972-523-665918

______________________________________________
R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.

Reply via email to