多面 ggplot 的不同图例和填充颜色?

发布于 2024-09-25 06:13:03 字数 2471 浏览 6 评论 0原文

抱歉,没有包含我的问题的任何示例数据。我找不到轻松生成示例形状文件的方法。希望有经验的 ggplot 用户可以从下面的描述中看到我想要做什么。

我有:

  • A data.frame X,其中包含有关示例图的信息(plotidvar1var2, var3, var4, …)

  • 多边形形状文件 Y 包含样地的空间信息

导入 shapefile Y(带有 < code>maptools) 和 fortify 作为 data.frame Z (ggplot2) 工作正常。 meltX 转换为 X_melted 同样可以正常工作。 merge-ing ZX_meltedmapdf 也可以。

这意味着现在我们有一个长格式的 data.frame ,其中包含空间信息和 var1var2var3 ,...

现在我想像这样绘制这个数据框:

pl1 <- ggplot(mapdf,aes(long,lat),group=group)
pl1 <- pl1 + geom_polygon(aes(group=group,fill=value),colour="black")
pl1 <- pl1 + facet_grid(variable ~ .)
pl1 <- pl1 + coord_equal(ratio = 1)
pl1

结果是一个很好的图,每个变量都有一个面板。面板的地图是相同的,但填充颜色随变量值的变化而变化。到目前为止,一切都很顺利……但有一个问题:

变量具有不同的最小值和最大值。例如,var105var20>400var3510 等。在该示例中,填充颜色的图例来自 0400var2 绘制得很好,但 var1var3 的颜色基本相同。

有没有办法可以为该方面的每个面板使用不同的图例?或者这对于ggplot中的facet_wrapfacet_grid根本不可能(还)实现吗?

我可以为每个变量制作单独的图,并将它们与视口连接起来,但是变量很多,这将需要大量工作。

或者我可以使用另一个包或方法来完成我想做的事情吗?

非常感谢您的帮助。 :)

编辑: 在 ggplot2 包描述的帮助下,我构建了一个示例来说明我的问题:

ids <- factor(c("1.1", "2.1", "1.2", "2.2", "1.3", "2.3"))
values <- data.frame(
id = ids,
val1 = cumsum(runif(6, max = 0.5)),
val2 = cumsum(runif(6, max = 50))
)
positions <- data.frame(
id = rep(ids, each = 4),
x = c(2, 1, 1.1, 2.2, 1, 0, 0.3, 1.1, 2.2, 1.1, 1.2, 2.5, 1.1, 0.3,
0.5, 1.2, 2.5, 1.2, 1.3, 2.7, 1.2, 0.5, 0.6, 1.3),
y = c(-0.5, 0, 1, 0.5, 0, 0.5, 1.5, 1, 0.5, 1, 2.1, 1.7, 1, 1.5,
2.2, 2.1, 1.7, 2.1, 3.2, 2.8, 2.1, 2.2, 3.3, 3.2)
)

values <- melt(values)
datapoly <- merge(values, positions, by=c("id"))

p <- ggplot(datapoly, aes(x=x, y=y)) + geom_polygon(aes(fill=value, group=id),colour="black")
p <- p + facet_wrap(~ variable)
p

右侧的面板说明了地图上 var2 的不同值。然而,在左侧面板上,所有多边形都具有相同的颜色。这是合乎逻辑的,因为所有面板仅使用一种颜色渐变。我可以为每个面板使用不同的颜色渐变吗?

Sorry for not included any example data for my problem. I couldn’t find a way to easily produce an example shape file. Hopefully, experienced users of ggplot can see what I’d like to do from the description below.

I’ve got:

  • A data.frame X with information about sample plots (plotid, var1, var2, var3, var4, …)

  • A polygon shapefile Y with spatial information for the sample plots

Importation of the shapefile Y (with maptools) and fortifying as data.frame Z (ggplot2) works fine. melting X to X_melted works equally fine. merge-ing Z and X_melted to mapdf works as well.

That means that now we have a data.frame in long form with spatial information and var1, var2, var3, …

Now I want to plot this data frame like this:

pl1 <- ggplot(mapdf,aes(long,lat),group=group)
pl1 <- pl1 + geom_polygon(aes(group=group,fill=value),colour="black")
pl1 <- pl1 + facet_grid(variable ~ .)
pl1 <- pl1 + coord_equal(ratio = 1)
pl1

The result is a nice plot with one panel for each variable. The maps of the panels are identical, but fill colour varies with the values of the variables. Up to now, everything works like a charm… with one problem:

