How to control aspect ratio with both continuous and discrete axes with geom_tile in ggplot2? - r

I want to produce a plot with ggplot2 and geom_tile(). I want the tiles to have same height and width, which seems to work fine if both x and y axis are discrete (as was discussed here: adjust ggplot2 geom tile height and width).
If I have values on the x axis that are interpreted as continuous, however, I either get a lot of grey space in the plot and no aspect ratio of 1 when I use a discrete scale for the x axis (MWE1), or I do get a plot without grey space with a continuous scale but still no aspect ratio of 1 (MWE2). (I would insert images but it seems it is not allowed because my reputation is not high enough.)
MWE1:
my <- data.frame(x=c(rep(c(0.1),3),rep(c(0.3),3),rep(c(0.5),3)),y=rep(c("frac(SP1)=0.5", "frac(SP1)=0.7", "frac(SP2)=0,3"),3),z=sample(seq(1:50),9))
p <- ggplot(my, aes(x, y)) + geom_tile(aes(fill = z)) +
scale_fill_gradient(low = "white",high = "steelblue") +
theme_grey() +
labs(x = "", y= "") +
scale_x_discrete(expand = c(0,0)) +
scale_y_discrete(expand = c(0,0)) +
coord_fixed(ratio=1) +
theme(axis.ticks = element_blank())
MWE2:
my <- data.frame(x=c(rep(c(0.1),3),rep(c(0.3),3),rep(c(0.5),3)),y=rep(c("frac(SP1)=0.5", "frac(SP1)=0.7", "frac(SP2)=0,3"),3),z=sample(seq(1:50),9))
p <- ggplot(my, aes(x, y)) + geom_tile(aes(fill = z)) +
scale_fill_gradient(low = "white",high = "steelblue") +
theme_grey() +
labs(x = "", y= "") +
scale_x_continuous(breaks=c(0.1,0.3,0.5),expand = c(0,0)) +
scale_y_discrete(expand = c(0,0)) +
coord_fixed(ratio=1) +
theme(axis.ticks = element_blank())
Is there a way that I can still control aspect ratio when dealing with discrete and continuous scale? Or a way to tell ggplot2 to interpret the x values as discrete?

I'm not sure I quite understand your question, but I think this is what you want:
p <- ggplot(my, aes(factor(x), y)) + geom_tile(aes(fill = z)) +
scale_fill_gradient(low = "white",high = "steelblue") +
theme_grey() +
labs(x = "", y= "") +
coord_fixed() +
theme(axis.ticks = element_blank())
print(p)
I converted your x variable to a factor since it's not really continuous anyways. Now you get a 3x3 heatmap:

Related

How to flip a geom_area to be under the line when using scale_y_reverse()

I had to flip the axis of my line, but still need the geom_area to be under the curve. However I cannot figure out how to do so.
This is the line of code I tried
ggplot(PalmBeachWell, aes(x=Date, y=Depth.to.Water.Below.Land.Surface.in.ft.)) +
geom_area(position= "identity", fill='lightblue') +
theme_classic() +
geom_line(color="blue") +
scale_y_reverse()
and here is what i got
One option would be to use a geom_ribbon to fill the area above the curve which after applying scale_y_reverse will result in a fill under the curve.
Using some fake example data based on the ggplot2::economics dataset:
library(ggplot2)
PalmBeachWell <- economics[c("date", "psavert")]
names(PalmBeachWell) <- c("Date", "Depth.to.Water.Below.Land.Surface.in.ft.")
ggplot(PalmBeachWell, aes(x = Date, y = Depth.to.Water.Below.Land.Surface.in.ft.)) +
geom_ribbon(aes(ymin = Depth.to.Water.Below.Land.Surface.in.ft., ymax = Inf),
fill = "lightblue"
) +
geom_line(color = "blue") +
scale_y_reverse() +
theme_classic()

ggplot geom_col won't dodge time series data

This is the code I am using -
g.volume <- ggplot (time_series, aes(x=quotedate, y=cv)) +
geom_col(position='dodge',fill='steelblue1', size=.8) +
geom_col(aes(x=quotedate, y=pv) ,position='dodge', fill='hotpink1', size=.8) +
labs(x = "", y = "Call / Put Volume") + theme_bw() +
theme(axis.ticks.x=element_blank(), axis.text.x=element_blank()) +
theme(panel.grid.major = element_line(colour = "grey", size=.5,linetype = 'dashed'))
The output is numerically correct but the two Y variables are stacked, not dodged side by side. None of the many examples on the web directly relate to time series data (X axis), but rather to a small number of categories/ My attempts to rotate the data were at best messy, and didn't work.
How about this, you melt your data and plot value
dat <- melt(df, id.vars = c("quotedate"))
ggplot(data=dat,aes(x= quotedate, y=value, fill=variable, color=variable)) +
geom_bar(stat="identity",position ="dodge")+
labs(x = "", y = "Call / Put Volume") + theme_bw() +
theme(axis.ticks.x=element_blank(), axis.text.x=element_blank()) +
theme(panel.grid.major = element_line(colour = "grey", size=.5,linetype = 'dashed'))

Controlling the total width of a barplot

