R ggplot set origin when using a log scale - r

The last line in the following code sets the origin of the plot at zero for the y-scale and the y-scale's limits. How do I do this for the x-scale when using a log10 grid?
breaks <- 10^(-10:10) # break for major axis
minor_breaks <- rep(1:9, 21)*(10^rep(-10:10, each = 9)) # breaks for minor axis
ggplot(data = cars, aes(x = dist, y = speed)) +
geom_point() +
scale_x_log10(breaks = breaks, minor_breaks = minor_breaks) + # use log10 scale for x
theme(panel.grid.major = element_line(colour = "grey50")) +
theme(panel.grid.minor = element_line(colour = "grey70")) +
theme_light(base_size = 12) +
scale_y_continuous(expand = c(0, 0), limits = c(0,30)) # sets origin and limits for y-scale

I suggest using a modified transformation, pseudo_log_trans, which accommodates zero values (and even negatives) by smoothly transitioning between a linear scale in [-1, 1] and a signed log scale beyond that range. The approximate point of transition can be modified using the first parameter, sigma.
ggplot(data = cars, aes(x = dist, y = speed)) +
geom_point() +
scale_x_continuous(trans = scales::pseudo_log_trans(1)) +
theme(panel.grid.major = element_line(colour = "grey50")) +
theme(panel.grid.minor = element_line(colour = "grey70")) +
theme_light(base_size = 12) +
coord_cartesian(expand = FALSE, # EDIT #2
xlim = c(0, 130), ylim = c(0, 30))
Here's how it transitions between the linear and log scales:
plot(scales::pseudo_log_trans(), xlim = c(-5, 10))
lines(scales::log_trans(), xlim = c(-5, 10), col = "red")

Related

Limit the X and Y axes of ggplot2 plot

I'm using secondary axes (scaled) to show metric/imperial units for a plot. I'd like to have the plot area to be limited to (1500,0) and (5000,350) - both sets in principal coordinates. I've tried the following:
xlim(c(1500,5000)) + ylim(c(0,350))
lims with the same arguments as above
coord_cartesian(xlim = c(1500, 5000), ylim = c(0, 350))
None of these made any change to my plot. I'd like to get rid of the areas highlighted by the red lines (crop the plot):
Here's a minimal working example using mtcars - despite specifying the upper x-limit to be 10, the plot shows data past that range. I'd like the plot to cropped to the limits specified. Is there a way to do this?
ggplot(as.data.table(mtcars)) +
geom_line(aes(x = wt, y = mpg, color= factor(cyl))) +
ylab('Fuel Economy (mpg)') +
scale_y_continuous(sec.axis = sec_axis(~.*1.6/3.7854, name = 'Fuel Economy (kmpl)')) +
xlab('Weight (lbs)') +
scale_x_continuous(sec.axis = sec_axis(~./2.20462, name = 'Weight (kg)'), position = 'bottom') +
theme_light() +
theme(
legend.position = c(0.15, 0.75),
legend.title = element_blank(),
axis.title.y.right = element_text(
angle = 90,
margin = margin(r = 0.8 * 11,
l = 0.8 * 11 / 2)
)
) +
coord_cartesian(xlim = c(0, 5), ylim = c(10, 35))
Add limits and expand arguments in scale_x_continuous and scale_y_continuous. You can add breaks as well.
ggplot(as.data.table(mtcars)) +
geom_line(aes(x = wt, y = mpg, color= factor(cyl))) +
ylab('Fuel Economy (mpg)') +
scale_y_continuous(limits = c(10, 35), expand = c(0, 0),
sec.axis = sec_axis(~.*1.6/3.7854, name = 'Fuel Economy (kmpl)')
) +
xlab('Weight (lbs)') +
scale_x_continuous(limits = c(0, 5), expand = c(0, 0),
sec.axis = sec_axis(~./2.20462, name = 'Weight (kg)'), position = 'bottom') +
theme_light() +
theme(
legend.position = c(0.15, 0.75),
legend.title = element_blank(),
axis.title.y.right = element_text(
angle = 90,
margin = margin(r = 0.8 * 11,
l = 0.8 * 11 / 2)
)
)

Setting only certain tick marks in Ggplot2

