I am a little lost. I have a stars object where I would like to use the first attribute and map it to the scale_fill*-function in ggplot.

I also have an polygon-object of class sf that has an attribute that I would also like to map to the scale_fill*-function.

I really tried to compile some data and a reproducible example and I got this far: It does not make any sense at all, but serves for the purpose:


# get elevation
alt <- getData('alt', country='CHE')
alt_stars = st_as_stars(alt)

ch_canvas = st_bbox(alt_stars) %>% opq()

# overpass query
ch_moto = ch_canvas %>%
  add_osm_feature(key = "highway",
                  value="motorway") %>% 

# get the sf object
df = ch_moto %>% pluck("osm_lines") %>% 
  dplyr::select("maxspeed") %>% 
         maxspeed != "none") %>% 
  mutate(maxspeed = as.numeric(maxspeed))

# make the polygons
df_buffer = st_buffer(df, 0.1)

ggplot() +
    data = alt_stars,
    aes(x=x, y=y, fill = CHE_msk_alt),
    downsample = 2
  ) +
  scale_fill_continuous(low="white", high="red") +
    data = df,
  ) +

I am then getting this message: Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

I would just like to know how to plot any two layers (in many cases a stars-object and a sf-object) on top of each other and fill both according to the values in a variable. I tried to use the cowplot-package and just define two ggplot objects and plot them above each other, but did not manage to make it work. Maybe someone has a pointer on what to do in these situations:)

  • 1
    I think you may want to explore tmap for this
    – dieghernan
    Commented Apr 19, 2021 at 18:26

1 Answer 1


Sounds like you are looking for something like the functionality in the ggnewscale package. In your case, you could use its new_scale_fill() function, like this:


# make the polygons (using a smaller buffer)
df_buffer = st_buffer(df, 0.01)

ggplot() +
    data = alt_stars,
    aes(x = x, y = y, fill = CHE_msk_alt),
    downsample = 2
  ) +
  scale_fill_continuous(low = "white", high = "red") +
  new_scale_fill() + ## geoms added after this will use a new scale definition
    data = df_buffer, 
    col = NA,
    aes(fill = maxspeed)
  ) +
  scale_fill_scico(palette = "berlin")

enter image description here

  • Awesome!! I did not know of that:) Thank you very much!
    – Lenn
    Commented Apr 22, 2021 at 16:22
  • 2
    @Lenn You bet! The package's README does warn that its "very experimental, so use at your own risk", but it has worked fine for me the half dozen or so times I've needed it. I'd be interested to know where it can go wrong. Commented Apr 22, 2021 at 21:10
  • Really great to know about that:)! I think this will come in quite handy many times
    – Lenn
    Commented Apr 23, 2021 at 21:08

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.