how to append line graph above barplot in ggplot - r

I have dataframe which have column age, gender (Male/Female). I want to plot grouped bar plot by Age and want to append line plot of ratio of male to female of each age.
test is dataframe with age, gender as column
ratio_df is new data frame store ratio of male to female in each age
ratio_df <- ddply(test, 'age', function(x) c('ratio' = sum(test$gender == 'Male') / sum(test$gender == 'Female')))
ggplot with barplot and ratio line in ggplot
ggplot(data = test, aes(x = factor(age), fill = gender)) + geom_bar() + geom_line(data = ratio_df, aes(x = age, y = ratio))

As mentioned above, your ddply call seems off to me - I think it always yields the same ratio (over the whole dataframe). I could not figure out a compact elegant one from the top of my head so I had to resort to a somewhat clunky one but it does work.
EDIT: I changed the code to reflect the workaround described by http://rwiki.sciviews.org/doku.php?id=tips:graphics-ggplot2:aligntwoplots to adress the OP's comment.
#sample data
test=data.frame(gender=c("m","m","f","m","f","f","f"),age=c(1,3,4,4,3,4,4))
require(plyr)
age_N <- ddply(test, c("age","gender"), summarise, N=length(gender))
require(reshape2)
ratio_df <- dcast(age_N, age ~ gender, value.var="N", fill=0)
ratio_df$ratio <- ratio_df$m / (ratio_df$f+ratio_df$m)
#create variables for facetting
test$panel = rep("Distribution",length(test$gender))
ratio_df$panel = rep("Ratio",length(ratio_df$ratio))
test$panel <- factor(test$panel,levels=c("Ratio","Distribution"))
require(ggplot2)
g <- ggplot(data = test, aes(x = factor(age)))
g <- g + facet_wrap(~panel,scale="free",ncol=1)
g <- g + geom_line(data = ratio_df, aes(x = factor(age), y = ratio, group=1))
g <- g + geom_bar(aes(fill=gender))
print(g)
Is this what you are looking for? However, I think #SvenHohenstein is right that the line does not any information as the split is evident form the fill.

Related

How to plot multiple facets histogram with ggplot in r?

i have a dataframe structured like this
Elem. Category. SEZa SEZb SEZc
A. ONE. 1. 3. 4
B. TWO. 4. 5. 6
i want to plot three histograms in three different facets (SEZa, SEZb, SEZc) with ggplot where the x values are the category values (ONE. e TWO.) and the y values are the number present in columns SEZa, SEZb, SEZc.
something like this:
how can I do? thank you for your suggestions!
Assume df is your data.frame, I would first convert from wide format to a long format:
new_df <- reshape2::melt(df, id.vars = c("Elem", "Category"))
And then make the plot using geom_col() instead of geom_histogram() because it seems you've precomputed the y-values and wouldn't need ggplot to calculate these values for you.
ggplot(new_df, aes(x = Category, y = value, fill = Elem)) +
geom_col() +
facet_grid(variable ~ .)
I think that what you are looking for is something like this :
library(ggplot2)
library(reshape2)
df <- data.frame(Category = c("One", "Two"),
SEZa = c(1, 4),
SEZb = c(3, 5),
SEZc = c(4, 6))
df <- melt(df)
ggplot(df, aes(x = Category, y = value)) +
geom_col(aes(fill = variable)) +
facet_grid(variable ~ .)
My inspiration is :
http://felixfan.github.io/stacking-plots-same-x/

ggplot2: Different vlines for each graph using facet_wrap [duplicate]