I want to recreate the following plot which only shows tick marks on y and x axis at the start and the end of the line.
Picture of Plot.
I have the following code so far:
elevation_plot <- StradeBianche%>%
ggplot(aes(x = `Accumulated Distance in Km`))+
geom_area(aes(y = elevation), fill = "grey")+
coord_cartesian(ylim = c(100,500))+
scale_y_continuous(expand = c(0,0), limits = c(0, 500), labels = label_number(suffix = " m"))+
scale_x_continuous(expand = c(0,0), breaks = seq(0, 180, 20), labels = label_number(suffix = ".0 km"))+
theme(panel.grid.minor = element_blank())+
theme(panel.grid.major = element_blank())+
theme(panel.background = element_rect(fill = "white"))+
theme(panel.border = element_blank())+
theme(axis.title = element_blank())+
theme(axis.ticks = element_blank())
The result is this:Picture of result. It comes quite close but the ticks are still missing...
I can either remove all axis ticks or none. But I can not manage to set only certain axis ticks without removing the x and y values along the axis.
Any help is greatly appreciated!
You could use the pretty_breaks function from the scales library:
ggplot(dat, aes(x,y)) + geom_point() +
scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) +
scale_y_continuous(breaks = scales::pretty_breaks(n = 10))
Where n defines the number of ticks
Check out https://stackoverflow.com/a/31408489/15235792
You can immitate ticks behaviour if you place geom_segment()s at the right coordinates and turn off the clipping of the data. The downside is that you cannot place the segment endpoints relative to the first in absolute units, so you'd have to fiddle with the offset and text margins. Example below:
library(ggplot2)
xlim <- c(1, 5)
ylim <- c(4, 8)
offset <- 0.05
seg <- data.frame(
x = xlim[c(1,2,1,1)],
xend = xlim[c(1,2,1,1)] - c(0, 0, offset, offset),
y = ylim[c(1,1,2,1)],
yend = ylim[c(1,1,2,1)] - c(offset, offset, 0, 0)
)
ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
geom_point(aes(colour = Species)) +
geom_segment(data = seg, aes(x = x, y = y, xend = xend, yend = yend)) +
coord_cartesian(clip = "off",
xlim = xlim,
ylim = ylim,
expand = FALSE) +
theme(axis.ticks = element_blank(),
axis.line = element_line(),
axis.text.x = element_text(margin = margin(t = 8)),
axis.text.y = element_text(margin = margin(r = 8)))
Created on 2021-03-25 by the reprex package (v1.0.0)

Log scale on y axis but data have negative values

I am trying to create a boxplot with a log y axis as I have some very small values and then some much higher values which do not work well in a boxplot with a continuous y axis. However, I have negative values which obviously do not work with a log scale. I was wondering if there was a way around this so that I can display my data on a boxplot which is still easy to interpret but has a more appropriate scale on the y axis.
p <- ggplot(data = Elstow.monthly.fluxes, aes(x = Month1, y = CH4.Flux)) + stat_boxplot(geom = "errorbar", linetype = 1, width = 0.5) + geom_boxplot() +
xlab(expression("Month")) + ylab(expression(~CH[4]~Flux~(µg~CH[4]~m^{-2}~d^{-1}))) +
scale_y_continuous(breaks = seq(-5000,40000,5000), limits = c(-5000,40000))+
theme(axis.text.x = element_text(colour = "black")) + theme(axis.text.y = element_text(colour =
"black")) +
theme(panel.background = element_rect("white", "black")) +
theme(panel.border = element_rect(colour = "black", fill=NA, size=0.5)) +
theme(axis.text = element_text(size = 12))+ theme(axis.title = element_text(size = 14))+
theme(axis.title.y = element_text(margin = margin(t = 0, r = 15, b = 0, l = 0))) +
theme(axis.title.x = element_text(margin = margin(t = 15, r = 0, b = 0, l = 0))) +
geom_hline(yintercept = 0, linetype ="dashed", colour = "black")
While you could indeed use the secondary axis to get the labels you want as Zhiqiang suggests, you could also use a transformation that fits your needs.
Consider the following skewed boxplots:
df <- data.frame(
x = rep(letters[1:2], each = 500),
y = rlnorm(1000) - 2
)
ggplot(df, aes(x, y)) +
geom_boxplot()
Instead, you could use the pseudo-log transformation to visualise your data:
ggplot(df, aes(x, y)) +
geom_boxplot() +
scale_y_continuous(trans = scales::pseudo_log_trans())
Alternatively, you could make any transformation you want. I personally like the inverse hyperbolic sine transformation, which is very much like the pseudo-log:
asinh_trans <- scales::trans_new(
"inverse_hyperbolic_sine",
transform = function(x) {asinh(x)},
inverse = function(x) {sinh(x)}
)
ggplot(df, aes(x, y)) +
geom_boxplot() +
scale_y_continuous(trans = asinh_trans)
I have a silly solution: trick the secondary axis to re-scale y axis. I do not have your data, just made up some numbers for the purpose of demonstration.
First convert y values as logy = log(y + 5000). When generating the graph, transform the values back to the original scale. I borrow the second axis to display the values. I am pretty sure others may have more elegant ways to do this.
I was lazy for not trying to find the right way to remove the primary y axis tick labels, just used breaks = c(0).
df<-data.frame(y = runif(33, min=-5000, max=40000),
x = rep(c("Aug", "Sep", "Oct"),33))
library(tidyverse)
df$logy = log(df$y+5000)
p <- ggplot(data = df, aes(x = x, y = logy)) +
stat_boxplot(geom = "errorbar", linetype = 1, width = 0.5) +
geom_boxplot() +
xlab(expression("Month")) +
ylab(expression(~CH[4]~Flux~(µg~CH[4]~m^{-2}~d^{-1}))) +
scale_y_continuous(sec.axis = sec_axis(~(exp(.) -5000),
breaks = c(-4000, 0, 5000, 10000, 20000, 40000)),
breaks = c(0))+
theme(axis.text.x = element_text(colour = "black")) +
theme(axis.text.y = element_text(colour = "black")) +
theme(panel.background = element_rect("white", "black")) +
theme(panel.border = element_rect(colour = "black", fill=NA, size=0.5)) +
theme(axis.text = element_text(size = 12))+
theme(axis.title = element_text(size = 14))+
theme(axis.title.y = element_text(margin = margin(t = 0, r = 15, b = 0, l = 0))) +
theme(axis.title.x = element_text(margin = margin(t = 15, r = 0, b = 0, l = 0))) +
geom_hline(yintercept = log(5000), linetype ="dashed", colour = "black")
p
coord_trans() is applied after the statistics are calculated (unlike scale). This can be combined with the pseudo_log_trans to cope with negatives.
library(plotly)
set.seed(1234)
dat <- data.frame(cond = factor(rep(c("A","B"), each=200)), rating = c(rnorm(200),rnorm(200, mean=500)))
pseudoLog <- scales::pseudo_log_trans(base = 10)
p <- ggplot(dat, aes(x=cond, y=rating)) + geom_boxplot() + coord_trans(y=pseudoLog)

