1

I have created a group of polygons from a data frame with that code :

P <- P %>% st_as_sf(coords = c("lon", "lat"), 
                            crs = 31370) %>% dplyr::group_by(Fr) %>% dplyr::summarize() %>% sf::st_cast("POLYGON")

Nevertheless, when I plot it I have this irregular shape. enter image description here

I would like to have polygons were points are jointed to the closest ones (lat, long) instead of just the closest in terms of longitude, or following the ID order. The polygons should have the shape of the dashed lines on the following figure: enter image description here

You will find an example of the dataset used on below:

P <- structure(list(ID = c("13-57-43", "13-58-18", "13-58-49", "13-59-14", 
"13-59-48", "14-00-13", "14-00-40", "14-01-03", "14-01-25", "14-01-52", 
"14-02-13", "14-02-43", "14-03-08", "14-03-39", "14-04-03", "14-04-32", 
"14-05-06", "14-05-41", "14-06-14", "14-06-40", "14-07-03", "14-07-34", 
"14-08-09", "14-08-42", "14-09-10", "14-09-40", "14-10-11", "14-11-02", 
"14-11-26", "14-11-47", "14-12-12", "14-12-34", "14-12-58", "14-13-25", 
"14-13-50", "14-14-28", "14-14-48", "14-15-11", "14-15-39", "14-16-02", 
"14-16-30", "14-16-53", "14-17-28", "14-28-23", "14-28-45", "14-29-09", 
"14-29-31", "14-30-27", "14-31-45", "14-32-11", "14-32-32", "14-32-54", 
"14-33-22", "14-33-45", "14-34-07", "14-34-33", "14-34-57", "14-35-17", 
"14-35-59", "14-36-24", "14-36-42", "14-37-24", "14-38-44", "14-39-09", 
"14-39-30", "14-39-56", "14-40-21", "14-40-43", "14-41-12", "14-41-49", 
"14-42-10", "14-42-37", "14-43-30", "14-43-58", "14-44-29", "14-45-08", 
"14-55-55", "14-56-37", "14-56-54", "14-57-12", "14-57-33", "14-58-20", 
"14-58-42", "14-59-03", "14-59-26", "14-59-50", "15-00-12", "15-00-45", 
"15-01-09", "15-01-30", "15-01-52", "15-02-13", "15-02-53", "15-03-17", 
"15-03-46", "15-04-06", "15-04-27", "15-04-48", "15-05-19", "15-05-42", 
"15-06-03", "15-06-29", "15-06-49", "15-07-11", "15-07-30", "15-07-54", 
"15-08-14", "15-08-34", "15-09-01", "15-09-19", "15-09-47", "15-10-13"
), lon = c(195905.778820844, 195905.974267758, 195906.521347454, 
195906.899081334, 195907.794221085, 195908.278097475, 195906.749400405, 
195905.530462325, 195904.169532708, 195903.415217152, 195902.583546779, 
195901.705310906, 195900.676225893, 195899.811829397, 195899.105876732, 
195898.496875417, 195897.417855528, 195896.305319914, 195894.789791642, 
195893.792658586, 195892.846626664, 195892.588160285, 195892.653321993, 
195893.352612261, 195893.325522819, 195892.724380256, 195895.024853343, 
195897.346640149, 195897.522357658, 195897.49907462, 195897.236040002, 
195897.483304948, 195898.30751539, 195899.333731338, 195899.575391337, 
195899.568317725, 195899.64883718, 195899.793165198, 195899.696078815, 
195899.772957444, 195899.71964308, 195901.848642919, 195904.020780265, 
195891.806884353, 195890.229643927, 195889.907273078, 195888.918089508, 
195888.469330492, 195888.697240747, 195887.928917165, 195886.736953866, 
195885.973581512, 195885.327462551, 195884.773745579, 195883.787523878, 
195882.808838648, 195881.820022116, 195881.159939463, 195880.535525829, 
195880.22736261, 195880.16798173, 195880.88351761, 195882.179482257, 
195881.58913656, 195882.244999483, 195883.07501506, 195882.431452093, 
195881.986614064, 195881.56612941, 195883.849986501, 195884.85633537, 
195886.271839823, 195887.256976464, 195889.473852909, 195890.964940259, 
195891.764793086, 195880.614164185, 195880.358714986, 195879.807625943, 
195879.063338423, 195878.122326135, 195877.507258557, 195876.493683828, 
195876.054792449, 195875.626907971, 195874.947148117, 195874.569675939, 
195875.073433679, 195875.336685869, 195874.99480784, 195874.243786076, 
195874.030479338, 195873.822854543, 195873.49650797, 195872.808159092, 
195872.126629216, 195871.945624596, 195872.299770002, 195871.828658921, 
195872.189569543, 195872.009561096, 195871.688583655, 195872.936862676, 
195873.688142326, 195874.526086933, 195875.189198156, 195875.987541361, 
195876.451614305, 195876.949504315, 195877.49530275, 195878.860639032, 
195879.976589664), lat = c(111925.087000872, 111924.746783252, 
111925.124000667, 111925.657795159, 111926.37396592, 111927.243937231, 
111927.492050366, 111927.580125541, 111927.540078711, 111928.148808956, 
111928.507004102, 111928.958462953, 111928.795704281, 111928.416179694, 
111928.56341283, 111928.766807706, 111928.924355094, 111928.910363058, 
111928.735907397, 111928.555450567, 111927.602310046, 111926.627976733, 
111926.154476976, 111926.535614232, 111925.940498663, 111925.246247372, 
111924.770627489, 111924.617882809, 111925.549537431, 111926.057332371, 
111926.169132436, 111926.810872482, 111926.802022958, 111926.558136608, 
111926.909623143, 111927.053772844, 111926.023246794, 111925.596421076, 
111925.219743649, 111924.848264531, 111924.299745381, 111924.183837869, 
111924.031228296, 111926.499693359, 111926.835912733, 111927.529247485, 
111927.931058974, 111928.262019288, 111929.355476192, 111929.588004993, 
111930.09344381, 111929.968575835, 111930.728207498, 111931.031143297, 
111931.689976808, 111932.506147532, 111932.746288973, 111932.722016854, 
111932.691102536, 111931.953822562, 111931.330709156, 111930.868375568, 
111931.817410667, 111930.581975062, 111931.070356929, 111929.611758211, 
111929.75447942, 111929.79541798, 111929.963250504, 111928.765700747, 
111928.158538985, 111926.958042713, 111927.173583846, 111926.498736853, 
111925.88847469, 111925.428917548, 111933.002101255, 111933.629642985, 
111934.153987348, 111935.017048392, 111935.705555274, 111936.292398511, 
111936.273914415, 111935.606822579, 111935.480749928, 111935.979567816, 
111936.252055673, 111936.397532031, 111936.914787345, 111937.462629294, 
111938.127551995, 111938.18262708, 111939.005547066, 111939.678609986, 
111940.11859558, 111939.925228463, 111939.338239755, 111938.820578336, 
111938.849445301, 111938.448843605, 111938.263539459, 111937.703195091, 
111936.385157215, 111935.722993995, 111934.915332276, 111934.351638136, 
111933.730103048, 111934.056092041, 111933.449662705, 111932.908020631, 
111932.870581986, 111932.607247015), Fr = c("10", "10", "10", 
"10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", 
"10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", 
"10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", 
"10", "10", "10", "10", "10", "10", "10", "11", "11", "11", "11", 
"11", "11", "11", "11", "11", "11", "11", "11", "11", "11", "11", 
"11", "11", "11", "11", "11", "11", "11", "11", "11", "11", "11", 
"11", "11", "11", "11", "11", "11", "11", "12", "12", "12", "12", 
"12", "12", "12", "12", "12", "12", "12", "12", "12", "12", "12", 
"12", "12", "12", "12", "12", "12", "12", "12", "12", "12", "12", 
"12", "12", "12", "12", "12", "12", "12", "12", "12", "12"), 
    Type = c("C", "C", "C", "C", "C", "C", "C", "C", "C", "C", 
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", 
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", 
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", 
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", 
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", 
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", 
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", 
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", 
    "C", "C", "C", "C", "C", "C")), row.names = c(NA, -112L), class = "data.frame")