The variables have different min and max values. For example var1 goes from 0 to 5, var2 from 0 to 400, var3 from 5 to 10, etc. In that example, the legend for the fill colour goes from 0 to 400. var2 is nicely drawn, but var1 and var3 are basically in the same colour.

Is there a way I could use a different legend for each panel of the facet? Or is this simply not (yet) possible with facet_wrap or facet_grid in ggplot?

I could make individual plots for each variable and join them with viewports, but there a plenty of variables and this would be a lot of work.

Or is there maybe another package or method I could use to accomplish what I’d like to do?

And help would be very much appreciated. :)

Edit:
With the help of the ggplot2-package description, I constructed an example that illustrates my problem:

ids <- factor(c("1.1", "2.1", "1.2", "2.2", "1.3", "2.3"))
values <- data.frame(
id = ids,
val1 = cumsum(runif(6, max = 0.5)),
val2 = cumsum(runif(6, max = 50))
)
positions <- data.frame(
id = rep(ids, each = 4),
x = c(2, 1, 1.1, 2.2, 1, 0, 0.3, 1.1, 2.2, 1.1, 1.2, 2.5, 1.1, 0.3,
0.5, 1.2, 2.5, 1.2, 1.3, 2.7, 1.2, 0.5, 0.6, 1.3),
y = c(-0.5, 0, 1, 0.5, 0, 0.5, 1.5, 1, 0.5, 1, 2.1, 1.7, 1, 1.5,
2.2, 2.1, 1.7, 2.1, 3.2, 2.8, 2.1, 2.2, 3.3, 3.2)
)

values <- melt(values)
datapoly <- merge(values, positions, by=c("id"))

p <- ggplot(datapoly, aes(x=x, y=y)) + geom_polygon(aes(fill=value, group=id),colour="black")
p <- p + facet_wrap(~ variable)
p

The panel on the right illustrates different values for var2 on the map. On the panel on the left however, all polygons have the same colour. This is logical, because only one colour gradient is used for all panels. Could I use a different colour gradient for each panel?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

悲欢浪云 2024-10-02 06:13:03

目前,每个图只能有一个比例(除了 x 和 y 之外的所有比例)。

Currently there can be only one scale per plot (for everything except x and y).

荒人说梦 2024-10-02 06:13:03

十多年后重新审视这个问题,优秀的 ggnewscale 包解决了具有多个色阶的问题。需要注意的是,您的方面数据需要两个单独的层,因此您必须将其稍微分解。将新比例添加到绘图中的顺序很重要,因此我建议使用“图层 - 比例 - new_scale - 图层 - 比例”的顺序。后续的新比例应重复“new_scale - 层 - 比例”模式。

library(ggplot2)
library(ggnewscale)

ids <- factor(c("1.1", "2.1", "1.2", "2.2", "1.3", "2.3"))
values <- data.frame(
  id = ids,
  val1 = cumsum(runif(6, max = 0.5)),
  val2 = cumsum(runif(6, max = 50))
)
positions <- data.frame(
  id = rep(ids, each = 4),
  x = c(2, 1, 1.1, 2.2, 1, 0, 0.3, 1.1, 2.2, 1.1, 1.2, 2.5, 1.1, 0.3,
        0.5, 1.2, 2.5, 1.2, 1.3, 2.7, 1.2, 0.5, 0.6, 1.3),
  y = c(-0.5, 0, 1, 0.5, 0, 0.5, 1.5, 1, 0.5, 1, 2.1, 1.7, 1, 1.5,
        2.2, 2.1, 1.7, 2.1, 3.2, 2.8, 2.1, 2.2, 3.3, 3.2)
)

values <- reshape2::melt(values)
#> Using id as id variables
datapoly <- merge(values, positions, by=c("id"))

ggplot(datapoly, aes(x=x, y=y)) + 
  geom_polygon(aes(fill=value, group=id),
               data = ~ subset(., variable == "val1"),
               colour="black") +
  scale_fill_distiller(palette = "Reds") +
  new_scale_fill() +
  geom_polygon(aes(fill=value, group=id),
               data = ~ subset(., variable == "val2"),
               colour="black") +
  scale_fill_distiller(palette = "Greens") +
  facet_wrap(~ variable)

reprex 包 (v1.0.0)

