I have this plot
library(dplyr)
library(ggplot2)
indexYear <- as.numeric(2000:2010)
lDLatIndex <- rep.int(4,11)
LDLoneYear <- c(rep.int(3,5), rep.int(2,6))
hba1catIndex <- c(rep.int(8,6), rep.int(7.5,5))
hba1coneYear <- rep.int(7,11)
LDLeffect <- data.frame(indexYear, lDLatIndex, hba1catIndex, hba1coneYear)
LDLeffect %>%
ggplot(., aes(x = indexYear))+
geom_line(aes(y = lDLatIndex, colour=rgb(237/255, 115/255,116/255)), linetype = "solid" , size = 2)+
theme_classic()+
theme(legend.position = "bottom")+
ylab("mean LDL cholesterol (mmol/l) ")+
xlab("Calendar year")+
theme(axis.title = element_text(size = 17, face="bold"), axis.text = element_text(size = 17, face = "bold"))+
scale_x_continuous(breaks = seq(2000,2015, by=1),labels = c(2000,rep("",4),2005,rep("",4), 2010, rep("",4),2015))+
scale_y_continuous(sec.axis = sec_axis(~(.-2.15)*10.929, name = "mean HbA1c (%) "))+
geom_line(aes(y = LDLoneYear, colour=rgb(237/255, 115/255,116/255)), linetype = "dashed" , size = 2)+
geom_line(aes(y = hba1coneYear, colour=rgb(152/255, 201/255,139/255)), linetype = "twodash" , size = 2)+
geom_line(aes(y = hba1catIndex, colour=rgb(152/255, 201/255,139/255)), linetype = "F1" , size = 2)
I know that usually, the best option is to supply data in long format for ggplot, but I couldn't get it to work. The plot above produces a strange legend that I cannot understand how got there.
I see that the names to the legend added are from the colour definitions.
What I want to make is legends that show the colour and linetype and name for each variable plotted, preferably with the option of adding custom names. I looked through a lot of pages with suggestions, but most makes use of long format which I cannot figure out because I wanted different linetypes and colours by two and two. The rest couldn't help me address this strange expression in the labelling.
Would below proposal go into right direction? Main points are: using "melt" from reshape2 for bringing data in ggplot-friendly shape. And with scale_linetype_manual and scale_colour_manual I'm explicitly providing colours and line types.
library(dplyr)
library(ggplot2)
library(reshape2) ## for "melt"
indexYear <- as.numeric(2000:2010)
lDLatIndex <- rep.int(4,11)
LDLoneYear <- c(rep.int(3,5), rep.int(2,6))
hba1catIndex <- c(rep.int(8,6), rep.int(7.5,5))
hba1coneYear <- rep.int(7,11)
LDLeffect <- data.frame(indexYear, lDLatIndex, hba1catIndex, hba1coneYear, LDLoneYear)
melted_df <- melt(LDLeffect, id.vars="indexYear", measure.vars=c("lDLatIndex", "hba1catIndex", "hba1coneYear", "LDLoneYear"))
ggplot(melted_df, aes(x=indexYear, value, colour=variable)) +
geom_line(aes(linetype=variable), size = 2) +
scale_linetype_manual(values=c("F1", "twodash", "solid", "dashed")) +
scale_colour_manual(values=c(rgb(237/255, 115/255,116/255), rgb(237/255, 115/255,116/255), rgb(152/255, 201/255,139/255), rgb(152/255, 201/255,139/255))) +
theme_classic() +
theme(legend.position = "bottom")+
ylab("mean LDL cholesterol (mmol/l)")+
xlab("Calendar year")+
theme(axis.title = element_text(size = 17, face="bold"), axis.text = element_text(size = 17, face = "bold"))+
scale_x_continuous(breaks = seq(2000,2015, by=1),labels = c(2000,rep("",4),2005,rep("",4), 2010, rep("",4),2015))+
scale_y_continuous(sec.axis = sec_axis(~(.-2.15)*10.929, name = "mean HbA1c (%)"))
Related
I'm trying to change the color of 9 states in the following image. Those states are top mining states and I want them to stand out in the image attached below. I probably need to modify my dataframe as the easiest step. But any other ideas?
ggplot(data = media_impact_by_state) +
#geom_hline(yintercept=0,linetype="dashed", color = "red") +
geom_bar(aes(x= reorder(GeoName,trustclimsciSSTOppose - mean(trustclimsciSSTOppose)),
y= CO2limitsOppose-mean(CO2limitsOppose), fill = "fill1"),
stat = 'identity') +
geom_point(aes(x = GeoName,
y = trustclimsciSSTOppose - mean(trustclimsciSSTOppose),
color = "dot1"),
size=3) +
scale_color_manual(values = c("black"),
label = "Distrust of Scientists",
name = "Mean Deviation") +
scale_fill_manual(values = c(fill1 = "darkorange1",fill2 = "blue"),
labels = c(fill1 = "Oppose Limits to Co2 Emissions",fill2 = "poop"),
name = "Mean Deviation") +
labs(x = "State",
y = "(%)",
title = "Distrust of Scientists") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1,size=12),
axis.text.y = element_text(size=14),
axis.title.y = element_text(size=16),
axis.title.x = element_text(size=16),
plot.title = element_text(size=16,hjust=0.5))
It will be difficult to offer guidance without seeing a subset of your data. To offer some suggestions, try amending the appropriate column(s) (i.e., variables) using ifelse() before feeding it to the fill aesthetic. Make sure this is wrapped inside of the aes() call. Your legend titled "Mean Deviation" should appropriately split into two categories. Then, simply amend the colors inside of scale_fill_manual() as needed.
ggplot(data = media_impact_by_state) +
geom_bar(aes(x = reorder(GeoName, trustclimsciSSTOppose - mean(trustclimsciSSTOppose)),
y = CO2limitsOppose - mean(CO2limitsOppose),
fill = factor(ifelse(GeoName %in% c(...), "Top 20", "Bottom 80"))), # index the states
stat = 'identity') +
geom_point(aes(x = GeoName,
y = trustclimsciSSTOppose - mean(trustclimsciSSTOppose),
color = "dot1"),
size = 3) +
scale_color_manual(name = "Mean Deviation"
values = c("black"),
labels = "Distrust of Scientists") +
scale_fill_manual(name = "Mean Deviation",
values = c("darkorange1", # supply the vector of colors
"blue"),
labels = c("Oppose (Top 20)", # supply the vector of labels
"Oppose (Bottom 80)") +
labs(x = "State",
y = "(%)",
title = "Distrust of Scientists") +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1, size = 12),
axis.text.y = element_text(size = 14),
axis.title.y = element_text(size = 16),
axis.title.x = element_text(size = 16),
plot.title = element_text(size = 16, hjust = 0.5)
)
However, if you want to flag the top 20 percent of states by any other arbitrary measures of mining output, then maybe you should consider modifying the existing data frame using one of R's generic functions. I'm not sure by what standard(s) you are using to determine the "top" mining states, but that is for you to decide. For example, try creating a variable ahead of time, call it fill_col and pass it to fill inside of the aes() call. Here is how you could pre-process the data:
media_impact_by_state %>%
arrange(GeoName, desc(mining_output)) %>% # order in descending order by mining output
mutate(fill_col = mining_output > quantile(mining_output, .8)) # flag the top 20 percent
In the end, there's nothing wrong with manually typing in all the states that you want to highlight, though it is harder on the eyes and could become unwieldy if you had more than 50 states (or 51 if you included the District of Columbia).
I hope this helps!
I've been stuck on an issue and can't find a solution. I've tried many suggestions on Stack Overflow and elsewhere about manually ordering a stacked bar chart, since that should be a pretty simple fix, but those suggestions don't work with the huge complicated mess of code I plucked from many places. My only issue is y-axis item ordering.
I'm making a series of stacked bar charts, and ggplot2 changes the ordering of the items on the y-axis depending on which dataframe I am trying to plot. I'm trying to make 39 of these plots and want them to all have the same ordering. I think ggplot2 only wants to plot them in ascending order of their numeric mean or something, but I'd like all of the bar charts to first display the group "Bird Advocates" and then "Cat Advocates." (This is also the order they appear in my data frame, but that ordering is lost at the coord_flip() point in plotting.)
I think that taking the data frame through so many changes is why I can't just add something simple at the end or use the reorder() function. Adding things into aes() also doesn't work, since the stacked bar chart I'm creating seems to depend on those items being exactly a certain way.
Here's one of my data frames where ggplot2 is ordering my y-axis items incorrectly, plotting "Cat Advocates" before "Bird Advocates":
Group,Strongly Opposed,Opposed,Slightly Opposed,Neutral,Slightly Support,Support,Strongly Support
Bird Advocates,0.005473026,0.010946052,0.012509773,0.058639562,0.071149335,0.31118061,0.530101642
Cat Advocates,0.04491726,0.07013396,0.03624901,0.23719464,0.09141056,0.23404255,0.28605201
And here's all the code that takes that and turns it into a plot:
library(ggplot2)
library(reshape2)
library(plotly)
#Importing data from a .csv file
data <- read.csv("data.csv", header=TRUE)
data$s.Strongly.Opposed <- 0-data$Strongly.Opposed-data$Opposed-data$Slightly.Opposed-.5*data$Neutral
data$s.Opposed <- 0-data$Opposed-data$Slightly.Opposed-.5*data$Neutral
data$s.Slightly.Opposed <- 0-data$Slightly.Opposed-.5*data$Neutral
data$s.Neutral <- 0-.5*data$Neutral
data$s.Slightly.Support <- 0+.5*data$Neutral
data$s.Support <- 0+data$Slightly.Support+.5*data$Neutral
data$s.Strongly.Support <- 0+data$Support+data$Slightly.Support+.5*data$Neutral
#to percents
data[,2:15]<-data[,2:15]*100
#melting
mdfr <- melt(data, id=c("Group"))
mdfr<-cbind(mdfr[1:14,],mdfr[15:28,3])
colnames(mdfr)<-c("Group","variable","value","start")
#remove dot in level names
mylevels<-c("Strongly Opposed","Opposed","Slightly Opposed","Neutral","Slightly Support","Support","Strongly Support")
mdfr$variable<-droplevels(mdfr$variable)
levels(mdfr$variable)<-mylevels
pal<-c("#bd7523", "#e9aa61", "#f6d1a7", "#999999", "#c8cbc0", "#65806d", "#334e3b")
ggplot(data=mdfr) +
geom_segment(aes(x = Group, y = start, xend = Group, yend = start+value, colour = variable,
text=paste("Group: ",Group,"<br>Percent: ",value,"%")), size = 5) +
geom_hline(yintercept = 0, color =c("#646464")) +
coord_flip() +
theme(legend.position="top") +
theme(legend.key.width=unit(0.5,"cm")) +
guides(col = guide_legend(ncol = 12)) + #has 7 real columns, using to adjust legend position
scale_color_manual("Response", labels = mylevels, values = pal, guide="legend") +
theme(legend.title = element_blank()) +
theme(axis.title.x = element_blank()) +
theme(axis.title.y = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.text.x = element_blank()) +
theme(legend.key = element_rect(fill = "white")) +
scale_y_continuous(breaks=seq(-100,100,100), limits=c(-100,100)) +
theme(panel.background = element_rect(fill = "#ffffff"),
panel.grid.major = element_line(colour = "#CBCBCB"))
The plot:
I think this works, you may need to play around with the axis limits/breaks:
library(dplyr)
mdfr <- mdfr %>%
mutate(group_n = as.integer(case_when(Group == "Bird Advocates" ~ 2,
Group == "Cat Advocates" ~ 1)))
ggplot(data=mdfr) +
geom_segment(aes(x = group_n, y = start, xend = group_n, yend = start + value, colour = variable,
text=paste("Group: ",Group,"<br>Percent: ",value,"%")), size = 5) +
scale_x_continuous(limits = c(0,3), breaks = c(1, 2), labels = c("Cat", "Bird")) +
geom_hline(yintercept = 0, color =c("#646464")) +
theme(legend.position="top") +
theme(legend.key.width=unit(0.5,"cm")) +
coord_flip() +
guides(col = guide_legend(ncol = 12)) + #has 7 real columns, using to adjust legend position
scale_color_manual("Response", labels = mylevels, values = pal, guide="legend") +
theme(legend.title = element_blank()) +
theme(axis.title.x = element_blank()) +
theme(axis.title.y = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.text.x = element_blank()) +
theme(legend.key = element_rect(fill = "white"))+
scale_y_continuous(breaks=seq(-100,100,100), limits=c(-100,100)) +
theme(panel.background = element_rect(fill = "#ffffff"),
panel.grid.major = element_line(colour = "#CBCBCB"))
produces this plot:
You want to factor the 'Group' variable in the order by which you want the bars to appear.
mdfr$Group <- factor(mdfr$Group, levels = c("Bird Advocates", "Cat Advocates")
I have a custom color pallet I'd like to use for a geom_bar plot. However I'd also like to set the luminance of these colors manually. When I run the scale_fill_manual() and scale_fill_hue() functions together in my ggplot code, I get the following error:
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
Which seems like one "scale_fill" function is overriding the other. It seemed logical to set the luminance within the scale_fill_manual() function like:
scale_fill_manual(values=cbPalette, l = 55)
But this doesn't work.
Thanks in advance for your help! Here is a version of the figure without the luminance set correctly (below are the data and code):
> Sex_age_survival
Sex age estimate lcl ucl
Female Adult 0.6826927 0.62881160 0.7320849
Male Adult 0.6941044 0.64680030 0.7376429
Female Juvenile 0.4062997 0.27163540 0.5566986
Male Juvenile 0.5270193 0.39998360 0.6506502
Female Chick 0.4296511 0.30855270 0.5394149
Male Chick 0.3987215 0.25969601 0.5252046
Salina Nest 0.5643484 0.52096067 0.6054399
Marsh Nest 0.1434720 0.04435806 0.3013856
limits <- aes(ymin = lcl, ymax = ucl)
dodge <- position_dodge(width=0.7)
cbPalette <- c("#E69F00", "#009E73", "#CC0000", "#0066CC")
Sex_age_plot2 <- ggplot(Sex_age_survival, aes(fill = Sex, x = age, y = estimate)) +
theme_bw() +
geom_bar(width = 0.7, position = "dodge", stat = "identity") +
geom_errorbar(limits, position = dodge, width=0.2, size = .6, shape = 1) +
theme(text=element_text(size = 16, family = "Candara"),
legend.text = element_text(size = 30),
legend.title = element_text(size = 30),
axis.title.x = element_text(size = 35, vjust = -0.1),
axis.text.x = element_text(size = 30),
axis.title.y = element_text(size = 35, vjust = 1.2),
axis.text.y = element_text(size = 30),
panel.grid.major = element_blank()) +
xlab("Life stage") +
ylab("Apparent survival (± 95% CI)") +
scale_y_continuous(limits = c(0, 1)) +
scale_fill_hue(l = 55) + # seems like I cannot run this in addition to scale_fill_manual()
scale_fill_manual(values=cbPalette) # seems like I cannot run this in addition to scale_fill_hue()
Sex_age_plot2
You can't combine scales like that in ggplot2: instead, you'll need to do the colour manipulation manually:
library(colorspace)
pal <- c("#E69F00", "#009E73", "#CC0000", "#0066CC")
hcl <- coords(as(hex2RGB(pal), "polarLUV"))
hcl[, "L"] <- 55
pal2 <- hex(polarLUV(hcl), fixup = TRUE)
plot(rep(1:4, 2), rep(1:2, each = 4), pch = 20, cex = 5, col = c(pal, pal2))
What I'm trying to do is overlay circles that have a dark outline over the ones I have but I'm not sure how to size them since I already have varying sizes. Also is there anyway to change the legend symbols to something like $1M, $2m?
mikebay_usergraph <-
ggplot(mikebay_movies_dt, aes(y = tomatoUserMeter, x = Released, label = Title)) +
geom_point(aes(size = BoxOffice)) + (aes(color = tomatoImage)) +
geom_text(hjust = .45, vjust = -.75, family = "Futura", size = 5, colour = "#535353") +
ggtitle("The Fall of Bayhem: How Michael Bay movies have declined") +
theme(plot.title = element_text(size = 15, vjust = 1, family = "Futura"),
axis.text.x = element_text(size = 12.5, family = "Futura"),
axis.text.y = element_text(size = 12.0, family = "Futura"),
panel.background = element_rect(fill = '#F0F0F0'),
panel.grid.major=element_line(colour ="#D0D0D0",size=.75)) +
scale_colour_manual(values = c('#336333', '#B03530')) +
geom_hline(yintercept = 0,size = 1.2, colour = "#535353") +
scale_x_date(limits = c(as.Date("1994-1-1"),as.Date("2017-1-1"))) +
theme(axis.ticks = element_blank())
I offer two possible solutions for adding a circle or outline around size-scaled points in a scatterplot. For the first solution, I propose using plotting symbols that allow separate fill and outline colors. The drawback here is that you cannot control the thickness of the outline. For the second solution I propose adding an extra layer of slightly larger black points positioned under the primary geom_point layer. In this case, the thickness of the outline can be manually adjusted by setting thickness to a value between 0 and 1.
Finally, dollar legend formatting can be added by loading the scales package, and adding scale_size_continuous(labels=dollar) to your ggplot call.
library(ggplot2)
library(scales) # Needed for dollar labelling.
dat = data.frame(rating=c(80, 60, 40),
date=as.Date(c("1995-1-1", "2005-1-1", "2015-1-1")),
boxoffice=c(3e7, 1e8, 7e7),
tomato=c("fresh", "rotten", "rotten"))
p1 = ggplot(dat, aes(x=date, y=rating, size=boxoffice, fill=tomato)) +
geom_point(shape=21, colour="black") +
scale_fill_manual(values = c(fresh="green", rotten="red")) +
scale_size_continuous(labels=dollar, range=c(8, 22))
thickness = 0.35
p2 = ggplot(dat, aes(x=date, y=rating)) +
geom_point(colour="black",
aes(size=boxoffice + (thickness * mean(boxoffice)))) +
geom_point(aes(colour=tomato, size=boxoffice)) +
scale_colour_manual(values = c(fresh="green", rotten="red")) +
scale_size_continuous(labels=dollar, range=c(8, 22), name="Box Office")
I have the following code:
library(ggplot2)
library(gridExtra)
data = data.frame(fit = c(9.8,15.4,17.6,21.6,10.8), lower = c(7.15,12.75,14.95,18.95,8.15), upper = c(12.44,18.04,20.24,24.24,13.44), factors = c(15,20,25,30,35), var = rep("Fator", 5))
gp <- ggplot(data, aes(x=factors, y=fit, ymax=upper, ymin=lower))
gp <- gp + geom_line(aes(group=var),size=1.2) +
geom_errorbar(width=.8, size=1, aes(colour='red')) +
geom_point(size=4, shape=21, fill="grey") +
labs(x = paste("\n",data$var[1],sep=""), y =paste("Values","\n",sep="")) +
theme(legend.position = 'none', axis.text = element_text(size = 11), plot.margin=unit(c(0.4,0.4,0.4,0.4), "cm"), axis.text.x = element_text(angle=45, hjust = 1, vjust = 1)) +
ylim((min(data$lower)), (max(data$upper)))
I want to change the line color after I have the ggplot object. I'm trying:
gp + scale_color_manual(values = "green")
but it change the error bar color and not the line color.
1)What should I do to change the line color?
2)How can I change the points color?
Thanks!
Try this:
gp$layers[[1]] <- NULL
gp + geom_line(aes(group = var),color = "green",size = 1.2)
A similar technique should work for the points layer. Technique was dredged up from my memories of a similar question.
I just looked at the contents of gp$layers manually to see which was which. I presume that the order will be the order in which they appear in your code, but I wouldn't necessarily rely on that.