Different axis limits per facet in ggplot2 - r

I am trying to make a faceted plot in ggplot2 where the y axis shows labels and the x axis should show line graphs with the value for each label in two different measures (which are on different scales). So far I have this:
Data <- structure(list(label = structure(
c(1L, 1L, 2L, 2L, 3L, 3L, 4L,
4L, 5L, 5L, 6L, 6L), .Label = c("A", "B", "C", "D", "E", "F"), class = "factor"),
facet = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L,
1L, 2L), .Label = c("A", "B"), class = "factor"), value = c(0.0108889081049711,
0.37984336540103, 0.0232500876998529, 0.777756493305787,
0.0552913920022547, 0.920194681268185, 0.0370863009011373,
0.114463779143989, 0.00536034172400832, 0.469208759721369,
0.0412159096915275, 0.587875489378348), group = c(1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1)), .Names = c("label", "facet",
"value", "group"), row.names = c(NA, -12L), class = "data.frame")
ggplot(Data, aes(x = label, y = value, group = group)) + geom_line() +
facet_grid(~ facet, scales = "free") + coord_flip()
Which creates the following plot:
The problem is that the measures are on different scales and I would prefer the A plot to have x limits from 0 to 0.1 and the B plot to have x limits from 0 to 1. I thought scales = "free" should fix this but it doesn't change the plot.

