3

Basic question

Working with the sf library in R, how can I add M-values to a geometry that doesn't already have them?

Or put differently, given an sf feature without M-values, how can I create a new object with the same coordinates as the original, but which also contains M-values (for example, just a bunch of zeroes)?

Example & code

Suppose I have an object called ml which contains a MultiLineString, as shown below:

library(sf)

wkt = "MULTILINESTRING((0 0, 0 1), (1 1, 1 2, 1 3))"
ml = st_as_sfc(wkt, 
               crs='epsg:4326')

Notice that the ml object was created from a WKT string that specified the geometry as a MultiLineString, not a MultiLineString M.

So how can I generate a new geometry that has the same coordinates as ml but also has M-values enabled? The M-values could be all zero - what matters aren't the individual M-values themselves. Instead, what matters is that, at the end of this process, I have a MultiLineString M geometry.

What I've tried

I tried using the st_cast function, but that doesn't seem to work:

st_cast(ml, "MULTILINESTRING M")
# Error in which_sfc_col(to) : st_cast for MULTILINESTRING M not supported

Manually editing the original WKT string is also a possibility here, but that won't really solve my problem since what I've described here is just a little small-scale version of the real bigger problem I'm trying to solve which involves a large feature with many, many coordinates. I want to avoid manually editing that thing as much as I can.

5
  • is there a good reason that are you dead set on adding M dimension? The reason I am asking is that adding Z dimension is much easier - st_zm(your_object, drop = F, what = "Z") - but for M dimension only dropping is currently implemented, not adding Commented Apr 23 at 13:58
  • The issue is that I'm reading a bunch of data that have M-values embedded in them from a layer inside GDB file. After reading in all that data, I then read in a GeoJSON string that does not have M-values and try to append that new row to the previously-read data and write it all back to disk. But it seems that the fact that the last row lacks M-values is blocking the writing process of going through.
    – Felipe D.
    Commented Apr 23 at 14:32
  • Oh snap, you just gave me an idea for a workaround!!! I can transform the geometry to a WKT with a Z value, then just do a search-and-replace the string to change MULTILINESTRING Z into MULTILINESTRING M and create a new geometry.
    – Felipe D.
    Commented Apr 23 at 14:42
  • @Jindra Lacko, thank you so much for the great idea!!!
    – Felipe D.
    Commented Apr 23 at 15:33
  • glad to be of service! happy for you to get the pesky problem working Commented Apr 23 at 19:05

1 Answer 1

4

WKT-based work-around

As pointed out by Jindra Lacko, the st_as_sfc function can be used to generate a MultiLineString Z, but not a MultiLineString M. But this gave me the idea of doing a simple WKT-based work-around: use st_as_sfc to add the Z dimension, transform back to WKT, then search-and-replace "MULTILINESTRING Z" with "MULTILINESTRING M" and then create a geometry again! Here is the solution in code:

# Loading tidyverse to have access to the piping %>% operator
library(tidyverse) 

ml_m = wkt %>% 
  st_as_sfc() %>%
  st_zm(drop = F, what = "Z")  %>%
  st_as_text() %>%
  str_replace('MULTILINESTRING Z', 'MULTILINESTRING M') %>%
  st_as_sfc()

And Bob's you're uncle! You've got the ml_m object that's a proper MULTILINESTRING M object.

Thanks again to Jindra Lacko for the idea!!!

1
  • Seing this, there is probably not much missing to make st_zm(ml, drop = FALSE, what = "M") work natively since st_as_sfc() properly returns a geometry set with XYM dimensions in the end? Nice workaround but maybe it's time for a little feature request reminder?
    – dimfalk
    Commented Apr 24 at 7:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.