2017-08-31 71 views
1

我想改变下图中点击点的形状和大小。如何实现它?对于这个玩具情节,我已经将原始100k的点数减少到了2k。因此,预期解决方案应该具有高度可扩展性,并且不会偏离原始图,即点击点更新前后的所有颜色应该相同。Shiny:如何更改点击点的形状和/或大小?

library(shiny) 
library(plotly) 

df <- data.frame(X=runif(2000,0,2), Y=runif(2000,0,20), 
       Type=c(rep(c('Type1','Type2'),600), 
         rep(c('Type3','Type4'),400)), 
       Val=sample(LETTERS,2000,replace=TRUE)) 

# table(df$Type, df$Val) 

ui <- fluidPage(
    title = 'Select experiment', 
    sidebarLayout(
    sidebarPanel(
     checkboxGroupInput("SelType", "Select Types to plot:", 
        choices = unique(df$Type), 
        selected = NA) 
    ), 
    mainPanel(
     plotlyOutput("plot", width = "400px"), 
     verbatimTextOutput("click") 
    ) 
) 
) 

server <- function(input, output, session) { 

    output$plot <- renderPlotly({ 
    if(length(input$SelType) != 0){ 
     df <- subset(df, Type %in% input$SelType) 
     p <- ggplot(df, aes(X, Y, col = as.factor(Val))) + 
     geom_point() 
    }else{ 
     p <- ggplot(df, aes(X, Y, col = as.factor(Val))) + 
     geom_point() 
    } 
    ggplotly(p) %>% layout(height = 800, width = 800) 

    }) 

    output$click <- renderPrint({ 
    d <- event_data("plotly_click") 
    if (is.null(d)) "Click events appear here (double-click to clear)" 
    else cat("Selected point associated with value: ", d$Val) 
    }) 

} 

shinyApp(ui, server) 

enter image description here

一个相关question这里已经问过,但强调有颜色的点的这种做法不工作(当一个变量的水平数为高,难以对可能已经存在于该图中的颜色进行硬编码)。

回答

2

Plotly的restyle函数不会帮助我们,但我们仍然可以使用onclickevent以及一点JavaScript。该代码具有10,000点的可接受性能。


我们可以用得到它被点击JavaScript中的一点:

var point = document.getElementsByClassName('scatterlayer')[0].getElementsByClassName('scatter')[data.points[0].curveNumber].getElementsByClassName('point')[data.points[0].pointNumber]; 

scatterlayer是所有散点图元件位于层, scatter[n]是第n个散点图和point[p]是其中的第p个点)

现在我们只是让这个点变大很多(或者任何其他想要的形状/变形):

point.setAttribute('d', 'M10,0A10,10 0 1,1 0,-10A10,10 0 0,1 10,0Z'); 

为了获得可能恢复一切,我们用的Plotly其余信息一起存储有关该点的不变信息:

var plotly_div = document.getElementsByClassName('plotly')[0]; 
plotly_div.backup = {curveNumber: data.points[0].curveNumber, 
        pointNumber: data.points[0].pointNumber, 
        d: point.attributes['d'].value 
        } 

,后来我们就可以恢复了一点:

var old_point = document.getElementsByClassName('scatterlayer')[0].getElementsByClassName('scatter')[plotly_div.backup.curveNumber].getElementsByClassName('point')[plotly_div.backup.pointNumber] 
old_point.setAttribute('d', plotly_div.backup.d); 

现在我们可以将所有代码添加到plotly小部件。

