具有 leafletR 可变点大小的交互式地图
interactive map with leafletR variable point size
我创建的交互式地图如下:
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)
现在,我想让圆的大小取决于另一个变量。假设变量 'stations'。我怎样才能做到这一点?如果这个包不可能,我愿意使用另一个包......只要我能放一个图例,地图是交互式的,点击时会出现一个弹出窗口,颜色可以取决于值一个连续变量。
我通读了 leafletR 包的 documentation,在我看来(我可能是错的)当前版本不支持同一数据集的多种样式。他们给出了一些示例,其中通过列出它们来组合 2 个 styleSingles(例如 style=list(sty.1, sty.2)
),但这仅适用于列出 2 个不同的数据集(有关更多详细信息,请参见文档中的第 8 页)。我尝试了各种技巧,但其中 none 对我有用。
但是,我提出了一个您可能想尝试的 hacky 解决方案。使用 leaflet()
函数创建 html 页面后,您可以编辑处理样式的 Javascript 代码,使 radius
属性 动态(这可能也适用于其他样式属性,例如 fill
、alpha
等)。
你需要知道的:
在 leaflet 创建的 HTML 文档中,搜索 style1(feature)
函数的定义。您应该找到以下代码段:
function style1(feature) {
return {"color": getValue(feature.properties.mag),
"fillOpacity": 0.7,
"radius": 8};
}
此函数基本上 returns 数据集中每条记录的样式。如您所见,当前形式的函数 returns 是 fillOpacity
和 radius
的静态值。但是,当涉及到颜色时,它会调用另一个名为 getValue
的函数并将 mag
(幅度)属性 传递给它。如果我们看一下 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";
}
函数定义真的很简单。如果 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)
};
}
因此,有了 style1(feature)
的新定义,现在我们可以控制数据点的颜色和半径。代码修改的结果如下所示:
这种方法的好处在于,它可以让您更精细地控制样式属性和它们可以具有的值的范围。主要的缺点是,如果您想为这些属性添加图例,则必须手动进行。 adding/editing 图例的逻辑应该在 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] + '–' + grades[i + 1] + '<br>';
}
return div;
};
上面的代码简单地遍历了幅度值的范围,并创建了一个框(具有适当的颜色,引用了我们之前看过的 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] + '–' + 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] + '–' + rad_grades[i + 1] + '</td></tr></table>';
}
return div;
};
如您所见,我们控制的样式类型 属性 将决定我们如何在图例中指定它。例如,如果您想为 alpha
属性 添加图例,那么您可能想尝试使用圆圈并控制其宽度和高度以外的其他方法。上述代码修改的最终结果如下所示:
此外,如果您想在弹出窗口中包含电台数量,则必须编辑 onEachFeature
函数。这将与我们对所有其他修改采用的方法相同,而且这是一个非常简单的更改。
onEachFeature
函数在原来的 HTML 中看起来像这样:
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.mag) {
layer.bindPopup("mag: " + feature.properties.mag);
}
}
如果你想在弹出窗口中也包含站点数,那么你需要将其包含在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);
}
}
此更改的最终结果如下:
希望这对您有所帮助。
我创建的交互式地图如下:
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)
现在,我想让圆的大小取决于另一个变量。假设变量 'stations'。我怎样才能做到这一点?如果这个包不可能,我愿意使用另一个包......只要我能放一个图例,地图是交互式的,点击时会出现一个弹出窗口,颜色可以取决于值一个连续变量。
我通读了 leafletR 包的 documentation,在我看来(我可能是错的)当前版本不支持同一数据集的多种样式。他们给出了一些示例,其中通过列出它们来组合 2 个 styleSingles(例如 style=list(sty.1, sty.2)
),但这仅适用于列出 2 个不同的数据集(有关更多详细信息,请参见文档中的第 8 页)。我尝试了各种技巧,但其中 none 对我有用。
但是,我提出了一个您可能想尝试的 hacky 解决方案。使用 leaflet()
函数创建 html 页面后,您可以编辑处理样式的 Javascript 代码,使 radius
属性 动态(这可能也适用于其他样式属性,例如 fill
、alpha
等)。
你需要知道的:
在 leaflet 创建的 HTML 文档中,搜索 style1(feature)
函数的定义。您应该找到以下代码段:
function style1(feature) {
return {"color": getValue(feature.properties.mag),
"fillOpacity": 0.7,
"radius": 8};
}
此函数基本上 returns 数据集中每条记录的样式。如您所见,当前形式的函数 returns 是 fillOpacity
和 radius
的静态值。但是,当涉及到颜色时,它会调用另一个名为 getValue
的函数并将 mag
(幅度)属性 传递给它。如果我们看一下 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";
}
函数定义真的很简单。如果 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)
};
}
因此,有了 style1(feature)
的新定义,现在我们可以控制数据点的颜色和半径。代码修改的结果如下所示:
这种方法的好处在于,它可以让您更精细地控制样式属性和它们可以具有的值的范围。主要的缺点是,如果您想为这些属性添加图例,则必须手动进行。 adding/editing 图例的逻辑应该在 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] + '–' + grades[i + 1] + '<br>';
}
return div;
};
上面的代码简单地遍历了幅度值的范围,并创建了一个框(具有适当的颜色,引用了我们之前看过的 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] + '–' + 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] + '–' + rad_grades[i + 1] + '</td></tr></table>';
}
return div;
};
如您所见,我们控制的样式类型 属性 将决定我们如何在图例中指定它。例如,如果您想为 alpha
属性 添加图例,那么您可能想尝试使用圆圈并控制其宽度和高度以外的其他方法。上述代码修改的最终结果如下所示:
此外,如果您想在弹出窗口中包含电台数量,则必须编辑 onEachFeature
函数。这将与我们对所有其他修改采用的方法相同,而且这是一个非常简单的更改。
onEachFeature
函数在原来的 HTML 中看起来像这样:
function onEachFeature(feature, layer) {
if (feature.properties && feature.properties.mag) {
layer.bindPopup("mag: " + feature.properties.mag);
}
}
如果你想在弹出窗口中也包含站点数,那么你需要将其包含在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);
}
}
此更改的最终结果如下:
希望这对您有所帮助。