This is a continuation of the question here: Create non-overlapping stacked area plot with ggplot2
I have a ggplot2 area chart created by the following code. I want the labels from names be aligned on the right side of the graph. I think directlabels might work, but am willing to try whatever is most clever.
require(ggplot2)
require(plyr)
require(RColorBrewer)
require(RCurl)
require(directlabels)
link <- getURL("http://dl.dropbox.com/u/25609375/so_data/final.txt")
dat <- read.csv(textConnection(link), sep=' ', header=FALSE,
col.names=c('count', 'name', 'episode'))
dat <- ddply(dat, .(episode), transform, percent = count / sum(count))
# needed to make geom_area not freak out because of missing value
dat2 <- rbind(dat, data.frame(count = 0, name = 'lane',
episode = '02-tea-leaves', percent = 0))
g <- ggplot(arrange(dat2,name,episode), aes(x=episode,y=percent)) +
geom_area(aes(fill=name, group = name), position='stack') + scale_fill_brewer()
g1 <- g + geom_dl(method='last.points', aes(label=name))
I'm brand new to directlabels and not really sure how to get the labels to align to right side of the graph with the same colors as the areas.
You can use simple geom_text to add labels. First, subset you data set to get the final x value:
dd=subset(dat, episode=="06-at-the-codfish-ball")
Then order the data frame by factor level:
dd = dd[with(dd, order(name, levels(dd$name))),]
Then work out the cumulative percent for plotting:
dd$cum = cumsum(dd$percent)
Then just use a standard geom_text call:
g + geom_text(data=dd, aes(x=6, y=cum, label=name))
Oh, and you may want to angle your x-axis labels to avoid over plotting:
g + opts(axis.text.x=theme_text(angle=-25, hjust=0.5, size = 8))
Graph
Related
I would like to have a separate scale bar for each variable.
I have measurements taken throughout the water column for which the means have been calculated into 50cm bins. I would like to use geom_tile to show the variation of each variable in each bin throughout the water column, so the plot has the variable (categorical) on the x-axis, the depth on the y-axis and a different colour scale for each variable representing the value. I am able to do this for one variable using
ggplot(data, aes(x=var, y=depth, fill=value, color=value)) +
geom_tile(size=0.6)+ theme_classic()+scale_y_continuous(limits = c(0,11), expand = c(0, 0))
But if I put all variables onto one plot, the legend is scaled to the min and max of all values so the variation between bins is lost.
To provide a reproducible example, I have used the mtcars, and I have included alpha = which, of course, doesn't help much because the scale of each variable is so different
data("mtcars")
# STACKS DATA
library(reshape2)
dat2b <- melt(mtcars, id.vars=1:2)
dat2b
ggplot(dat2b) +
geom_tile(aes(x=variable , y=cyl, fill=variable, alpha = value))
Which produces
Is there a way I can add a scale bar for each variable on the plot?
This question is similar to others (e.g. here and here), but they do not use a categorical variable on the x-axis, so I have not been able to modify them to produce the desired plot.
Here is a mock-up of the plot I have in mind using just four of the variables, except I would have all legends horizontal at the bottom of the plot using theme(legend.position="bottom")
Hope this helps:
The function myfun was originally posted by Duck here: R ggplot heatmap with multiple rows having separate legends on the same graph
library(purrr)
library(ggplot2)
library(patchwork)
data("mtcars")
# STACKS DATA
library(reshape2)
dat2b <- melt(mtcars, id.vars=1:2)
dat2b
#Split into list
List <- split(dat2b,dat2b$variable)
#Function for plots
myfun <- function(x)
{
G <- ggplot(x, aes(x=variable, y=cyl, fill = value)) +
geom_tile() +
theme(legend.direction = "vertical", legend.position="bottom")
return(G)
}
#Apply
List2 <- lapply(List,myfun)
#Plot
reduce(List2, `+`)+plot_annotation(title = 'My plot')
patchwork::wrap_plots(List2)
I am trying to combine a line plot and horizontal barplot on the same plot. The difficult part is that the barplot is actually counts of the y values of the line plot.
Can someone show me how this can be done using the example below ?
library(ggplot2)
library(plyr)
x <- c(1:100)
dff <- data.frame(x = x,y1 = sample(-500:500,size=length(x),replace=T), y2 = sample(3:20,size=length(x),replace=T))
counts <- ddply(dff, ~ y1, summarize, y2 = sum(y2))
# line plot
ggplot(data=dff) + geom_line(aes(x=x,y=y1))
# bar plot
ggplot() + geom_bar(data=counts,aes(x=y1,y=y2),stat="identity")
I believe what I need is presented in the pseudocode below but I do not know how to write it out in R.
Apologies. I actually meant the secondary x axis representing the value of counts for the barplot, while primary y-axis is the y1.
ggplot(data=dff) + geom_line(aes(x=x,y=y1)) + geom_bar(data=counts , aes(primary y axis = y1,secondary x axis =y2),stat="identity")
I just want the barplots to be plotted horizontally, so I tried the code below which flip both the line chart and barplot, which is also not I wanted.
ggplot(data=dff) +
geom_line(aes(x=x,y=y1)) +
geom_bar(data=counts,aes(x=y2,y=y1),stat="identity") + coord_flip()
You can combine two plots in ggplot like you want by specifying different data = arguments in each geom_ layer (and none in the original ggplot() call).
ggplot() +
geom_line(data=dff, aes(x=x,y=y1)) +
geom_bar(data=counts,aes(x=y1,y=y2),stat="identity")
The following plot is the result. However, since x and y1 have different ranges, are you sure this is what you want?
Perhaps you want y1 on the vertical axis for both plots. Something like this works:
ggplot() +
geom_line(data=dff, aes(x=y1 ,y = x)) +
geom_bar(data=counts,aes(x=y1,y=y2),stat="identity", color = "red") +
coord_flip()
Maybe you are looking for this. Ans based on your last code you look for a double axis. So using dplyr you can store the counts in the same dataframe and then plot all variables. Here the code:
library(ggplot2)
library(dplyr)
#Data
x <- c(1:100)
dff <- data.frame(x = x,y1 = sample(-500:500,size=length(x),replace=T), y2 = sample(3:20,size=length(x),replace=T))
#Code
dff %>% group_by(y1) %>% mutate(Counts=sum(y2)) -> dff2
#Scale factor
sf <- max(dff2$y1)/max(dff2$Counts)
# Plot
ggplot(data=dff2)+
geom_line(aes(x=x,y=y1),color='blue',size=1)+
geom_bar(stat='identity',aes(x=x,y=Counts*sf),fill='tomato',color='black')+
scale_y_continuous(name="y1", sec.axis = sec_axis(~./sf, name="Counts"))
Output:
I'm trying to plot a line graph (data points between 0 and 2.5, with interval of 0.5). I want to plot some bars in the same chart on the right-hand axis (between 0 and 60 with interval of 10). I am making some mistake in my code such that the bars get plotted in the left hand axis.
Here's some sample data and code:
Month <- c("J","F","M","A")
Line <- c(2.5,2,0.5,3.4)
Bar <- c(30,33,21,40)
df <- data.frame(Month,Line,Bar)
ggplot(df, aes(x=Month)) +
geom_line(aes(y = Line,group = 1)) +
geom_col(aes(y=Bar))+
scale_y_continuous("Line",
sec.axis = sec_axis(trans= ~. /50, name = "Bar"))
Here's the output
Thanks in advance.
Try this approach with scaling factor. It is better if you work with a scaling factor between your variables and then you use it for the second y-axis. I have made slight changes to your code:
library(tidyverse)
#Data
Month <- c("J","F","M","A")
Line <- c(2.5,2,0.5,3.4)
Bar <- c(30,33,21,40)
df <- data.frame(Month,Line,Bar)
#Scale factor
sfactor <- max(df$Line)/max(df$Bar)
#Plot
ggplot(df, aes(x=Month)) +
geom_line(aes(y = Line,group = 1)) +
geom_col(aes(y=Bar*sfactor))+
scale_y_continuous("Line",
sec.axis = sec_axis(trans= ~. /sfactor, name = "Bar"))
Output:
I made two heatmaps with the code:
I create the first heatmap
heatmap1<-ggplot(mod_mat_constraint, aes(x=Categorie, y=label)) +
geom_tile(aes(fill=Value)) + scale_fill_manual(values = c("#86d65e","#404040","#86d65e","#40c5e8","#e84a4a","#86d65e","#404040","#e2e2e2"), breaks=label_text)
I create the second heatmap
heatmap2<-ggplot(mod_mat_gen_env, aes(x=Categorie, y=label)) +
geom_tile(aes(fill=Value)) + scale_fill_manual(values = c("#86d65e","#404040","#86d65e","#40c5e8","#e84a4a","#86d65e","#404040","#e2e2e2"), breaks=label_text)
and I add them with a tree with:
heatmap2 %>% insert_left(tree) %>% insert_right(heatmap1, width=.5)
which gives me:
and I wondered if there were a way with ggplot2 to add an additional df box at the right corner such as:
from a dataframe called DF1
COL1 COL2 COL3
0.1 Peter USA
Hard to help precisely without a dataset, but to get a table overlaid on your plot, probably the best way would be to use annotation_custom() with a tableGrob() from the gridExtra package.
Here's an example heatmap pulled right from the R Graph Gallery which I used to add in your table as a grob.
# Library
library(ggplot2)
library(gridExtra)
# Dummy data
x <- LETTERS[1:20]
y <- paste0("var", seq(1,20))
data <- expand.grid(X=x, Y=y)
data$Z <- runif(400, 0, 5)
# Heatmap
p <- ggplot(data, aes(X, Y, fill= Z)) +
geom_tile()
df <- data.frame(COL1=0.1,COL2='Peter',COL3='USA')
# adding the table
p + coord_cartesian(clip='off') +
theme(plot.margin = margin(r=140)) +
annotation_custom(
grob=tableGrob(df, theme=ttheme_default(base_size = 7)),
xmin=20, xmax=27, ymin=1, ymax=5
)
You can probably use a similar approach in your case. Note the few things that I had to do here to get this to work:
add the grob as annotation_custom(). You will need to play around with the positioning... really just play with those numbers. Also note you may want to play with the base size to ensure the table is the right aspect ratio compared to your plot.
Extend the plot margin so that you have the real estate on that side to include the table.
Turn clipping off so that you can see things outside the plot area properly.
I am working in the updated ggplot2 (2.2.0). A great new feature is the ability to plot along each x-axis for an uneven number of plots, as per this page.
I wish to plot with the same x-axis in each facet. However, this does not work when missing data is introduced. As an example, I shall draw upon the example data in this question.
# Example dataset
dataf <- data.frame(x=c(1:30), A=rnorm(30,20,5), B=rnorm(30,15,0.5))
datam <- melt(dataf, id="x")
# Plot in ggplot2
ggplot(datam, aes(factor(x), value)) +
geom_bar(stat="identity") +
facet_wrap(~variable,nrow = 2,scales = "free")
When I remove particular rows and introduce missing data (as per my code below), I am no longer to have the same x-axis labels for both "A" and "B".
# Remove certain rows to introduce missing data
datam <- datam[-c(2, 4, 58), ]
I can plot missing values and align to the bottom x-axis using scales = fixed although I no longer have x-axis tick mark labels for group "A" in the facet.
ggplot(datam, aes(factor(x), value)) +
geom_bar(stat="identity") +
facet_wrap(~variable,nrow = 2,scales = "fixed")
How do have the exact same x-axis labels showing for every facet, even when there is missing data?
Thank you.
You could do something like:
library(reshape2)
library(ggplot2)
dataf <- data.frame(x=c(1:30), A=rnorm(30,20,5), B=rnorm(30,15,0.5))
datam <- melt(dataf, id="x")
datam2 <- datam[-c(2, 4, 58), ] #mising rows
graph<-ggplot(datam2, aes(factor(x), value)) +
geom_bar(stat="identity") +
facet_wrap(~variable,nrow = 2,scales = "fixed")
library(gtable)
library(grid)
g <- ggplotGrob(graph) #retrieve grob from graph
panels <- grep("panel", g$layout$name)
top <- unique(g$layout$t[panels])
all <- gtable:::rbind_gtable(gtable:::rbind_gtable(g[seq.int(min(top)), ],
g[max(top)+1,], "first"),
g[seq(min(top)+1, nrow(g)),], "first")
grid.newpage()
grid.draw(all)
Pretty sure that a solution I found on SO at some point. But can't remember the original post.
Here is a solution using only ggplot2 functionality. There is a drop parameter in scale_x_discreet' and scale_y_discreet' when set to FALSE, it shows all factors regardless if no data exist for that factor.
See ? scale_x_discreet. The first step is to factor datam$x.
library(ggplot2)
dataf <- data.frame(x=c(1:30), A=rnorm(30,20,5), B=rnorm(30,15,0.5))
datam <- melt(dataf, id="x")
# missing data
datam <- datam[-c(2, 4, 58), ]
# solution
ggplot(datam, aes(factor(x), value)) +
geom_bar(stat="identity") +
facet_wrap(~variable,nrow = 2, scales = "free") +
scale_x_discrete(drop=FALSE)