How to display clusterproperties on unclustered-point layout? - mapbox

I have MapBox map with clustered-points of cities.
On these clusters, I display the number of address by cities with the clusterProperties "sumAddress: ["+", ["get", "nbAdresses"]]".
If y want display the number of cities dynamically, it doesn't work:
layout: {
"text-field": "{sumAddress}",
"text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
"text-size": 10,
},
And if I replace "{sumAddress}" by string number "1", it's correctly displayed!
Why does the code work with clusters and not with unclustered points?
Complete code:
this.map.on("style.load", () => {
this.map.addSource("cities", {
type: "geojson",
data: this.clustersCoords,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50,
clusterProperties: {
sumAddress: ["+", ["get", "nbAdresses"]], // number of address by cities
},
});
this.map.addLayer({
id: "clusters",
type: "circle",
source: "cities",
filter: ["has", "point_count"],
paint: {
"circle-color": [
"step",
["get", "point_count"],
"#ef9a9a",
100,
"#ea524f",
750,
"#b83523",
],
"circle-radius": [
"step",
["get", "point_count"],
20,
100,
30,
750,
40,
],
},
});
this.map.addLayer({
id: "cluster-label",
type: "symbol",
source: "cities",
filter: ["has", "point_count"],
layout: {
"text-field": "{sumAddress}", // correctly displayed on the clusters
"text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
"text-size": 12,
},
paint: {
"text-color": "#fff",
},
});
// final point, circle displayed but not the symbol whith the dynamic text-field:
this.map.addLayer({
id: "unclustered-point",
type: "circle",
source: "cities",
filter: ["!", ["has", "point_count"]],
paint: {
"circle-color": "#f6ccd2",
"circle-radius": 14,
"circle-stroke-width": 2,
"circle-stroke-color": "#fff",
},
});
this.map.addLayer({
id: "uncluster-label",
type: "symbol",
source: "cities",
filter: ["!", ["has", "point_count"]],
layout: {
"text-field": "{sumAddress}", // not displayed, why ?
"text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
"text-size": 10,
},
paint: {
"text-color": "#000",
},
});
});

Related

How filter features by status

I want to show in my map in a cluster layer filtering by if is opened or not. How can do it? Should I create two layers?
One with filter: filter["has", "opened"] and other with filter: filter["!", ["has", "opened"]]?
export const clusterLayerOpened = {
id: "clusters",
type: "circle",
source: "earthquakes",
filter: ["has", "opened"],
paint: {
"circle-color": [ "step", ["get", "opened"], "#51bbd6",100,"#f1f075",750,"#f28cb1", ],
"circle-radius": ["step", ["get", "opened"], 20, 100, 30, 750, 40],
},
};
export const clusterLayerNoOpened = {
id: "clusters",
type: "circle",
source: "earthquakes",
filter: ["!", ["has", "opened"]],
paint: {
"circle-color": [ "step", ["get", "opened"], "#51bbd6",100,"#f1f075",750,"#f28cb1", ],
"circle-radius": ["step", ["get", "opened"], 20, 100, 30, 750, 40],
},
};
This is my geojson:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": "ak16994521",
"mag": 2.3,
"time": 1507425650893,
"felt": null,
"tsunami": 0,
"opened": true
},
"geometry": {
"type": "Point",
"coordinates": [-151.5129, 63.1016, 0.0]
}
},
{
"type": "Feature",
"properties": {
"id": "ak16994519",
"mag": 1.7,
"time": 1507425289659,
"felt": null,
"tsunami": 0,
"opened": false
},
"geometry": {
"type": "Point",
"coordinates": [-150.4048, 63.1224, 105.5]
}
}
]
}
It's not necessary to create two separate layers to filter by whether the a point has been opened or not. Here is some code showing how to add a layer which displays all points with the property "opened": true, and hides all points with "opened": false:
map.addLayer({
'id': 'opened',
'type': 'circle',
'source': 'points',
'paint': {
'circle-radius': 10,
'circle-opacity': ["match", ["to-string", ["get", "opened"]], 'true', 1 , 'false', 0, 0]
}
});
To instead show all points with the property "opened": false, you can switch the 'circle-opacity' expression to read:
["match", ["to-string", ["get", "opened"]], 'true', 0 , 'false', 1, 0]
This code makes use of a few Mapbox expressions. I've linked the documentation to each relevant expression here: match, to-string, and get.
Here is a JSFiddle where two layers are added to the map: https://jsfiddle.net/hpkzrm4n/. The points with "opened": true are shown in red and the points with "opened": false are shown in blue. Note that you will need to add your own Mapbox access token where indicated in order to view the results. Here is a screenshot, as a preview:

Visibility of villages in Mapbox

In my Mapbox GL project, I have a layer with towns and villages which looks like this:
{
"id": "towns",
"type": "symbol",
"source": "composite",
"source-layer": "place_label",
"minzoom": 1,
"maxzoom": 14,
"filter": [
"all",
[
"match",
["get", "type"],
["town", "village", "hamlet"],
true,
false
],
["match", ["get", "name"], [
// list of villages
], true, false]
],
"layout": {
"text-variable-anchor": ["top", "bottom", "left", "right"],
"text-allow-overlap": true,
"text-ignore-placement": true,
"icon-allow-overlap": true,
"text-field": ["get", "name"],
"text-font": ["Roboto Regular", "Arial Unicode MS Regular"],
"text-size": [
"interpolate",
["linear"],
["zoom"],
3,
8,
22,
16
]
},
"paint": {
"text-halo-color": "hsla(0, 0%, 100%, 0.95)",
"text-halo-width": 1,
"text-halo-blur": 0.4
}
},
The text-size zoom interpolation works fine for the towns. However, the village will only show up after a zoomlevel of 9. Is there any way I could make the villages visible at all time?
Most likely, the Mapbox Streets Tileset you're using only includes those villages in the data after zoom 9, so there is nothing you can do in the style to make it show up earlier.
You'd need to create your own dataset which includes the data you want at lower zoom levels (and maybe just check this is the cause first in Mapbox Studio data view).