Revisiting this question more than 10 years later, the excellent ggnewscale package solves the problem of having multiple colour scales. Caveat is that you'd need two seperate layers for your facet data, so you'd have to break it up a bit. The order in which new scales are added to the plot matters, so I recommend the order 'layer - scale - new_scale - layer - scale'. Subsequent new scales should repeat the 'new_scale - layer - scale' pattern.

library(ggplot2)
library(ggnewscale)

ids <- factor(c("1.1", "2.1", "1.2", "2.2", "1.3", "2.3"))
values <- data.frame(
  id = ids,
  val1 = cumsum(runif(6, max = 0.5)),
  val2 = cumsum(runif(6, max = 50))
)
positions <- data.frame(
  id = rep(ids, each = 4),
  x = c(2, 1, 1.1, 2.2, 1, 0, 0.3, 1.1, 2.2, 1.1, 1.2, 2.5, 1.1, 0.3,
        0.5, 1.2, 2.5, 1.2, 1.3, 2.7, 1.2, 0.5, 0.6, 1.3),
  y = c(-0.5, 0, 1, 0.5, 0, 0.5, 1.5, 1, 0.5, 1, 2.1, 1.7, 1, 1.5,
        2.2, 2.1, 1.7, 2.1, 3.2, 2.8, 2.1, 2.2, 3.3, 3.2)
)

values <- reshape2::melt(values)
#> Using id as id variables
datapoly <- merge(values, positions, by=c("id"))

ggplot(datapoly, aes(x=x, y=y)) + 
  geom_polygon(aes(fill=value, group=id),
               data = ~ subset(., variable == "val1"),
               colour="black") +
  scale_fill_distiller(palette = "Reds") +
  new_scale_fill() +
  geom_polygon(aes(fill=value, group=id),
               data = ~ subset(., variable == "val2"),
               colour="black") +
  scale_fill_distiller(palette = "Greens") +
  facet_wrap(~ variable)

Created on 2021-02-12 by the reprex package (v1.0.0)

来日方长 2024-10-02 06:13:03

与网格善良

align.plots <- function(..., vertical=TRUE){
#http://ggextra.googlecode.com/svn/trunk/R/align.r
  dots <- list(...)
  dots <- lapply(dots, ggplotGrob)
  ytitles <- lapply(dots, function(.g) editGrob(getGrob(.g,"axis.title.y.text",grep=TRUE), vp=NULL))
  ylabels <- lapply(dots, function(.g) editGrob(getGrob(.g,"axis.text.y.text",grep=TRUE), vp=NULL))
  legends <- lapply(dots, function(.g) if(!is.null(.g$children$legends))
                    editGrob(.g$children$legends, vp=NULL) else ggplot2:::.zeroGrob)

  gl <- grid.layout(nrow=length(dots))
  vp <- viewport(layout=gl)
  pushViewport(vp)
  widths.left <- mapply(`+`, e1=lapply(ytitles, grobWidth),
                        e2= lapply(ylabels, grobWidth), SIMPLIFY=F)
  widths.right <- lapply(legends, function(g) grobWidth(g) + if(is.zero(g)) unit(0, "lines") else unit(0.5, "lines")) # safe margin recently added to ggplot2
  widths.left.max <- max(do.call(unit.c, widths.left))
  widths.right.max <- max(do.call(unit.c, widths.right))

  for(ii in seq_along(dots)){
    pushViewport(viewport(layout.pos.row=ii))
    pushViewport(viewport(x=unit(0, "npc") + widths.left.max - widths.left[[ii]],
                          width=unit(1, "npc") - widths.left.max + widths.left[[ii]] -
                                                 widths.right.max + widths.right[[ii]],
                          just="left"))
    grid.draw(dots[[ii]])
  upViewport(2)
  }
}



p <- ggplot(datapoly[datapoly$variable=="val1",], aes(x=x, y=y)) + geom_polygon(aes(fill=value, group=id),colour="black")
p1 <- ggplot(datapoly[datapoly$variable=="val2",], aes(x=x, y=y)) + geom_polygon(aes(fill=value, group=id),colour="black")
align.plots( p,p1)

With grid goodness

