11

我在 R Riverplot (v0.5) 中制作了一个桑基图,在 RStudio 中输出看起来很小,但是当导出或放大它时,颜色有深色轮廓或网格线。

此处链接的 Riverplot 图像显示了问题

我认为这可能是因为形状的轮廓与我要用于填充的透明度不匹配?

我可能需要找到一种方法来完全摆脱轮廓(而不是让它们半透明),因为我认为它们也是为什么值为零的流仍然显示为细线的原因。

我的代码在这里:

#loading packages
library(readr)
library("riverplot", lib.loc="C:/Program Files/R/R-3.3.2/library")
library(RColorBrewer)

#loaing data
Cambs_flows <- read_csv("~/RProjects/Cambs_flows4.csv")

#defining the edges
edges = rep(Cambs_flows, col.names = c("N1","N2","Value"))
edges    <- data.frame(edges)
edges$ID <- 1:25

#defining the nodes
nodes <- data.frame(ID = c("Cambridge","S Cambs","Rest of E","Rest of UK","Abroad","to Cambridge","to S Cambs","to Rest of E","to Rest of UK","to Abroad"))
nodes$x = c(1,1,1,1,1,2,2,2,2,2)
nodes$y = c(1,2,3,4,5,1,2,3,4,5)

#picking colours
palette = paste0(brewer.pal(5, "Set1"), "90")

#plot styles
styles = lapply(nodes$y, function(n) {
  list(col = palette[n], lty = 0, textcol = "black")
})

#matching nodes to names
names(styles) = nodes$ID

#defining the river
r <- makeRiver( nodes, edges,
                node_labels = c("Cambridge","S Cambs","Rest of E","Rest of UK","Abroad","to Cambridge","to S Cambs","to Rest of E","to Rest of UK","to Abroad"),
                node_styles = styles)

#Plotting
plot( r, plot_area = 0.9)

我的数据在这里

dput(Cambs_flows)
structure(list(N1 = c("Cambridge", "Cambridge", "Cambridge", 
"Cambridge", "Cambridge", "S Cambs", "S Cambs", "S Cambs", "S Cambs", 
"S Cambs", "Rest of E", "Rest of E", "Rest of E", "Rest of E", 
"Rest of E", "Rest of UK", "Rest of UK", "Rest of UK", "Rest of UK", 
"Rest of UK", "Abroad", "Abroad", "Abroad", "Abroad", "Abroad"
), N2 = c("to Cambridge", "to S Cambs", "to Rest of E", "to Rest of UK", 
"to Abroad", "to Cambridge", "to S Cambs", "to Rest of E", "to Rest of UK", 
"to Abroad", "to Cambridge", "to S Cambs", "to Rest of E", "to Rest of UK", 
"to Abroad", "to Cambridge", "to S Cambs", "to Rest of E", "to Rest of UK", 
"to Abroad", "to Cambridge", "to S Cambs", "to Rest of E", "to Rest of UK", 
"to Abroad"), Value = c(0L, 1616L, 2779L, 13500L, 5670L, 2593L, 
0L, 2975L, 4742L, 1641L, 2555L, 3433L, 0L, 0L, 0L, 6981L, 3802L, 
0L, 0L, 0L, 5670L, 1641L, 0L, 0L, 0L)), class = c("tbl_df", "tbl", 
"data.frame"), row.names = c(NA, -25L), .Names = c("N1", "N2", 
"Value"), spec = structure(list(cols = structure(list(N1 = structure(list(), class = c("collector_character", 
"collector")), N2 = structure(list(), class = c("collector_character", 
"collector")), Value = structure(list(), class = c("collector_integer", 
"collector"))), .Names = c("N1", "N2", "Value")), default = structure(list(), class = c("collector_guess", 
"collector"))), .Names = c("cols", "default"), class = "col_spec"))
4

2 回答 2

13

罪魁祸首是riverplot::curveseg. 我们可以破解这个函数来修复它,或者还有一个非常简单的解决方法,不需要破解这个函数。事实上,在许多情况下,简单的解决方案可能是最好的,但首先我解释了如何破解这个函数,这样我们就明白了为什么这个变通方法也有效。如果您只想要简单的解决方案,请滚动到此答案的末尾:

更新:下面建议的更改现已在 Riverplot 版本 0.6 中实施

要编辑功能,您可以使用

trace(curveseg, edit=T)

然后找到函数末尾附近的行

polygon(c(xx[i], xx[i + 1], xx[i + 1], xx[i]), c(yy[i], 
      yy[i + 1], yy[i + 1] + w, yy[i] + w), col = grad[i], 
      border = grad[i])

