I am trying to change my the labels in plot's legend to say "yearling" and "adult" not "1" and "-1". I first run this code to make this plot:
cols <- c("dodgerblue", "goldenrod") #designate colors
density_age_plot <- plot_model(density_model, type = "pred",
terms = c("density_std", "ageclass_std"),
color = cols, show.data = TRUE, jitter = 0.1,
axis.title = c("Density", "Proportional Mass Gain"),
title = "Density*Age Class", alpha = 0) +
theme_classic() +
labs(color = "Age Class") +
theme(legend.position = c(0.8, 0.9)) +
theme(plot.title = element_text(hjust = 0.5))
This is the graph it makes
I then try density_age_plot + scale_color_discrete(labels = c("yearling", "adult")) but I get this error:
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
Error: Continuous value supplied to discrete scale
Can anyone help me? ggplot2 is NOT my thing! Thanks!
OP, you can probably use scale_color_manual(). Here's a reprex, since I don't have your data. You pass a vector to the values= argument to control the color and a vector to the labels= argument to control the labelling. If you supply a named vector, you can explicitly specify which value (color) or label is associated with each factor. Otherwise, it will default to either the levels of the factor or order your items alphanumerically.
df <- data.frame(x=1:10, y=1:10, category = rep(c(1,-1), 5))
ggplot(df, aes(x,y,color=factor(category))) + geom_point() +
scale_color_manual(
values=c('1'='blue','-1'='red'),
labels=c('1'="positive",'-1'="negative"))
Note that if you have numbers as factor levels, you would have to refer to them with the backtick syntax (since names cannot be numbers), but if it is a factor, quotes work fine.
Without scale_color_manual(), it looks like this:
Related
I'm creating a stacked bar plot of relative abundance data, but I only want to display selected few interesting taxa in the legend. I have tried using scale_fill_manual(values = sample(col_vector), breaks = legend_list). The result only shows selected legend in my legend_list as I wish, but all other factors shows no color. How do I show all the colors as stacked bar plot, but only show legend for factors in legend_list?
My code:
ggplot(df, aes_string(x = x, y = y, fill = fill)) +
geom_bar(stat="identity", position="stack") +
scale_fill_manual(values = sample(col_vector),
breaks = legend_list) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
The reason for your issue is most likely that you are using an unnamed vector of colors. Under the hood, when you pass a vector to the breaks argument this vector is used as names for the color vector passed to the values argument. However, when the number of breaks is smaller than the number of colors only some colors get named while the names for all other colors are set to NA. As a consequence only the categories specified via the breaks argument are assigned a fill color while all other categories are assigned the na.value which by default is "grey50".
As your provided no minimal reproducible example I use a basic example based on the ggplot2::mpg dataset to first try to reproduce you issue before offering a fix:
library(ggplot2)
library(dplyr)
base <- ggplot(mpg, aes(class, fill = manufacturer)) +
geom_bar()
legend_list <- c("audi", "volkswagen")
col_vector <- scales::hue_pal()(n_distinct(mpg$manufacturer))
base + scale_fill_manual(values = sample(col_vector), breaks = legend_list)
One option to fix the issue is to use a named vector of colors. Doing so all categories are assigned a color but only the categories specified via the breaks argument will show up in the legend:
names(col_vector) <- sample(unique(mpg$manufacturer))
base + scale_fill_manual(values = col_vector, breaks = legend_list)
I am trying to overlay a bar graph (primary axis) and line (secondary axis), but I keep getting an error that I don't understand how to fix. I have tried to follow multiple examples from other questions, but I'm still not getting the result I need.
Here's my code:
ggplot(data = MRIP, aes(x = Length_mm)) +
geom_bar(aes(y = Perc.of.Fish), stat="identity", width = 10, fill = "black") +
geom_line(aes(y = Landings), stat = "identity", size = 2, color = "red") +
scale_y_continuous(name = "Percentage", sec.axis = sec_axis (~./Landings, name = "Landings"))
How do I fix this error: "Error in f(...) : object 'Landings' not found"?
Try this:
coef <- 4000
MRIP %>%
mutate(LandingsPlot=Landings/coef) %>%
ggplot(aes(x = Length_mm)) +
geom_col(aes(y = Perc.of.Fish), width = 10, fill = "black") +
geom_line(aes(y = LandingsPlot), size = 2, color = "red") +
scale_y_continuous(
name = "Percentage",
sec.axis = sec_axis (trans= ~.*coef, name = "Landings")
)
Giving
Why does this work? The scale factor used to define the secondary axis cannot be part of the input data.frame - because if it were, it could potentially vary across rows (as it does here). That would mean you had a separate scale for each row of the input data.frame. That doesn't make sense. So, you scale the secondary variable to take a similar range to that of the primary variable. I chose coef <- 4000 by eye. The exact value doesn't matter, so long as it's sensible.
Having divided by the scale factor to obtain the plotted values, you need to multiply by the scale factor in the transformation in order to get the correct labels on the secondary axis.
Thank you for providing a good MWE. But next time, for extra marks, please post the results of dput() in your question rather than in the comments...
Update
To answer OP's follow up question in the comments: legends are linked to aesthetics. So to get a legend, move the attribute that you want to label inside aes(). You can then define and customise the legend using the appropriate scale_<aesthetic>_<type>. However it's worth noting that if you write, say, aes(colour="black") then "black" is just a character string. It doesn't define a colour. (Using the standard defaults, it will in fact appear as a slightly pinkish red, labelled "black"!) This can be confusing, so it might be a good idea to use arbitrary strings like "a", "b" and "c" (or "Landings" and "Percentage") in the aesthetics. Anyway...
coef <- 4000
#Note fill and color have moved inside aes()
MRIP %>%
mutate(LandingsPlot=Landings/coef) %>%
ggplot(aes(x = Length_mm)) +
geom_col(aes(y = Perc.of.Fish, fill = "black"), width = 10,) +
geom_line(aes(y = LandingsPlot, color = "red"), size = 2) +
scale_y_continuous(
name = "Percentage",
sec.axis = sec_axis (trans= ~.*coef, name = "Landings")
) +
scale_color_manual(values=c("red"), labels=c("Landings"), name=" ") +
scale_fill_manual(values=c("black"), labels=c("Percentage"), name=" ")
Gives
So I'm using ggplot2 to plot both a bar graph and points. I'm currently getting this:
As you can see the bars are nicely separated and colored in the desired colors. However my points are all uncolored and stacked ontop of eachother. I would like the points to be above their designated bar and in the same color.
#Add bars
A <- A + geom_col(aes(y = w1, fill = factor(Species1)),
position = position_dodge(preserve = 'single'))
#Add colors
A <- A + scale_fill_manual(values = c("A. pelagicus"= "skyblue1","A. superciliosus"="dodgerblue","A. vulpinus"="midnightblue","Alopias sp."="black"))
#Add points
A <- A + geom_point(aes(y = f1/2.5),
shape= 24,
size = 3,
fill = factor(Species1),
position = position_dodge(preserve = 'single'))
#change x and y axis range
A <- A + scale_x_continuous(breaks = c(2000:2020), limits = c(2016,2019))
A <- A + expand_limits(y=c(0,150))
# now adding the secondary axis, following the example in the help file ?scale_y_continuous
# and, very important, reverting the above transformation
A <- A + scale_y_continuous(sec.axis = sec_axis(~.*2.5, name = " "))
# modifying axis and title
A <- A + labs(y = " ",
x = " ")
A <- A + theme(plot.title = element_text(size = rel(4)))
A <- A + theme(axis.text.x = element_text(face="bold", size=14, angle=45),
axis.text.y = element_text(face="bold", size=14))
#A <- A + theme(legend.title = element_blank(),legend.position = "none")
#Print plot
A
When I run this code I get the following error:
Error: Unknown colour name: A. pelagicus
In addition: Warning messages:
1: Width not defined. Set with position_dodge(width = ?)
2: In max(table(panel$xmin)) : no non-missing arguments to max; returning -Inf
I've tried a couple of things but I can't figure out it does work for geom_col and not for geom_points.
Thanks in advance
The two basic problems you have are dealing with your color error and not dodging, and they can be solved by formatting your scale_...(values= argument using a list instead of a vector, and applying the group= aesthetic, respectively.
You'll see the answer to these two question using an example:
# dummy dataset
year <- c(rep(2017, 4), rep(2018, 4))
species <- rep(c('things', 'things1', 'wee beasties', 'ew'), 2)
values <- c(10, 5, 5, 4, 60, 10, 25, 7)
pt.value <- c(8, 7, 10, 2, 43, 12, 20, 10)
df <-data.frame(year, species, values, pt.value)
I made the "values" set for my column heights and I wanted to use a different y aesthetic for points for illustrative purposes, called "pt.value". Otherwise, the data setup is similar to your own. Note that df$year will be set as numeric, so it's best to change that into either Date format (kinda more trouble than it's worth here), or just as a factor, since "2017.5" isn't gonna make too much sense here :). The point is, I need "year" to be discrete, not continuous.
Solve the color error
For the plot, I'll try to create it similar to you. Here note that in the scale_fill_manual object, you have to set the values= argument using a list. In your example code, you are using a vector (c()) to specify the colors and naming. If you have name1=color1, name2=color2,..., this represents a list structure.
ggplot(df, aes(x=as.factor(year), y=values)) +
geom_col(aes(fill=species), position=position_dodge(width=0.62), width=0.6) +
scale_fill_manual(values=
list('ew' = 'skyblue1', 'things' = 'dodgerblue',
'things1'='midnightblue', 'wee beasties' = 'gray')) +
geom_point(aes(y=pt.value), shape=24, position=position_dodge(width=0.62)) +
theme_bw() + labs(x='Year')
So the colors are applied correctly and my axis is discrete, and the y values of the points are mapped to pt.value like I wanted, but why don't the points dodge?!
Solve the dodging issue
Dodging is a funny thing in ggplot2. The best reasoning here I can give you is that for columns and barplots, dodging is sort of "built-in" to the geom, since the default position is "stack" and "dodge" represents an alternative method to draw the geom. For points, text, labels, and others, the default position is "identity" and you have to be more explicit in how they are going to dodge or they just don't dodge at all.
Basically, we need to let the points know what they are dodging based on. Is it "species"? With geom_col, it's assumed to be, but with geom_point, you need to specify. We do that by using a group= aesthetic, which let's the geom_point know what to use as criteria for dodging. When you add that, it works!
ggplot(df, aes(x=as.factor(year), y=values, group=species)) +
geom_col(aes(fill=species), position=position_dodge(width=0.62), width=0.6) +
scale_fill_manual(values=
list('ew' = 'skyblue1', 'things' = 'dodgerblue',
'things1'='midnightblue', 'wee beasties' = 'gray')) +
geom_point(aes(y=pt.value), shape=24, position=position_dodge(width=0.62)) +
theme_bw() + labs(x='Year')
I am relatively new to R and I have some difficulties with ggplot2. I have a data frame consisting of three variables (alpha, beta, gamma) and I want to plot them together. I get the plot but I have two problems:
legend is outside the plot and I want it to be inside
linetypes are changed to "solid", "dashed" and "dotted"!
Any ideas/suggestions would be more than welcome!
p <- ggplot() +
geom_line(data=my.data,aes(x = time, y = alpha,linetype = 'dashed')) +
geom_line(data=my.data,aes(x = time, y = beta, linetype = 'dotdash')) +
geom_line(data=my.data,aes(x = time, y = gamma,linetype = 'twodash')) +
scale_linetype_discrete(name = "", labels = c("alpha", "beta", "gamma"))+
theme_bw()+
xlab('time (years)')+
ylab('Mean optimal paths')
print(p)
What you are after is easier to achieve if you first rearrange your data to long format, with one observation per row.
You can do this with tidyr's gather function. Then you can simply map the linetype to the variable in your data.
In your original approach, you tried to assign a literal 'linetype' by using aes(), but ggplot interprets this as you saying, 'assign a line type here as if the variable that is mapped to linetype had the value dashed/dotdash/twodash'. When drawing the plot, it looks up the linetypes in the default scale_linetype_discrete, the first three values of which happen to be solid, dotted and dashed, which is why you're seeing the confusing replacement. You can specify linetypes by using scale_linetype_manual.
The position of the legend is adjustable in theme().
legend.position = c(0,1) defines the legend to be placed at the left, top corner.
legend.justification = c(0,1) sets the anchor to use in legend.position to the left, top corner of the legend box.
library(tidyr)
library(ggplot2)
# Create some example data
my.data <- data.frame(
time=1:100,
alpha = rnorm(100),
beta = rnorm(100),
gamma = rnorm(100)
)
my.data <- my.data %>%
gather(key="variable", value="value", alpha, beta, gamma)
p <- ggplot(data=my.data, aes(x=time, y=value, linetype=variable)) +
geom_line() +
scale_linetype_manual(
values=c("solid", "dotdash", "twodash"),
name = "",
labels = c("alpha", "beta", "gamma")) +
xlab('time (years)')+
ylab('Mean optimal paths') +
theme_bw() +
theme(legend.position=c(0.1, 0.9), legend.justification=c(0,1))
print(p)
I have data which comes from a statistical test (gene set enrichment analysis, but that's not important), so I obtain p-values for statistics that are normally distributed, i.e., both positive and negative values:
The test is run on several categories:
set.seed(1)
df <- data.frame(col = rep(1,7),
category = LETTERS[1:7],
stat.sign = sign(rnorm(7)),
p.value = runif(7, 0, 1),
stringsAsFactors = TRUE)
I want to present these data in a geom_tile ggplot such that I color code the df$category by their df$p.value multiplied by their df$stat.sign (i.e, the sign of the statistic)
For that I first take the log10 of df$p.value:
df$sig <- df$stat.sign*(-1*log10(df$p.value))
Then I order the df by df$sig for each sign of df$sig:
library(dplyr)
df <- rbind(dplyr::filter(df, sig < 0)[order(dplyr::filter(df, sig < 0)$sig), ],
dplyr::filter(df, sig > 0)[order(dplyr::filter(df, sig > 0)$sig), ])
And then I ggplot it:
library(ggplot2)
df$category <- factor(df$category, levels=df$category)
ggplot(data = df,
aes(x = col, y = category)) +
geom_tile(aes(fill=sig)) +
scale_fill_gradient2(low='darkblue', mid='white', high='darkred') +
theme_minimal() +
xlab("") + ylab("") + labs(fill="-log10(P-Value)") +
theme(axis.text.y = element_text(size=12, face="bold"),
axis.text.x = element_blank())
which gives me:
Is there a way to manipulate the legend such that the values of df$sig are represented by their absolute value but everything else remains unchanged? That way I still get both red and blue shades and maintain the order I want.
If you check ggplot's documentation, scale_fill_gradient2, like other continuous scales, accepts one of the following for its labels argument:
NULL for no labels
waiver() for the default labels computed for the transofrmation object
a character vector giving labels (must be same length as breaks)
a function that takes the breaks as input and returns labels as output
Since you only want the legend values to be absolute, I assume you're satisfied with the default breaks in the legend colour bar (-0.1 to 0.4 with increments in 0.1), so all you really need is to add a function that manipulates the labels.
I.e. instead of this:
scale_fill_gradient2(low = 'darkblue', mid = 'white', high = 'darkred') +
Use this:
scale_fill_gradient2(low = 'darkblue', mid = 'white', high = 'darkred',
labels = abs) +
I'm not sure I did understood what you're looking for. Do you meant that you wan't to change the labels within legends? If you want to change labels manipulating breaks and labels given by scale_fill_gradient2() shall do it.
ggplot(data=df,aes(x=col,y=category)) +
geom_tile(aes(fill=sig)) +
scale_fill_gradient2(low='darkblue',mid='white',high='darkred',
breaks = order(unique(df$sig)),
labels = abs(order(unique(df$sig)))) +
theme_minimal()+xlab("")+ylab("")+labs(fill="-log10(P-Value)") +
theme(axis.text.y=element_text(size=12,face="bold"),axis.text.x=element_blank())
For what you're looking for maybe you could display texts inside the figure to show the values, try stacking stat_bin_2d() like this:
ggplot(data=df,aes(x=col,y=category)) +
geom_tile(aes(fill=sig)) +
scale_fill_gradient2(low='darkblue',mid='white',high='darkred',
breaks = order(unique(df$sig)),
labels = abs(order(unique(df$sig)))) +
theme_minimal()+xlab("")+ylab("")+labs(fill="-log10(P-Value)") +
stat_bin_2d(geom = 'text', aes(label = sig), colour = 'black', size = 16) +
theme(axis.text.y=element_text(size=12,face="bold"),axis.text.x=element_blank())
You might want to give the size and colour arguments some tries.