I came up with something similar to df239:
ggplot(Data, aes(y = label, x = value, group=group)) + geom_path() +
facet_wrap( ~ facet, scales = "free")
Note you have to use geom_path, and take care with the ordering of your points because just switching x and y is not the same as coord_flip (which as noted in the other answer isn't supported with facet_wrap).

Change axes orientation manually, the problem is: *ggplot2 does not currently support free scales with a non-cartesian coord or coord_flip.*
ggplot(Data, aes(y = label, x = value, group = group)) + geom_line() +
facet_grid(~ facet, scales = "free")

Related

Faceted ggplot boxplot with different X axes by column [duplicate]

I am trying to make a faceted plot in ggplot2 where the y axis shows labels and the x axis should show line graphs with the value for each label in two different measures (which are on different scales). So far I have this:
Data <- structure(list(label = structure(
c(1L, 1L, 2L, 2L, 3L, 3L, 4L,
4L, 5L, 5L, 6L, 6L), .Label = c("A", "B", "C", "D", "E", "F"), class = "factor"),
facet = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L,
1L, 2L), .Label = c("A", "B"), class = "factor"), value = c(0.0108889081049711,
0.37984336540103, 0.0232500876998529, 0.777756493305787,
0.0552913920022547, 0.920194681268185, 0.0370863009011373,
0.114463779143989, 0.00536034172400832, 0.469208759721369,
0.0412159096915275, 0.587875489378348), group = c(1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1)), .Names = c("label", "facet",
"value", "group"), row.names = c(NA, -12L), class = "data.frame")
ggplot(Data, aes(x = label, y = value, group = group)) + geom_line() +
facet_grid(~ facet, scales = "free") + coord_flip()
Which creates the following plot:
The problem is that the measures are on different scales and I would prefer the A plot to have x limits from 0 to 0.1 and the B plot to have x limits from 0 to 1. I thought scales = "free" should fix this but it doesn't change the plot.
I came up with something similar to df239:
ggplot(Data, aes(y = label, x = value, group=group)) + geom_path() +
facet_wrap( ~ facet, scales = "free")
Note you have to use geom_path, and take care with the ordering of your points because just switching x and y is not the same as coord_flip (which as noted in the other answer isn't supported with facet_wrap).
Change axes orientation manually, the problem is: *ggplot2 does not currently support free scales with a non-cartesian coord or coord_flip.*
ggplot(Data, aes(y = label, x = value, group = group)) + geom_line() +
facet_grid(~ facet, scales = "free")

qplot limit of facets [duplicate]

I am trying to make a faceted plot in ggplot2 where the y axis shows labels and the x axis should show line graphs with the value for each label in two different measures (which are on different scales). So far I have this:
Data <- structure(list(label = structure(
c(1L, 1L, 2L, 2L, 3L, 3L, 4L,
4L, 5L, 5L, 6L, 6L), .Label = c("A", "B", "C", "D", "E", "F"), class = "factor"),
facet = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L,
1L, 2L), .Label = c("A", "B"), class = "factor"), value = c(0.0108889081049711,
0.37984336540103, 0.0232500876998529, 0.777756493305787,
0.0552913920022547, 0.920194681268185, 0.0370863009011373,
0.114463779143989, 0.00536034172400832, 0.469208759721369,
0.0412159096915275, 0.587875489378348), group = c(1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1)), .Names = c("label", "facet",
"value", "group"), row.names = c(NA, -12L), class = "data.frame")
ggplot(Data, aes(x = label, y = value, group = group)) + geom_line() +
facet_grid(~ facet, scales = "free") + coord_flip()
Which creates the following plot:
The problem is that the measures are on different scales and I would prefer the A plot to have x limits from 0 to 0.1 and the B plot to have x limits from 0 to 1. I thought scales = "free" should fix this but it doesn't change the plot.
I came up with something similar to df239:
ggplot(Data, aes(y = label, x = value, group=group)) + geom_path() +
facet_wrap( ~ facet, scales = "free")
Note you have to use geom_path, and take care with the ordering of your points because just switching x and y is not the same as coord_flip (which as noted in the other answer isn't supported with facet_wrap).
Change axes orientation manually, the problem is: *ggplot2 does not currently support free scales with a non-cartesian coord or coord_flip.*
ggplot(Data, aes(y = label, x = value, group = group)) + geom_line() +
facet_grid(~ facet, scales = "free")

How to organize percentage values on top of a stacked bar chart ggplot2

I have a very skewed bar chart in ggplot2.
Here's the dput text output:
structure(list(Name = structure(c(1L, 3L, 4L, 5L, 6L, 2L, 1L,
3L, 4L, 5L, 6L, 2L), .Label = c("A", "Average", "B", "C", "D",
"E"), class = "factor"), variable = structure(c(1L, 1L, 1L, 1L,
1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("Undiscounted", "Discounted"
), class = "factor"), value = c(18453601.4400001, 11941354.11,
10748756.04, 6488253.74000001, 6078914.73000002, 2509377.50173653,
1157538776.56, 833907589.89, 674006380.96, 574466340.26, 534854603.27,
13191411.5509581)), row.names = c(NA, -12L), .Names = c("Name",
"variable", "value"), class = "data.frame")
Here's the code I use to plot it:
library(ggplot2)
text_size= 18
label_bottom_size=18
plot1<- ggplot(df1, aes(x = Name, y = value, fill = variable)) +
geom_bar(stat = "identity")+
ggtitle(sprintf("Bar chart of Stuff" ))+
theme(axis.title=element_text(size=text_size))+
theme(plot.title=element_text(size=text_size+20))+
theme(axis.text.x= element_text(size=label_bottom_size))+
theme(axis.text.y= element_text(size=text_size))+
theme(legend.text = element_text(size=text_size))+
theme(legend.title = element_text(size=text_size))
As some of the bar charts are so small and text doesn't fit, what I want to do is just have a (X%/Y%) above each bar that shows the percentage breakout. The values shown are in dollars.
Thank you!
This is some hack using data.table for aggregating the data and then displaying it with geom_text (there are probably better ways though)
library(data.table)
temp <- data.table(df1)[, per := (value/sum(value))*100, by = Name]
temp <- temp[, list(value = sum(value),
per = paste(sprintf("%.02f%%", per), collapse = " / "),
variable = variable), by = Name]
library(ggplot2)
text_size= 18
label_bottom_size=18
ggplot(df1, aes(x = Name, y = value, fill = variable)) +
geom_bar(stat = "identity")+
ggtitle(sprintf("Bar chart of Stuff" ))+
theme(axis.title=element_text(size=text_size),
plot.title=element_text(size=text_size+20),
axis.text.x= element_text(size=label_bottom_size),
axis.text.y= element_text(size=text_size),
legend.text = element_text(size=text_size),
legend.title = element_text(size=text_size)) +
geom_text(data = temp, aes(x = Name, y = value, label = per), vjust=-0.3)

ggplot2 + gridExtra: how to ensure geom_bar in different size plot grobs result in exact same bar width

This question is motivated by further exploring this question. The problem with the accepted solution becomes more obvious when there is a greater disparity in the number of bars per facet. Take a look at this data and the resultant plot using that solution:
# create slightly contrived data to better highlight width problems
data <- data.frame(ID=factor(c(rep(1,9), rep(2,6), rep(3,6), rep(4,3), rep(5,3))),
TYPE=factor(rep(1:3,length(ID)/3)),
TIME=factor(c(1,1,1,2,2,2,3,3,3,1,1,1,2,2,2,1,1,1,2,2,2,1,1,1,1,1,1)),
VAL=runif(27))
# implement previously suggested solution
base.width <- 0.9
data$w <- base.width
# facet two has 3 bars compared to facet one's 5 bars
data$w[data$TIME==2] <- base.width * 3/5
# facet 3 has 1 bar compared to facet one's 5 bars
data$w[data$TIME==3] <- base.width * 1/5
ggplot(data, aes(x=ID, y=VAL, fill=TYPE)) +
facet_wrap(~TIME, ncol=1, scale="free") +
geom_bar(position="stack", aes(width = w),stat = "identity") +
coord_flip()
You'll notice the widths look exactly right, but the whitespace in facet 3 is quite glaring. There is no easy way to fix this in ggplot2 that I have seen yet (facet_wrap does not have a space option).
Next step is to try to solve this using gridExtra:
# create each of the three plots, don't worry about legend for now
p1 <- ggplot(data[data$TIME==1,], aes(x=ID, y=VAL, fill=TYPE)) +
facet_wrap(~ TIME, ncol=1) +
geom_bar(position="stack", show_guide=FALSE) +
coord_flip()
p2 <- ggplot(data[data$TIME==2,], aes(x=ID, y=VAL, fill=TYPE)) +
facet_wrap(~ TIME, ncol=1) +
geom_bar(position="stack", show_guide=FALSE) +
coord_flip()
p3 <- ggplot(data[data$TIME==3,], aes(x=ID, y=VAL, fill=TYPE)) +
facet_wrap(~ TIME, ncol=1) +
geom_bar(position="stack", show_guide=FALSE) +
coord_flip()
# use similar arithmetic to try and get layout correct
require(gridExtra)
heights <- c(5, 3, 1) / sum(5, 3, 1)
print(arrangeGrob(p1 ,p2, p3, ncol=1,
heights=heights))
You'll notice I used the same arithmetic previously suggested based off the number of bars per facet, but in this case it ends up horribly wrong. This seems to be because there are extra "constant height" elements that I need to take into consideration in the math.
Another complication (I believe) is that the final output (and whether or not the widths match) will also depend on the width and height of where I'm outputting the final grob to, whether its in a R/RStudio environment, or to a PNG file.
How can I accomplish this?
Something like this appear to work, but it doesn't - not completely. It has the appearance of working because the levels of the ID factor are sequential. Anything else, and scale = "free" fails. But it might be possible to develop further. The method uses facet_grid, and thus space = "free" can be used. The method uses geom_rect to layer differently coloured rectangles on top of each other. It needs cumulative sums to be calculated so that the right-hand edge of each rectangle can be positioned.
data <- data.frame(ID=factor(c(rep(1,9), rep(2,6), rep(3,6), rep(4,3), rep(5,3))),
TYPE=factor(rep(1:3,3)),
TIME=factor(c(1,1,1,2,2,2,3,3,3,1,1,1,2,2,2,1,1,1,2,2,2,1,1,1,1,1,1)),
VAL=runif(27))
library(ggplot2)
library(plyr)
# Get the cumulative sums
data = ddply(data, .(ID, TIME), mutate, CUMSUMVAL = cumsum(VAL))
ggplot(data, aes(x=VAL, y = as.numeric(ID), fill=TYPE)) +
geom_rect(data = subset(data, TYPE == 3), aes(xmin = 0, xmax = CUMSUMVAL, ymin = as.numeric(ID)-.2, ymax = as.numeric(ID)+.2)) +
geom_rect(data = subset(data, TYPE == 2), aes(xmin = 0, xmax = CUMSUMVAL, ymin = as.numeric(ID)-.2, ymax = as.numeric(ID)+.2)) +
geom_rect(data = subset(data, TYPE == 1), aes(xmin = 0, xmax = CUMSUMVAL, ymin = as.numeric(ID)-.2, ymax = as.numeric(ID)+.2)) +
facet_grid(TIME~., space = "free", scale="free") +
scale_y_continuous(breaks = c(1:5), expand = c(0, 0.2))
EDIT: OR really thick lines work a little better (I think)
ggplot(data, aes(x=VAL, y = ID, colour=TYPE)) +
geom_segment(data = subset(data, TYPE == 3), aes(x = 0, xend = CUMSUMVAL, y = ID, yend = ID), size = 10) +
geom_segment(data = subset(data, TYPE == 2), aes(x = 0, xend = CUMSUMVAL, y = ID, yend = ID), size = 10) +
geom_segment(data = subset(data, TYPE == 1), aes(x = 0, xend = CUMSUMVAL, y = ID, yend = ID), size = 10) +
facet_grid(TIME~., space = "free", scale="free")
Additional Edit Taking the data from your earleir post, and modifying it a little.
Updated opts is deprecated; using theme instead.
df <- structure(list(ID = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L,
2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 5L,
5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L), .Label = c("a",
"b", "c", "d", "e", "f", "g"), class = "factor"), TYPE = structure(c(1L,
2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L, 4L, 5L, 6L,
1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L, 4L,
5L, 6L, 1L, 2L, 3L), .Label = c("1", "2", "3", "4", "5", "6",
"7", "8"), class = "factor"), TIME = structure(c(2L, 2L, 2L,
2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 3L, 3L, 3L, 3L, 3L,
1L, 1L, 1L), .Label = c("One", "Five", "Fifteen"), class = "factor"), VAL = c(0.937377670081332,
0.522220720537007, 0.278690102742985, 0.967633064137772, 0.116124767344445,
0.0544306698720902, 0.470229141646996, 0.62017166428268, 0.195459847105667,
0.732876230962574, 0.996336271753535, 0.983087373664603, 0.666449476964772,
0.291554537601769, 0.167933790013194, 0.860138458199799, 0.172361251665279,
0.833266809117049, 0.620465772924945, 0.786503327777609, 0.761877260869369,
0.425386636285111, 0.612077651312575, 0.178726130630821, 0.528709076810628,
0.492527724476531, 0.472576208412647, 0.0702785139437765, 0.696220921119675,
0.230852259788662, 0.359884874196723, 0.518227979075164, 0.259466265095398,
0.149970305617899, 0.00682218233123422, 0.463400925742462, 0.924704828299582,
0.229068386601284)), .Names = c("ID", "TYPE", "TIME", "VAL"), row.names = c(NA,
-38L), class = "data.frame")
library(ggplot2)
library(plyr)
data = ddply(df, .(ID, TIME), mutate, CUMSUMVAL = cumsum(VAL))
ggplot(data, aes(x=VAL, y = ID, colour=TYPE)) +
geom_segment(data = subset(data, TYPE == 6), aes(x = 0, xend = CUMSUMVAL, y = ID, yend = ID), size = 10) +
geom_segment(data = subset(data, TYPE == 5), aes(x = 0, xend = CUMSUMVAL, y = ID, yend = ID), size = 10) +
geom_segment(data = subset(data, TYPE == 4), aes(x = 0, xend = CUMSUMVAL, y = ID, yend = ID), size = 10) +
geom_segment(data = subset(data, TYPE == 3), aes(x = 0, xend = CUMSUMVAL, y = ID, yend = ID), size = 10) +
geom_segment(data = subset(data, TYPE == 2), aes(x = 0, xend = CUMSUMVAL, y = ID, yend = ID), size = 10) +
geom_segment(data = subset(data, TYPE == 1), aes(x = 0, xend = CUMSUMVAL, y = ID, yend = ID), size = 10) +
facet_grid(TIME~., space = "free", scale="free") +
theme(strip.text.y = element_text(angle = 0))
Changing the gtable doesn't help, unfortunately, as the bar width is in relative units,
g = ggplot_gtable(ggplot_build(p))
panels = which(sapply(g$heights, attr, "unit") == "null")
g$heights[[panels[1]]] <- unit(5, "null")
g$heights[[panels[2]]] <- unit(3, "null")
g$heights[[panels[3]]] <- unit(1, "null")
grid.draw(g)

