通过内部标记着色簇

时间:2017-11-27 09:42:00

标签: r shiny leaflet

我想知道,如何根据其中的图标为群集着色。

我的数据:

remorque       time.stamp      lat      long geolocalisation maintenance temperature appairage
1        21/11/2017 10:36 48.86272 2.2875920          OnMouv        noir                      
2        21/11/2017 10:36 43.60776 1.4421606       StartMouv                   rouge          
3        21/11/2017 10:36 46.58619 0.3388710          OnMouv                   rouge          
4        21/11/2017 10:36 45.76695 3.0556216            Life                  orange          
5        21/11/2017 10:36 45.14555 1.4751652         EndMouv                             rouge
6        21/11/2017 10:36 46.81157 1.6936336            Life                  orange          
7        21/11/2017 10:36 47.36223 0.6751146          alerte                             rouge
8        21/11/2017 10:36 47.36032 1.7441244       StartMouv                                  
9        21/11/2017 10:36 48.85333 1.8215332       StartMouv                                  
10       21/11/2017 10:36 48.84429 1.7913208          alerte                                  
11       21/11/2017 10:36 48.81356 1.6759643         EndMouv                                  

示例:

如果群集中有图标,并且appairage = rouge,则群集的颜色应为红色。

如果没有红色图标,如果我的群集中有一个图标,温度=橙色,则群集的颜色应为橙色。

...对于每个变量(温度,应用,维护)。如果culster中的所有图标的变量都正常,则群集应为绿色。

我的地图如下:

Beanshell Server

我找到了一种方法来改变互联网上群集着色的范围。但我不想为群集中的每个标记数着色。

2 个答案:

答案 0 :(得分:6)

可以根据聚集在一起的图标的属性为聚类图标着色。最简单的方法可能是使用htmlwidgets并在地图渲染上调用javascript函数。

但是,在访问htmlwidget之前,您需要为集群层设置clusterId:

