2

enter image description here

I am facing a problem with R, ggplot2. I used facet to indicate feature "gear" of my data, then for the y-axis feature, I'd like to use 2 types of legends. But my codes only shows the legend for one type(layer 1) data. * I want data2 to use colourful round dots, data1 use black * (shape=4). Please help. Thank you.

data1 <- subset(mtcars, carb==4)
data2 <- subset(mtcars, !carb==4)
ggplot(mapping = aes(x = mpg, y = wt, color= carb)) + 
  geom_point(data=data2, mapping = aes(x = mpg, y = wt, color= carb), size=0.2) + 
  facet_wrap(~ gear, nrow = 1) +
  labs(y='wt value', x= "mpg type") + 
  geom_point(data=data1, color = "black", shape=4, size=0.7, mapping=aes(x = mpg, y = wt, color= carb)) +
  facet_wrap(~ gear, nrow = 1) 
tjebo
  • 21,977
  • 7
  • 58
  • 94
Beryl
  • 39
  • 5

2 Answers2

2

There needs some little changes to be made. You can not use 2 facets like this. Have look to the following code. You can make carb a factor in data2 which will give you the colored points and legend. If that is what you are looking for, you will find the differences in the above mentioned points. PS: I have enlarged the point size a bit.

library(ggplot2)
data <- mtcars 
data1 <- subset(data, carb==4)
data2 <- subset(data, !carb==4)
ggplot(mapping = aes(x = mpg, y = wt, color= carb)) + 
  geom_point(data=data2, mapping = aes(x = mpg, y = wt, color= factor(carb)), size=4) + 
  geom_point(data=data1, mapping=aes(x = mpg, y = wt), shape =4, size=8, color= 'black') +
  facet_wrap(~ gear, nrow = 1) +
  theme_bw() +
  labs(y='wt value', x= "mpg type") 

Created on 2020-02-03 by the reprex package (v0.3.0)


library(ggplot2)
data <- mtcars 
data1 <- subset(data, carb==4)
data2 <- subset(data, !carb==4)
ggplot(mapping = aes(x = mpg, y = wt, color= carb)) + 
  geom_point(data=data2, mapping = aes(x = mpg, y = wt, color= factor(carb)), size=4) + 
  geom_point(data=data1, mapping=aes(x = mpg, y = wt, shape = factor(carb)),  size=8, color= 'black') +
  scale_shape_manual(values = c(4))+
  facet_wrap(~ gear, nrow = 1) +
  labs(shape = '')+
  #scale_color_discrete(guide = FALSE)+
  theme_bw() +
  labs(y='wt value', x= "mpg type") 

Created on 2020-02-03 by the reprex package (v0.3.0)

I brought the shape back into the aesthetics of data1 but then switched off the title of this by labs(shape = '') . By adding scale_shape_manual(values = c(4)) the shape is defined. Because I was not sure, if you want the first legend or not I have put #scale_color_discrete(guide = FALSE) into the code, but commented it. You may remove the commenting and will get rid of the first legend completely.

MarBlo
  • 4,195
  • 1
  • 13
  • 27
  • Hi Marblo, thank you for your reply. Usually the colorful points won't be the problem, they were generated by default. My problem was in the legend part, the other layer won't show up. I wish there is "X 4" after the current legend. – Beryl Feb 03 '20 at 18:00
  • @Quan Cui, OK understand. I have edited the original post, see below the horizontal line. – MarBlo Feb 03 '20 at 18:42
  • I would recommend against using `labs(shape = '')` because ggplot will actually draw something here. Use `shape = NULL` instead. Also you don't need to call `labs` twice;) – tjebo Feb 03 '20 at 20:00
1

Legends are only created for variables that appear in aes. So you need to add shape to it. There are many different ways how to change your color for a variable that fulfils one condition, and the probably easiest is what you have done, to plot different subsets. If you decide so, best practice is not to use aes within the main call, because it can mess up your plot quite a bit.

I have used a conditional statement for your shape and format the shape with scale_shape. I personally find the added difference in color unnecessary for the plot, and I would probably not have done so, but because you have asked for it - here we go.

I also transformed carb to characters - you can also transform it to a factor. Because it is a categorical variable, it makes sense to also show it as such.

edit as per comment

As usual, there are plenty of ways of achieving things. Below two different ways of changing/ removing the titles of the legends and only showing the shape and value for 4. Comments in the code.

Option 1: remove shape from the subset without '4', change legend title e.g. using labs.

library(ggplot2)

ggplot() + 
  geom_point(data = subset(mtcars, carb !=4), aes(x = mpg, y = wt, color = as.character(carb)), shape = 1) +
  geom_point(data = subset(mtcars, carb ==4), aes(x = mpg, y = wt, shape = carb  == 4), color = 'black')+
  scale_shape_manual(values = c(`TRUE` = 4, `FALSE` = 1)) +
  labs(shape = NULL, color = 'Model prediction') +
  guides(color = guide_legend(order = 1), shape = guide_legend(order = 2)) +
## I had to change the legend order, because the shape legend would draw on top otherwise. See link below! 
  facet_wrap(~ gear, nrow = 1)

Now - the legends are a bit separated, and believe me, it's quite tricky to bring them closer together.

Therefore:

option 2 Factorise your categorical data, subset your data, use drop = FALSE in the scale_color function, and change the legend aesthetic with override.aes. Sounds like a hack, but still easier and safer than trying to reduce the distance between two legends.

mtcars2 <- mtcars
mtcars2$carb2 <- factor(mtcars$carb, levels = c(1:3,6,8,4))

ggplot() + 
  geom_point(data = subset(mtcars2, carb != 4), aes(x = mpg, y = wt, color= carb2), shape = 1) +
  geom_point(data = subset(mtcars, carb == 4), aes(x = mpg, y = wt), shape = 4, color = 'black') +
  facet_wrap(~ gear, nrow = 1) +
  scale_color_discrete(drop = FALSE) +
  labs(color = 'Model prediction') +
  guides(color = guide_legend(override.aes = list(shape = c(rep(1, 5), 4),
                                                  color = c(RColorBrewer::brewer.pal(5, 'Dark2'), 'black'))))

Created on 2020-02-03 by the reprex package (v0.3.0)

Some links to learn from

Legend order is weird

change shapes in legend

tjebo
  • 21,977
  • 7
  • 58
  • 94
  • Hi Tjebo, thank you. This way works for me. But how can I change the text in the legend part? I'd like 1) "as.character(carb)" change into "Model prediction", 2) don't show "carb==4", and "o FALSE", for the second part in legend, only show"x 4" . Thank you. – Beryl Feb 03 '20 at 17:54
  • Thank you so much. – Beryl Feb 04 '20 at 16:27