如何使用 plotly 在散点图中同时应用颜色/形状/大小? [英] How to simultaneously apply color/shape/size in a scatter plot using plotly?

查看:23
本文介绍了如何使用 plotly 在散点图中同时应用颜色/形状/大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建(在 plotly 中)一个散点图,它通过两种(或三种)美学——颜色、形状、大小来区分同一系列的点.最终目标是能够使用三种美学中的任何一种来通过图例打开/关闭点组.这适用于一种美学.

[添加于 2016-06-20] 扩展所需的交互行为:这个想法是,一旦显示了图形,就能够通过单击任何点来切换点组传说.例如(在下面的示例数据中),如果我单击图例中的 y,它将隐藏/显示所有系列中的点 #4、5 和 10.如果点击 A,则切换点 #1、2 和 8.作为现实生活中的用例——想想债券价格,横轴是到期日,纵轴是价格.债券的特点是来源国、信用等级和发行规模.因此,如果我点击信用评级A",我希望隐藏所有 A 级问题,无论大小和原产国如何.目前,它们仅隐藏在与评级相关的跟踪中.轨迹中反映其他属性(大小和国家/地区)的点仍然显示.鉴于下面的详细答案,我倾向于将此作为功能请求发布在 plotly 的网站上.

我已经为 plotly 提出了问题,但是如果可以在 R 的另一个包/库中以相对较低的痛苦程度(意味着没有自定义 JavaScript 等)实现此行为,我也会接受这个作为答案.[结束编辑]

静态部分很容易在 ggplot2 中完成,但我无法在 plotly 中重新创建它(用于交互性),即使使用 ggplotly().不确定这是否可能,但我想我会问.样本数据和代码如下.

