✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚾️ It's finally Baseball season! Root for the home team... & Register for our Sports Analytics Webinar!

Using scattermapbox on top of choroplethmapbox

Hi,

I want to use scattermapbox to show pin point on top of another layer of choropleth mapbox. It works well on default symbol style, which is circle in this case.
image

However, I want to change the symbol of the marker and the marker won’t show up after i change the symbol of the marker. Has anyone runs into similar issue as mine?

Helps are appreciated very much.

Thanks and regards.

Hey, two things

  1. You need to set the mapbox token to use symbol markers
  2. From my experience not all maki symbols work properly, I’d advise to try out a few
1 Like

Ahh… mislook this in the documentation…

I’d like to keep the style I am using now… I guess I can cope with the default style, thanks for the tips :wink:

Hey @RenaudLN, it’s me again :slight_smile:

Regarding to the image above, I was thinking to do a blinking effect instead of locating a pin point on the desired location/country, something looks like this:

I tried to look around Plotly js function but there doesn’t seem a way for me to achieve that.

Is it possible to achieve that with mapbox object?

I guess you could create an animation with different opacities for the marker, see here for explanation on animations.

I see… I am using Python Dash here… Is there a way for me to trigger the animation without using a button, after creating all the frames?

Currently I am trying to trigger the blinking animation, chained after a callback (i.e. searching on particular country on the map). How can I animate the figure after the figure object is returned?

What are you animating? Did you try a clientside callback?

As @RenaudLN suggesting here, I am trying to animating the opacity on the selected country on my choroplethmapbox trace to create a blinking effect. (not through a click/hover event, is a chained action after choosing a value from a dropdown)

I did try clientside callback, but I didn’t quite sure how the graph created in Python can be used in clientside callback. This is what i did in my clientside callback:

if (!window.dash_clientside) {
    window.dash_clientside = {};
}

window.dash_clientside.clientside = {
    onMapSearch: function(countryName) {
        var mapObj = document.getElementById('my-map-id');
        var data = mapObj.children[1].data[0]
        var layout = mapObj.children[1].layout

        var frames = []
        var opacities = []
        var locList = data.locations

        // setting up the array of marker opacities here
        // 0 for the selected country, else 1
        for (let n in locList) {
            if (locList[n] === countryName) {
                opacities.push(0)
                console.log(countryName)
            }
            else opacities.push(1)
        }

        // setting up frames with different opacity
        for (i = 0; i < 6; i++) {
            if (i % 2 == 0) {
                data.marker.opacity = 1
            } else {
                data.marker.opacity = opacities
            }
            frames.push(data)
        }

        Plotly.newPlot('my-map-id', data, layout)
        Plotly.animate('my-map-id', frames, {transition: {duration: 0},frame:{duration:0}});
    }
}

When I try the callback in my Dash app, the graph becomes empty after the callback triggered. Also, the animation is not running. What is the way to get the things work correctly here?

Again thanks for the time and helps :slight_smile:

Here is a small example to illustrate how it can be done with a clientside callback,

import dash
import dash_leaflet as dl
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input

update_interval = 100  # in milliseconds
opacity_steps = 15
# Create small example app.
app = dash.Dash(update_title=None)
app.layout = html.Div([
    dl.Map([dl.TileLayer(), dl.Marker(id="marker", position=(56, 10))], style={'width': '1000px', 'height': '500px'}),
    dcc.Interval(interval=update_interval, id="ticker")
])
app.clientside_callback(
    f"""
    function(ticker) {{
        state = (ticker/{opacity_steps})%2;
        return state < 1 ? state : 2 - state;
    }}
    """, Output("marker", "opacity"), Input("ticker", "n_intervals")
)

if __name__ == '__main__':
    app.run_server()

Thanks @Emil! :slight_smile:

This could be the solution and I will give it a try once I have the time.