具有leafletR可变点大小的交互式地图

Rog*_*ger 1 r leaflet

我创建了一个交互式地图如下:

library(leafletR)
data(quakes)

# store data in GeoJSON file (just a subset here)
q.dat <- toGeoJSON(data=quakes[1:99,], dest=tempdir(), name="quakes")

# make style based on quake magnitude
q.style <- styleGrad(prop="mag", breaks=seq(4, 6.5, by=0.5), style.val=rev(heat.colors(5)), leg="Richter Magnitude", fill.alpha=0.7, rad=8)

# create map
q.map <- leaflet(data=q.dat, dest=tempdir(), title="Fiji Earthquakes", base.map="osm", style=q.style, popup="mag")

# view map in browser
rstudio::viewer(q.map)
Run Code Online (Sandbox Code Playgroud)

现在,我想让圆的大小依赖于另一个变量.让我们说变量'station'.我怎样才能做到这一点?如果这个包不可能,我打开使用另一个包...只要我可以放一个图例,地图是交互式的,点击时会出现一个弹出窗口,颜色可能取决于连续变量.

sza*_*bad 9

我阅读了leafletR包的文档,在我看来(我可能错了)当前版本不支持同一数据集的多个样式.他们给出了一些例子,他们通过列出它们来组合2个样式(例如style=list(sty.1, sty.2)),但这只与列出2个不同的数据集一起使用(更多细节请参见文档中的P.8).我尝试了各种技巧,但没有一个能为我工作.

但是,我想出了一个你可能想尝试的hacky解决方案.通过创建HTML页面后leaflet()功能,您可以编辑处理的造型,使Javascript代码radius属性的动态(这也可以工作,为其他样式属性,如fill,alpha等).

你需要知道的:

在传单创建的HTML文档中,搜索style1(feature)函数的定义.您应该找到以下代码段:

function style1(feature) {
    return {"color": getValue(feature.properties.mag),
            "fillOpacity": 0.7, 
            "radius": 8};
}
Run Code Online (Sandbox Code Playgroud)

此函数基本上返回数据集中每条记录的样式.正如你所看到的,在目前形式的函数返回一个静态值fillOpacityradius.但是,当涉及到颜色时,它会调用另一个被调用的函数getValue并将其传递给mag(magnitude)属性.如果我们看一下getValue函数的定义,我们会看到它只是定义了每种颜色的幅度范围:

function getValue(x) {
    return x >= 6.5 ? "#808080" :
           x >= 6 ? "#FF0000" :
           x >= 5.5 ? "#FF5500" :
           x >= 5 ? "#FFAA00" :
           x >= 4.5 ? "#FFFF00" :
           x >= 4 ? "#FFFF80" :
           "#808080";
}  
Run Code Online (Sandbox Code Playgroud)

功能定义非常简单.如果x(在这种情况下的大小)大于或等于6.5,则该数据点的颜色将为"#808080".如果它在6到6.5之间,那么颜色将是#FF0000".依此类推.

你可以做什么:

现在我们看到Javascript代码如何处理颜色如何分配给每个数据点,我们可以用很少的努力为所有其他样式属性做类似的事情.例如,以下代码段显示了如何根据区域中的工作站数量使半径动态化:

/* The getValue function controls the color of the data points */ 
function getValue(x) {
    return x >= 6.5 ? "#808080" :
           x >= 6 ? "#FF0000" :
           x >= 5.5 ? "#FF5500" :
           x >= 5 ? "#FFAA00" :
           x >= 4.5 ? "#FFFF00" :
           x >= 4 ? "#FFFF80" :
           "#808080";
}

/* The getRadValue function controls the radius of the data points */ 
function getRadValue(x) {
    return x >= 100 ? 24 :
           x >= 80 ? 20 :
           x >= 60 ? 16 :
           x >= 40 ? 12 :
           8;
}

/* The updated definition of the style1 function */
function style1(feature) {
    return {"color": getValue(feature.properties.mag),
            "fillOpacity": 0.7, 
            "radius": getRadValue(feature.properties.stations)
            };
}
Run Code Online (Sandbox Code Playgroud)

因此,使用新定义style1(feature),现在我们可以控制数据点的颜色和半径.代码修改的结果如下所示:

在此输入图像描述