1
  • 1
    your points are sorted based on the longitude instead of being ordered according to their drawing order (clockwise). Did you try to sort by IDs?
    – radouxju
    Commented Feb 22, 2023 at 16:34

2 Answers 2

2

Split your data frame by the splitting variable, construct a linestring from the lat-long coordinates, cast to polygons to save having to match the first and last coordinates, then string them all together using st_sfc:

p3 = do.call(st_sfc, lapply(split(P, P$Fr), function(d){st_cast(st_linestring(cbind(d$lon, d$lat)),"POLYGON")}))

That gets you a geometry vector. plot(p3):

enter image description here

Then you can use the standard sf functions for constructing a spatial data frame, if that's what you need.

d = st_as_sf(data.frame(Fr=unique(P$Fr), geometry=p3), crs=31370)
ggplot(d) + geom_sf(aes(fill=Fr))

enter image description here

You should probably really get the Fr names from the names of the split object, but I've stuck it inside that one-liner. Maybe:

> splitP = split(P, P$Fr)
> p3 = do.call(st_sfc, lapply(splitP, function(d){st_cast(st_linestring(cbind(d$lon, d$lat)),"POLYGON")}))
> d = st_as_sf(data.frame(Fr=names(splitP), geometry=p3), crs=31370)

Put that all in a function so your `p3 object isn't hanging around.

Note the ID values are dropped because each polygon is a single feature and so values attached to individual points aren't really supported.

1
  • Thanks a lot for this answer! It was exactly what I wanted.
    – C. Guff
    Commented Feb 23, 2023 at 8:59
1

Assuming you just want a single polygon by group, you can lapply concaveman and create the convex hull of the points by group. This is not perfect (see the bottom of the red polygon) but hopefully you find it useful:

P <- structure(list(
  ID = c(
    "13-57-43", "13-58-18", "13-58-49", "13-59-14",
    "13-59-48", "14-00-13", "14-00-40", "14-01-03", "14-01-25", "14-01-52",
    "14-02-13", "14-02-43", "14-03-08", "14-03-39", "14-04-03", "14-04-32",
    "14-05-06", "14-05-41", "14-06-14", "14-06-40", "14-07-03", "14-07-34",
    "14-08-09", "14-08-42", "14-09-10", "14-09-40", "14-10-11", "14-11-02",
    "14-11-26", "14-11-47", "14-12-12", "14-12-34", "14-12-58", "14-13-25",
    "14-13-50", "14-14-28", "14-14-48", "14-15-11", "14-15-39", "14-16-02",
    "14-16-30", "14-16-53", "14-17-28", "14-28-23", "14-28-45", "14-29-09",
    "14-29-31", "14-30-27", "14-31-45", "14-32-11", "14-32-32", "14-32-54",
    "14-33-22", "14-33-45", "14-34-07", "14-34-33", "14-34-57", "14-35-17",
    "14-35-59", "14-36-24", "14-36-42", "14-37-24", "14-38-44", "14-39-09",
    "14-39-30", "14-39-56", "14-40-21", "14-40-43", "14-41-12", "14-41-49",
    "14-42-10", "14-42-37", "14-43-30", "14-43-58", "14-44-29", "14-45-08",
    "14-55-55", "14-56-37", "14-56-54", "14-57-12", "14-57-33", "14-58-20",
    "14-58-42", "14-59-03", "14-59-26", "14-59-50", "15-00-12", "15-00-45",
    "15-01-09", "15-01-30", "15-01-52", "15-02-13", "15-02-53", "15-03-17",
    "15-03-46", "15-04-06", "15-04-27", "15-04-48", "15-05-19", "15-05-42",
    "15-06-03", "15-06-29", "15-06-49", "15-07-11", "15-07-30", "15-07-54",
    "15-08-14", "15-08-34", "15-09-01", "15-09-19", "15-09-47", "15-10-13"
  ), lon = c(
    195905.778820844, 195905.974267758, 195906.521347454,
    195906.899081334, 195907.794221085, 195908.278097475, 195906.749400405,
    195905.530462325, 195904.169532708, 195903.415217152, 195902.583546779,
    195901.705310906, 195900.676225893, 195899.811829397, 195899.105876732,
    195898.496875417, 195897.417855528, 195896.305319914, 195894.789791642,
    195893.792658586, 195892.846626664, 195892.588160285, 195892.653321993,
    195893.352612261, 195893.325522819, 195892.724380256, 195895.024853343,
    195897.346640149, 195897.522357658, 195897.49907462, 195897.236040002,
    195897.483304948, 195898.30751539, 195899.333731338, 195899.575391337,
    195899.568317725, 195899.64883718, 195899.793165198, 195899.696078815,
    195899.772957444, 195899.71964308, 195901.848642919, 195904.020780265,
    195891.806884353, 195890.229643927, 195889.907273078, 195888.918089508,
    195888.469330492, 195888.697240747, 195887.928917165, 195886.736953866,
    195885.973581512, 195885.327462551, 195884.773745579, 195883.787523878,
    195882.808838648, 195881.820022116, 195881.159939463, 195880.535525829,
    195880.22736261, 195880.16798173, 195880.88351761, 195882.179482257,
    195881.58913656, 195882.244999483, 195883.07501506, 195882.431452093,
    195881.986614064, 195881.56612941, 195883.849986501, 195884.85633537,
    195886.271839823, 195887.256976464, 195889.473852909, 195890.964940259,
    195891.764793086, 195880.614164185, 195880.358714986, 195879.807625943,
    195879.063338423, 195878.122326135, 195877.507258557, 195876.493683828,
    195876.054792449, 195875.626907971, 195874.947148117, 195874.569675939,
    195875.073433679, 195875.336685869, 195874.99480784, 195874.243786076,
    195874.030479338, 195873.822854543, 195873.49650797, 195872.808159092,
    195872.126629216, 195871.945624596, 195872.299770002, 195871.828658921,
    195872.189569543, 195872.009561096, 195871.688583655, 195872.936862676,
    195873.688142326, 195874.526086933, 195875.189198156, 195875.987541361,
    195876.451614305, 195876.949504315, 195877.49530275, 195878.860639032,
    195879.976589664
  ), lat = c(
    111925.087000872, 111924.746783252,
    111925.124000667, 111925.657795159, 111926.37396592, 111927.243937231,
    111927.492050366, 111927.580125541, 111927.540078711, 111928.148808956,
    111928.507004102, 111928.958462953, 111928.795704281, 111928.416179694,
    111928.56341283, 111928.766807706, 111928.924355094, 111928.910363058,
    111928.735907397, 111928.555450567, 111927.602310046, 111926.627976733,
    111926.154476976, 111926.535614232, 111925.940498663, 111925.246247372,
    111924.770627489, 111924.617882809, 111925.549537431, 111926.057332371,
    111926.169132436, 111926.810872482, 111926.802022958, 111926.558136608,
    111926.909623143, 111927.053772844, 111926.023246794, 111925.596421076,
    111925.219743649, 111924.848264531, 111924.299745381, 111924.183837869,
    111924.031228296, 111926.499693359, 111926.835912733, 111927.529247485,
    111927.931058974, 111928.262019288, 111929.355476192, 111929.588004993,
    111930.09344381, 111929.968575835, 111930.728207498, 111931.031143297,
    111931.689976808, 111932.506147532, 111932.746288973, 111932.722016854,
    111932.691102536, 111931.953822562, 111931.330709156, 111930.868375568,
    111931.817410667, 111930.581975062, 111931.070356929, 111929.611758211,
    111929.75447942, 111929.79541798, 111929.963250504, 111928.765700747,
    111928.158538985, 111926.958042713, 111927.173583846, 111926.498736853,
    111925.88847469, 111925.428917548, 111933.002101255, 111933.629642985,
    111934.153987348, 111935.017048392, 111935.705555274, 111936.292398511,
    111936.273914415, 111935.606822579, 111935.480749928, 111935.979567816,
    111936.252055673, 111936.397532031, 111936.914787345, 111937.462629294,
    111938.127551995, 111938.18262708, 111939.005547066, 111939.678609986,
    111940.11859558, 111939.925228463, 111939.338239755, 111938.820578336,
    111938.849445301, 111938.448843605, 111938.263539459, 111937.703195091,
    111936.385157215, 111935.722993995, 111934.915332276, 111934.351638136,
    111933.730103048, 111934.056092041, 111933.449662705, 111932.908020631,
    111932.870581986, 111932.607247015
  ), Fr = c(
    "10", "10", "10",
    "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10",
    "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10",
    "10", "10", "10", "10", "10", "10", "10", "10", "10", "10", "10",
    "10", "10", "10", "10", "10", "10", "10", "11", "11", "11", "11",
    "11", "11", "11", "11", "11", "11", "11", "11", "11", "11", "11",
    "11", "11", "11", "11", "11", "11", "11", "11", "11", "11", "11",
    "11", "11", "11", "11", "11", "11", "11", "12", "12", "12", "12",
    "12", "12", "12", "12", "12", "12", "12", "12", "12", "12", "12",
    "12", "12", "12", "12", "12", "12", "12", "12", "12", "12", "12",
    "12", "12", "12", "12", "12", "12", "12", "12", "12", "12"
  ),
  Type = c(
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C",
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C",
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C",
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C",
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C",
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C",
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C",
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C",
    "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "C",
    "C", "C", "C", "C", "C", "C"
  )
), row.names = c(NA, -112L), class = "data.frame")



library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1; sf_use_s2() is TRUE
library(tidyverse)

P <- P %>% st_as_sf(
  coords = c("lon", "lat"),
  crs = 31370
)

ggplot(P) +
  geom_sf(aes(color = Fr))


x <- P$Fr[1]

final_P <- lapply(unique(P$Fr), function(x) {
  group <- P[P$Fr == x, ]

  conc <- concaveman::concaveman(group, length_threshold = 0,
                                 concavity = 0.999999)

  conc$Fr <- x

  conc
}) %>% bind_rows()


ggplot(final_P) +
  geom_sf(aes(fill = Fr)) +
  geom_sf(data = P, fill=NA, shape=21, size=0.7) 

Created on 2023-02-22 with reprex v2.0.2

4
  • You can play with length_threshold, concavity parameters to fine-tuning the results
    – dieghernan
    Commented Feb 22, 2023 at 15:08
  • No need to do this, the points are in the correct order for making a polygon in the data. Something in the OP's pipeline has re-ordered the coordinates. Its the summarize which converts grouped POINT to MULTIPOINT and at that stage the ordering is out of the user's control and sf does whatever it does which appears to be X-ordering but that might not be consistent or documented...
    – Spacedman
    Commented Feb 22, 2023 at 16:14
  • Oops! Didn’t check, thanks @Spacedman
    – dieghernan
    Commented Feb 22, 2023 at 17:09
  • That answer is quite interesting and complete if I want to smooth the shape of the polygons. But for the present case, I want to keep the exact shape of the polygon. Thank you anyway for this nice answer.
    – C. Guff
    Commented Feb 23, 2023 at 8:57

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.