【问题标题】:How to draw rotated axes in R?如何在R中绘制旋转轴?
【发布时间】:2014-03-30 15:38:44
【问题描述】:

我想将六因素人格测试的结果绘制成一个环。

所讨论的测试是 Allgemeiner Interessen-Struktur-Test (AIST-R; Bergmann & Eder, 2005) [General Interest Structure Test],它基于 JL 理论衡量职业选择荷兰 (Holland codes, RIASEC)。您可以使用下面的答案来绘制手册中推荐的“Felddarstellung”[字段表示],而不是兴趣配置文件,以更好地可视化分化向量。

生成的图形应如下所示:

测试结果以角度和长度的形式给出。

  • 如何在 R 中从具有特定长度的起点绘制轴或几何矢量,而不定义结束坐标(按照arrows 的要求)?

  • 如何为这样的向量添加刻度线?

  • 如何以类似的方式定义多边形的点(此处为灰色),即提供与原点的角度和距离,而不是坐标)?

我当然可以计算端点,但我想避免这种情况。另外,我不知道如何在箭头上添加刻度线。


我的尝试没有成功:

par(pin = c(4, 4))
plot(0, 0, type = "n", xlim = c(-60, 60), ylim = c(-60, 60))
symbols(c(0, 0, 0), c(0, 0, 0), circles = c(60, 1.5, 1.5), inches = FALSE, add = TRUE, fg = c("black", "black", "white"), bg = c("transparent", "#000000", "transparent"))
arrows(0, 0, length = c(60, 60, 60, 60, 60, 60), angle = c(0, 60, 120, 180, 240, 300))

【问题讨论】:

  • 我认为它们被称为雷达图,见Star (Spider/Radar) Plots and Segment Diagrams
  • 看看radial.plot in plotrix
  • 因为问“我想制作这个情节,告诉我怎么做”显示很少努力,这是关闭的原因,或者答案将是“使用函数 foo”,这是关闭的另一个原因.
  • 这就像在我知道勺子存在之前让我展示我用来尝试吃汤的叉子。看到叉子对你有什么帮助?但我会发布它。
  • 我给了你一个评论,但也按最初的要求投票关闭。原因是 Stack Overflow 专为特定问题而设计,可以通过清晰、具体和完整的解决方案来回答。如果问题是:“为什么这个绘图代码不能处理这些数据?”那么它就是主题,因为有人可以使用您的数据来绘制您想要的情节。如果是:“我用什么包来制作这样的情节?”它几乎不需要付出任何努力,而且很难用代码来回答,因为没有人知道你从什么开始。

标签: r plot


【解决方案1】:

以下使用base 函数和我们自己定义的几个函数。

虽然您请求的方法不需要计算线段端点坐标,但我认为这是不可能的。但是,我们可以定义一个简单的辅助函数,它使用一些基本的三角函数来计算给定角度(从正 y 轴顺时针方向)和段长度的坐标。我们在下面执行此操作,并定义一个绘制旋转轴的函数。

get.coords <- function(a, d, x0, y0) {
  a <- ifelse(a <= 90, 90 - a, 450 - a)
  data.frame(x = x0 + d * cos(a / 180 * pi), 
             y = y0+ d * sin(a / 180 * pi))
}

rotatedAxis <- function(x0, y0, a, d, symmetrical=FALSE, tickdist, ticklen, ...) {
  if(isTRUE(symmetrical)) {
    axends <- get.coords(c(a, a + 180), d, x0, y0)    
    tick.d <- c(seq(0, d, tickdist), seq(-tickdist, -d, -tickdist))      
  } else {
    axends <- rbind(get.coords(a, d, x0, y0), c(x0, y0))
    tick.d <- seq(0, d, tickdist)
  }
  invisible(lapply(apply(get.coords(a, d=tick.d, x0, y0), 1, function(x) {
    get.coords(a + 90, c(-ticklen, ticklen), x[1], x[2])
  }), function(x) lines(x$x, x$y, ...)))
  lines(axends$x, axends$y, ...)
}

get.coords 接受参数a(角度向量)、d(线段长度向量)以及x0y0,即已知点的坐标。向量 ad 在必要时被回收。该函数返回一个 data.frame 与元素 xy 给出对应于每个角度/长度对的坐标。

