R中的Riverplot包 - 输出图以网格线或轮廓覆盖

时间:2016-12-11 17:07:19

标签: r sankey-diagram riverplot

我在R Riverplot中制作了一张Sankey图表(v0.5),在RStudio中输出看起来很小,但在导出或放大时,颜色会有黑色轮廓或网格线。

The Riverplot image linked here shows the problem

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

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

我的代码在这里:

#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"))

2 个答案:

答案 0 :(得分: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(更新:请参阅this answer以获取包装作者为何这样做的解释) 。通过添加lty = 0(或者,如果您愿意,border = NA)更改此行,并且它可以按预期用于OP案例。 (但请注意,如果您希望渲染pdf,这可能效果不佳 - 请参阅here

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)

enter image description here

作为旁注,这也解释了评论中有些奇怪的报告行为&#34;如果你运行它两次,第二次情节看起来没问题,虽然导出它并且线条返回&# 34; 。如果未在lty的调用中指定polygon,则其使用的默认值为lty = par("lty")。最初,默认par("lty")是一条实线,但在运行riverplot函数一次后,par("lty")在调用riverplot:::draw.nodes期间被设置为0,从而在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)

答案 1 :(得分:10)

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

问题在于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,您将在重复之间看到一条细白线:

enter image description here

当您将河流图形渲染为PDF时,如上所示,这看起来非常糟糕:

enter image description here

因此我强行添加边框,但忘了检查透明度。当没有使用透明度时,这看起来没问题 - 边框与多边形以及彼此重叠,但是你看不到它。 PDF现已被接受。但是,如果你有透明度,它会弄乱这个数字。

编辑

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

底线和现在的解决方案:

  1. 使用riverplot 0.6`
  2. 如果要渲染PDF,请不要使用透明度并使用fix.pdf = TRUE
  3. 如果您想同时使用透明度和PDF,请帮助我解决问题。