How to plot chart by ggplot2 with fixed scale? - r

I need to draw different kind of pics using ggplot2 in R and it have to be in proper scale when I print it. It means that I have to define exact image and chart size, the same scale of x/y-axes.
Could you please advice me what kind of options I should to use?
ggplot(Surface, aes(x, y, z = z)) +
geom_contour_filled(binwidth = 10, alpha = 0.6) +
geom_textcontour(binwidth = 20, size = 2.5)

Maybe you want to use coord_fixed with ratio argument:
aspect ratio, expressed as y / x
Here is your code:
library(ggplot2)
ggplot(Surface, aes(x, y, z = z)) +
geom_contour_filled(binwidth = 10, alpha = 0.6) +
geom_textcontour(binwidth = 20, size = 2.5) +
coord_fixed(ratio = 2/1)

If you mean geom_text_contour from metR package then we could do:
This example is taken from here How to add labels in a contour plot using ggplot2? (credits #bbiasi)
library(metR)
library(tidyverse)
library(data.table)
v <- data.table::melt(volcano)
ggplot(v, aes(Var1, Var2)) +
ggplot2::geom_contour(aes(z = value))+
metR::geom_text_contour(aes(z = value))
# adding ggsave with width and height
ggsave("test_myplot.png", width = 9, height = 7)

Related

ggplot density function not correct (normal percent from Stata)

I am trying to replicate the hist normal percent. The problem is that the density plot (or normal distribution) is completely off:
library(scales)
library(ggplot2)
a <- data.frame(rnorm(100,0,1))
colnames(a) <- c("test")
ggplot(a,aes(test)) +
geom_histogram(aes(y=(..count..)/sum(..count..))) +
scale_y_continuous(labels=scales::percent) +
stat_function(fun='dnorm')
The line should be much closer to the graph, but instead it is scaled by a factor of about 10.
Not familiar with that command from Stata, but is this what you want? Density with bar height scaled so that the total area integrates to 1, like the normal curve you showed. The reason your attempt doesn't work is because you didn't account for the bin width; each bin contributes area of the width times the count. You can do this manually if you set the bin width, or you can just use the computed ..density.. variable.
library(ggplot2)
set.seed(12345)
a <- data.frame(test = rnorm(100, 0, 1))
ggplot(a, aes(x = test)) +
geom_histogram(aes(y = ..count.. / (sum(..count..) * 0.2)), binwidth = 0.2) +
scale_y_continuous(labels = scales::percent) +
stat_function(fun = "dnorm")
ggplot(a, aes(x = test)) +
geom_histogram(aes(y = ..density..), binwidth = 0.2) +
scale_y_continuous(labels = scales::percent) +
stat_function(fun = "dnorm")
Created on 2018-08-27 by the reprex package (v0.2.0).

ggplot - Find coordinates of facet spacing

I have, e.g., the following plot:
library(ggplot2)
dat = data.frame(x = rnorm(100), y = rexp(100), grp = factor(sample(1:2, 100, replace = TRUE)))
ggplot(dat, aes(x = x, y = y, color = grp)) +
geom_point() +
facet_wrap(~grp) +
theme(panel.spacing = unit(2, "lines"))
and want to add a vertical line between the two plots - that is, in the middle of the panel spacing. My problem is, I am not sure of how to get the coordinates of the inner plot edges / the panel spacing in native units.
Both panels have unit 0.5 npc -- and I am not sure how I would convert this. I tried using viewports, but that did not work. Is there a way other than arranging plot 1 - plot of vertical line - plot 2 ?
Is this what you had in mind? You can tweak around with the parameter to change the position where the line will appear.
# loading the libraries
library(ggplot2)
library(grid)
library(cowplot)
# preparing the data
dat = data.frame(x = rnorm(100),
y = rexp(100),
grp = factor(sample(1:2, 100, replace = TRUE)))
# preparing the plot
plot <- ggplot(dat, aes(x = x, y = y, color = grp)) +
geom_point() +
facet_wrap( ~ grp) +
theme(panel.spacing = unit(2, "lines"))
# preparing the line
gline <- grid::linesGrob(x = 0.5)
# plotting both the plot and the line
cowplot::ggdraw() +
cowplot::draw_plot(plot) +
cowplot::draw_plot(gline)
Created on 2018-01-24 by the reprex
package (v0.1.1.9000).
library(grid)
library(gtable)
library(magrittr)
ggplotGrob(p) %>%
gtable_add_grob(segmentsGrob(0.5, 0, 0.5, 1),
t = 4, b = 8, l = 7, r = 7) %>%
grid.draw()
enter image description here

Transforming the y-axis without changing raw data in ggplot2

I have a question about how to transform the y-axis in ggplot2. My plot now has two lines and a scatter plot. For the scatter plot, I am very interested in the area around zero. Is there a possible way to enlarge the space between 0% and 5% and narrow the space between 20% and 30%?
I have tried to use coord_trans(y = "log10") to transform into a log form. But in this case, I have a lot of negative values, so if I want to use sqrt or log, the negative values will be removed. Do you have any suggestions?
Example of data points:
df1 = data.frame(y = runif(200,min = -1, max = 1))
df1 = data.frame( x= seq(1:200), y = df1[order(abs(df1$y)),])
ggplot(df1) +
geom_point(colour = "black",aes(x,y) ,size = 0.1)
I want to have more space between 0% and 5 % and less space between 5% and 30%.
I have tried to use trans_new() to transform the axes.
eps <- 1e-8
tn <- trans_new("logpeps",
function(x) (x+eps)^(3),
function(y) ((y)^(1/3) ),
domain=c(- Inf, Inf)
)
ggplot(df1)+ geom_point(colour = "black",aes(x,y) ,size = 0.1) +
# xlab("Observations sorted by PD in v3.1") + ylab("Absolute PD difference ") +
# ggtitle("Absolute PD for RiskCalc v4.0 relative to v3.1") +
scale_x_continuous(breaks = seq(0, round(rownum/1000)*1000, by = round(rownum/100)*10)) +
scale_y_continuous(limits = c(-yrange,yrange),breaks = c(-breaksY,breaksY),
sec.axis = sec_axis(~.,breaks = c(-breaksY[2:length(breaksY)],breaksY), labels = scales:: percent
)) +
# geom_line(data = df, aes(x,y[,3], colour = "blue"),size = 1) +
# geom_line(data = ds,aes(xval, yval,colour = "red"),size = 1) +
coord_trans(y = tn) +
scale_color_discrete(name = element_blank())
But it compresses the plot to the center, which is opposite to what I want. Then I try to use y = y^3, but it shows an
ERROR: zero_range(range)
Try a cube root transform on the y values:
aes(y=yVariable^(1/3))
or use trans_new() to define a new transformation (such as cube root, with pleasing breaks and labels).
A couple thoughts:
You can remove the empty edges of the plot like so:
scale_y_continuous(expand = c(0,0))
If you want to try the log transformation, just do:
scale_y_log10()
If you want to focus the window:
scale_y_continuous(limits=c(-.15,.15), expand=c(0,0))
Also consider adding theme_bw() for a cleaner look

Know proportions of ggplot2 plot

I usually save the plots from ggplot2 using the the png device. The width and the height of the output are set by the arguments of the function. Blank zones are drawn when the "natural proportions" of the graph dont't suit the proportions of the device. In order to avoid this and use the whole defined canvas, the proportions of the plot must be known. ¿Is there a way to find out this value without trial and error?
This code can be used as an example:
x <- seq(from = 0, to = 1, by = 0.1)
y <- seq(from = 1, to = 2, by = 0.1)
df <- expand.grid(x = x, y = y)
df <- cbind(df, z = rnorm(ncol(df), 0, 1))
p <- ggplot(df, aes(x,y, fill = z)) + geom_raster() + coord_fixed()
ppi <- 300
#Value 0.4 is used to change inches into milimeters
png("plot.png", width = 16*0.4*ppi, height = 20*0.4*ppi, res = ppi)
print(p)
dev.off()
It can be seen that some blank space is added at the top and at the bottom to fill the png file. This could be easily corrected by using a proportion different from 20/16, which is not optimal.
You can modify the ratio arg inside coord_fixed():
p <- ggplot(df, aes(x,y, fill = z)) +
geom_raster() +
coord_fixed(ratio = 20/16)
Alteratively you can specify the aspect.ratio inside the theme():
p <- ggplot(df, aes(x,y, fill = z)) +
geom_raster() +
theme(aspect.ratio = 20/16)
The result is the same:

R: How to spread (jitter) points with respect to the x axis?

I have the following code snippet in R:
dat <- data.frame(cond = factor(rep("A",10)),
rating = c(1,2,3,4,6,6,7,8,9,10))
ggplot(dat, aes(x=cond, y=rating)) +
geom_boxplot() +
guides(fill=FALSE) +
geom_point(aes(y=3)) +
geom_point(aes(y=3)) +
geom_point(aes(y=5))
This particular snippet of code produces a boxplot where one point goes over another (in the above case one point 3 goes over another point 3).
How can I move the point 3 so that the point remains in the same position on the y axis, but it is slightly moved left or right on the x axis?
This can be achieved by using the position_jitter function:
geom_point(aes(y=3), position = position_jitter(w = 0.1, h = 0))
Update:
To only plot the three supplied points you can construct a new dataset and plot that:
points_dat <- data.frame(cond = factor(rep("A", 3)), rating = c(3, 3, 5))
ggplot(dat, aes(x=cond, y=rating)) +
geom_boxplot() +
guides(fill=FALSE) +
geom_point(aes(x=cond, y=rating), data = points_dat, position = position_jitter(w = 0.05, h = 0))
ggplot2 now includes position_dodge(). From the help's description: "Dodging preserves the vertical position of an geom while adjusting the horizontal position."
Thus you can either use it as geom_point(position = position_dodge(0.5)) or, if you want to dodge points that are connected by lines and need the dodge to the be the same across both geoms, you can use something like:
dat <- data.frame(cond = rep(c("A", "B"), each=10), x=rep(1:10, 2), y=rnorm(20))
dodge <- position_dodge(.3) # how much jitter on the x-axis?
ggplot(dat, aes(x, y, group=cond, color=cond)) +
geom_line(position = dodge) +
geom_point(position = dodge)
ggplot2 now has a separate geom for this called geom_jitter so you don't need the position = dodge or position = position_dodge()) argument. Here applied to OP's example:
dat <- data.frame(cond = factor(rep("A",10)),
rating = c(1,2,3,4,6,6,7,8,9,10))
ggplot(dat, aes(x=cond, y=rating)) +
geom_boxplot() +
guides(fill=FALSE) +
geom_jitter(aes(y=c(3, 3, 5)))

Resources