Symbol placed with line-center doesn't rotate as the map rotates - mapbox

I'm having a problem rotating an image with property symbol-placement set to line-center.
This is what it looks like
Removing the property half-solve the issue; the icon rotate as I rotate the map, but they position at the start of the line, and it's not what I'm trying to do.
The definition of my layer is:
{
"id": "my_symbol",
"type": "symbol",
"source": "XXXX",
"source-layer": "XXXXXXX",
"minzoom": 19,
"layout": {
"symbol-placement": "line-center",
"icon-size": {
"stops": [
[20, 0.2],
[21, 0.1],
[22, 0.3],
[23, 0.5],
[24, 0.7]
]
},
"icon-image": [
"concat",
"edge_",
["get", "status_list"]
],
"icon-allow-overlap": true
}
}
I'm trying to achieve this behaviour only by the layer's definition.
I tried looking for a solution, here on SO and on some other sites but I haven't found anything that would help me.

you can set your icon rotation with icon-rotation-alignment
setting it to viewport will fix the icon rotation to your viewport while setting it to map won't rotate it
i'm sorry the gif is hard to see!
{
"id": "my_symbol",
"type": "symbol",
"source": "XXXX",
"source-layer": "XXXXXXX",
"minzoom": 19,
"layout": {
"symbol-placement": "line-center",
"icon-size": {
"stops": [
[20, 0.2],
[21, 0.1],
[22, 0.3],
[23, 0.5],
[24, 0.7]
]
},
"icon-image": [
"concat",
"edge_",
["get", "status_list"]
],
"icon-allow-overlap": true,
"symbol-placement": "line-center",
"icon-rotation-alignment": "viewport"
}
}

Related

Remove empty space from Streamlit Echarts

I am rendering a gauge component in the following way, within my Streamlit app:
option = {
"series": [
{
"type": "gauge",
"startAngle": 180,
"endAngle": 0,
"min": min_range_val,
"max": max_range_val,
"center": ["40%", "40%"],
"splitNumber": 5,
"axisLine": {
"lineStyle": {
"width": 6,
"color": [
[0.25, "#FF403F"],
[0.5, "#ffa500"],
[0.75, "#FDDD60"],
[1, "#64C88A"],
],
}
},
"pointer": {
"icon": "path://M12.8,0.7l12,40.1H0.7L12.8,0.7z",
"length": "12%",
"width": 30,
"offsetCenter": [0, "-60%"],
"itemStyle": {"color": "auto"},
},
"axisTick": {"length": 10, "lineStyle": {"color": "auto", "width": 2}},
"splitLine": {"length": 15, "lineStyle": {"color": "auto", "width": 5}},
"axisLabel": {
"color": "#464646",
"fontSize": 12,
"distance": -60,
},
"title": {"offsetCenter": [0, "-20%"], "fontSize": 20},
"detail": {
"fontSize": 30,
"offsetCenter": [0, "0%"],
"valueAnimation": True,
"color": "auto",
"formatter": "{value}%",
},
"data": [{"value": value, "name": caption}],
}
]
}
st_echarts(option, width="450px", height="350px", key="gauge")
However, it seems like an additional empty extra white space is added at the bottom of the component (as from the following image).
How can I effectively remove that and keep only a tiny margin all around the gauge?
The following parameters must be added:
radius: '120%',
center: ['50%', '80%']
The latter one should be adjusted according to specific use cases.

Extrude land in MapBox

I am trying to emphasize the fact that the land is higher than the water in my map so wanted to add an extrusion to the land layer. I thought taking the https://docs.mapbox.com/mapbox-gl-js/example/3d-buildings/ of the one with buildings and changing the layer source to 'land' would work but it didn't. Is this something specific to building layers or am I doing something wrong? Here is my layer definition in my style JSON:
{
"id": "3d-land",
"source": "composite",
"source-layer": "land", # Changed this from building
"filter": ["==", "extrude", "true"],
"type": "fill-extrusion",
"minzoom": 0,
"paint": {
"fill-extrusion-color": "#000",
"fill-extrusion-height": [
"interpolate", ["linear"], ["zoom"],
15, 0,
18.0, 30.0
],
"fill-extrusion-base": [
"interpolate", ["linear"], ["zoom"],
15, 0,
18.0, ["get", "min_height"]
],
"fill-extrusion-opacity": 0.8
}
}
First reason is as the console says, "land" does not exist on source "composite". "land" layer is background layer which is exist separately in the style. You cannot use fill-extrusion for background layer. You may want to use layers which use "compose" source.
The other reason is from filter. "filter": ["==", "extrude", "true"] means filtering if the value of layer's property called "extrude" is "true". land layer doesn't have a property extrude so it's always false.
So, the result of fix would be looks like:
map.addLayer(
{
id: "3d-landcover",
source: "composite",
"source-layer": "landcover",
"type": "fill-extrusion",
"minzoom": 0,
"paint": {
"fill-extrusion-color": "#000",
"fill-extrusion-height": [
"interpolate", ["linear"], ["zoom"],
15, 0,
18.0, 30.0
],
"fill-extrusion-base": [
"interpolate", ["linear"], ["zoom"],
15, 0,
18.0, ["get", "min_height"]
],
"fill-extrusion-opacity": 0.8
}
}
);
As the first reason, all the layers except water should be added as above if you want to make the land higher than water. it's not very effective.

