I want to plot y=log(1+x) and y=x in the range [-0.25, 0.25]. Here is my code so far -
library(ggplot2)
log1plusx <- function(x) log(1+x)
self <- function(x) x
ggplot(data.frame(x=c(-0.25, 0.25)), aes(x=x)) + stat_function(fun=log1plusx, color="red") + stat_function(fun=self, color="blue")
I can't figure out how to add the legends for these two lines. Tried using guide_legend, but nothing works so far.
Any ideas?
Partial answer:
ggplot(data.frame(x=c(-0.25, 0.25)), aes(x=x)) +
geom_path(aes(colour="red"), stat="function", fun=log1plusx)+
geom_path(aes(colour="blue"), stat="function", fun=self) +
scale_colour_identity("Function", guide="legend",
labels = c("log1plusx", "self"),
breaks = c("red", "blue"))
Though in my opinion you'll be better off building a data.frame before plotting.
Here is how I solved it. Other ideas are welcome.
log1plusx <- function(x) log(1+x)
self <- function(x) x
plot.range1 <- data.frame(x=c(-0.25, 0.25), Functions = factor(1))
plot.range2 <- data.frame(x=c(-0.25, 0.25), Functions = factor(2))
ggplot(NULL, aes(x=x, colour=Functions)) +
stat_function(data = plot.range1, fun = log1plusx) +
stat_function(data = plot.range2, fun = self) +
scale_colour_manual(values = c("red", "green"), labels = c("log(1+x)", "x")) +
theme(axis.title.y=element_blank())
Related
I can't seem to find a way to combine two ggplots having different function ranges.
library(ggplot2)
myfun <- function(x) {
1/(1 + exp(-x))}
ggplot( NULL,aes(x)) +
stat_function(data=data.frame(x=c(0, 20)),fun=myfun, geom="line") +
stat_function(data=data.frame(x=c(10, 20)),fun=1/myfun, geom="line")
EDIT: Had a mistake in the question: 1/myfunc instead of myfunc in the second function data.
I am not sure if this is what you want, but I give your function two different colors based on two ranges. You can use the following code:
library(ggplot2)
myfun <- function(x) {
1/(1 + exp(-x))}
ggplot(NULL) +
stat_function(data= data.frame(x = c(0, 10)), aes(x, color = "blue"), fun=myfun, xlim = c(0,10)) +
stat_function(data= data.frame(x = c(10, 20)), aes(x, color = "red"), fun=myfun, xlim = c(10,20)) +
scale_color_manual(labels = c("blue", "red"), values = c("blue", "red"))
Output:
As you can see in the plot, the function is plotted within two different ranges.
Answer to edited question
I would suggest to just make a second function like this:
library(ggplot2)
myfun1 <- function(x) {
1/(1 + exp(-x))}
myfun2 <- function(x) {
1/(1/(1 + exp(-x)))}
ggplot( NULL) +
stat_function(data=data.frame(x=c(0, 20)),fun=myfun1, geom="line") +
stat_function(data=data.frame(x=c(10, 20)),fun=myfun2, geom="line")
Output:
I am trying to show a legend to accompany a plot created using ggplot and geom_col - my legend isn't showing up. I originally plotted these data using geom_bar (with a visible legend but some other problems), but after more research it seems more appropriate to use geom_col.
I know this topic has a ton of google-able questions and answers, but after many searches and code variations I still have no success.
How can I make my legend visible?
My reproducible code is below.
site <- c(0.700, 0.854)
site <- lapply(site, function(x) round((x*100),1))
site <- unlist(site, use.names=FALSE)
state <- c(0.726, 0.808)
state <- lapply(state, function(x) round((x*100),1))
state <- unlist(state, use.names=FALSE)
measure <- c("Individual", "Coalition")
measure <- unlist(measure, use.names=FALSE)
df1 <- data.frame(site,state,measure)
df2 <- melt(df1, id.vars='measure')
df2$variable <- factor(df2$variable,
levels = c('state','site'),ordered = TRUE)
fillcolors <- c("#7189A6", "#817BB0", "#7189A6", "#817BB0")
myplot <-
ggplot(df2, aes(measure, value, group = variable)) +
geom_col(width=.75, position=position_dodge(width=0.80), fill=fillcolors) +
labs(title = paste0("Knowledge & Skills Gained", paste0(rep("", 0), collapse = " ")),
x = "", y = "", fill="") +
scale_y_continuous(limits=c(0,100), labels = function(x){ paste0(x, "%") }) +
coord_flip() +
geom_text(aes(label=(paste0(value,"%"))), size=3,
colour = "#57585a",
position=position_dodge(width=0.75), vjust=.3, hjust=-.1) +
theme(legend.position="right", title = element_text(colour = "#57585a"),
legend.text = element_text(colour="#57585a", size = 9))
myplot
This results in the following plot: myplot
Thank you in advance!
The main issue is that you should use fill=, not group=:
ggplot(df2, aes(measure, value, fill = variable)) +
geom_col(width=.75, position=position_dodge(width=0.80)) +
labs(title = paste0("Knowledge & Skills Gained", paste0(rep("", 0), collapse = " ")),
x = "", y = "", fill="") +
scale_y_continuous(limits=c(0,100), labels = function(x){ paste0(x, "%") }) +
coord_flip() +
geom_text(aes(label=(paste0(value,"%"))), size=3,
colour = "#57585a",
position=position_dodge(width=0.75), vjust=.3, hjust=-.1) +
scale_fill_manual(values = c("#817BB0", "#7189A6")) +
guides(fill = guide_legend(reverse=T))
(There are a lot of other ways in which your code could be cleaned up; I focused only on getting the legend to appear.)
I made the following plot in Excel:
But then I thought I would make it prettier by using ggplot. I got this far:
If you're curious, the data is based on my answer here, although it doesn't really matter. The plot is a standard ggplot2 construct with some prettification, and the thick line for the x-axis through the middle is achieved with p + geom_hline(aes(yintercept=0)) (p is the ggplot object).
I feel that the axis configuration in the Excel plot is better. It emphasizes the 0 line (important when the data is money) and finding intercepts is much easier since you don't have to follow lines from all the way at the bottom. This is also how people draw axes when plotting on paper or boards.
Can the axis be moved like this in ggplot as well? I want not just the line, but the tick labels as well moved. If yes, how? If no, is the reason technical or by design? If by design, why was the decision made?
try this,
shift_axis <- function(p, y=0){
g <- ggplotGrob(p)
dummy <- data.frame(y=y)
ax <- g[["grobs"]][g$layout$name == "axis-b"][[1]]
p + annotation_custom(grid::grobTree(ax, vp = grid::viewport(y=1, height=sum(ax$height))),
ymax=y, ymin=y) +
geom_hline(aes(yintercept=y), data = dummy) +
theme(axis.text.x = element_blank(),
axis.ticks.x=element_blank())
}
p <- qplot(1:10, 1:10) + theme_bw()
shift_axis(p, 5)
I tried to change the theme's axis.text.x,but only can change hjust.
So I think you can delete axis.text.x,then use geom_text() to add.
For example:
test <- data.frame(x=seq(1,5), y=seq(-1,3))
ggplot(data=test, aes(x,y)) +
geom_line() +
theme(axis.text.x=element_blank(), axis.ticks.x=element_blank()) +
geom_text(data=data.frame(x=seq(1,5), y=rep(0,5)), label=seq(1,5), vjust=1.5)
Maybe these codes are useful.
just to complete baptiste's excellent answer with the equivalent for moving the y axis:
shift_axis_x <- function(p, x=0){
g <- ggplotGrob(p)
dummy <- data.frame(x=x)
ax <- g[["grobs"]][g$layout$name == "axis-l"][[1]]
p + annotation_custom(grid::grobTree(ax, vp = grid::viewport(x=1, width = sum(ax$height))),
xmax=x, xmin=x) +
geom_vline(aes(xintercept=x), data = dummy) +
theme(axis.text.y = element_blank(),
axis.ticks.y=element_blank())
}
As alistaire commented it can be done using geom_hline and geom_text as shown below.
df <- data.frame(YearMonth = c(200606,200606,200608,200701,200703,200605),
person1 = c('Alice','Bob','Alice','Alice','Bob','Alice'),
person2 = c('Bob','Alice','Bob','Bob','Alice','Bob'),
Event = c('event1','event2','event3','event3','event2','event4')
)
df$YM <- as.Date(paste0("01",df$YearMonth), format="%d%Y%m")
rangeYM <- range(df$YM)
ggplot()+geom_blank(aes(x= rangeYM, y = c(-1,1))) + labs(x = "", y = "") +
theme(axis.ticks = element_blank()) +
geom_hline(yintercept = 0, col = 'maroon') +
scale_x_date(date_labels = '%b-%y', date_breaks = "month", minor_breaks = NULL) +
scale_y_continuous(minor_breaks = NULL) +
geom_text(aes(x = df$YM, y = 0, label = paste(format(df$YM, "%b-%y")), vjust = 1.5), colour = "#5B7FA3", size = 3.5, fontface = "bold")
I would like to have grouped boxplots which whiskers is defined by stat_summary. With help of changing-whisker-definition I wrote the following code:
# Data
xdf2 <- data.frame(month = rep(1:6,each=100)
, grp = rep(c('A','B'), 50*6)
)
xdf2$m <- rpois(n=nrow(xdf2),10)
# Definition of whiskers
f <- function(x) {
r <- quantile(x, probs = c(0.10, 0.25, 0.5, 0.75, 0.90))
names(r) <- c("ymin", "lower", "middle", "upper", "ymax")
r
}
# Add points outside of whiskers
o <- function(x) {
subset(x, x < quantile(x,probs=0.1) | quantile(x,probs=0.9) < x)
}
# Plot
ggplot(data = xdf2
, aes(factor(month),m, color=grp)
) +
stat_summary(fun.data = f
, geom="boxplot"
, position=position_dodge(width=1)
, size=1
) +
stat_summary(fun.y = o, geom="point", position=position_dodge(width=1)) +
scale_color_manual(values = c("gray30","darkgrey"),labels = c("AAA","BBB")) +
theme_bw()
which gives the following graphs:
There are some changes I would like to perform:
How can I change the width of the boxes?
How can I fill the boxes with the same color of the border?
I would be happy for any help. Thanks a lot.
Map fill aesthetic to grp and add a similar scale for it. I'm using slightly different colours to make the mean visible.
To change boxplot widths, use ggsave with various width parameters, boxplots will be adjusted automatically. If you would like to add some space in between, you'll have to cheat a bit, see below.
It is not easy to modify width in conjunction with stat_summary: though there is a width parameter for geom_bar and geom_boxplot, I couldn't make it work properly with stat_summary. Instead, I'm using some dirty tricks with scale_x.
K <- length(unique(xdf2$month))
lev <- seq_len(1 + 2 * K)
xdf2$month2 <- factor(2 * xdf2$month,
levels = lev)
ggplot(data = xdf2, aes(month2, m, color = grp, fill = grp)) +
stat_summary(fun.data = f, geom="boxplot",
position=position_dodge(width=1.5), size=1) +
stat_summary(fun.y = o, geom="point", position=position_dodge(width=1.5)) +
scale_color_manual(values = c("gray30","darkgrey"),labels = c("AAA","BBB")) +
scale_fill_manual(values = c("gray20","grey75"),labels = c("AAA","BBB")) +
theme_bw() +
scale_x_discrete(limits = lev, breaks = 1:K*2, labels = 1:K)
Play around width in position_dodge for additional adjustment.
I'm working with this function here:
library(ggplot2)
getp1 <- function(names, data, colors) {
num_lines <- length(names)
p1_colors <- colors
names(p1_colors) <- names
p1 <- ggplot(data.frame(x = c(0,720)), aes(x)) +
stat_function(fun=data[[1]], geom="line", aes(colour=names[1]), size=1) +
stat_function(fun=data[[2]], geom="line", aes(colour=names[2])) +
stat_function(fun=data[[3]], geom="line", aes(colour=names[3])) +
stat_function(fun=data[[4]], geom="line", aes(colour=names[4])) +
scale_x_continuous(name="") + scale_y_continuous(name="") +
scale_colour_manual(name = "", guide = FALSE, values = p1_colors)
return(p1)
}
Right now, I get four data lines from this. But I want it to plot exactly num_lines lines, so I guess I need to find some way to "copy" the stat_function() bit num_lines times. Any idea how I can do that?
Completely fail to see the purpose of this and may have misunderstood the question. But I think that you can just use lapply to achieve what you want.
library(ggplot2)
# your version, changed so it works for me...
# (may already be something else than you expected?)
getp1_old <- function(names, data, colors) {
p1 <- ggplot(data.frame(x = c(0,720)), aes(x)) +
stat_function(fun=data[[1]], geom="line", colour=colors[1], size=1) +
stat_function(fun=data[[2]], geom="line", colour=colors[2]) +
stat_function(fun=data[[3]], geom="line", colour=colors[3]) +
stat_function(fun=data[[4]], geom="line", colour=colors[4]) +
scale_x_continuous(name="") + scale_y_continuous(name="") +
scale_colour_manual(guide = FALSE, values = colors)
return(p1)
}
# my version, with lapply
getp1_new <- function(names, data, colors) {
num_lines <- length(names)
stat_fct_combine <- lapply(1:num_lines, function(index){
stat_function(fun=data[[index]], geom="line", colour=colors[index])
})
p1 <- ggplot(data.frame(x = c(0,720)), aes(x)) +
stat_fct_combine +
scale_x_continuous(name="") +
scale_y_continuous(name="") +
scale_colour_manual(guide = FALSE, values = colors)
return(p1)
}
# reproducible example
nms <- paste0('nr', 1:6)
dta <- list(function(x) 1, function(x) 2, function(x) 3, function(x) 4,
function(x) 5, function(x) 6)
cols <- rep(c('red', 'green', 'black', 'blue'), length=6)
# example plots
getp1_old(nms, dta, cols)
getp1_new(nms[1:4], dta, cols)
getp1_new(nms, dta, cols)