rotatedAxisx0, y0 和点d 之间以角度a 沿直线相隔一个单位绘制一个轴。如果symmetricalTRUE,则轴以相反方向延伸d 个单位。高度为ticklen 的刻度线以tickdist 为单位绘制。

绘制圆使用get.coords 计算沿圆周的坐标,并绘制连接这些与polygon (inspired by @timriffe) 的线。

下面我们使用这些函数来复制 OP 提供的绘图。

# Set up plotting device
plot.new()
plot.window(xlim=c(-70, 70), ylim=c(-70, 70), asp=1)

# Plot circle with radius = 60 units and centre at the origin.
polygon(get.coords(seq(0, 360, length.out=1000), 60, 0, 0), lwd=2)

# Plot a polygon with vertices along six axes, at distances of 17, 34, 44, 40,
# 35, and 10 units from the centre.
poly.pts <- get.coords(seq(0, 300, 60), c(17, 34, 44, 40, 35, 10), 0, 0)
polygon(poly.pts$x, poly.pts$y, col='gray', lwd=2)

# Plot the rotated axes
rotatedAxis(0, 0, a=60, d=60, symmetrical=TRUE, tickdist=10, ticklen=1)
rotatedAxis(0, 0, a=120, d=60, symmetrical=TRUE, tickdist=10, ticklen=1)
rotatedAxis(0, 0, a=180, d=60, symmetrical=TRUE, tickdist=10, ticklen=1)

# Add text labels to circumference
text.coords <- get.coords(seq(0, 300, 60), 65, 0, 0)
text(text.coords$x, text.coords$y, c('I', 'A', 'S', 'E', 'C', 'R'))    

# Plot a second point and connect to centre by a line
point2 <- get.coords(145, 50, 0, 0)
points(point2, pch=20, cex=2)
segments(0, 0, point2$x, point2$y, lwd=3)

# Plot central point
points(0, 0, pch=21, bg=1, col=0, lwd=2, cex=2)

(编辑:我对这篇文章进行了大量编辑 - 没有大幅改变它的一般信息 - 以使其更易于阅读和更普遍适用。添加/更改包括我现在定义一个函数绘制旋转轴,通过计算沿圆周的顶点坐标绘制圆并使用polygon 绘制,受@timriffe 的启发。)

【讨论】:

  • 非常好!但是您的比例是真实值的十分之一:range(ticks) 显示的值范围是 -6 到 6。我如何将此代码调整为从 -60 到 60 的范围,以便它可以与 plotrix 代码结合使用?跨度>
  • 可以通过更改为ticks.locs &lt;- lapply(seq(60, 360, 60), get.coords, d=10*(1:6))来调整刻度的比例。为了与我的其余代码兼容,我们必须进行一些其他调整。我没时间解释代码,但会回来解释。曲线在您的机器上看起来是否也是波浪形的?我一直在 Windows 上遇到抗锯齿问题(请注意,即使我的多边形也有波浪线) - 认为在其他人的系统上看起来还不错。
  • 仅供参考:我对这篇文章进行了一些编辑,通过定义一个绘制旋转轴的函数,使其更普遍有用/更灵活(不是特定于 OP 的确切问题)。通过沿圆的圆周计算顶点并使用polygon 绘图,可以缓解之前遇到的波浪线问题。
【解决方案2】:

基于 Thomas 的评论和 jbaums 的回答的解决方案。

  • 我使用 jbaums 的方法来绘制坐标轴,因为我不想要 plotrix 提供的完整圆形网格。
  • 我没有使用 jbaums 的方法画圆,因为它有一条波浪线/凹凸不平的线。
  • 我打电话给par(new = TRUE) 两次,因为 jbaums 答案中的比例是真实比例的十分之一,我不知道如何调整它。
  • 我手动放置了标签,对此我不满意。
  • 那里还有很多多余的代码,但我留下了它以防有人想用它来处理他们自己的版本。

代码如下:

# test results
R <- 95
I <- 93
A <- 121
S <- 111
E <- 114
C <- 80

dimensions <- c("R", "I", "A", "S", "E", "C")
values <- c(R, I, A, S, E, C)

RIASEC   <- data.frame(
                "standard.values" = values,
                "RIASEC" = dimensions
            )

