I'm trying to plot a number-line for floating point numbers (slightly simplified, with a sign bit, one bit for the coefficient (when not zero), and two bits for the exponent). I have this:
library(ggplot2)
library(tibble)
library(ggrepel)
d <- tribble(
~repr, ~number,
"1.1[2] %*% 2^-11", 2**-3 + 2**-4,
"1.0[2] %*% 2^-11", 2**-3,
"1.1[2] %*% 2^-10", 2**-2 + 2**-3,
"1.0[2] %*% 2^-10", 2**-2,
"1.1[2] %*% 2^-01", 2**-1 + 2**-2,
"1.0[2] %*% 2^-01", 2**-1,
"1.0[2] %*% 2^0", 1,
"1.1[2] %*% 2^0", 1 + 2**-1,
"0.0[2] %*% 2^0", 0,
"1.1[2] %*% 2^01", 2 + 1,
"1.0[2] %*% 2^01", 2,
"1.1[2] %*% 2^10", 2**2 + 2**1,
"1.0[2] %*% 2^10", 2**2,
"1.1[2] %*% 2^11", 2**3 + 2**2,
"1.0[2] %*% 2^11", 2**3,
"-1.1[2] %*% 2^-11", -(2**-3 + 2**-4),
"-1.0[2] %*% 2^-11", -(2**-3),
"-1.1[2] %*% 2^-10", -(2**-2 + 2**-3),
"-1.0[2] %*% 2^-10", -(2**-2),
"-1.1[2] %*% 2^-01", -(2**-1 + 2**-2),
"-1.0[2] %*% 2^-01", -(2**-1),
"-1.0[2] %*% 2^0", -1,
"-1.1[2] %*% 2^0", -(1 + 2**-1),
"-1.1[2] %*% 2^01", -(2 + 1),
"-1.0[2] %*% 2^01", -2,
"-1.1[2] %*% 2^10", -(2**2 + 2**1),
"-1.0[2] %*% 2^10", -2**2,
"-1.1[2] %*% 2^11", -(2**3 + 2**2),
"-1.0[2] %*% 2^11", -2**3
)
ggplot(d) +
geom_text_repel(aes(x = number, y = -0.1, label = number),
parse = TRUE,
angle = 0,
ylim = c(NA, -0.1)) +
geom_text_repel(aes(x = number, y = 0.1, label = repr),
angle = 0,
parse = TRUE, direction = "both", #angle = 90,
ylim = c(0.1, NA)) +
geom_hline(yintercept = 0) +
coord_cartesian(ylim = c(-2, 2)) +
labs(x = NULL, y = NULL) +
theme_classic() +
theme(axis.line.y = element_blank(),
axis.ticks = element_blank(),
axis.text = element_blank())
The result looks like this:
This is almost what I want, but I would prefer if the labels were ordered, left to right, in the same order as the numbers (and I would like to avoid crossing any lines).
Is there a way to avoid crossing any lines with geom_text_repel
? I don't mind having a larger spread of labels around zero, where there is a lot of values, I just think it is hard to read the plot as it is, since the labels are scrambled in order the way they are.
Let's add another column to position the text labels:
d <- d[order(d$number),]
d$i <- seq(min(d$number), max(d$number), length.out = nrow(d))
head(d)
Here it is:
repr number i
-1.1[2] %*% 2^11 -12 -12.00000
-1.0[2] %*% 2^11 -8 -11.14285
-1.1[2] %*% 2^10 -6 -10.28571
-1.0[2] %*% 2^10 -4 -9.428571
-1.1[2] %*% 2^01 -3 -8.571429
-1.0[2] %*% 2^01 -2 -7.714286
We don't need ggrepel:
ggplot() +
geom_point(
data = d,
mapping = aes(x = 0, y = number),
size = 0.1
) +
geom_text(
data = d,
mapping = aes(x = 0.05, y = i, label = repr),
parse = TRUE, hjust = 0
) +
geom_segment(
data = d,
mapping = aes(x = 0, xend = 0.05, y = number, yend = i),
size = 0.1
) +
scale_y_continuous(
breaks = c(-12, -8, -6, -4, -3, -2, -1, 0, 1, 2, 3, 4, 6, 8, 12)
) +
coord_cartesian(xlim = c(-0.01, 0.12)) +
theme_classic(base_size = 14) +
labs(x = NULL, y = NULL) +
theme(
axis.line.y = element_line(size = 0.2),
axis.ticks.y = element_line(size = 0.2),
axis.line.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.x = element_blank()
)