ggplot2:在非正交(例如,-45 度)轴上投影点或分布
ggplot2: Projecting points or distribution on a non-orthogonal (eg, -45 degree) axis
下图是Michael Clark使用的概念图,
https://m-clark.github.io/docs/lord/index.html
解释回归中的洛德悖论和相关现象。
我的问题是在这种情况下提出的,并使用 ggplot2
但它在几何和图形方面更广泛。
我想重现这样的数字,但要使用实际数据。我需要知道:
- 如何在原点绘制一条新轴,角度为 -45 度,对应于
y-x
的值
- 如何绘制小的正态分布或密度图,或投影到此轴上的值的其他表示
y-x
。
我的最小基础示例使用 ggplot2
、
library(ggplot2)
set.seed(1234)
N <- 200
group <- rep(c(0, 1), each = N/2)
initial <- .75*group + rnorm(N, sd=.25)
final <- .4*initial + .5*group + rnorm(N, sd=.1)
change <- final - initial
df <- data.frame(id = factor(1:N),
group = factor(group,
labels = c('Female', 'Male')),
initial,
final,
change)
#head(df)
#' plot, with regression lines and data ellipses
ggplot(df, aes(x = initial, y = final, color = group)) +
geom_point() +
geom_smooth(method = "lm", formula = y~x) +
stat_ellipse(size = 1.2) +
geom_abline(slope = 1, color = "black", size = 1.2) +
coord_fixed(xlim = c(-.6, 1.2), ylim = c(-.6, 1.2)) +
theme_bw() +
theme(legend.position = c(.15, .85))
这给出了下图:
在几何学中,我要描绘的分布的-45度旋转轴的坐标是
(y-x), (x+y) 在原图 space 中。但是我怎样才能用
ggplot2
还是其他软件?
一个公认的解决方案可能对如何表示 (y-x) 的分布含糊不清,
但应该解决如何在 (y-x) 轴上显示它的问题。
有趣的问题!我还没有遇到过,但可能有一个包可以帮助自动执行此操作。这是使用两个 hack 的手动方法:
coord_*
函数的 clip = "off"
参数,允许我们在绘图区域外添加注释。
- 构建密度图,提取其坐标,然后旋转和平移这些坐标。
首先,我们可以绘制从初始到最终变化的密度图,看到左偏分布:
(my_hist <- df %>%
mutate(gain = final - initial) %>% # gain would be better name
ggplot(aes(gain)) +
geom_density())
现在我们可以提取该图的内容,并将坐标转换为我们希望它们出现在组合图中的位置:
a <- ggplot_build(my_hist)
rot = pi * 3/4
diag_hist <- tibble(
x = a[["data"]][[1]][["x"]],
y = a[["data"]][[1]][["y"]]
) %>%
# squish
mutate(y = y*0.2) %>%
# rotate 135 deg CCW
mutate(xy = x*cos(rot) - y*sin(rot),
dens = x*sin(rot) + y*cos(rot)) %>%
# slide
mutate(xy = xy - 0.7, # magic number based on plot range below
dens = dens - 0.7)
下面是与原剧情的结合:
ggplot(df, aes(x = initial, y = final, color = group)) +
geom_point() +
geom_smooth(method = "lm", formula = y~x) +
stat_ellipse(size = 1.2) +
geom_abline(slope = 1, color = "black", size = 1.2) +
coord_fixed(clip = "off",
xlim = c(-0.7,1.6),
ylim = c(-0.7,1.6),
expand = expansion(0)) +
annotate("segment", x = -1.4, xend = 0, y = 0, yend = -1.4) +
annotate("path", x = diag_hist$xy, y = diag_hist$dens) +
theme_bw() +
theme(legend.position = c(.15, .85),
plot.margin = unit(c(.1,.1,2,2), "cm"))
下图是Michael Clark使用的概念图, https://m-clark.github.io/docs/lord/index.html 解释回归中的洛德悖论和相关现象。
我的问题是在这种情况下提出的,并使用 ggplot2
但它在几何和图形方面更广泛。
我想重现这样的数字,但要使用实际数据。我需要知道:
- 如何在原点绘制一条新轴,角度为 -45 度,对应于
y-x
的值
- 如何绘制小的正态分布或密度图,或投影到此轴上的值的其他表示
y-x
。
我的最小基础示例使用 ggplot2
、
library(ggplot2)
set.seed(1234)
N <- 200
group <- rep(c(0, 1), each = N/2)
initial <- .75*group + rnorm(N, sd=.25)
final <- .4*initial + .5*group + rnorm(N, sd=.1)
change <- final - initial
df <- data.frame(id = factor(1:N),
group = factor(group,
labels = c('Female', 'Male')),
initial,
final,
change)
#head(df)
#' plot, with regression lines and data ellipses
ggplot(df, aes(x = initial, y = final, color = group)) +
geom_point() +
geom_smooth(method = "lm", formula = y~x) +
stat_ellipse(size = 1.2) +
geom_abline(slope = 1, color = "black", size = 1.2) +
coord_fixed(xlim = c(-.6, 1.2), ylim = c(-.6, 1.2)) +
theme_bw() +
theme(legend.position = c(.15, .85))
这给出了下图:
在几何学中,我要描绘的分布的-45度旋转轴的坐标是
(y-x), (x+y) 在原图 space 中。但是我怎样才能用
ggplot2
还是其他软件?
一个公认的解决方案可能对如何表示 (y-x) 的分布含糊不清, 但应该解决如何在 (y-x) 轴上显示它的问题。
有趣的问题!我还没有遇到过,但可能有一个包可以帮助自动执行此操作。这是使用两个 hack 的手动方法:
coord_*
函数的clip = "off"
参数,允许我们在绘图区域外添加注释。- 构建密度图,提取其坐标,然后旋转和平移这些坐标。
首先,我们可以绘制从初始到最终变化的密度图,看到左偏分布:
(my_hist <- df %>%
mutate(gain = final - initial) %>% # gain would be better name
ggplot(aes(gain)) +
geom_density())
现在我们可以提取该图的内容,并将坐标转换为我们希望它们出现在组合图中的位置:
a <- ggplot_build(my_hist)
rot = pi * 3/4
diag_hist <- tibble(
x = a[["data"]][[1]][["x"]],
y = a[["data"]][[1]][["y"]]
) %>%
# squish
mutate(y = y*0.2) %>%
# rotate 135 deg CCW
mutate(xy = x*cos(rot) - y*sin(rot),
dens = x*sin(rot) + y*cos(rot)) %>%
# slide
mutate(xy = xy - 0.7, # magic number based on plot range below
dens = dens - 0.7)
下面是与原剧情的结合:
ggplot(df, aes(x = initial, y = final, color = group)) +
geom_point() +
geom_smooth(method = "lm", formula = y~x) +
stat_ellipse(size = 1.2) +
geom_abline(slope = 1, color = "black", size = 1.2) +
coord_fixed(clip = "off",
xlim = c(-0.7,1.6),
ylim = c(-0.7,1.6),
expand = expansion(0)) +
annotate("segment", x = -1.4, xend = 0, y = 0, yend = -1.4) +
annotate("path", x = diag_hist$xy, y = diag_hist$dens) +
theme_bw() +
theme(legend.position = c(.15, .85),
plot.margin = unit(c(.1,.1,2,2), "cm"))