(可能与

调用 ggplotly(p) 会产生一堆警告:

警告信息:1: 如果 (s == Inf) { :条件长度 >1 并且只使用第一个元素2: 如果 (s == Inf) { :条件长度 >1 并且只使用第一个元素3:如果(s == Inf){:条件长度 >1 并且只使用第一个元素4: 如果 (s == Inf) { :条件长度 >1 并且只使用第一个元素5: 如果 (s == Inf) { :条件长度 >1 并且只使用第一个元素6: 如果 (s == Inf) { :条件长度 >1 并且只使用第一个元素7: 如果 (s == Inf) { :条件长度 >1 并且只使用第一个元素8: 如果 (s == Inf) { :条件长度 >1 并且只使用第一个元素

并产生这个数字:

尝试使用 plot_ly(),我得到以下信息:

plot_ly(data = DT, x = x, y = y, color = gr1, symbol = gr2, type = "scatter", mode = "markers", marker = list(size = 10 * gr3)) # size 乘以 10,在 plotly 中以像素为单位

问题在图的中间最为明显——不是彩色十字,而是多个不同颜色的形状相互叠加.由于这是一个单点,我期待一个单一颜色的形状,如 ggplot.在情节中,颜色"、符号"和大小"参数是否创建了新的轨迹?

我对 plotly 还是很陌生,所以我可能遗漏了一些明显的东西.

以上是在Windows下使用R 3.2.2完成的,带有plotly_2.0.16ggplot2_2.0.0.

解决方案

不幸的是,plotly 不会自动给出这种行为.但是,它可以通过单独指定每个点的颜色、形状和大小来完成——使用 colors =size =symbols= 参数.这允许控制点的绘制方式,但不会获得您想要的图例.因此,我们在主图中使用 showlegend = FALSE 并通过添加另外三个(不可见)轨迹来构建图例,这些轨迹仅用于生成图例项.

请注意,我们还需要在这里应用一个技巧.要获得显示颜色或大小的图例,您可以使用参数 visible = "legendonly" 来创建图例条目,而不会在图表上过度绘制额外的点.但这不适用于形状.将 visible = "legendonly"symbols = 组合似乎有一个错误,会在图例中放置错误的项目.因此,要为形状创建图例条目,您可以将它们绘制在平流层中一个它们永远不可见的位置(这里我使用 x=y=1e6)并设置 x 和 y 轴限制以将它们排除在外观点.

DT <- data.table(x = c(1:10), y = 1:10/2,gr1 = as.factor(c(A", A", B", C", D", D", B", A", E", E")),gr2 = as.factor(c(x",x",x",y",y",z",z",x",x",y")),gr3 = c(1,2,2,1,3,4,1,2,2,1))形状 <- c(圆形"、方形"、菱形"、十字"、x"、方形开口"、圆形开口"、菱形开口")DT$shapes <-shapes[DT$gr1]DT$col <- 彩虹(3)[DT$gr2]DT$size <- DT$gr3*10plot_ly() %>%add_trace(data = DT, x = x, y = y, type = "scatter", mode = "markers",颜色=gr2,颜色=col,标记=列表(大小=大小,符号=形状),showlegend=F)%>%add_trace(data = DT, x = x, y = y, type = "scatter",mode = "markers",颜色=因子(gr2),颜色=col,可见="legendonly",showlegend=T,legendgroup="color",标记 = 列表(大小 = 14))%>%add_trace(data = DT, x = x, y = y, type = "scatter",mode = "markers",颜色=因子(gr3),颜色=#000000",标记=列表(大小=大小),可见="legendonly",showlegend=T,legendgroup="size") %>%add_trace(data = DT, x = 1e6, y = 1e6, type = "scatter", mode = "markers",颜色=因子(gr1),颜色=#000000",标记=列表(大小=14,符号=形状),showlegend=T, legendgroup="shape") %>%布局(图例=列表(traceorder =分组+反转",tracegroupgap = 30),xaxis=列表(范围=c(0,12)),yaxis=list(范围=c(0,6)))

I am trying to create (in plotly) a scatterplot which distinguishes the points of the same series by two (or three) aesthetics -- color, shape, size. Ultimately the objective is to be able to toggle groups of points on/off via the legend, using any of the three aesthetics. This works well for one aesthetic.

[Added 2016-06-20] To expand on the desired interactive behavior: The idea is, once the figure is shown, to be able to toggle groups of points by clicking on any of the legends. For example (in the sample data below), if I were to click on y in the legend, it would hide/show points #4, 5 and 10 from all series. If there's a click on A, then toggle points #1, 2 and 8. As a real-life use case -- think bond prices, with maturity on the horizontal axis and price on the vertical. Bonds are characterized by country of origin, credit rating and issue size. So if I click on, say, credit rating "A", I'd like all A-rated issues, regardless of size and country of origin, to be hidden. Currently they are only hidden from the rating-related trace. The points in the traces which reflect the other attributes (size & country) remain shown. Given the detailed answer below, I am inclined to post this as a feature request on plotly's site.

I have framed the question for plotly, but if this behavior can be achieved in another package/library from R with relatively low pain levels (meaning no custom JavaScript or the like), I will accept that as an answer too. [end edit]

The static part is easily done in ggplot2 but I cannot recreate it in plotly (for the interactivity), even using ggplotly(). Not sure if it is possible at all, but thought I'd ask. Sample data & code below.

(Possibly related to Using 2+ legends from R to plotly / plot.ly)

Generate some dummy data:

library(data.table)
library(plotly)
library(ggplot2)


DT <- data.table(
    x = c(1:10), y = 1:10/2,
    gr1 = c("A", "A", "B", "C", "D", "D", "B", "A", "E", "E"),
    gr2 = c("x", "x", "x", "y", "y", "z", "z", "x", "x", "y"),
    gr3 = c(1,2,2,1,3,4,1,2,2,1)
)

The ggplot() version looks like this, and is what I'd like to get in plotly:

p <- ggplot(data = DT) + geom_point(aes(x = x, y = y, color = gr1, shape = gr2, size = gr3))
p

There are three groups of criteria in the legend, and the points have varying color, shape and size.

Calling ggplotly(p) generates a bunch of warnings:

Warning messages:
1: In if (s == Inf) { :
  the condition has length > 1 and only the first element will be used
2: In if (s == Inf) { :
  the condition has length > 1 and only the first element will be used
3: In if (s == Inf) { :
  the condition has length > 1 and only the first element will be used
4: In if (s == Inf) { :
  the condition has length > 1 and only the first element will be used
5: In if (s == Inf) { :
  the condition has length > 1 and only the first element will be used
6: In if (s == Inf) { :
  the condition has length > 1 and only the first element will be used
7: In if (s == Inf) { :
  the condition has length > 1 and only the first element will be used
8: In if (s == Inf) { :
  the condition has length > 1 and only the first element will be used

and produces this figure:

Trying to use plot_ly(), I get the following:

plot_ly(data = DT, x = x, y = y, color = gr1, symbol = gr2, type = "scatter", mode = "markers", marker = list(size = 10 * gr3)) # size is multiplied by 10, in plotly it is in pixels

The problem is most obvious in the middle of the figure -- instead of a colored cross, there are several shapes in different colors overlaid onto one another. Since this is a single point, I am expecting a single colored shape, as in ggplot. In plotly, do the 'color', 'symbol' and 'size' arguments create a new trace?

I am still quite new to plotly, so I may be missing something obvious.

The above is done using R 3.2.2 under Windows, with plotly_2.0.16 and ggplot2_2.0.0.

解决方案

Unfortunately, plotly does not give this behaviour automatically. But, it can be done simply enough by specifying the colour, shape, and size of each point individually -- using the colors =, size =, and symbols = arguments. This allows control over how the points are plotted, but does not get the legend you want. So we use showlegend = FALSE in the main plot and construct the legend by adding three more (invisible) traces that are only there to generate the legend items.

Note that there is one more trick we need to apply here. To get a legend showing colours or sizes, you can use the argument visible = "legendonly" which creates a legend entry without over-plotting extra points on the graph. BUT this does not work with shapes. Combining visible = "legendonly" with symbols = seems to have a bug that puts the wrong items in the legend. So, to create the legend entries for shapes, you can plot them at a location far out in the stratosphere where they will never be visible (here I used x=y=1e6) and set the x and y axis limits to keep these out of view.

DT <- data.table(
  x = c(1:10), y = 1:10/2,
  gr1 = as.factor(c("A", "A", "B", "C", "D", "D", "B", "A", "E", "E")),
  gr2 = as.factor(c("x", "x", "x", "y", "y", "z", "z", "x", "x", "y")),
  gr3 = c(1,2,2,1,3,4,1,2,2,1)
)
shapes <- c("circle", "square", "diamond","cross", "x","square-open","circle-open","diamond-open")
DT$shapes <- shapes[DT$gr1]
DT$col <- rainbow(3)[DT$gr2]
DT$size <- DT$gr3*10

plot_ly() %>%
  add_trace(data = DT, x = x, y = y, type = "scatter", mode = "markers", 
            color=gr2, colors=col,
            marker = list(size = size, symbol=shapes), showlegend=F) %>%
  add_trace(data = DT, x = x, y = y, type = "scatter",mode = "markers", 
            color= factor(gr2), colors=col, 
            visible="legendonly", showlegend=T, legendgroup="color",
            marker = list(size = 14)) %>%
  add_trace(data = DT, x = x, y = y, type = "scatter",mode = "markers", 
            color=factor(gr3), colors="#000000", 
            marker = list(size = size),
            visible="legendonly", showlegend=T, legendgroup="size") %>%
  add_trace(data = DT, x = 1e6, y = 1e6, type = "scatter", mode = "markers", 
            color=factor(gr1), colors="#000000", 
            marker = list(size=14, symbol=shapes),
            showlegend=T, legendgroup="shape") %>%
  layout(legend=list(traceorder="grouped+reversed", tracegroupgap =30),
         xaxis=list(range=c(0,12)),
         yaxis=list(range=c(0,6)))

这篇关于如何使用 plotly 在散点图中同时应用颜色/形状/大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