rggplot2geom-sf

geom_sf color multipolygons


I have multiplygon data read from a geojson file

geojson <- read_sf (filename)

Data looks like that:

Simple feature collection with 4 features and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -16.64523 ymin: 27.23105 xmax: 39.81916 ymax: 65.99652
Geodetic CRS:  WGS 84
# A tibble: 4 × 2
  id                                                                    geometry
  <chr>                                                       <MULTIPOLYGON [°]>
1 Coverage           (((-7.599085 33.35191, -7.813386 33.43519, -7.728468 33.51…
2 HighInterference   (((30.60789 42.13764, 30.638 42.22092, 30.75046 42.22092, …
3 LowInterference    (((24.75786 59.54255, 24.80001 59.62583, 24.96471 59.62583…
4 MediumInterference (((26.36263 58.87633, 26.40755 58.95961, 26.56905 58.95961…

Then I use geom_sf to show each row of data with its color:

library ("ggplot2")
library ("sf")
library ("rnaturalearth")
library ("rnaturalearthdata")
library ("ggspatial")
library ("geojsonR")

europe <- ne_countries (scale = "medium", returnclass = "sf")
class (europe)

filename <- "geojson.geojson"

geojson <- read_sf (filename)

p <- ggplot () + geom_sf (data = europe)
p <- p + geom_sf (data = geojson[geojson$id == "Coverage", ], color = alpha ("green", 0.1), fill = alpha ("green", 0.1))
p <- p + geom_sf (data = geojson[geojson$id == "LowInterference", ], color = alpha ("yellow", 0.5), fill = alpha ("yellow", 0.5))
p <- p + geom_sf (data = geojson[geojson$id == "MediumInterference", ], color = alpha ("orange", 0.5), fill = alpha ("orange", 0.5))
p <- p + geom_sf (data = geojson[geojson$id == "HighInterference", ], color = alpha ("red", 0.5), fill = alpha ("red", 0.5))
p <- p + coord_sf (xlim = c(-20, 42), ylim = c(33, 72))
plot (p)

ggsave (paste (filename, ".pdf", sep = ""))
ggsave (paste (filename, ".png", sep = ""))

I have a feeling that is way to show a legend. There are not always all layers present in the file. The example shown has all, but any one or more might be missing. The legend can always have all possible values. I have a feeling it can be done, but I have no idea how.


Here is a geojson example:

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {

            },
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [
                                0,
                                40
                            ],
                            [
                                10,
                                50
                            ],
                            [
                                0,
                                60
                            ],
                            [
                                -10,
                                55
                            ],
                            [
                                0,
                                40
                            ]
                        ]
                    ]
                ]
            },
            "id": "Coverage"
        },
        {
            "type": "Feature",
            "properties": {

            },
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [
                                20,
                                45
                            ],
                            [
                                25,
                                50
                            ],
                            [
                                20,
                                60
                            ],
                            [
                                0,
                                50
                            ],
                            [
                                20,
                                45
                            ]
                        ]
                    ]
                ]
            },
            "id": "HighInterference"
        },
        {
            "type": "Feature",
            "properties": {

            },
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [
                                10,
                                35
                            ],
                            [
                                20,
                                35
                            ],
                            [
                                20,
                                40
                            ],
                            [
                                10,
                                40
                            ],
                            [
                                10,
                                35
                            ]
                        ]
                    ]
                ]
            },
            "id": "LowInterference"
        },
        {
            "type": "Feature",
            "properties": {

            },
            "geometry": {
                "type": "MultiPolygon",
                "coordinates": [
                    [
                        [
                            [
                                30,
                                50
                            ],
                            [
                                40,
                                50
                            ],
                            [
                                40,
                                60
                            ],
                            [
                                30,
                                60
                            ],
                            [
                                30,
                                50
                            ]
                        ]
                    ]
                ]
            },
            "id": "MediumInterference"
        }
    ]
}

Edit: Now, the whole R source is included. The sample is now fully reproducible with R source and geojson content.


Solution

  • You could set fill and colour in the aesthetics and apply manual fill/color scales like so:

    europe <- ne_countries (scale = "medium", returnclass = "sf",
                            continent = 'Europe' ## filter for Europe
                            )
    geojson <- read_sf('geojson.geojson')
    
    
    color_mapping <- c(
      Coverage = alpha ("green", 0.1),
      LowInterference = alpha ("yellow", 0.5),
      MediumInterference = alpha ("orange", 0.5),
      HighInterference = alpha ("red", 0.5)
    )
    
    ## make the id column a factor, so legend entries are displayed
    ## even w/o any observation in this category (`drop = FALSE`)
    geojson$id <-factor(geojson$id, levels = names(color_mapping))
    
    ggplot() +
      geom_sf(data = europe) +
      geom_sf(data = geojson, aes(fill = id, color = id)) +
      scale_fill_manual(values = color_mapping,
                        drop = FALSE, ## display legend entry even w/o observations
                        ) + 
      scale_color_manual(values = color_mapping, drop = FALSE)
    
    

    Note: scale_..._manual also takes an argument na.value to set a fill/color for NAs.

    set fill and color in geom_sf