我们可以在这里看到包作者选择不将lty参数传递给polygon(更新:请参阅此答案以解释为什么包作者这样做)。lty = 0通过添加(或者,如果您愿意, )更改此行border = NA,它可以按 OPs 案例的预期工作。(但请注意,如果您希望渲染 pdf,这可能效果不佳 - 请参阅此处

polygon(c(xx[i], xx[i + 1], xx[i + 1], xx[i]), c(yy[i], 
      yy[i + 1], yy[i + 1] + w, yy[i] + w), col = grad[i], 
      border = grad[i], lty=0)

在此处输入图像描述

作为旁注,这也解释了评论中有些奇怪的报告行为“如果你运行它两次,第二次情节看起来不错,尽管导出它并且线条回来了”。如果lty在对 的调用中未指定polygon,则它使用的默认值为lty = par("lty")。最初,默认par("lty")值为实线,但在运行一次 riverplot 函数后,par("lty")在调用期间设置为 0,riverplot:::draw.nodes因此在第二次运行时抑制线条riverplot。但是,如果您随后尝试导出图像,则打开新设备会重置par("lty")为其默认值。

使用此编辑更新函数的另一种方法assignInNamespace是使用您自己的版本覆盖包函数。像这样:

curveseg.new = function (x0, x1, y0, y1, width = 1, nsteps = 50, col = "#ffcc0066", 
          grad = NULL, lty = 1, form = c("sin", "line")) 
{
  w <- width
  if (!is.null(grad)) {
    grad <- colorRampPaletteAlpha(grad)(nsteps)
  }
  else {
    grad <- rep(col, nsteps)
  }
  form <- match.arg(form, c("sin", "line"))
  if (form == "sin") {
    xx <- seq(-pi/2, pi/2, length.out = nsteps)
    yy <- y0 + (y1 - y0) * (sin(xx) + 1)/2
    xx <- seq(x0, x1, length.out = nsteps)
  }
  if (form == "line") {
    xx <- seq(x0, x1, length.out = nsteps)
    yy <- seq(y0, y1, length.out = nsteps)
  }
  for (i in 1:(nsteps - 1)) {
    polygon(c(xx[i], xx[i + 1], xx[i + 1], xx[i]), 
            c(yy[i], yy[i + 1], yy[i + 1] + w, yy[i] + w), 
            col = grad[i], border = grad[i], lty=0)
    lines(c(xx[i], xx[i + 1]), c(yy[i], yy[i + 1]), lty = lty)
    lines(c(xx[i], xx[i + 1]), c(yy[i] + w, yy[i + 1] + w), lty = lty)
  }
}

assignInNamespace('curveseg', curveseg.new, 'riverplot', pos = -1, envir = as.environment(pos))

现在对于简单的解决方案,它不需要更改功能:

par(lty=0)只需在绘制之前添加行!!!!

于 2017-02-16T20:11:42.097 回答
11

这是包的作者。我现在正在努力寻找一个令人满意的解决方案,以便将其包含在包的下一个版本中。

与位图相比,问题在于 R 如何渲染 PDF。在包的原始版本中,我确实将 lty=0 传递给了 polygon() (您仍然可以在注释的源代码中看到它)。但是,无边框的多边形仅在 png 图形上看起来不错。在 pdf 输出中,多边形之间出现细白线。看一看:

cc <- "#E41A1C90"
plot.new()
rect(0.2, 0.2, 0.4, 0.4, col=cc, border=NA)
rect(0.4, 0.2, 0.6, 0.4, col=cc, border=NA)
dev.copy2pdf(file="riverplot.pdf")

在 X 或 png 上,输出是正确的。但是,如果呈现为 PDF,您会在矩形之间看到一条细白线:

在此处输入图像描述

当您像上面那样将河图图形渲染为 PDF 时,这看起来非常糟糕:

在此处输入图像描述

因此,我强制添加边框,但忘记检查透明度。当不使用透明度时,这看起来不错 - 边界与多边形重叠以及彼此重叠,但您看不到它。PDF 现在可以接受。但是,如果你有透明度,它会弄乱这个数字。

编辑

我现在已将 Riverplot 的 0.6 版上传到 CRAN。除了一些新的东西(您现在可以将河图添加到现有绘图的任何部分),默认情况下它再次使用 lty=0。但是,现在有一个名为“fix.pdf”的选项,您可以将其设置为 TRUE,以便再次在线段周围绘制边框。

底线和目前的解决方案:

  1. 使用河图 0.6`
  2. 如果要渲染 PDF,请不要使用透明度并使用 fix.pdf=TRUE
  3. 如果您想同时使用透明度和 PDF,请帮我解决问题。
于 2017-02-17T09:36:24.047 回答