Echarts 4 graph plot: specify symbol per category

I am trying to create a graph plot in Echarts 4, where each node belongs to one of two categories: https://codepen.io/autarkie/pen/LqqZjM:
var nodes = [{
"id": 1,
"category": 1
}, {
"id": 2,
"category": 0
}, {
"id": 3,
"category": 1
}, {
"id": 4,
"category": 0
}];
var links = [{
"source": "3",
"target": "1"
}, {
"source": "3",
"target": "2"
}, {
"source": "1",
"target": "2"
}, {
"source": "2",
"target": "4"
}];
var myChart = echarts.init(document.getElementById('chart'));
var option = {
backgroundColor: new echarts.graphic.RadialGradient(0.4, 0.4, 0.7, [{
offset: 0,
color: '#162436'
}, {
offset: 1,
color: '#000'
}]),
legend: {
data: ["Type 1", "Type 2"],
textStyle: {
color: '#fff'
},
icon: 'circle',
type: 'scroll',
orient: 'vertical',
left: 10,
top: 20,
bottom: 20,
itemWidth: 10,
itemHeight: 10
},
animationDurationUpdate: 300,
animationEasingUpdate: 'quinticInOut',
series: [{
type: 'graph',
layout: 'force',
// symbol: 'rect',
//symbolSize: 10,
lineStyle: {
normal: {
curveness: 0.1
}
},
roam: true,
focusNodeAdjacency: true,
legendHoverLink: true,
draggable: true,
force: {
repulsion: 30,
gravity: 0.03,
edgeLength: 50,
layoutAnimation: true
},
data: nodes,
links: links,
categories: [{
name: 'Type 1',
symbol: 'diamond', // !!! DOES NOT WORK !!!
symbolSize: 30, // !!! DOES NOT WORK !!!
itemStyle: {
color: '#79d2a6'
}
},
{
name: 'Type 2',
symbol: "rect", // DOES NOT WORK
symbolSize: 20, // DOES NOT WORK
itemStyle: {
color: '#ff9900'
}
}
],
}]
};
myChart.setOption(option);
Each category should have its own symbol. I know it is possible to specify the symbol for each node separately, like so:
var node_shaped = [{
"id": 1,
"symbol": "rect",
"category": 1
}]
but it this is quite inelegant. Echarts documentation (https://ecomfe.github.io/echarts-doc/public/en/option.html#series-graph.categories.symbol) specifies the option to include a symbol per category, like in the code above. However, that option has no effect whatsoever on the node shapes. Instead, the default circle shape is used. It is possible to change category color using a similar category-wide option, so I am at loss as to why the shape specification doesn't work. Thanks for taking a look.

ChartJS Annotation issue

I'm attempting to use a float/double value for my annotation vertical line depicting the mean of a bell curve. When I use the provided annotation plugin for chartjs, it won't let me use a floating value with a decimal.
var opt1 = {
canvasBorders: true,
canvasBordersWidth: 3,
canvasBordersColor: "black",
legend: true,
datasetFill: false,
annotateDisplay: true,
pointDot: false,
animationLeftToRight: true,
animationEasing: "linear",
yAxisMinimumInterval: 0.02,
graphTitleFontSize: 18,
scales: {
yAxes: [{
position: "left",
"id": "y-axis-0"
}, {
position: "right",
"id": "y-axis-1"
}],
xAxes: [{
"id": "tots-1",
}]
},
annotation: {
annotations: [{
id: 'a-line-1', // optional
type: 'line',
mode: 'vertical',
scaleID: 'tots-1',
value: average,
borderColor: 'red',
borderWidth: 5,}]
}
},
}
Any thoughts?

Styling markers from GeoJSON based on non-string feature properties in Mapbox

as the title suggests, I would like to style some markers stored in a GeoJSON file. In each feature, I saved a "rotate": some_integer, based on how I want to rotate the marker.
In the stylejson in Mapbox I wrote the following style for the markers:
{
"id": "markers_test",
"type": "symbol",
"source": "markers_test",
"layout": {
"symbol-placement": "point",
"icon-image": "marker_{style_id}",
"icon-rotate": "{rotate}",
"text-field": "{name}",
"text-font": ["Open Sans Semibold"],
"text-anchor": "top-left",
"text-padding": 20,
"text-size": 10,
"text-optional": true
},
"paint": {
"text-color": "#dddddd",
"text-halo-color": "#0000ff",
"text-halo-width": 1,
"text-halo-blur": 1
}
}
Setting the correct name and icon works flawlessly, but as soon as I try to set up rotate, it crashes saying the value should be a number, not a string. Only - how do i reference a property of a feature outside a string?
The {token} syntax only works for text-field and icon-image. For all other properties you must use the property function syntax.
{
"id": "markers_test",
"type": "symbol",
"source": "markers_test",
"layout": {
"symbol-placement": "point",
"icon-image": "marker_{style_id}",
"icon-rotate": {
"property": "rotate",
"stops": [[0, 0], [365, 365]]
},
"text-field": "{name}",
"text-font": ["Open Sans Semibold"],
"text-anchor": "top-left",
"text-padding": 20,
"text-size": 10,
"text-optional": true
},
"paint": {
"text-color": "#dddddd",
"text-halo-color": "#0000ff",
"text-halo-width": 1,
"text-halo-blur": 1
}
}