Legend units for geom_point size - r

I have used geom_point in ggplot2 to display values as the area of each point:
geom_point(aes(size = sqrt(z/pi))
However, the legend units are the transformed values, is it possible to have the legend display the original values alongside their respective bubble size?
Edit: sorry I should have provided more information to begin with
library(ggplot2)
data <- data.frame(x = sample(1:10), y = sample(1:10), z = sample(1:10), colour = c("red", "yellow", "green","pink","black","brown","grey","white","purple","beige"))
ggplot(data, aes(x = x, y = y)) + geom_point(aes(size = sqrt(z/pi)), pch = 21) + aes(fill = colour) + scale_fill_brewer(palette = "set1")

Try adding:
+scale_colour_manual(guide = guide_legend(override.aes=aes(size=values)))

Related

ggplot2 fill legend does not display the correct "fill" color

I am confused of this problem for a long time. A simple data frame is constructed as follows
data <- data.frame(
x = 1:5,
y = 5:1,
fill = c(rep("pink", 3), rep("blue", 2)),
shape = c(rep(21, 3), rep(22, 2))
)
Suppose I wand to show the legend of the fill
uniFill <- unique(data$fill)
p <- ggplot(data,
mapping = aes(x = x,
y = y,
fill = fill)) +
geom_point(shape = data$shape) +
# show legend so that I do not call `scale_fill_identity()`
scale_fill_manual(values = uniFill,
labels = uniFill,
breaks = uniFill)
p
The graphics are OK, however, the legend is not correct
I guess, maybe different shapes (21 to 25) cannot be merged? Then, I partition the data into two subsets where the first set has shape 21 and the second has shape 22.
data1 <- data[1:3, ]
data2 <- data[4:5, ]
# > data1$shape
# [1] 21 21 21
# > data2$shape
# [1] 22 22
ggplot(mapping = aes(x = x,
y = y,
fill = fill)) +
geom_point(data = data1, shape = data1$shape) +
geom_point(data = data2, shape = data2$shape) +
scale_fill_manual(values = uniFill,
labels = uniFill,
breaks = uniFill)
Unfortunately, the legend does not change. Then, I changed the shape from a vector to a scalar, as in
ggplot(mapping = aes(x = x,
y = y,
fill = fill)) +
geom_point(data = data1, shape = 21) +
geom_point(data = data2, shape = 22) +
scale_fill_manual(values = uniFill,
labels = uniFill,
breaks = uniFill)
The legend of the fill color is correct finally...
So what happens here? Is it a bug? Is it possible to just add a single layer but with different shapes (21 to 25)?
A possible solution is that one can add component guides(), as in
p +
guides(fill = guide_legend(override.aes = list(fill = uniFill,
shape = 21)))
But I am more interested in why p does not work (legend)
The main reason your legend is not working in your first example is because you did not put your shape in the aesthetics.
I have a couple other suggestions: Do not define colors in your data frame; instead define a column to change the aesthetics using a code. Then define your fill and shape values explicitly. Each of the scales needs to have the same name - in this case "Legend."
Give this edit a try.
data <- data.frame(
x = 1:5,
y = 5:1,
fill = c(rep("p", 3), rep("b", 2))
)
uniFill <- c("p"="pink", "b"="blue")
uniShape <- c("p" = 21, "b" = 22)
p <- ggplot(data,
mapping = aes(x = x,
y = y,
fill = fill,
shape = fill)) +
geom_point() +
# show legend so that I do not call `scale_fill_identity()`
scale_fill_manual("Legend",values = uniFill,
labels = uniFill)+
scale_shape_manual("Legend",values = uniShape,
labels = uniFill)
p
(edit) If your fill and shape aesthetics do not match up, I don't see any other way than to use guides and two legends. Notice that if your attribute column is descriptive, you do not need to set the labels and your code will be cleaner (see shape vs fill aesthetics).
data <- data.frame(
x = 1:5,
y = 5:1,
fill = c(rep("p", 3), rep("b", 2)),
shape = c(rep("circles", 2), rep("squares", 3))
)
uniFill <- c("p"="pink", "b"="blue")
uniShape <- c("circles" = 21, "squares" = 22)
p <- ggplot(data,
mapping = aes(x = x,
y = y,
fill = fill,
shape = shape)) +
geom_point() +
# show legend so that I do not call `scale_fill_identity()`
scale_fill_manual("Legend fill",values = uniFill,
labels = uniFill)+
scale_shape_manual("Legend shape",values = uniShape )+
guides(fill = guide_legend("Legend fill", override.aes = list(shape = 21)))
p

overlay 2 point graphs on box plot in R

I'm having some issue overlaying 2 point graphs on a box plot. The code seems to work well when i added only one point graph. Here is the code below:
ggplot(data1, aes(x= reorder(DMU,order), y = Efficiency)) +
geom_boxplot() +
geom_point(data = data2, aes(x = dmu, y = eff, color = "eff")) +
scale_color_manual("", breaks = c("eff"), values = c("blue")) +
geom_point(data = data3, aes(x = DMU, y = eff2, color = "eff2")) +
scale_color_manual("", breaks = c("eff2"), values = c("red"))
I keep getting the error below:
Scale for 'colour' is already present. Adding another scale for
'colour', which will replace the existing scale.
Error: Insufficient values in manual scale. 2 needed but only 1 provided.
You cannot add scale_color_manual() twice.
Build a single dataframe for the colon:
df_points <- data.frame(x = c(data2$dmu, data3$DMU),
y = c(data2$eff, data3$eff2),
data = c("data2", "data3")
)
And then:
ggplot(data1, aes(x = reorder(DMU,order), y = Efficiency)) +
geom_boxplot() +
geom_point(data = df_points, aes(x = x, y = y, color = data)) +
scale_colour_manual(values = c("red", "blue") +
theme(legend.position = "none")
Not having the data available I could have made a mistake

How to add line to point shapes in ggplot2 legend

I want to create a black and white plot using ggplot2, where the data is plotted by category using a combination of lines and points. However, the legend only shows the point shape, with no line running through it, unless I add color to the plot.
Here is some example data to illustrate the problem with:
## Create example data
set.seed(123)
dat <- data.frame(
time_period = rep(1:4, each = 3),
category = rep(LETTERS[1:3], 4),
y = rnorm(12)
)
Here is an example of a color plot, so you can see how I want the legend to look:
library(ggplot2)
## Generate plot with color
ggplot(data = dat, mapping = aes(x = time_period, y = y, color = category)) +
geom_line(aes(group = category)) +
geom_point(aes(shape = category), size = 2) +
theme_bw()
However, if I move to grayscale (which I need to be able to do), the line running through the point in the legend disappears, which I'd like to avoid:
## Generate plot without color
ggplot(data = dat, mapping = aes(x = time_period, y = y)) +
geom_line(aes(group = category)) +
geom_point(aes(shape = category), size = 2) +
theme_bw()
How can I add a line through the point symbols in the legend with a grayscale plot?
I would suggest this approach:
#Plot
ggplot(data = dat, mapping = aes(x = time_period, y = y,group = category,shape = category)) +
geom_line(color='gray',show.legend = T) +
geom_point(size = 2) +
theme_bw()
Output:

Set the legend of a ggplotly() plot to have only the color and not the shape index

I have the dataframe below:
etf_id<-c("a","b","c","d","e","a","b","c","d","e","a","b","c","d","e")
factor<-c("A","A","A","A","A","B","B","B","B","B","C","C","C","C","C")
normalized<-c(-0.048436801,2.850578601,1.551666490,0.928625186,-0.638111793,
-0.540615895,-0.501691539,-1.099239823,-0.040736139,-0.192048665,
0.198915407,-0.092525810,0.214317734,0.550478998,0.024613778)
df<-data.frame(etf_id,factor,normalized)
and I create a ggplotly() boxplot with:
library(ggplot2)
library(plotly)
ggplotly(ggplot(data = df, aes(x = factor, y = normalized)) +
geom_boxplot(aes(fill = as.factor(factor)),outlier.colour = 'black') +
geom_point(data = df, position = position_dodge(0.75))+geom_point(data = df,
aes(x = factor, y = normalized, shape = etf_id, color = etf_id),
size = 2))
I take as a result a boxplot with this legend:
but I want my legend to have only the color distinction like below. Note that the factors wont be 3 every time but may vary from 1 to 8.
The recommended way to alter plotly elements is to use the style() function. You can identify the elements and traces by inspecting plotly_json().
I'm not sure if there's a more compact way, but you can achieve the desired result using:
p <- ggplotly(ggplot(data = df, aes(x = factor, y = normalized)) +
geom_boxplot(aes(fill = as.factor(factor)),outlier.colour = 'black') +
geom_point(data = df, position = position_dodge(0.75))+geom_point(data = df,
aes(x = factor, y = normalized, shape = etf_id, color = etf_id),
size = 2))
p <- style(p, showlegend = FALSE, traces = 5:9)
for (i in seq_along(levels(df$factor))) {
p <- style(p, name = levels(df$factor)[i], traces = i)
}
p
Note that in this case the factor levels and traces align but that won't always be the case so you may need to adjust this (i.e. i + x).
One quick way would be to add show.legend = FALSE to supress the legend from showing.
library(ggplot2)
ggplot(data = df, aes(x = factor, y = normalized)) +
geom_boxplot(aes(fill = as.factor(factor)),outlier.colour = 'black') +
geom_point(position = position_dodge(0.75)) +
geom_point(aes(x = factor, y = normalized, shape = etf_id, color = etf_id),
size = 2, show.legend=FALSE)
Unfortunately, this does not work when this is passed to ggplotly. You can use theme(legend.position='none') which works but suppresses all the legends instead of specific ones. One dirty hack is to disable specific legend manually
temp_plot <- ggplotly(ggplot(data = df, aes(x = factor, y = normalized)) +
geom_boxplot(aes(fill = as.factor(factor)),outlier.colour = 'black') +
geom_point(position = position_dodge(0.75)) +
geom_point(aes(x = factor, y = normalized, shape = etf_id, color = etf_id),size = 2))
temp_plot[[1]][[1]][4:9] <- lapply(temp_plot[[1]][[1]][4:9], function(x) {x$showlegend <- FALSE;x})
temp_plot

Have separate legends for a set of point-line plots, and a vertical line plot

Example data frame (if there's a better/more idiomatic way to do this, let me know):
n <- 10
group <- rep(c("A","B","C"),each = n)
x <- rep(seq(0,1,length = n),3)
y <- ifelse(group == "A",1+x,ifelse(group == "B",2+2*x,3+3*x))
df <- data.frame(group,x,y)
xd <- 0.5
des <- data.frame(xd)
I want to plot create point-line plots for the data in df, add a vertical curve at the x location indicated by xd, and get readable legends for both. I tried the following:
p <- ggplot(data = df, aes(x = x, y = y, color = group)) + geom_point() + geom_line(aes(linetype=group))
p <- p + geom_vline(data = des, aes(xintercept = xd), color = "blue")
p
Not quite what I had in mind, there's no legend for the vertical line.
A small modification (I don't understand why geom_vline is one of the few geometries with a show.legend parameter, which moreover defaults to FALSE!):
p <- ggplot(data = df, aes(x = x, y = y, color = group)) + geom_point() + geom_line(aes(linetype=group))
p <- p + geom_vline(data = des, aes(xintercept = xd), color = "blue", show.legend = TRUE)
p
At least now the vertical bar is showing in the legend, but I don't want it to go in the same "category" (?) as group. I would like another legend entry, titled Design, and containing only the vertical line. How can I achieve this?
A possible approach is to add an extra dummy aesthetic like fill =, which we'll subsequently use to create the second legend in combination with scale_fill_manual() :
ggplot(data = df, aes(x = x, y = y, color = group)) +
geom_point() +
geom_line(aes(linetype=group), show.legend = TRUE) +
geom_vline(data = des,
aes(xintercept = xd, fill = "Vertical Line"), # add dummy fill
colour = "blue") +
scale_fill_manual(values = 1, "Design", # customize second legend
guide = guide_legend(override.aes = list(colour = c("blue"))))

Resources