I've poked around, but been unable to find an answer. I want to do a weighted geom_bar plot overlaid with a vertical line that shows the overall weighted average per facet. I'm unable to make this happen. The vertical line seems to a single value applied to all facets.
require('ggplot2')
require('plyr')
# data vectors
panel <- c("A","A","A","A","A","A","B","B","B","B","B","B","B","B","B","B")
instrument <-c("V1","V2","V1","V1","V1","V2","V1","V1","V2","V1","V1","V2","V1","V1","V2","V1")
cost <- c(1,4,1.5,1,4,4,1,2,1.5,1,2,1.5,2,1.5,1,2)
sensitivity <- c(3,5,2,5,5,1,1,2,3,4,3,2,1,3,1,2)
# put an initial data frame together
mydata <- data.frame(panel, instrument, cost, sensitivity)
# add a "contribution to" vector to the data frame: contribution of each instrument
# to the panel's weighted average sensitivity.
myfunc <- function(cost, sensitivity) {
return(cost*sensitivity/sum(cost))
}
mydata <- ddply(mydata, .(panel), transform, contrib=myfunc(cost, sensitivity))
# two views of each panels weighted average; should be the same numbers either way
ddply(mydata, c("panel"), summarize, wavg=weighted.mean(sensitivity, cost))
ddply(mydata, c("panel"), summarize, wavg2=sum(contrib))
# plot where each panel is getting its overall cost-weighted sensitivity from. Also
# put each panel's weighted average on the plot as a simple vertical line.
#
# PROBLEM! I don't know how to get geom_vline to honor the facet breakdown. It
# seems to be computing it overall the data and showing the resulting
# value identically in each facet plot.
ggplot(mydata, aes(x=sensitivity, weight=contrib)) +
geom_bar(binwidth=1) +
geom_vline(xintercept=sum(contrib)) +
facet_wrap(~ panel) +
ylab("contrib")
If you pass in the presumarized data, it seems to work:
ggplot(mydata, aes(x=sensitivity, weight=contrib)) +
geom_bar(binwidth=1) +
geom_vline(data = ddply(mydata, "panel", summarize, wavg = sum(contrib)), aes(xintercept=wavg)) +
facet_wrap(~ panel) +
ylab("contrib") +
theme_bw()
Example using dplyr and facet_wrap incase anyone wants it.
library(dplyr)
library(ggplot2)
df1 <- mutate(iris, Big.Petal = Petal.Length > 4)
df2 <- df1 %>%
group_by(Species, Big.Petal) %>%
summarise(Mean.SL = mean(Sepal.Length))
ggplot() +
geom_histogram(data = df1, aes(x = Sepal.Length, y = ..density..)) +
geom_vline(data = df2, mapping = aes(xintercept = Mean.SL)) +
facet_wrap(Species ~ Big.Petal)
vlines <- ddply(mydata, .(panel), summarize, sumc = sum(contrib))
ggplot(merge(mydata, vlines), aes(sensitivity, weight = contrib)) +
geom_bar(binwidth = 1) + geom_vline(aes(xintercept = sumc)) +
facet_wrap(~panel) + ylab("contrib")

how to get a stacked bar chart for a dummy variable

my column in a dataset look like this:
teacher student
y n
y n
y y
y n
y n
n n
n n
n y
y y
n y
y n
I used
barchart(data$teacher)
for a graph for teacher, which shows the frequency of y and n in two separate bars, but now I want to show y and n stacked for both variables, so one bar each variable. I tried many things like chart.StackedBar but they all didn't work. Thanks for any help!
Read the man pages, bro. This is what you want:
barplot(matrix(c(table(df$teacher), table(df$student)), ncol=2),
col=c('red', 'blue'),
names.arg=c('teacher', 'student'),
legend.text=c('y', 'n'))
EDIT: based on your comment, is this what you are looking for?
library(reshape2)
tmp <- melt(dat, id.vars = NULL)
names(tmp) <- c('Occupation', 'ID')
ggplot(data = tmp, aes(x = Occupation, fill= ID)) + geom_histogram()
ORIGINAL:
I've approached this type of graph using ggplot. Here is a simple example:
library(ggplot2)
set.seed(1618)
dat <- data.frame(teacher = sample(c('y','n'),10,replace=T),
student = sample(c('y','n'),10,replace=T))
ggplot(data = dat, aes(x = teacher, fill = student)) + geom_histogram()
You might also consider
ggplot(data = dat, aes(x = teacher, fill = student)) +
geom_histogram(alpha= .5, position = 'identity')
Which would look like:
If you can't tell, the second graph is just "overlaying" the bars rather than stacking them.
I'm not great at ggplot, but hopefully this helps a bit.

Plot two graphs in the same plot [duplicate]

