I would like to create a plot with multiple breaks of different sized intervals on the y axis. The closest post I could find is this Show customised X-axis ticks in ggplot2 But it doesn't fully solve my problem.
# dummy data
require(ggplot2)
require(reshape2)
a<-rnorm(mean=15,sd=1.5, n=100)
b<-rnorm(mean=1500,sd=150, n=100)
df<-data.frame(a=a,b=b)
df$x <- factor(seq(100), ordered = T)
df.m <- melt(df)
ggplot(data = df.m, aes(x = x, y=value, colour=variable, group=variable)) +
geom_line() + scale_y_continuous(breaks = c(seq(from = 0, to = 20, by = 1),
seq(from = 1100, to = max(y), by = 100))) +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
The problem is how to get the first set of breaks to be proportional to the second (thus visible).
Any pointer would be very much appreciated, thanks!
You can try something like this:
# Rearrange the factors in the data.frame
df.m$variable <- factor(df.m$variable, levels = c("b", "a"))
ggplot(data = df.m, aes(x = x, y=value, colour=variable, group=variable)) +
geom_line() + facet_grid(variable~., scales = "free")
Hope this helps
Related
I have a data.frame that has counts for several groups:
set.seed(1)
df <- data.frame(group = sample(c("a","b"),200,replace = T),
n = round(runif(200,1,2)))
df$n <- as.integer(df$n)
And I'm trying to display a histogram of df$n, facetted by the group using ggplot2's geom_histogram:
library(ggplot2)
ggplot(data = df, aes(x = n)) + geom_histogram() + facet_grid(~group) + theme_minimal()
Any idea how to get ggplot2 to label the x-axis ticks with the integers the histogram is summarizing rather than the numeric values it is currently showing?
You could tweak this by the binwidth argument of geom_histogram:
library(ggplot2)
ggplot(data = df, aes(x = n)) +
geom_histogram(binwidth = 0.5) +
facet_grid(~group) +
theme_minimal()
Another example:
set.seed(1)
df <- data.frame(group = sample(c("a","b"),200,replace = T),
n = round(runif(200,1,5)))
library(ggplot2)
ggplot(data = df, aes(x = n)) +
geom_histogram(binwidth = 0.5) +
facet_grid(~group) +
theme_minimal()
You can manually specify the breaks with scale_x_continuous(breaks = seq(1, 2)). Alternatively, you can set the breaks and labels separately as well.
I have created one monthly plot with facet_wrap
.
So in the plot I have 3 rows and 4 columns. Now I want to set my common y axis for each rows e.g 1st row should have one common y values, same goes with the 2nd and 3rd rows.
I tried but not able to do it.
I used
ggplot(data = PB,
aes(x = new_date, y = Mean, group = 1)) +
geom_line(aes(color = experiment)) +
theme(legend.title = element_blank()) +
facet_wrap( ~MonthAbb, ncol = 4, scales = "free")
The issue is the scales = "free". Remove this and it will set a common scale across rows and columns (or use "free_y" or "free_x" to adjust accordingly).
If what you're looking for is a separate scale for each row, it will require a bit more work. Check this solution at R: How do I use coord_cartesian on facet_grid with free-ranging axis which layers invisible points on the plot to force the look you want. Otherwise a simple solution might to look at using gridExtra and plot each row separately, then merge into a grid.
Edit: a gridExtra solution would look something like:
library(gridExtra)
g1 <- ggplot(data = PB1, aes(x=new_date, y = Mean, group = 1)) +
geom_line(aes(color = experiment)) +
theme(legend.title = element_blank())
g2 <- ggplot(data = PB2, aes(x=new_date, y = Mean, group = 1)) +
geom_line(aes(color = experiment)) +
theme(legend.title = element_blank())
grid.arrange(g1, g2, nrow=2)
Here is an option to set these on a per-panel basis. It is based on a function I've put in a github package. I'm using some dummy data as example.
library(ggplot2)
library(ggh4x)
df <- data.frame(
x = rep(1:20, 9),
y = c(cumsum(rnorm(60)) + 90,
cumsum(rnorm(60)) - 90,
cumsum(rnorm(60))),
row = rep(LETTERS[1:3], each = 60),
col = rep(LETTERS[1:3], each = 20)
)
ggplot(df, aes(x, y)) +
geom_line() +
facet_wrap(row ~ col, scales = "free_y") +
facetted_pos_scales(
y = rep(list(
scale_y_continuous(limits = c(90, 100)),
scale_y_continuous(limits = c(-100, -80)),
scale_y_continuous(limits = c(0, 20))
), each = 3)
)
I have a basic bar graph I've created from ggplot2. The y variable contains both positive and negative values and about half the vector of values are negative. I would like to customize the axis labels such that when the y value of that corresponding x factor is a negative, its label is red. Here's a reproducible example:
#Create data
x <- c("a","b","c","d","e","f")
y <- c("10", "9","-10","11","-3","-15")
data <- data.frame(x, y)
data$y <- as.numeric(as.character(data$y))
data$category <- ifelse(as.numeric(data$y)<0, 0, 1)
data$category <- as.factor(data$category)
#Graph
library(cowplot) #theme
library(ggplot2)
ggplot(data, aes(x=x, y=y)) +
geom_bar(stat = "identity", aes(fill=category)) +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
theme(axis.text.x = element_text(colour = "black"))
What I need is a way to change the label colors of "c", "e", and "f" to the color of my choosing. I tried toggling theme(aes(axis.text.x=element_text(colour=Air_pricier))) but that produced an error.
You can provide a vector of colors to the axis.text.x option of theme():
a <- ifelse(data$category == 0, "red", "blue")
ggplot(data, aes(x = x, y = y)) +
geom_bar(stat = "identity", aes(fill = category)) +
theme(axis.text.x = element_text(angle = 45, hjust = 1, colour = a))
I, too, get the warning message mentioned in #Mark Neal's comment; it makes me nervous. Here's an alternative approach with the ggtext package. You can wrap the categories for the x-axis in <span>s and specify the color you want, and then use element_markdown in the theme:
library(ggtext)
library(tidyverse)
data %>%
mutate(x.label = paste("<span style = 'color: ",
ifelse(y > 0, "black", "red"),
";'>",
x,
"</span>", sep = ""),
x.label = fct_reorder(x.label, as.character(x))) %>%
ggplot(aes(x=x.label, y=y)) +
geom_bar(stat = "identity", aes(fill=category)) +
theme(axis.text.x = element_markdown(angle = 45, hjust = 1))
Building on a-s-k's answer I put this in a more flexible form using glue templates and a discrete scale. With this option you don't have to change your data but just define a labeler in the scale that does everything for you, this is handy if you want to color the x-axis in many similar plots with different data.
(In the case of the original question the color depends on more of the data, than just the x-values, but I guess this could still be handy for some users.)
library(ggtext)
library(tidyverse)
library(glue)
#Create data
x <- c("a","b","c","d","e","f")
y <- c("10", "9","-10","11","-3","-15")
data <- data.frame(x, y)
data$y <- as.numeric(as.character(data$y))
data$category <- ifelse(as.numeric(data$y)<0, 0, 1)
data$category <- as.factor(data$category)
# create the labels
my_labels <- glue_data(
data,
"<span style='color: {if_else(category==0, 'red', 'blue')}'>{x}</span>"
)
names(my_labels) <- data$x
# plot as you normally would
# use element_markdown as axis.text.x
# and the labels defined before as labels in a discrete scale
ggplot(data, aes(x=x, y=y)) +
geom_bar(stat = "identity", aes(fill=category)) +
theme(
axis.text.x = element_markdown(angle = 45, hjust = 1)
) +
scale_x_discrete(labels=my_labels)
I want to explore the directlabels package with ggplot. I am trying to plot labels at the endpoint of a simple line chart; however, the labels are clipped by the plot panel. (I intend to plot about 10 financial time series in one plot and I thought directlabels would be the best solution.)
I would imagine there may be another solution using annotate or some other geoms. But I would like to solve the problem using directlabels. Please see code and image below. Thanks.
library(ggplot2)
library(directlabels)
library(tidyr)
#generate data frame with random data, for illustration and plot:
x <- seq(1:100)
y <- cumsum(rnorm(n = 100, mean = 6, sd = 15))
y2 <- cumsum(rnorm(n = 100, mean = 2, sd = 4))
data <- as.data.frame(cbind(x, y, y2))
names(data) <- c("month", "stocks", "bonds")
tidy_data <- gather(data, month)
names(tidy_data) <- c("month", "asset", "value")
p <- ggplot(tidy_data, aes(x = month, y = value, colour = asset)) +
geom_line() +
geom_dl(aes(colour = asset, label = asset), method = "last.points") +
theme_bw()
On data visualization principles, I would like to avoid extending the x-axis to make the labels fit--this would mean having data space with no data. Rather, I would like the labels to extend toward the white space beyond the chart box/panel (if that makes sense).
In my opinion, direct labels is the way to go. Indeed, I would position labels at the beginning and at the end of the lines, creating space for the labels using expand(). Also note that with the labels, there is no need for the legend.
This is similar to answers here and here.
library(ggplot2)
library(directlabels)
library(grid)
library(tidyr)
x <- seq(1:100)
y <- cumsum(rnorm(n = 100, mean = 6, sd = 15))
y2 <- cumsum(rnorm(n = 100, mean = 2, sd = 4))
data <- as.data.frame(cbind(x, y, y2))
names(data) <- c("month", "stocks", "bonds")
tidy_data <- gather(data, month)
names(tidy_data) <- c("month", "asset", "value")
ggplot(tidy_data, aes(x = month, y = value, colour = asset, group = asset)) +
geom_line() +
scale_colour_discrete(guide = 'none') +
scale_x_continuous(expand = c(0.15, 0)) +
geom_dl(aes(label = asset), method = list(dl.trans(x = x + .3), "last.bumpup")) +
geom_dl(aes(label = asset), method = list(dl.trans(x = x - .3), "first.bumpup")) +
theme_bw()
If you prefer to push the labels into the plot margin, direct labels will do that. But because the labels are positioned outside the plot panel, clipping needs to be turned off.
p1 <- ggplot(tidy_data, aes(x = month, y = value, colour = asset, group = asset)) +
geom_line() +
scale_colour_discrete(guide = 'none') +
scale_x_continuous(expand = c(0, 0)) +
geom_dl(aes(label = asset), method = list(dl.trans(x = x + .3), "last.bumpup")) +
theme_bw() +
theme(plot.margin = unit(c(1,4,1,1), "lines"))
# Code to turn off clipping
gt1 <- ggplotGrob(p1)
gt1$layout$clip[gt1$layout$name == "panel"] <- "off"
grid.draw(gt1)
This effect can also be achieved using geom_text (and probably also annotate), that is, without the need for direct labels.
p2 = ggplot(tidy_data, aes(x = month, y = value, group = asset, colour = asset)) +
geom_line() +
geom_text(data = subset(tidy_data, month == 100),
aes(label = asset, colour = asset, x = Inf, y = value), hjust = -.2) +
scale_x_continuous(expand = c(0, 0)) +
scale_colour_discrete(guide = 'none') +
theme_bw() +
theme(plot.margin = unit(c(1,3,1,1), "lines"))
# Code to turn off clipping
gt2 <- ggplotGrob(p2)
gt2$layout$clip[gt2$layout$name == "panel"] <- "off"
grid.draw(gt2)
Since you didn't provide a reproducible example, it's hard to say what the best solution is. However, I would suggest trying to manually adjust the x-scale. Use a "buffer" increase the plot area.
#generate data frame with random data, for illustration and plot:
p <- ggplot(tidy_data, aes(x = month, y = value, colour = asset)) +
geom_line() +
geom_dl(aes(colour = asset, label = asset), method = "last.points") +
theme_bw() +
xlim(minimum_value, maximum_value + buffer)
Using scale_x_discrete() or scale_x_continuous() would likely also work well here if you want to use the direct labels package. Alternatively, annotate or a simple geom_text would also work well.
I don't know the name of this type of plot (comments around this are welcomed). Essentially it is a barplot with glyphs that are filled to indicate a loss/gain. The glyph is arrow like encoding information about direction, magnitude, and allowing the bar geom under to be seen.
This looks interesting but can't think of how to do it in ggplot2 (grid frame work). How could we recreate this plot in ggplot2/grid framework (base solutions welcomed as well for completeness of question). Specifically the glyphs, not the text as this is pretty straight forward in ggplot2 already.
Here is some code to create data and traditional overlaid & coordinate flipped dodged bar plots and line graphs to show typical ways of visualizing this type of data.
set.seed(10)
x <- sample(30:60, 12)
y <- jitter(x, 60)
library(ggplot2)
dat <- data.frame(
year = rep(2012:2013, each=12),
month = rep(month.abb, 2),
profit = c(x, y)
)
ggplot() +
geom_bar(data=subset(dat, year==2012), aes(x=month, weight=profit)) +
geom_bar(data=subset(dat, year==2013), aes(x=month, weight=profit), width=.5, fill="red")
ggplot(dat, aes(x=month, fill=factor(year))) +
geom_bar(position="dodge", aes(weight=profit)) +
coord_flip
ggplot(dat, aes(x=month, y=profit, group = year, color=factor(year))) +
geom_line(size=1)
Here is an example, perhaps there are other ways though,
dat <- data.frame(
year = rep(2012:2013, each=12),
month = factor(rep(1:12, 2), labels=month.abb),
profit = c(x, y)
)
dat2 <- reshape2::dcast(dat, month~ year, value.var = "profit")
names(dat2)[2:3] <- paste0("Y", names(dat2)[2:3])
ggplot(dat2) +
geom_bar(aes(x=month, y = Y2012), stat = "identity", fill = "grey80", width = 0.6) +
geom_segment(aes(x=as.numeric(month)-0.4, xend = as.numeric(month)+0.4, y = Y2013, yend = Y2013)) +
geom_segment(aes(x = month, xend = month, y = Y2013, yend = Y2012, colour = Y2013 < Y2012),
arrow = arrow(60, type = "closed", length = unit(0.1, "inches")), size = 1.5) +
theme_bw()