Alignment of numbers on the individual bars

I have the need to place labels above bars on ggplot. I used to use the method found (HERE) but this does not appear to work anymore since my ggplot2 update as I now get the error message:
Error in continuous_scale(c("y", "ymin", "ymax", "yend", "yintercept", :
unused argument(s) (formatter = "percent")
How can I again plot numeric values above the bars when using the example:
df <- structure(list(A = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L,
3L), .Label = c("0-50,000", "50,001-250,000", "250,001-Over"), class = "factor"),
B = structure(c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), .Label = c("0-50,000",
"50,001-250,000", "250,001-Over"), class = "factor"), Freq = c(0.507713884992987,
0.258064516129032, 0.23422159887798, 0.168539325842697, 0.525280898876405,
0.306179775280899, 0.160958904109589, 0.243150684931507,
0.595890410958904)), .Names = c("A", "B", "Freq"), class = "data.frame", row.names = c(NA,
-9L))
library(ggplot2)
ggplot(data=df, aes(x=A, y=Freq))+
geom_bar(aes(fill=B), position = position_dodge()) +
geom_text(aes(label = paste(sprintf("%.1f", Freq*100), "%", sep=""),
y = Freq+0.015, x=A),
size = 3, position = position_dodge(width=0.9)) +
scale_y_continuous(formatter = "percent") +
theme_bw()
Running R 2.15 ggplot2 0.9 on a win 7 machine
The error is from the scale_y_continuous call. Formatting of labels is now handled by the labels argument. See the ggplot2 0.9.0 transition guide for more details.
There was another problem with the labels not lining up correctly; I fixed that by adding a group=B to the aesthetics for the geom_text; I'm not quite sure why this is necessary, though. I also took out x=A from the geom_text aesthetics because it was not needed (it would be inherited from the ggplot call.
library("ggplot2")
library("scales")
ggplot(data=df, aes(x=A, y=Freq))+
geom_bar(aes(fill=B), position = position_dodge()) +
geom_text(aes(label = paste(sprintf("%.1f", Freq*100), "%", sep=""),
y = Freq+0.015, group=B),
size = 3, position = position_dodge(width=0.9)) +
scale_y_continuous(labels = percent) +
theme_bw()

Resources