Setting x-axis breaks to the negative of the x aesthetics - r

I would like to make a plot where the breaks along the x-axis are the negative of the actual values I plot. Something like this
df <- tibble(x = seq(-1000, 0, length.out = 100),
y = 2 * x + 3)
ggplot(df) +
geom_line(aes(x = x, y = y)) +
scale_x_continuous(breaks = df$x, labels = -df$x)
except that this puts a break at every x value and I would like the breaks to be what I would get using waiver(). I recall seeing a solution for this, but for the life of me I cannot remember what it is.

ggplot(df) +
geom_line(aes(x = x, y = y)) +
scale_x_continuous(breaks = pretty(df$x), labels = -pretty(df$x))
pretty is all you need.
Alternatively, just plot directly and use a reversed scale:
ggplot(df) +
geom_line(aes(x = -x, y = y)) +
scale_x_reverse()

Related

ggplot2 and log scale don't show values = 1

I want to plot a diagram with a log scales y axis:
data <- data.frame(x = seq_len(5), y = c(2,1,100,500,30))
ggplot(data) + aes(x,y) + geom_col() + scale_y_log10()
But because the horizontal axis always crosses the vertical axis at y = 1, the bar for y = 1 is never drawn.
I know that log(1) = 0, but can I set the plot base to 0.1 to let the bar start below 1?
Can't you just multiply the values of y by 10 but divide the labels by the same amount?
ggplot(data) + aes(x, y * 10) + geom_col() +
scale_y_log10(labels = function(x) x/10, name = "y")
You could do the same with a histogram:
set.seed(2)
ggplot(data.frame(x = rnorm(1000)), aes(x)) +
geom_histogram(aes(y = ..count.. * 10), color = "black", fill = "gold") +
scale_y_log10(labels = function(x) x/10, name = "count")
An alternative solution is to place the bottom of the bars at -Inf, so that the log10(1) still shows up. This is a bit tricky, because you have to reparameterise the bars as rectangles and get the geom to understand that the -Inf is after scale transformation.
library(ggplot2)
data <- data.frame(x = seq_len(5), y = c(2,1,100,500,30))
ggplot(data) +
geom_rect(
aes(xmin = x - 0.45, xmax = x + 0.45,
ymin = stage(1, after_scale = -Inf), ymax = y)
) +
scale_y_log10()
Created on 2020-11-03 by the reprex package (v0.3.0)

Force size aesthetic to scale to given breaks

I am creating several plots in order to create frames for a gif. It is supposed to show growing points over time. (see plot 1 and 2 - the values increase). Using size aesthetic is problematic, because the scaling is done for each plot individually.
I tried to set breaks with scale_size_area() to provide a sequence of absolute values, in order to scale on 'all values' rather than only the values present in each plot. (no success).
Plot 3 shows how the points should be scaled, but this scaling should be achieved in each plot.
library(tidyverse)
df1 <- data.frame(x = letters[1:5], y = 1:5, size2 = 21:25)
ggplot(df1, aes(x, y, size = y)) +
geom_point() +
scale_size_area(breaks = seq(0,25,1))
ggplot(df1, aes(x, y, size = size2)) +
geom_point() +
scale_size_area(breaks = seq(0,25,1))
df2 <- data.frame(x = letters[1:5], y = 1:5, size2 = 21:25) %>% gather(key, value, y:size2)
ggplot(df2, aes(x, value, size = value)) +
geom_point() +
scale_size_area(breaks = seq(0,25,1))
Created on 2019-05-12 by the reprex package (v0.2.1)
Pass lower and upper bound to limits argument in scale_size_area function:
ggplot(df1, aes(x, y, size = y)) +
geom_point() +
labs(
title = "Y on y-axis",
size = NULL
) +
scale_size_area(limits = c(0, 25))
ggplot(df1, aes(x, y, size = size2 )) +
geom_point() +
labs(
title = "size2 on y-axis",
size = NULL
) +
scale_size_area(limits = c(0, 25))
How about this?
library("ggplot2")
df1 <- data.frame(x = letters[1:5],
y = 1:5)
ggplot(data = df1,
aes(x = x,
y = y,
size = y)) +
geom_point() +
scale_size_area(breaks = seq(1,25,1),
limits = c(1, 25))

Detailed axis and legend in ggplot2

I'd like to put legend and more values in x limits.
test <- data.frame(x = runif(10), y = runif(10), mean_y = 0.1)
ggplot(test, aes(x = x, y = y)) + geom_point(color = 'red') +
geom_line(aes(x, mean_y))
Your question needs a bit more explanation and a reproducible example, but to get "more values in x limits" you can try adding
+ expand_limits(x = c(1, 1000))
Just replace the values in the vector by the ones that actually fit your needs.