这种方法的好处在于它可以让您对样式属性和它们可以拥有的值范围进行更细粒度的控制.主要的缺点是如果你想为这些属性添加一个图例,那么你必须手动完成.添加/编辑图例的逻辑应位于HTML文档的最底部,如果您了解Javascript/HTML/CSS,则编辑该代码段应该不会太困难.

更新:

要为新动态变量添加图例(在我们的示例中为半径),您需要编辑.onAdd附加到图例对象的处理程序.正如我之前所说,此处理程序的定义通常位于html页面的底部,如果我们运行您在问题中提供的一些代码,那么处理程序应如下所示:

legend.onAdd = function (map) {
    var div = L.DomUtil.create('div', 'legend');
    var labels = [];
    var grades = [4, 4.5, 5, 5.5, 6, 6.5];

    div.innerHTML += 'Richter Magnitude<br>';
    for (var i = 0; i < grades.length - 1; i++) {
        div.innerHTML += '<i style="background:' + getValue(grades[i]) + '"></i> ' + grades[i] + '&ndash;' + grades[i + 1] + '<br>';
    }

    return div;
};
Run Code Online (Sandbox Code Playgroud)

上面的代码只是循环遍历大小的值范围,并创建一个框(具有适当的颜色,引用getValue我们之前查看过的函数)和一个标签.如果你想为stations变量创建类似的东西,比方说,我们可以使用上面相同的逻辑.虽然在这种情况下不是改变颜色,但我们将改变圆的大小.以下代码段显示了如何实现:

legend.onAdd = function (map) {
    var div = L.DomUtil.create('div', 'legend');
    var labels = [];
    var grades = [4, 4.5, 5, 5.5, 6, 6.5];

    div.innerHTML += 'Richter Magnitude<br>';
    for (var i = 0; i < grades.length - 1; i++) {
        div.innerHTML += '<i style="background:' + getValue(grades[i]) + '"></i> ' + grades[i] + '&ndash;' + grades[i + 1] + '<br>';
    }

    // Adding the range of possible of values that the variable might take
    // This should be in sync with the range of values you considered in
    // the getRadValue function. 

    var rad_grades = [40, 60, 80, 100];
    // The title for this section of the legend
    div.innerHTML += 'Number of stations<br>'
    for (var i = 0; i < rad_grades.length - 1; i++) {
        div.innerHTML += '<table style="border: none;"><tr><td class="circle" style="width: ' +  
            (getRadValue(rad_grades[rad_grades.length - 2]) * 2 + 6) + 'px;"><svg style="width: ' +  
            (getRadValue(rad_grades[i]) * 2 + 6) + 'px; height: ' + (getRadValue(rad_grades[i]) * 2 + 6) +  
            'px;" xmlns="http://www.w3.org/2000/svg" version="1.1"><circle cx="' + (getRadValue(rad_grades[i]) + 3) + '" cy="' + 
            (getRadValue(rad_grades[i]) + 3) + '" r="' + getRadValue(rad_grades[i]) + '" /></svg></td><td class="value">' + 
            rad_grades[i] + '&ndash;' + rad_grades[i + 1] + '</td></tr></table>';
        }

    return div;
};
Run Code Online (Sandbox Code Playgroud)

如您所见,我们控制的样式属性类型将决定我们如何在图例中指定它.例如,如果要为alpha属性添加图例,则可能需要尝试其他方法,而不是使用圆并控制其宽度和高度.上面代码修改的最终结果如下所示:

在此输入图像描述

此外,如果要在弹出窗口中包含站点数,则必须编辑该onEachFeature功能.它将与我们对所有其他修改采用的方法相同,而且这是一个非常简单的更改.

onEachFeature函数在原始HTML中如下所示:

function onEachFeature(feature, layer) {
    if (feature.properties && feature.properties.mag) {
        layer.bindPopup("mag: " + feature.properties.mag);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果要在弹出窗口中包含站点数,则需要将其包含在bindPopup方法的参数中,如下所示:

function onEachFeature(feature, layer) {
    if (feature.properties && feature.properties.mag && feature.properties.stations) {
        layer.bindPopup("mag: " + feature.properties.mag + "<br> # Stations: " + feature.properties.stations);
    }
} 
Run Code Online (Sandbox Code Playgroud)

此更改的最终结果如下:

在此输入图像描述

希望这可以帮助.