How to annotate lines like this in ggplot2? - r

See example:
I hope I don't need to manually assign the coordinators of the texts. If this is too complicated to achieve in ggplot2, what are the alternatives in R? Or maybe even not in R?

As #Axeman says, ggrepel is a decent option. Unfortunately it will only avoid overlap with other labels, and not the lines, so the solution isn't quite perfect.
library(ggplot2)
install.packages("ggrepel")
library(ggrepel)
set.seed(50)
d <- data.frame(y = c(rnorm(50), rnorm(50, 5), rnorm(50, 10)),
x = rep(seq(50), times = 3),
group = rep(LETTERS[seq(3)], each = 50))
ggplot(d, aes(x, y, group = group, label = group)) +
geom_line() +
geom_text_repel(data = d[d$x == sample(d$x, 1), ], size = 10)

Related

How to produce a similar plot? [R]

The authors of this paper (https://www.sciencedirect.com/science/article/pii/S0092867415006418) mention in their supplementary file that these were produced in Matlab. Due to lack of proficiency, time to learn it, and the license, I was trying to replicate the figure below (Figure 2 of the paper, specifically figure 2A on the left) in R:
Any suggestions? What is this plot called more generally?
Thank you!
To me it looks like a classic point plot! You can reproduce this kind of plot in R with ggplot:
# Fake dataframe with xy coordinates, type of data (for the coloring), pvalue (for size), and different panel
df <- data.frame(
x = rep(1:20, 10),
y = rnorm(200, mean = 0, sd = 2),
type = rep(rep(LETTERS[1:5], each = 4), 10),
pvalue = sample(0:50, size = 200, replace = T)/1000,
panel = sample(rep(paste0("panel", 1:4), each = 50)), 200, replace = F)
# plot
library(ggplot2)
ggplot(df, aes(x, y*x , color = type, size = pvalue)) + geom_hline(yintercept = 0) + geom_point() + facet_wrap(~panel, ncol = 2)
ggsave("demo.png")

breaks at integer powers of ten on ggplot2 log10 axes

Transforming ggplot2 axes to log10 using scales::trans_breaks() can sometimes (if the range is small enough) produce un-pretty breaks, at non-integer powers of ten.
Is there a general purpose way of setting these breaks to occur only at 10^x, where x are all integers, and, ideally, consecutive (e.g. 10^1, 10^2, 10^3)?
Here's an example of what I mean.
library(ggplot2)
# dummy data
df <- data.frame(fct = rep(c("A", "B", "C"), each = 3),
x = rep(1:3, 3),
y = 10^seq(from = -4, to = 1, length.out = 9))
p <- ggplot(df, aes(x, y)) +
geom_point() +
facet_wrap(~ fct, scales = "free_y") # faceted to try and emphasise that it's general purpose, rather than specific to a particular axis range
The unwanted result -- y-axis breaks are at non-integer powers of ten (e.g. 10^2.8)
p + scale_y_log10(
breaks = scales::trans_breaks("log10", function(x) 10^x),
labels = scales::trans_format("log10", scales::math_format(10^.x))
)
I can achieve the desired result for this particular example by adjusting the n argument to scales::trans_breaks(), as below. But this is not a general purpose solution, of the kind that could be applied without needing to adjust anything on a case-by-case basis.
p + scale_y_log10(
breaks = scales::trans_breaks("log10", function(x) 10^x, n = 1),
labels = scales::trans_format("log10", scales::math_format(10^.x))
)
Should add that I'm not wed to using scales::trans_breaks(), it's just that I've found it's the function that gets me closest to what I'm after.
Any help would be much appreciated, thank you!
Here is an approach that at the core has the following function.
breaks = function(x) {
brks <- extended_breaks(Q = c(1, 5))(log10(x))
10^(brks[brks %% 1 == 0])
}
It gives extended_breaks() a narrow set of 'nice numbers' and then filters out non-integers.
This gives us the following for you example case:
library(ggplot2)
library(scales)
#> Warning: package 'scales' was built under R version 4.0.3
# dummy data
df <- data.frame(fct = rep(c("A", "B", "C"), each = 3),
x = rep(1:3, 3),
y = 10^seq(from = -4, to = 1, length.out = 9))
ggplot(df, aes(x, y)) +
geom_point() +
facet_wrap(~ fct, scales = "free_y") +
scale_y_continuous(
trans = "log10",
breaks = function(x) {
brks <- extended_breaks(Q = c(1, 5))(log10(x))
10^(brks[brks %% 1 == 0])
},
labels = math_format(format = log10)
)
Created on 2021-01-19 by the reprex package (v0.3.0)
I haven't tested this on many other ranges that might be difficult, but it should generalise better than setting the number of desired breaks to 1. Difficult ranges might be those just in between -but not including- powers of 10. For example 11-99 or 101-999.

Plot unsimilar data with ggplot

I am trying to plot the different lines, but one of the observations is far more beyond the normal scale.
library(ggplot2)
library(reshape)
library(dplyr)
a = matrix(rnorm(50, 0, 1), ncol=5)
b = c(rnorm(5, 0, 2), rnorm(5,20,2))
dt = data.frame(a,b)
rownames(dt) = paste0('Day',1:10)
colnames(dt) = c('A','B','C','D','E','F')
mdt = melt(as.matrix(dt), varnames=c('Date', 'Model'))
head(mdt)
ggplot(mdt, aes(x=Date, y=value, group=Model, color=Model))+
geom_line(size=1.2)
This is what I got:
As you can see, the large fluctuation of F enlarges my general y axis scale and makes the other five observations' trends unclear.
I tried to set the ylim=(-5,5), then I lost the entire F:
I am not entirely sure how shall I plot all of them together, but I am thinking is it possible to scale the out of range part, like the following part, or you actually wouldn't recommend this?
Any advice is highly appreciated. Thanks!
I don't know if this is the best option for you data, but you can divide each group by it's range to make it more like a ratio.
library(data.table)
library(ggplot2)
set.seed(99)
dt <- data.table(value = c(rnorm(10, 0, 5), rnorm(20)),
cat = rep(c("x", "y", "z"), each = 10),
id = rep(1:10, 3))
ggplot(dt, aes(id, value, color = cat)) +
geom_line(size = 2)
ggplot(dt[, ratio := value / diff(range(value)), cat], aes(id, ratio, color = cat)) +
geom_line(size = 2)

ggplot2 R, Fixing much values in axis (Line-plot)

I can't read my y-axis since is has a lot of values. I tried rotating it and it doesn't work like I want, neither is it something I want to do.
I want to specify the values in the axis, to be from say 20 to 30, maybe with step 0.1.
But the length of the values are 1000, so I guess the range suggested above doesn't work (?).
Ex:
runNumbers <- seq(from = 1, to = 1000)
tempVector <- seq(from = 20.0010, to = 30, by = 0.01)
plotData <- data.frame(RunNumber = runNumbers, temp = tempVector,
myUglyPlot <- ggplot(data = plotData, mapping = aes(x = RunNumber, y = temp, group = 1)) + geom_line()
#
#http://stackoverflow.com/questions/14428887/overflowing-x-axis-ggplot2?noredirect=1&lq=1
require(scales) # for removing scientific notation
# manually generate breaks/labels
labels <- seq(from = 0, to = 30, length.out = 1000)
# and set breaks and labels
myUglyPlot <- myUglyPlot + scale_y_discrete(breaks = labels, labels = as.character(labels))
# And now my graph is without labels, why?
Is there another way to do this, without rotating my labels? Or am I doing something wrong in the code from the other question (I tried to follow what he did...)?
Later I will have 10 000 values instead, so I really need to change this, I want to have a readable axis, that I can put the interval in.
Maybe I'm missing in some simple concept, I tried to search and read R Graphics Cookbook, but without success for now.
Thanks for your time.
Update
Im trying to use breaks, thanks for the help guys. Here's what I'm doing now (only this):
myUglyPlot <- ggplot(data = plotData, mapping = aes(x = RunNo, y = t_amb, group = 1)) + geom_line()
myUglyPlot <- myUglyPlot + scale_y_discrete(breaks=seq(from = 1, to = 50, by = 0.01))
But my it doesn't give me any breaks. See pic.
You are almost there.. Since your y-axis is a continuous value, you need to use scale_y_continuous instead of scale_y_discrete.
myUglyPlot <- myUglyPlot + scale_y_continuous(breaks = labels)

Creating Multiple y-axes scales (or alternatives?) using ggplot2 in R [duplicate]

How it is possible (if at all) to show two alternative units on axis ticks in ggplot2?
What I would like to achieve is something like this:
Here's a hacky way of doing that:
d = data.frame(x = 1:20, y = rnorm(20, 5, 5))
ggplot(data = d, aes(x = x, y = y)) +
scale_x_continuous(breaks = c(1:20, seq(2.54, 20, 2.54)),
labels = c(1:20, paste0("\n", 1:as.integer(20/2.54), "\""))) +
geom_point()

Resources