ordering y axis ggplot2()

I'm trying to reorder the y axis numbers in a ggplot2 graph (see the example below). By default it is ordered by only considering the first number and I want it reordered in ascending order.
plot <- ggplot(top.OTUs.abun.melt, aes(C, test, size = SA)) +
geom_point(aes(size = SA / 110), shape = 21) +
scale_size_identity(trans = "sqrt", breaks = c(100, 1000, 5000, 20000)) +
theme(panel.grid.major = element_line(linetype = 2, color = "black", size = 0.025),
axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.2)) +
scale_y_discrete(expand = c(0, 2.5))
plot2 <- plot + guides(colour = guide_legend(override.aes = list(size = 5)))
plot2
no no, that's not the solution here. You are not plotting factors; you're plotting numerics. This is what you want to do before plotting:
top.OTUs.abun.melt$test <- as.numeric(as.character(top.OTUs.abun.melt$test))

How to make data points equal to 0 appear on axis using ggplot? [duplicate]

This question already has answers here:
Avoid clipping of points along axis in ggplot
(4 answers)
Closed 6 years ago.
I am trying to make my data points that are equal to 0 appear on the x axis and avoid having data points cut by the axis.
I also want to keep my origin as it is (same 0 for both axis).
Here is my graph:
I used this to obtain the origin at 0 and to set the limits of my axis:
scale_y_continuous(limits = c(0, 40), expand = c(0, 0))+
scale_x_continuous(limits = c(0, 30), expand = c(0, 0))
If I change the limit of y for
scale_y_continuous(limits = c(-1, 40))
it also changes the origin...
Here is all I my code in case you need it:
require(ggplot2)
myplot<-ggplot(data=NULL,aes(x = Length, y = Complete)) +
geom_point(data = C,shape=1, size=3)+
geom_point(data = T, size=3)+
scale_y_continuous(limits = c(0, 40), expand = c(0, 0))+
scale_x_continuous(limits = c(0, 30), expand = c(0, 0))+
xlab("Inflorescence Length (cm)")+
ylab("Successful Weevils")+
theme_bw() +
theme(panel.border = element_blank())+
theme(panel.grid.major = element_blank())+
theme(panel.grid.minor = element_blank())+
theme(axis.text=element_text(size=12))+
theme(axis.title=element_text(size=14,face="bold"))+
theme(axis.line.x=element_line())+
theme(axis.line.y=element_line())+
theme(plot.margin = unit(c(1,1,1,1), "cm"))+
stat_smooth(data = C, method = lm, se=FALSE, color="grey")+
stat_smooth(data = T, method = lm, se=FALSE, color="black")
myplot
Thank you!
You have to turn off clipping:
library(grid)
library(ggplot2)
df <- data.frame(x=1:1000, y=runif(1000))
p <- ggplot(df, aes(x,y)) + geom_point() + scale_y_continuous(limits = c(0,1), expand=c(0,0))
gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name=="panel"] <- "off"
grid.draw(gt)

Resources