How to set Mapbox heatmap color by data value?

I would like to display a heatmap of Bluetooth scans such that scans with strong signals appear green and scans with weak signal strength appear red. I have tried playing with all of the Mapbox heatmap properties (weight, intensity, radius, color, opacity) and have not been able to achieve this effect. Is there any advice on how to do this?
GeoJSON data format ("rssi" is the signal strength)
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-79.92068447220412,
43.259061411756505
]
},
"properties": {
"name": "heatmap",
"rssi": "55"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-79.92068446786702,
43.25906141184957
]
},
"properties": {
"name": "heatmap",
"rssi": "59"
}
},
...
]
}
Heatmap layer so far
map.addLayer({
id: 'heatmap_heatmap_layer_id',
type: 'heatmap',
source: 'heatmap_source_id',
maxzoom: 24,
paint: {
'heatmap-weight': {
property: 'rssi',
type: 'exponential',
stops: [
[0, 1],
[120, 10]
]
},
'heatmap-intensity': {
stops: [
[currentZoom, 1],
[24, 2]
]
},
'heatmap-color': [
'interpolate',
['linear'],
['heatmap-density'],
0, 'rgba(240,29,29,0)',
0.2, 'rgba(198,0,12,1)',
0.4, 'rgba(32,43,222,1)',
0.7, 'rgba(1,1,1,1)',
1.0, 'rgba(200,144,153,1)'
],
'heatmap-radius': {
stops: [
[currentZoom, 20],
[middleZoom, 30]
]
},
'heatmap-opacity': {
default: 1,
stops: [
[currentZoom, 1],
[24, 1]
]
},
}
});
This one's a bit tricky, as heatmaps automatically blend and add points in close proximity with one another. This means that a single point of strong signal will appear the same color, as many points of weak signal close together.
You may be better off visualizing the points as discrete circles, colored by RSSI.

mapbox gl data driven style: What does the "value" parameter do?

I'm modifying my icon size based on the current zoom value by using the zoom data to drive the size.
As I understand it, I'm using the property "zoom" to track the zoom value (This is required as per the spec), In the stops I setup each desired "zoom" value and then output the icon-size value for that state (shown by the 0-1 > 3 range). If I don't include the parameter "value": something the code fails. If I set it all to 1, it works fine, so it seems that this value is ignored.
Can anyone explain its actual use?
// Add layer to map populating data from Geojson
map.addLayer({
"id": "seed",
"type": "symbol",
"source": "objects",
"layout": {
"icon-rotation-alignment": "map",
"icon-keep-upright": true,
"icon-rotate": 0,
"icon-image": "{icon}",
"icon-allow-overlap": true,
"icon-size": {
"property": "zoom",
"type": "exponential",
"stops": [
[{ "zoom": 15, "value": 1}, 0.1],
[{ "zoom": 16, "value": 1}, 0.3],
[{ "zoom": 17, "value": 1}, 0.6],
[{ "zoom": 18, "value": 1}, 0.8],
[{ "zoom": 19, "value": 1}, 2],
[{ "zoom": 20, "value": 1}, 3]
]
}
}
});
});
Apologies for the confusion #stuffyjoelab!
There are three types of functions in Mapbox GL:
Zoom functions allow the appearance of a map feature to change with map’s zoom level
Property functions allow the appearance of a map feature to change with its properties.
Zoom-and-property functions allow the appearance of a map feature to change with both its properties and zoom.
(There's more info about these in our style spec docs)
I'm using the property "zoom" to track the zoom value
We define a "property" as being per-feature metadata, a la GeoJSON feature properties. By this definition, zoom is not a property (unless you have a property on your features called zoom)
If you switch to the zoom function syntax by removing "property": "zoom" and replacing the {zoom, value} objects from your stops with numeric zooms, everything should work as expected.
// Add layer to map populating data from Geojson
map.addLayer({
"id": "seed",
"type": "symbol",
"source": "objects",
"layout": {
"icon-rotation-alignment": "map",
"icon-keep-upright": true,
"icon-rotate": 0,
"icon-image": "{icon}",
"icon-allow-overlap": true,
"icon-size": {
"type": "exponential",
"stops": [
[15, 0.1],
[16, 0.3],
[17, 0.6],
[18, 0.8],
[19, 2],
[20, 3]
]
}
}
});

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
}
}