How to get rid of all this space where the blue lines are?
Data:
data = data.frame(is_repeat = c(0,0,0,1,1,1,1,1,1,1),
value = c(12000,8000,20000,14000,15000,11000,20000,60000,20000, 20000))
data$is_repeat = factor(data$is_repeat, levels = c(0,1),
labels = c("One-time", "Repeat"))
Plot:
ggplot(data, aes(is_repeat, value)) +
geom_bar(stat = "identity", width = 0.3) +
ggtitle("Title") +
xlab("Type of event") +
ylab("Total Value") +
ylim(0, 150000) +
theme_minimal()
edit: I looked at that question and it did NOT solve my problem. My guess is that in the other question's plot, there are 4 bars, so it looks filled. I want to reduce the total width of the X axis.
another edit: Added data.
If you are looking to remove the space between the bars completely and you don't mind the width of bars you could do it with:
geom_bar(stat="identity", position="stack", width=1)
or theme(aspect.ratio=1)
And to remove the space from the end of the plot to the bars you need
scale_x_discrete(expand = c(0,0), limits=c("One-time", "Repeat"))
So your code looks like this:
ggplot(data, aes(is_repeat, value)) +
geom_bar(stat="identity", position="stack", width=1) +
ggtitle("Title") +
xlab("Type of event") +
ylab("Total Value") +
ylim(0, 150000) +
scale_x_discrete(expand = c(0,0), limits=c("One-time", "Repeat")) +
theme_minimal()
And the output:
You can add space between bars with changing the width=1

Vertical line in histogram in r

I'm struggeling a bit with a peace of code in R. I am trying to create 6 different histograms in the same figure. It works fine, but I need to place 1 vertical line in each of the 6 histograms. The code I am working with could look something like this:
require(ggplot2)
require(reshape2)
require(gdata)
MC_beta=rbind(rnorm(1000,-2,0.1),rnorm(1000,-1,0.1),rnorm(1000,0,0.1),rnorm(1000,0.5,0.1),rnorm(1000,1,0.1),rnorm(1000,2,0.1))
df <- data.frame(MC_beta[1,], MC_beta[2,], MC_beta[3,], MC_beta[4,],MC_beta[5,],MC_beta[6,])
names(df)[1:6]<-c("1", "2", "3", "4","5","6")
df2 = melt(df)
z=c(-2,-1,0,0.5,1,2)
ggplot(df2, aes(x=value, fill = variable)) + geom_vline(xintercept = z, colour="black") +geom_histogram(binwidth=0.03,colour = "black") + scale_fill_manual(name = "",values = c('red','blue',"red","blue","red","blue")) +
facet_wrap(~variable,nrow=6, ncol=1) + scale_x_continuous(breaks=seq(-2.5,2.5,0.5)) + guides(fill=FALSE) +
theme_bw() + theme(strip.background = element_blank(),axis.text=element_text(size=14.5),strip.text.x = element_text(size = 14.5)) + stat_function(fun = dnorm)
The problem is with the statement geom_vline(xintercept = z, colour = "black"). Apparently instead of placing one vertical line in each histogram, it places all 6 lines in each histogram. So instead, I want the first element in z to make a vertical line in the first histogram, the second element in z to make a vertical line in the second histogram and so fourth.
Thanks
Your z needs to be a data.frame with the corresponding xintercept for every value of the variable that defines the facet. Try these changes:
z <- data.frame(variable=levels(df2$variable),
mean=c(-2,-1,0,0.5,1,2))
ggplot(df2, aes(x=value, fill = variable))+
geom_vline(data=z, aes(xintercept = mean), colour="black") +
geom_histogram(binwidth=0.03,colour = "black") +
scale_fill_manual(name = "",values = c('red','blue',"red","blue","red","blue")) +
facet_wrap(~variable,nrow=6, ncol=1) +
scale_x_continuous(breaks=seq(-2.5,2.5,0.5))+ guides(fill=FALSE) +
theme_bw() +
theme(strip.background = element_blank(), axis.text=element_text(size=14.5), strip.text.x = element_text(size = 14.5)) +
stat_function(fun = dnorm)
I hope that helps.
You have z outside the data, so you will draw a vertical line in each facet. Use
df2 <- (merge(df2, cbind.data.frame(variable=names(df), z)))
and then
geom_vline(aes(xintercept = z), colour="black")

can one offset jitter points in ggplot boxplot

In a ggplot boxplot, it is easy to use jitter to add the raw data points with varying degrees of jitter. With zero jitter the following code
dat <- data.frame(group=c('a', 'b', 'c'), values = runif(90))
ggplot(dat, aes(group, values)) +
geom_boxplot(outlier.size = 0) +
geom_jitter(position=position_jitter(width=0), aes(colour=group), alpha=0.7) +
ylim(0, 1) + stat_summary(fun.y=mean, shape=3, col='red', geom='point') +
opts(legend.position = "right") + ylab("values") + xlab("group")
produces the plot below.
Is it possible to use zero jitter but add an offset such that the points are in a line but shifted left by 25% of the box width? I tried geom_point with dodge but this generated a jitter.
If we convert group to numeric and then add an offset, you seem to get your desired output. There is probably a more effective / efficient way, but give this a whirl:
ggplot(dat, aes(group, values)) +
geom_boxplot(outlier.size = 0) +
geom_point(aes(x = as.numeric(group) + .25, colour=group), alpha=0.7) +
ylim(0, 1) + stat_summary(fun.y=mean, shape=3, col='red', geom='point') +
opts(legend.position = "right") + ylab("values") + xlab("group")

Resources