Jon,
Used your solution and it worked great, but I’m struggling to get a text label to display along my json data - have you had any luck with this?
Jon,
Used your solution and it worked great, but I’m struggling to get a text label to display along my json data - have you had any luck with this?
Thanks - to add some detail - I’m using a geojson to display points on a mapbox map, but whenever I call the “title” as a text field in the “layout” options the json fails to display. As soon as that line is removed it works fine.
self.mapbox.addSource('mills',
{'type':'geojson',
'data':{"type":"FeatureCollection",
"features":[
{"type":"Feature",
"properties":{"title":"test point"},
"geometry":
{"type":"Point",
"coordinates":[-3.83,50.672]}}]}})
self.mapbox.addLayer(
{'id': 'millLayer',
'type': 'circle',
'source': 'mills',
'layout':{},
'paint': {'circle-radius': 8,
'circle-color': 'blue'}
})
I’ve tried adding ‘text-field’:[‘get’,‘title’] to the layout {} but that results in the object not being drawn, though no error is thrown. Adding anything to layout seems to have the same result - I’m stuck trying to add icons etc etc.
Reference example I’m using:
This is a case of the library not throwing the error - but reporting it in the javascript console.
If you open up the developer tools in chrome (best to do this when running the app in a new tab) you’ll see something like the following error reported.
Since mapbox never throws this error it’s not reported by anvil’s error handling mechanism.
I the docs you linked - the "text-field"
layout property is being applied to a symbol layer.
But you’re trying to apply it to a circle layer.
I couldn’t find any appropriate docs that explicitly mentioned which layout properties apply to which layer types.
I did find these type definitions in the source code that might help to decipher what’s going on.
You can see - for example - the "text-field"
layout property is only applicable to the SymbolLayerSpecification
.
Sorry I can’t offer any help on this @johnOsweet. In my solution I moved away from the JSON representation and used a Mapbox marker instead. Initially I was exporting the records from an Anvil database to JSON then trying to manipulate the JSON with Mapbox. I found this to be too awkward. The database had the lat/long values anyway, so I just used those with some text to create markers with popups. See my example below.
for mill in self.mills:
popup_html = f'''<h6>{mill['name']}</h6>
<h6>[{mill['mill_product']['product']}]</h6>
<h6>{mill['telephone']}</h6'''
marker.setLngLat({'lng': float(mill['longitude']), 'lat': float(mill['latitude'])})
popup = mapboxgl.Popup()
popup.setHTML(popup_html)
marker.setPopup(popup)
marker.addTo(self.mapbox)
Jon - did you figure out how to use a custom marker at all - I’m using markers for one application with labels fine. However, one of the rationales behind using geojson was to be able to differentiate between points more easily as I couldn’t convince custom markers to work. Can’t get custom symbols working with geojson either (see reply to stucork)
Stu:
Thanks for that - I’ve read the same thing and come to the same conclusion. However, I can’t get symbols to work either. Anything I drop into the layout field seems to immediately break the layer in a similar way, and using symbols requires use of the layout field.
Ironically I can get it working just fine as standalone javascript on a separate page, but I need python processes running in the background and the hosting functions anvil provides.
I’m just working to get an MVP out before the weekend, but once I’ve got that, I’ll throw in some code examples trying to get symbols to work. Thanks for the help
Do you have an example of code that you’re using that should work?
Sorry about the delay, I’ve been working on other stuff.
So I’ve tried your suggestion of moving across to another layer type - I’m trying “symbol” type. However, the first stumbling block I hit is the loadImage (https://docs.mapbox.com/mapbox-gl-js/api/map/#map#loadimage).
Mapbox calls for something like the following:
map.loadImage('http://placekitten.com/50/50', (error, image) => {
if (error) throw error;
// Add the loaded image to the style's sprite with the ID 'kitten'.
map.addImage('kitten', image);
I’ve no idea how to replicate the loadImage line in python in Anvil?
Reading javascript and converting to python is tricky.
Taking the example from the original blog post and combining it with this example from the map box docs.
def form_show(self, **event_arg):
self.mapbox = mapboxgl.Map(
{
"container": self.dom,
#'style': 'mapbox://styles/mapbox/streets-v11',
"style": "mapbox://styles/brookemyers/cklk04z7x1f5d17pedafupa3e",
"center": [0.1218, 52.2053], # center on Cambridge
"zoom": 12,
}
)
self.mapbox.on("load", self.on_load)
...
def on_load(self, *args):
url = "https://docs.mapbox.com/mapbox-gl-js/assets/cat.png"
self.mapbox.loadImage(url, self.on_load_image)
def on_load_image(self, error, image):
if error:
raise error
self.mapbox.addImage("cat", image)
self.mapbox.addSource(
"point",
{
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{"type": "Feature", "geometry": {"type": "Point", "coordinates": [0.1218, 52.2053]}}],
},
},
)
self.mapbox.addLayer(
{
"id": "points",
"type": "symbol",
"source": "point", # // reference the data source
"layout": {"icon-image": "cat", "icon-size": 0.25}, # // reference the image
}
)
This is a case of a library using callback as part of their api.
Whenever the library requires a callback I provide it with a method on the form.
Side note: If using a python function as a javsacript callback it’s often necessary to use *args
since the javascript library may provide you with additional args you don’t need (and that are not documented )
Thanks for that - making the callback a method makes sense. I’ve the cat on my screen, so a good start, I’ll have a play around at adapting it to my use case. Feedback from a weekend of users with the MVP was really great, so cracking this issue will top off a pretty good week.