我在R Riverplot(v0.5)中制作了Sankey图,在RStudio中输出看起来还可以,但是当导出或放大时,颜色具有深色轮廓或网格线。



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

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

我的代码在这里:

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

最佳答案

罪魁祸首是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)


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

作为附带说明,这也解释了注释中报告的奇怪行为,即“如果运行两次,尽管导出并返回行,但第二次显示就可以了”。在对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)线!!!

07-24 13:58