Home > Software design >  How to "break" a continuous variable into discrete intervals using only ggplot2 commands
How to "break" a continuous variable into discrete intervals using only ggplot2 commands

Time:09-22

I'm trying to make a graph in ggplot with a geom_sf geometry. I can graph using scale_fill_scontinuous, however I would like to break my caption into discrete intervals, so that instead of using scale_fill_scontinuous, I can use scale_fill_brewer. I wouldn't want to create an intermediate data.frame or a vector outside of ggplot.

Currently my chart looks like this:

ggplot(data=uniao3, aes(fill=`Área Úmida`)) 
  geom_sf() 
  scale_fill_continuous(limits=c(0,20000),
                        breaks=c(500,2000,8000,15000,20000),
                        labels=c('500','200-2k','2k-8k','8k-15k','15k>'),
                        name="Wetland") 
    facet_wrap(~Ano)

out enter image description here

I would like that instead of the legend (scale) to be presented as a gradient, it would be presented as blocks similar to this one:

enter image description here

I know the scale_fill_brewer command does this quite elegantly and efficiently, but how can I set my continuous variable to discrete inside ggplot?

CodePudding user response:

I would go for scale_fill_stepsn, although there are multiple other solutions in the comments. That function takes care of discretizing a continuous variable according to your desired breaks, and it allows to use any colours in the colours vector (not just pre-brewed palettes).

Another advantage is that the breaks and colour vectors do not need to match up in length.

Get an sf object

library(ggplot2)
library(sf)
#> Linking to GEOS 3.8.1, GDAL 3.2.1, PROJ 7.2.1

# get sf data
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)

Use scale_fill_stepsn

This is probably the easiest and most adequate way for continuous data which is cut into discrete slices.

# set breaks and colours
breaks <- seq(0, 0.3, by = 0.02)
breaks
#>  [1] 0.00 0.02 0.04 0.06 0.08 0.10 0.12 0.14 0.16 0.18 0.20 0.22 0.24 0.26 0.28
#> [16] 0.30

cols <- RColorBrewer::brewer.pal(9, "Spectral")
cols
#> [1] "#D53E4F" "#F46D43" "#FDAE61" "#FEE08B" "#FFFFBF" "#E6F598" "#ABDDA4"
#> [8] "#66C2A5" "#3288BD"

# plot
ggplot(data = nc, aes(fill = AREA))  
  geom_sf()  
  scale_fill_stepsn(colours = cols,
                    breaks = breaks,
                    name = "area")  
  theme_minimal()

Note that I assigned the breaks and cols outside of the ggplot call for clarity, but you can of course specify them directly in the ggplot call.

Use scale_fill_brewer

This is more adequate for real discrete data, but also works for discretized continuous data.

Here, you need to do the cutting yourself, before setting the scale. Using cut with specified breaks in your ggplot2 call will turn your numeric variable into a factor.

It is a bit less flexible regarding the choice of colours using scale_fill_brewer, because you need (?) to use an existing RColorBrewer colour palette.

This way, the colour legend looks more similar to your example legend, where each cut is labelled, rather than the break points.

# plot
ggplot(data = nc, aes(fill = cut(AREA, breaks = seq(0, 0.3, by = 0.02))))  
  geom_sf()  
  scale_fill_brewer(type = "qual",
                    # labels = labels, # if you must
                    palette = "Spectral",
                    name = "area")  
  theme_minimal()

Created on 2021-09-19 by the reprex package (v2.0.1)

  • Related