align.plots <- function(..., vertical=TRUE){
#http://ggextra.googlecode.com/svn/trunk/R/align.r
  dots <- list(...)
  dots <- lapply(dots, ggplotGrob)
  ytitles <- lapply(dots, function(.g) editGrob(getGrob(.g,"axis.title.y.text",grep=TRUE), vp=NULL))
  ylabels <- lapply(dots, function(.g) editGrob(getGrob(.g,"axis.text.y.text",grep=TRUE), vp=NULL))
  legends <- lapply(dots, function(.g) if(!is.null(.g$children$legends))
                    editGrob(.g$children$legends, vp=NULL) else ggplot2:::.zeroGrob)

  gl <- grid.layout(nrow=length(dots))
  vp <- viewport(layout=gl)
  pushViewport(vp)
  widths.left <- mapply(`+`, e1=lapply(ytitles, grobWidth),
                        e2= lapply(ylabels, grobWidth), SIMPLIFY=F)
  widths.right <- lapply(legends, function(g) grobWidth(g) + if(is.zero(g)) unit(0, "lines") else unit(0.5, "lines")) # safe margin recently added to ggplot2
  widths.left.max <- max(do.call(unit.c, widths.left))
  widths.right.max <- max(do.call(unit.c, widths.right))

  for(ii in seq_along(dots)){
    pushViewport(viewport(layout.pos.row=ii))
    pushViewport(viewport(x=unit(0, "npc") + widths.left.max - widths.left[[ii]],
                          width=unit(1, "npc") - widths.left.max + widths.left[[ii]] -
                                                 widths.right.max + widths.right[[ii]],
                          just="left"))
    grid.draw(dots[[ii]])
  upViewport(2)
  }
}



p <- ggplot(datapoly[datapoly$variable=="val1",], aes(x=x, y=y)) + geom_polygon(aes(fill=value, group=id),colour="black")
p1 <- ggplot(datapoly[datapoly$variable=="val2",], aes(x=x, y=y)) + geom_polygon(aes(fill=value, group=id),colour="black")
align.plots( p,p1)
忘东忘西忘不掉你 2024-10-02 06:13:03

冒着陈述显而易见的风险,似乎您应该按百分比而不是原始值着色。然后你的转换后的值和你的图例从 0 到 1。

At the risk of stating the obvious, it seems like you should be coloring by percents instead of raw values. Then your transformed values and your legend go from 0 to 1.

一杯敬自由 2024-10-02 06:13:03

也许有点不正统,但你可以尝试考虑你的“价值”。例如:

p <- ggplot(datapoly, aes(x=x, y=y)) + geom_polygon(aes(fill=factor(value), group=id),colour="black")
p <- p + facet_wrap(~ variable)
p

ggplot2 使用因子来创建图例。因此,如果您可以添加一个采用“值”并将其分解为因子范围的列,则可以将“值”替换为范围。

创建一个列,例如“f”:

    id variable        value   x    y f
1  1.1     val1   0.09838607 2.0 -0.5 0.09-0.13
2  1.1     val1   0.09838607 1.0  0.0 0.09-0.13
3  1.1     val1   0.09838607 1.1  1.0 0.09-0.13
4  1.1     val1   0.09838607 2.2  0.5 0.09-0.13
25 2.1     val1   0.13121347 1.0  0.0 0.13-0.20

...

然后使用:

p <- ggplot(datapoly, aes(x=x, y=y)) + geom_polygon(aes(fill=f, group=id),colour="black")
p <- p + facet_wrap(~ variable)
p

您必须指定所需的类别,这可能非常耗时。但至少图表会按照您想要的方式显示。基本上,您会将数据重新编码到另一列中。以下是一些示例:

http://www.statmethods.net/management/variables.html

Perhaps a little unorthodox, but you could try factoring your "value". For example:

p <- ggplot(datapoly, aes(x=x, y=y)) + geom_polygon(aes(fill=factor(value), group=id),colour="black")
p <- p + facet_wrap(~ variable)
p

ggplot2 uses factors to create legends. So if you could add a column that takes "value" and breaks it into factored ranges, you could replace "value" with the ranges.

Create a column, like "f":

    id variable        value   x    y f
1  1.1     val1   0.09838607 2.0 -0.5 0.09-0.13
2  1.1     val1   0.09838607 1.0  0.0 0.09-0.13
3  1.1     val1   0.09838607 1.1  1.0 0.09-0.13
4  1.1     val1   0.09838607 2.2  0.5 0.09-0.13
25 2.1     val1   0.13121347 1.0  0.0 0.13-0.20

...

Then use:

p <- ggplot(datapoly, aes(x=x, y=y)) + geom_polygon(aes(fill=f, group=id),colour="black")
p <- p + facet_wrap(~ variable)
p

You'd have to specify the categories that you want, which could be time consuming. But at least the graph would come out how you want it to. Basically, you'd be recoding the data into another column. Here are some examples:

http://www.statmethods.net/management/variables.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文