addAwesomeMarkers(clusterId = "cluster" ...

现在我们可以在htmlwidget中找到这个图层:

function(el, x) {
  map = this;  // the map object
  var cluster = map.layerManager.getLayer('cluster','cluster'); // the cluster layer

在群集层中,我们要为图标属性iconCreateFunction创建一个函数:

cluster.options.iconCreateFunction = function(d) {
    // generate icon
}

此功能应该:

  1. 遍历群集标记所代表的所有子标记
  2. 确定这些儿童标记的最高等级
  3. 返回合适的图标
  4. <强> 1。通过子标记迭代

    对于第一,并在上面构建,我们可以使用:

    遍历每个子标记
    cluster.options.iconCreateFunction = function(c) {
        var markers = c.getAllChildMarkers();
        markers.forEach(function(m) {
           // do something for each marker
        })
    }
    

    我正在使用c来表示群集,m来表示每个子标记

    <强> 2。获得最高排名标记

    列表中的主要挑战是识别子图标的最高等级 - 因为数据未绑定到我们在选项中受限的图标。假设图标的颜色对应于数据框中项目的颜色代码,我将使用图标的颜色来确定其优先级/等级。在确定排名最高的孩子之后,我将根据孩子的等级为群集着色。

    我将按如下方式为群集着色(因为我相信这是您的预期结果):

    • 红色,如果有任何子图标为红色,
    • 橙色,如果没有红色,但有一些橙色的孩子,
    • 绿色,如果没有橙色或红色的孩子。

    要获得颜色,我需要访问适当的属性。 (真棒)标记的颜色(填充)位于:

    marker.options.icon.options.markerColor
    

    为了比较颜色,我将使用一个对象来表示每种颜色的等级,这将允许简单的颜色比较:

    var priority = {
      'green':0,
      'orange':1,
      'red':2
    }
    

    这允许:

    cluster.options.iconCreateFunction = function(c) {
      var markers = c.getAllChildMarkers();
      var priority = {
        'green': 0,
        'orange': 1,
        'red': 2
      };
      var highestRank = 0; // defaults to the lowest level to start
    
      markers.forEach(function(m) {
        var color = m.options.icon.options.markerColor;
    
        // check each marker to see if it is the highest value
        if(priority[color] > highestRank) {
          highestRank = priority[color];  
        }                      
      })
    }
    

    第3。返回图标

    现在我们有一个代表颜色的值,我们可以返回一个图标。 Leaflet集群图标具有有限的样式选项。他们使用L.divIcon(),这在某种程度上限制了选项。当与群集标签的CSS样式结合使用时,它们会创建一个熟悉的绿色,黄色和橙色圆圈。

    这些默认样式具有以下css类:

    .marker-cluster-small // green
    .marker-cluster-medium  // yellow
    .marker-cluster-large // orange
    

    如果我们对使用这些类感到满意,我们可以轻松地设置聚簇多边形的样式:

    var styles = [
        'marker-cluster-small', // green
        'marker-cluster-medium',  // yellow
        'marker-cluster-large' // orange
    ]
    
    var style = styles[highestRank];
    var count = markers.length;
    
    return L.divIcon({ html: '<div><span>'+count+'</span></div>', className: 'marker-cluster ' + style, iconSize: new L.Point(40, 40) });
    

    因此整个小部件看起来像:

    function(el,x) {
      map = this;  
      var cluster = map.layerManager.getLayer('cluster','cluster'); 
      cluster.options.iconCreateFunction = function(c) {
        var markers = c.getAllChildMarkers();
        var priority = {
          'green': 0,
          'orange': 1,
          'red': 2
        };
        var highestRank = 0; // defaults to the lowest level to start
    
        markers.forEach(function(m) {
          var color = m.options.icon.options.markerColor;
    
          // check each marker to see if it is the highest value
          if(priority[color] > highestRank) {
            highestRank = priority[color];  
          }                      
        })
    
        var styles = [
          'marker-cluster-small', // green
          'marker-cluster-medium',  // yellow
          'marker-cluster-large' // orange
        ]
    
        var style = styles[highestRank];
        var count = markers.length;
    
        return L.divIcon({ html: '<div><span>'+count+'</span></div>', className: 'marker-cluster ' + style, iconSize: new L.Point(40, 40) });
      }
    }
    

    优化图标

    更改颜色

    您可能希望高优先级图标显示为红色。这可以完成,但您需要为地图添加CSS样式。

    在更改上面的图标功能的同时执行此操作的一种方法是在窗口小部件中使用javascript将样式附加到页面。你需要制作两种风格,一种用于拿着图标的div,另一种用于图标,你可以同时做两种:

    var style = document.createElement('style');
      style.type = 'text/css';
      style.innerHTML = '.red, .red div { background-color: rgba(255,0,0,0.6); }'; // set both at the same time
      document.getElementsByTagName('head')[0].appendChild(style);
    

    (来自https://stackoverflow.com/a/1720483/7106086

    不要忘记更新样式数组中使用的类:

        var styles = [
          'marker-cluster-small', // green
          'marker-cluster-medium',  // yellow
          'red' // red
        ]
    

    在图标中显示更多信息

    您不仅限于图标中的数字,您可以显示1-3-5,表示一个高优先级,三个中等。您只需要跟踪每个优先级中有多少个子图标簇:

    var children = [0,0,0];
    markers.forEach(function(m) {
      var color = m.options.icon.options.markerColor;
      children[priority[color]]++; // increment the appropriate value in the children array.
      ...
    

    然后用:

    显示
    return L.divIcon({ html: '<div><span>'+children.reverse()+'</span>...
    

    提供类似的内容:

    enter image description here

    测试示例

    这应该是copy and pastable以显示除图标中的其他文本之外的所有内容(使用这些documentation examples中的代码作为基础):

    library(leaflet)
    
    # first 20 quakes
    df.20 <- quakes[1:50,]
    
    getColor <- function(quakes) {
      sapply(quakes$mag, function(mag) {
        if(mag <= 4) {
          "green"
        } else if(mag <= 5) {
          "orange"
        } else {
          "red"
        } })
    }
    
    icons <- awesomeIcons(
      icon = 'ios-close',
      iconColor = 'black',
      library = 'ion',
      markerColor = getColor(df.20)
    )
    
    leaflet(df.20) %>% addTiles() %>%
      addAwesomeMarkers(~long, ~lat, icon=icons, label=~as.character(mag), clusterOptions = markerClusterOptions(), group = "clustered", clusterId = "cluster") %>%
      htmlwidgets::onRender("function(el,x) {
      map = this;  
    
      var style = document.createElement('style');
      style.type = 'text/css';
      style.innerHTML = '.red, .red div { background-color: rgba(255,0,0,0.6); }'; // set both at the same time
      document.getElementsByTagName('head')[0].appendChild(style);
    
    
      var cluster = map.layerManager.getLayer('cluster','cluster'); 
      cluster.options.iconCreateFunction = function(c) {
        var markers = c.getAllChildMarkers();
        var priority = {
         'green': 0,
         'orange': 1,
         'red': 2
        };
        var highestRank = 0; // defaults to the lowest level to start
    
        markers.forEach(function(m) {
        var color = m.options.icon.options.markerColor;
    
        // check each marker to see if it is the highest value
        if(priority[color] > highestRank) {
           highestRank = priority[color];  
         }                      
      })
    
      var styles = [
        'marker-cluster-small', // green
        'marker-cluster-large',  // orange
        'red' // red
      ]
    
      var style = styles[highestRank];
      var count = markers.length;
    
       return L.divIcon({ html: '<div><span>'+count+'</span></div>', className: 'marker-cluster ' + style, iconSize: new L.Point(40, 40) });
     }
    }")
    

答案 1 :(得分:0)

您现在还可以在iconCreateFunction中使用markerClusterOptions。确保在markerOptions中传递要用于着色的变量。

另请参阅:leaflet R, how to make appearance of clustered icon related to statistics of the children?

一个例子是:

legend_pal <- hcl.colors(10, palette='Spectral', rev = T)

leaflet(quakes) %>% addTiles() %>% addMarkers(
  options = markerOptions(mag = ~mag),
  clusterOptions = markerClusterOptions(
    iconCreateFunction=~JS(paste0("function (cluster) {    
                          var markers = cluster.getAllChildMarkers();
                          var sum = 0; 
                          for (i = 0; i < markers.length; i++) {
                            sum += Number(markers[i].options.mag);
                          }
                          var palette = ['", paste0(legend_pal, collapse="','"),"'];
                          var domain = [", paste0(sort(unique(na.omit(mag))), collapse=','),"];

                          var count = markers.length;
                          var avg = sum/count;
                          c = palette[Math.round(palette.length*(avg-Math.min(...domain))/(Math.max(...domain) - Math.min(...domain)))];


                          return L.divIcon({ 
                            html: '<div style=\"background-color:'+c+'\"><span>'+avg+'</span></div>', 
                            className: 'marker-cluster', 
                            iconSize: new L.Point(40, 40) });
                          }")))) %>% 
  addLegend(pal=colorNumeric(
    palette = legend_pal,
    domain = quakes$mag,
    na.color = 'transparent'), values = ~mag)