How to make text appear in the corner of a ggplot with log scales

I usually use infinite values in the position aesthetics of ggplot text objects to make labels appear in the corner of the plot regardless of the data scale. I mainly use this when making multi-panel figures which should have letters in each panel to identify each panel in the figure legend. However, this does not seem to work with log scales if I want the label to appear on the left or bottom, since obviously transforming log(-Inf) returns NaN. Is there an easy fix for this? I could do a long workaround but I was hoping there is something easier. Example is below:
notlogdata <- data.frame(x = 1:3,y = 1:3)
ggplot(notlogdata, aes(x = x,y = y)) +
geom_point() +
geom_text(data = data.frame(x = -Inf, y = Inf, l = 'a'), aes(label = l), hjust = -0.5, vjust = 1)
logdata <- data.frame(x = 10^(1:3), y = 10^(1:3))
ggplot(logdata, aes(x = x,y = y)) +
geom_point() +
geom_text(data = data.frame(x = -Inf, y = Inf, l = 'a'), aes(label = l), hjust = -0.5, vjust = 1) +
scale_x_log10() +
scale_y_log10()
First plot with untransformed axes appears fine:
The second plot does not have a label and returns the warning:
Warning messages:
1: In self$trans$transform(x) : NaNs produced
2: Removed 1 rows containing missing values (geom_text).
annotation_custom(gTree(children=gList(textGrob("a", hjust=0,x=0,vjust=1,y=1))))
You can take a log of Inf --- log(Inf) is Inf. The issue is you can't take a log of a negative like -Inf. But log(0) is -Inf, so if you set x = 0 it will work as expected.
ggplot(logdata, aes(x = x,y = y)) +
geom_point() +
geom_text(
data = data.frame(x = 0, y = Inf, l = 'a'),
aes(label = l), hjust = -0.5, vjust = 1
) +
scale_x_log10() +
scale_y_log10()
It does not appear to be possible to use negative positioning aesthetics, including -Inf, on a log-transformed axis. Here is a solution using cowplot as suggested by zx8754
library(cowplot)
notlogdata <- data.frame(x = 1:3,y = 1:3)
notlogplot <- ggplot(notlogdata, aes(x = x,y = y)) +
geom_point()
logdata <- data.frame(x = 10^(1:3), y = 10^(1:3))
logplot <- ggplot(logdata, aes(x = x,y = y)) +
geom_point() +
scale_x_log10() +
scale_y_log10()
plot_grid(notlogplot, logplot, labels=c('a','b'), hjust=-8)
This outputs the plot below:

Setting individual y axis limits with facet wrap NOT with scales free_y

I have this data
library(ggplot2)
dat = data.frame(x = c(1,2,1,2),
group = c("a","a","b","b"),
y = c(10,20,1000,2000))
ggplot(dat, aes(x = x, y = y)) +
geom_point() +
geom_line() +
facet_wrap(~group, ncol = 1) +
coord_cartesian(ylim = c(0, 30))
You can see the B group does not show up because I set the y limit to 0,30. I want to manually set the individual y limits for each chart. I do NOT want to use scales = "free_y" because I need control over the limits in each chart.
Is there a way this can be done? Can you somehow supply y limits for each chart in a facet wrap?
Unless you want to decrease your plotting area (i.e. not plot some points), you can still have "full" control over your y limits while using scales = "free_y".
You can use the same trick I have given to answer your other question: how to set limits on rounded facet wrap y axis?
dat <- data.table(dat)
dat[,y_min := y*0.5, by = group]
dat[,y_max:= y*1.5, by = group]
ggplot(dat, aes(x = x, y = y)) +
geom_point() +
geom_line() +
facet_wrap(~group, ncol = 1, scales = "free_y") +
geom_blank(aes(y = y_min)) +
geom_blank(aes(y = y_max))
For others reading this question, trick is to explicitly create y_min and y_max variables for each group. And "plot" them via geom_blank(). (Nothing is actually plotted, but each facet's plotting area is adjusted based on y_min and y_max values for that group).
If for some reasons, you want to manually give min and max (instead of a rule), none is stopping you. But it is tedious:
dat[group == "a",y_min := 0]
dat[group == "a",y_max := 30]
dat[group == "b",y_min := 0]
dat[group == "b",y_max := 3000]
ggplot(dat, aes(x = x, y = y)) +
geom_point() +
geom_line() +
facet_wrap(~group, ncol = 1, scales = "free_y") +
geom_blank(aes(y = y_min)) +
geom_blank(aes(y = y_max))
But, as I have mentioned this works if you want to extend your limits, not decrease them.

Resources