javascript <- " 
function(el, x){ 
    el.on('plotly_click', function(data) { 
    var point = document.getElementsByClassName('scatterlayer')[0].getElementsByClassName('scatter')[data.points[0].curveNumber].getElementsByClassName('point')[data.points[0].pointNumber]; 
    var plotly_div = document.getElementsByClassName('plotly')[0]; 
    if (plotly_div.backup !== undefined) { 
     var old_point = document.getElementsByClassName('scatterlayer')[0].getElementsByClassName('scatter')[plotly_div.backup.curveNumber].getElementsByClassName('point')[plotly_div.backup.pointNumber] 
     if (old_point !== undefined) { 
     old_point.setAttribute('d', plotly_div.backup.d); 
     } 
    } 
    plotly_div.backup = {curveNumber: data.points[0].curveNumber, 
         pointNumber: data.points[0].pointNumber, 
         d: point.attributes['d'].value, 
         style: point.attributes['style'].value 
         } 

    point.setAttribute('d', 'M10,0A10,10 0 1,1 0,-10A10,10 0 0,1 10,0Z'); 
    }); 
}" 

[...] 

ggplotly(p) %>% onRender(javascript) 

或者你可以把基于点击点的位置,但在颜色的新SVG元素,塑造你想。


你可以在这里试试没有R/Shiny。

//create some random data 
 
var data = []; 
 
for (var i = 0; i < 10; i += 1) { 
 
    data.push({x: [], 
 
      y: [], 
 
      mode: 'markers', 
 
      type: 'scatter'}); 
 
    for (var p = 0; p < 200; p += 1) { 
 
    data[i].x.push(Math.random()); 
 
    data[i].y.push(Math.random()); 
 
    } 
 
} 
 
//create the plot 
 
var myDiv = document.getElementById('myDiv'); 
 
Plotly.newPlot(myDiv, data, layout = { hovermode:'closest'}); 
 

 
//add the same click event as the snippet above 
 
myDiv.on('plotly_click', function(data) { 
 
    //let's check if some traces are hidden 
 

 
    var traces = document.getElementsByClassName('legend')[0].getElementsByClassName('traces'); 
 
    var realCurveNumber = data.points[0].curveNumber; 
 
    for (var i = 0; i < data.points[0].curveNumber; i += 1) { 
 
     if (traces[i].style['opacity'] < 1) { 
 
      realCurveNumber -= 1 
 
     } 
 
    } 
 

 
    data.points[0].curveNumber = realCurveNumber; 
 
    var point = document.getElementsByClassName('scatterlayer')[0].getElementsByClassName('scatter')[data.points[0].curveNumber].getElementsByClassName('point')[data.points[0].pointNumber]; 
 
    var plotly_div = document.getElementsByClassName('plotly')[0]; 
 
    if (plotly_div.backup !== undefined) { 
 
     var old_point = document.getElementsByClassName('scatterlayer')[0].getElementsByClassName('scatter')[plotly_div.backup.curveNumber].getElementsByClassName('point')[plotly_div.backup.pointNumber] 
 
     if (old_point !== undefined) { 
 
     old_point.setAttribute('d', plotly_div.backup.d); 
 
     } 
 
    } 
 
    plotly_div.backup = {curveNumber: data.points[0].curveNumber, 
 
         pointNumber: data.points[0].pointNumber, 
 
         d: point.attributes['d'].value, 
 
         style: point.attributes['style'].value 
 
         } 
 

 
    point.setAttribute('d', 'M10,0A10,10 0 1,1 0,-10A10,10 0 0,1 10,0Z'); 
 
    });
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script> 
 
<div id="myDiv">

+0

同样优异的溶液(1)最大。 – Prradep

+0

将解决方案合并到发布的场景中后,我注意到了一个奇怪的行为(我不确定它是否是预期的)。当没有选择任何“类型”并且点击某个点时,点击的点会以相同的颜色增加大小。虽然形状没有改变,但它具有可扩展性并与其他附近的点明显区分开来。现在,当您选择一个“类型”时,会在同一区域生成一个新图。令人惊讶的是,点击点时上述效果不可用。我认为应该有一点调整来解决这个问题。 – Prradep

+0

另一个观察结果是,如果我们取消选择所选类型并返回到原始绘图,上述功能将被恢复。 – Prradep