This question already has answers here:
Plotting two variables as lines using ggplot2 on the same graph
(5 answers)
Closed 4 years ago.
The solution with ggplot in this question worked really well for my data. However, I am trying to add a legend and everything that I tried does not work...
For example, in the ggplot example in the above question, how I can add a legend to show that the red curve is related to "Ocean" and the green curve is related to "Soil"? Yes, I want to add text that I will define and it is not related to any other variable in my data.frame.
The example below is some of my own data...
Rate Probability Stats
1.0e-04 1e-04 891.15
1.0e-05 1e-04 690
...
etc (it's about 400 rows). And I have two data frames similar to the above one.
So My code is
g <- ggplot(Master1MY, aes(Probability))
g <- g + geom_point(aes(y=Master1MY$Stats), colour="red", size=1)
g <- g + geom_point(aes(y=Transposon1MY$Stats), colour="blue", size=1)
g + labs(title= "10,000bp and 1MY", x = "Probability", y = "Stats")
The plot looks like
I just want a red and blue legend saying "Master" and "Transposon"
Thanks!
In ggplot it is generally most convenient to keep the data in a 'long' format. Here I use the function melt from the reshape2 package to convert your data from wide to long format. Depending how you specify different aesthetics (size, shape, colour et c), corresponding legends will appear.
library(ggplot2)
library(reshape2)
# data from the example you were referring to, in a 'wide' format.
x <- seq(-2, 2, 0.05)
ocean <- pnorm(x)
soil <- pnorm(x, 1, 1)
df <- data.frame(x, ocean, soil)
# melt the data to a long format
df2 <- melt(data = df, id.vars = "x")
# plot, using the aesthetics argument 'colour'
ggplot(data = df2, aes(x = x, y = value, colour = variable)) + geom_line()
Edit, set name and labels of legend
# Manually set name of the colour scale and labels for the different colours
ggplot(data = df2, aes(x = x, y = value, colour = variable)) +
geom_line() +
scale_colour_discrete(name = "Type of sample", labels = c("Sea water", "Soil"))
Edit2, following new sample data
Convert your data, assuming its organization from your update, to a long format. Again, I believe you make your ggplot life easier if you keep your data in a long format. I relate every step with the simple example data which I used in my first answer. Please note that there are many alternative ways to rearrange your data. This is one way, based on the small (non-reproducible) parts of your data you provided in the update.
# x <- seq(-2, 2, 0.05)
# Master1MY$Probability
Probability <- 1:100
# ocean <- pnorm(x)
# Master1MY$Stats
Master1MY <- rnorm(100, mean = 600, sd = 20)
# soil <- pnorm(x,1,1)
# Transposon1MY$Stats
Transposon1MY <- rnorm(100, mean = 100, sd = 10)
# df <- data.frame(x, ocean, soil)
df <- data.frame(Probability, Master1MY, Transposon1MY)
# df2 <- melt(df, id.var = "x")
df2 <- melt(df, id.var = "Probability")
# default
ggplot(data = df2, aes(x = Probability, y = value, col = variable)) +
geom_point()
# change legend name and labels, see previous edit using 'scale_colour_discrete'
# set manual colours scale using 'scale_colour_manual'.
ggplot(data = df2, aes(x = Probability, y = value, col = variable)) +
geom_point() +
scale_colour_manual(values = c("red","blue"), name = "Type of sample", labels = c("Master", "Transposon"))

How can a line be overlaid on a bar plot using ggplot2?

I'm looking for a way to plot a bar chart containing two different series, hide the bars for one of the series and instead have a line (smooth if possible) go through the top of where bars for the hidden series would have been (similar to how one might overlay a freq polynomial on a histogram). I've tried the example below but appear to be running into two problems.
First, I need to summarize (total) the data by group, and second, I'd like to convert one of the series (df2) to a line.
df <- data.frame(grp=c("A","A","B","B","C","C"),val=c(1,1,2,2,3,3))
df2 <- data.frame(grp=c("A","A","B","B","C","C"),val=c(1,4,3,5,1,2))
ggplot(df, aes(x=grp, y=val)) +
geom_bar(stat="identity", alpha=0.75) +
geom_bar(data=df2, aes(x=grp, y=val), stat="identity", position="dodge")
You can get group totals in many ways. One of them is
with(df, tapply(val, grp, sum))
For simplicity, you can combine bar and line data into a single dataset.
df_all <- data.frame(grp = factor(levels(df$grp)))
df_all$bar_heights <- with(df, tapply(val, grp, sum))
df_all$line_y <- with(df2, tapply(val, grp, sum))
Bar charts use a categorical x-axis. To overlay a line you will need to convert the axis to be numeric.
ggplot(df_all) +
geom_bar(aes(x = grp, weight = bar_heights)) +
geom_line(aes(x = as.numeric(grp), y = line_y))
Perhaps your sample data aren't representative of the real data you are working with, but there are no lines to be drawn for df2. There is only one value for each x and y value. Here's a modifed version of your df2 with enough data points to construct lines:
df <- data.frame(grp=c("A","A","B","B","C","C"),val=c(1,2,3,1,2,3))
df2 <- data.frame(grp=c("A","A","B","B","C","C"),val=c(1,4,3,5,0,2))
p <- ggplot(df, aes(x=grp, y=val))
p <- p + geom_bar(stat="identity", alpha=0.75)
p + geom_line(data=df2, aes(x=grp, y=val), colour="blue")
Alternatively, if your example data above is correct, you can plot this information as a point with geom_point(data = df2, aes(x = grp, y = val), colour = "red", size = 6). You can obviously change the color and size to your liking.
EDIT: In response to comment
I'm not entirely sure what the visual for a freq polynomial over a histogram is supposed to look like. Are the x-values supposed to be connected to one another? Secondly, you keep referring to wanting lines but your code shows geom_bar() which I assume isn't what you want? If you want lines, use geom_lines(). If the two assumptions above are correct, then here's an approach to do that:
#First let's summarise df2 by group
df3 <- ddply(df2, .(grp), summarise, total = sum(val))
> df3
grp total
1 A 5
2 B 8
3 C 3
#Second, let's plot df3 as a line while treating the grp variable as numeric
p <- ggplot(df, aes(x=grp, y=val))
p <- p + geom_bar(alpha=0.75, stat = "identity")
p + geom_line(data=df3, aes(x=as.numeric(grp), y=total), colour = "red")

Resources