person.typ   <- paste(
                    head(
                        RIASEC[
                            with(
                                RIASEC,
                                order(-standard.values)
                            ),
                        ]$RIASEC,
                        3
                    ),
                    collapse = ""
                )

# length of vector
vi1 <- 0
vi2 <- I
va1 <- 0.8660254 * A
va2 <- 0.5 * A
vs1 <- 0.8660254 * S
vs2 <- -0.5 * S
ve1 <- 0
ve2 <- -E
vc1 <- -0.8660254 * C
vc2 <- -0.5 * C
vr1 <- -0.8660254 * R
vr2 <- 0.5 * R
vek1 <- va1 + vi1 + vr1 + vc1 + ve1 + vs1  # x-axix
vek2 <- vr2 + vi2 + va2 + vs2 + ve2 + vc2  # y-axis
vektor <- sqrt(vek1^2 + vek2^2)            # vector length

# angle of vector
if (vek1 == 0) {tg <- 0} else {tg <- vek2 / vek1}
wink <- atan(tg) * 180 / pi
if (vek1 > 0) {
    winkel <- 90 - wink
} else if (vek1 == 0) {
    if (vek2 >= 0) {winkel <- 360}
    else if (vek2 < 0) {winkel <- 180}
} else if (vek1 < 0) {
    if (vek2 <= 0) {winkel <- 270 - wink}
    else if (vek2 >= 0) {winkel <- 270 - wink}
}

library(plotrix)
axis.angle <- c(0, 60, 120, 180, 240, 300)
axis.rad <- axis.angle * pi / 180
value.length <- values - 70
dev.new(width = 5, height = 5)
radial.plot(value.length, axis.rad, labels = dimensions, start = pi-pi/6, clockwise=TRUE,
    rp.type="p", poly.col = "grey", show.grid = TRUE, grid.col = "transparent", radial.lim = c(0,60))
radial.plot.labels(value.length + c(4, 2, -2, 1, 1, 4), axis.rad, radial.lim = c(0,60), start = pi-pi/6, clockwise = TRUE, labels = values, pos = c(1,2,3,1,2,1))

get.coords <- function(a, d, x0=0, y0=0) {
    a <- ifelse(a <= 90, 90 - a, 450 - a)
    data.frame(x = x0 + d * cos(a / 180 * pi), y = y0+ d * sin(a / 180 * pi)  )
}
par(new = TRUE)
plot(NA, xlim = c(-6, 6), ylim=c(-6, 6), type='n', xlab='', ylab='', asp = 1,
     axes=FALSE, new = FALSE, bg = "transparent")
circumf.pts <- get.coords(seq(60, 360, 60), 6)
segments(circumf.pts$x[1:3], circumf.pts$y[1:3],
         circumf.pts$x[4:6], circumf.pts$y[4:6])
ticks.locs <- lapply(seq(60, 360, 60), get.coords, d=1:6)

ticks <- c(apply(do.call(rbind, ticks.locs[c(1, 4)]), 1, function(x)
             get.coords(150, c(-0.1, 0.1), x[1], x[2])),
           apply(do.call(rbind, ticks.locs[c(2, 5)]), 1, function(x)
             get.coords(30, c(-0.1, 0.1), x[1], x[2])),
           apply(do.call(rbind, ticks.locs[c(3, 6)]), 1, function(x)
             get.coords(90, c(-0.1, 0.1), x[1], x[2])))

lapply(ticks, function(x) segments(x$x[1], x$y[1], x$x[2], x$y[2]))

par(new = TRUE)
plot(NA, xlim = c(-60, 60), ylim=c(-60, 60), type='n', xlab='', ylab='', asp = 1,
     axes=FALSE, new = FALSE, bg = "transparent")
segments(0, 0, vek1, vek2, lwd=3)
points(vek1, vek2, pch=20, cex=2)
symbols(c(0, 0, 0), c(0, 0, 0), circles = c(60, 2, 1.3), inches = FALSE, add = TRUE, fg = c("black", "white", "black"), bg = c("transparent", "white", "black"))

这是图形:

【讨论】:

  • plotrix: library(plotrix); demo(plotrix,package="plotrix")中有很多有趣的情节
  • 很高兴你明白了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多