I get warning message :
In as_grob.default(plot) : Cannot convert object of class LayerInstanceLayerggprotogg into a grob.
The geom_text I would like to add is geom_text(aes(label = rownames(data)), size = 4).
If I add it in the ggplot function, I get this warning message ,When trying to run the ggarrange :
Error: Aesthetics must be either length 1 or the same as the data (87): label
mgp_df = ggplot2::mpg
mpg_df2 = mgp_df[1:50,]
rownames(mgp_df)<-make.names(mgp_df$manufacturer, unique = TRUE)
p1<-ggplot(mgp_df, aes(x=cty, y=hwy)) +
geom_smooth(method=lm)+
theme_classic()+
geom_text(aes(label = rownames(mgp_df)), size = 4) +
scale_x_continuous(name="testx")+
scale_y_continuous(name="testy", limits=c(35, 90))
p2<-ggplot(mpg_df2, aes(x=cty, y=hwy)) +
geom_smooth(method=lm)+
theme_classic()+
geom_text(aes(label = rownames(mpg_df2)), size = 4) +
scale_x_continuous(name="testx")+
scale_y_continuous(name="testy", limits=c(35, 90))
figure <- ggarrange(p1, p2,
labels = c("test1", " test2"),
ncol = 1, nrow = 2)
figure
Create a column in data for the labels:
data$labs <- rownames(data)
Then change geom_text to:
geom_text(aes(label = labs), size = 4)
Related
I am creating a forest plot for a meta-analysis using ggplot2. I want to manually add a skewed diamond shape (asymmetric on the y-scale) to represent an effect size and confidence interval.
I can draw the forest plot and add four segments to create the diamond but this doesn't give a nice clear, sharp diamond. Instead I've used geom_polygon with a set of co-ordinates in a second dataframe. When I try to write to pdf I receive the following error
summarydiamond <- data.frame(
x = c(sleepstress.r.CI.L, sleepstress.r.estimate, sleepstress.r.CI.U, sleepstress.r.estimate, sleepstress.r.CI.L),
y = c(-1, -1.5, -1, -0.5, -1)
)
forest.plot <-
dat.sleepstress %>%
ggplot(aes(x = rev(key.pairing), y = r, ymin = r.CI.lower, ymax = r.CI.upper))+
geom_errorbar(width = 0.5) +
geom_point(aes(size = r.weights)) +
scale_size(range = c(1, 7)) +
geom_hline(yintercept = 0) +
theme_minimal() +
coord_flip() +
theme(legend.position = "none") +
labs(x = "", y = "Correlation coefficient") +
theme(text = element_text(size=14)) +
scale_x_discrete(limits=rev) +
geom_text(aes(label = paste0(format(round(r, 2),nsmall = 2),
" (",
format(round(r.CI.lower, 2),nsmall = 2),
", ",
format(round(r.CI.upper, 2),nsmall = 2),
")"),
y = 0.85),
hjust="inward") +
geom_polygon(aes(x=x, y=y), data = summarydiamond)
pdf(file = 'forestplot.pdf', width = 10, height = 10)
forest.plot
dev.off()
Output:
forest.plot
Error in FUN(X[[i]], ...) : object 'r.CI.lower' not found
I've tried adding the data= argument to all of the geom_ calls but this doesn't fix it.
I am using the windrose function posted here: Wind rose with ggplot (R)?
I need to have the percents on the figure showing on the individual lines (rather than on the left side), but so far I have not been able to figure out how. (see figure below for depiction of goal)
Here is the code that makes the figure:
p.windrose <- ggplot(data = data,
aes(x = dir.binned,y = (..count..)/sum(..count..),
fill = spd.binned)) +
geom_bar()+
scale_y_continuous(breaks = ybreaks.prct,labels=percent)+
ylab("")+
scale_x_discrete(drop = FALSE,
labels = waiver()) +
xlab("")+
coord_polar(start = -((dirres/2)/360) * 2*pi) +
scale_fill_manual(name = "Wind Speed (m/s)",
values = spd.colors,
drop = FALSE)+
theme_bw(base_size = 12, base_family = "Helvetica")
I marked up the figure I have so far with what I am trying to do! It'd be neat if the labels either auto-picked the location with the least wind in that direction, or if it had a tag for the placement so that it could be changed.
I tried using geom_text, but I get an error saying that "aesthetics must be valid data columns".
Thanks for your help!
One of the things you could do is to make an extra data.frame that you use for the labels. Since the data isn't available from your question, I'll illustrate with mock data below:
library(ggplot2)
# Mock data
df <- data.frame(
x = 1:360,
y = runif(360, 0, 0.20)
)
labels <- data.frame(
x = 90,
y = scales::extended_breaks()(range(df$y))
)
ggplot(data = df,
aes(x = as.factor(x), y = y)) +
geom_point() +
geom_text(data = labels,
aes(label = scales::percent(y, 1))) +
scale_x_discrete(breaks = seq(0, 1, length.out = 9) * 360) +
coord_polar() +
theme(axis.ticks.y = element_blank(), # Disables default y-axis
axis.text.y = element_blank())
#teunbrand answer got me very close! I wanted to add the code I used to get everything just right in case anyone in the future has a similar problem.
# Create the labels:
x_location <- pi # x location of the labels
# Get the percentage
T_data <- data %>%
dplyr::group_by(dir.binned) %>%
dplyr::summarise(count= n()) %>%
dplyr::mutate(y = count/sum(count))
labels <- data.frame(x = x_location,
y = scales::extended_breaks()(range(T_data$y)))
# Create figure
p.windrose <- ggplot() +
geom_bar(data = data,
aes(x = dir.binned, y = (..count..)/sum(..count..),
fill = spd.binned))+
geom_text(data = labels,
aes(x=x, y=y, label = scales::percent(y, 1))) +
scale_y_continuous(breaks = waiver(),labels=NULL)+
scale_x_discrete(drop = FALSE,
labels = waiver()) +
ylab("")+xlab("")+
coord_polar(start = -((dirres/2)/360) * 2*pi) +
scale_fill_manual(name = "Wind Speed (m/s)",
values = spd.colors,
drop = FALSE)+
theme_bw(base_size = 12, base_family = "Helvetica") +
theme(axis.ticks.y = element_blank(), # Disables default y-axis
axis.text.y = element_blank())
All I want is this R code to display the names of players inside the "topName" while hiding the names inside the "otherNames" by plotting both of them using two different geom_col().
epldata <- read.csv(file = 'epldata.csv')
epldata$srno <- c(1:461)
attach(epldata)
points <- epldata[order(-fpl_points),]
detach(epldata)
topNames[24:461]<-NA epldata$topNames <- topNames
topPoints[24:461]<-NA epldata$topPoints <- topPoints
epldata$otherNames <- NA epldata$otherNames[24:461] <-
as.character(points$name[c(24:461)]) epldata$otherPoints <- NA
epldata$otherPoints[24:461] <-
as.numeric(points$fpl_points[c(24:461)])
ggplot(data = epldata)+ geom_col(aes(x=epldata$topNames,
y=epldata$topPoints), fill = "red", alpha = 1) +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
annotate("text", x=epldata$topNames, y=-50, #epldata$topPoints,
label = epldata$topNames, fontface = 1, size = 2, hjust = 0)+ geom_col(aes(x=epldata$otherNames, y=epldata$otherPoints), fill
= "gray", alpha = 0.3)+ theme(legend.position = "none")+ #theme(axis.text.x = element_text(angle = 90, hjust = 1))+ xlab("Player Names")+ ylab("FPL Points")+ guides(fill=FALSE,
color=FALSE, guide = FALSE) + coord_flip() + theme(axis.text.y =
element_blank(),
axis.ticks.y = element_blank())
This is the kind of output I am looking for but without using the Annotate Hack that I am currently using but directly plotting the names on the axis.
Update : have added the entire code and the link to the data set is below :
https://drive.google.com/open?id=1KTitWDcLIBmeBsz8mLcHXDIyhQLZnlhS
Once you've created a list of topNames, you can use scale_x_continuous to display only these axis labels:
scale_x_discrete(breaks = topNames)
Also, rather than using two separate geom_col() geometries, you can create a new "highlight" column in the dataframe and use that with the fill and alpha aesthetics:
library(dplyr)
library(ggplot2)
# read data from google drive
id <- "1KTitWDcLIBmeBsz8mLcHXDIyhQLZnlhS" #google file ID
epldata <- read.csv(sprintf("https://docs.google.com/uc?id=%s&export=download", id),
stringsAsFactors = FALSE)
N <- 24 #number of players to highlight
#get list of names of top N players
topNames <- epldata %>%
arrange(-fpl_points) %>%
head(N) %>%
pull(name)
#> Warning: package 'bindrcpp' was built under R version 3.5.1
# make variable for highlighting
epldata <- epldata %>%
mutate(highlight = ifelse(name %in% topNames, TRUE, FALSE))
ggplot(data = epldata,
aes(x = name, y = fpl_points, fill = highlight, alpha = highlight)) +
geom_col() +
scale_fill_manual(guide = FALSE,
values = c("gray", "red")) +
scale_alpha_manual(guide = FALSE,
values = c(0.4, 1)) +
scale_x_discrete(breaks = topNames) + #use breaks to determine axis labels
coord_flip() +
ylab("FPL Points") +
theme_classic() +
theme(axis.ticks.y = element_blank(),
axis.title.y = element_blank())
Created on 2018-09-19 by the reprex package (v0.2.1)
I have NA values in a data set, which I would like to include in my ggplot as well as in the legend. I thought this would be easily done by specifying the na.values="somecolour" option, as shown e.g. in this post. However, for my example the code runs without plotting any of the NAs, nor including an entry in the legend. Instead rows with missing values are automatically removed. Here's some code for illustration:
set.seed(42)
lat <- rnorm(10, 54, 12)
long <- rnorm(10, 44, 12)
val <- rnorm(6, 10, 3)
val <- c(val,NA,NA,NA,NA)
df <- as.data.frame(cbind(long, lat, val))
library(ggplot2)
library(scales)
ggplot() +
geom_point(data=df, aes(x=lat, y=long, size=val, fill=val),shape=21,alpha=0.6) +
scale_size_continuous(range = c(2, 12), breaks=pretty_breaks(4)) +
scale_fill_distiller(direction = -1, palette="RdYlBu", breaks=pretty_breaks(4),na.value = "black") +
guides(fill = guide_legend(), size = guide_legend()) +
theme_minimal()
What am I doing wrong?
Problem comes from setting size in aes as you can't set size for NA values in scale_size_continuous.
My solution would be to plot NA values separately (not perfect, but works). To add them to legend set some dummy value within aes to call there guide.
However, there is a problem that NA legend doesn't align nicely with non-NA legend. To adjust the alignment we have to plot another set of invisible NA values with the size of maximum non-NA values.
ggplot(df, aes(lat, long, size = val, fill = val)) +
geom_point(shape = 21,alpha = 0.6) +
geom_point(data = subset(df, is.na(val)), aes(shape = "NA"),
size = 1, fill = "black") +
geom_point(data = subset(df, is.na(val)), aes(shape = "NA"),
size = 14, alpha = 0) +
scale_size_continuous(range = c(2, 12), breaks = pretty_breaks(4)) +
scale_fill_distiller(direction = -1, palette = "RdYlBu", breaks = pretty_breaks(4)) +
labs(shape = " val\n",
fill = NULL,
size = NULL) +
guides(fill = guide_legend(),
size = guide_legend(),
shape = guide_legend(order = 1)) +
theme_minimal() +
theme(legend.spacing.y = unit(-0.4, "cm"))
PS: requires ggplot2_3.0.0.
I have the following data.frame:
hist.df <- data.frame(y = c(rnorm(30,1,1), rnorm(15), rnorm(30,0,1)),
gt = c(rep("ht", 30), rep("hm", 15), rep("hm", 30)),
group = c(rep("sc", 30), rep("am", 15), rep("sc",30)))
from which I produce the following faceted histogram ggplot:
main.plot <- ggplot(data = hist.df, aes(x = y)) +
geom_histogram(alpha=0.5, position="identity", binwidth = 2.5,
aes(fill = factor(gt))) +
facet_wrap(~group) +
scale_fill_manual(values = c("darkgreen","darkmagenta"),
labels = c("ht","hm"),
name = "gt",
limits=c(0, 30))
In addition, I have this data.frame:
text.df = data.frame(ci.lo = c(0.001,0.005,-10.1),
ci.hi = c(1.85,2.25,9.1),
group = c("am","sc","sc"),
factor = c("nu","nu","alpha"))
Which defines the text annotations I want to add to the faceted histograms, so that the final figure will be:
So text.df$ci.lo and text.df$ci.hi are confidence intervals on the corresponding text.df$factor and they correspond to the faceted histograms through text.df$group
Note that not every histogram has all text.df$factor's.
Ideally, the ylim's of the faceted histograms will leave enough space for the text to be added above the histograms so that they appear only on the background.
Any idea how to achieve this?
Wrapping my comment into an answer:
text.df$ci <- paste0(text.df$factor, ' = [', text.df$ci.lo, ', ', text.df$ci.hi, ']')
new_labels <- aggregate(text.df$ci, by = list(text.df$group),
FUN = function(x) paste(x, collapse = '\n'))$x
hist.df$group <- factor(hist.df$group)
hist.df$group <- factor(hist.df$group,
labels = paste0(levels(hist.df$group), '\n', new_labels))
main.plot <- ggplot(data = hist.df, aes(x = y)) +
geom_histogram(alpha=0.5, position="identity", binwidth = 2.5,
aes(fill = factor(gt))) +
facet_wrap(~group) +
scale_fill_manual(values = c("darkgreen","darkmagenta"),
labels = c("ht","hm"),
name = "gt")
main.plot + theme(strip.text = element_text(size=20))
If you wish to stick to the original idea, this question has an answer that will help.