1

I am trying to create a map that is updated continuously with received data and I have a problem. the map moves every time a new marker is added and it is making it useless as it should be zoomed to get more detail. I don't know what is the problem when I test a simple 3 marker map it doesn't move, but when I create a function to update the map it moves to the latest added marker.

This is my simple code that doesn't move(works correctly):

cell1:

from ipyleaflet import Marker, DivIcon, Map, LegendControl


def create_triangle_icon(max_intensity, scaling_factor, font_size, font_family, border_color, background_color, text_color):


    html = f"""
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Equilateral Triangle</title>
    <style>
      .equilateral-triangle {{
        width: 0;
        height: 0;
        border-left: {25 * scaling_factor}px solid transparent;
        border-right: {25 * scaling_factor}px solid transparent;
        border-bottom: {43.3 * scaling_factor}px solid {border_color}; /* Hex color: {border_color} */
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
      }}
      .equilateral-triangle::after {{
        content: "{max_intensity:.1f}";
        position: absolute;
        bottom: -{50 * scaling_factor}px; /* Adjust the vertical position of the text as needed */
        left: 50%;
        transform: translateX(-50%);
        color: {text_color}; /* Text color */
        font-size: {font_size}px; /* Font size */
        font-family: {font_family}; /* Font family */
      }}
    </style>
    </head>
    <body>
    <div class="equilateral-triangle"></div>
    </body>
    </html>
    """
    return html


def create_star_icon(color, size, Mw):
    html = f"""
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Star Icon</title>
    <style>
      .star-container {{
        position: relative;
        display: flex;
        justify-content: center;
        align-items: center;
        width: {size}px;
        height: {size}px;
      }}
      .five-point-star {{
        width: 0px;
        height: 0px;
        border-right: {size * 2}px solid transparent;
        border-bottom: {size * 1.5}px solid {color};
        border-left: {size * 2}px solid transparent;
        transform: rotate(37deg);
      }}
      .five-point-star:before {{
        content: "";
        position: absolute;
        top: -{size * 0.78}px;
        left: -{size}px;
        width: 0px;
        height: 0px;
        border-bottom: {size * 1.12}px solid {color};
        border-left: {size * 0.37}px solid transparent;
        border-right: {size * 0.37}px solid transparent;
        transform: rotate(323deg);
      }}
      .five-point-star:after {{
        content: "";
        position: absolute;
        top: 0;
        left: -{size * 2}px;
        width: 0px;
        height: 0px;
        border-right: {size * 2}px solid transparent;
        border-bottom: {size * 1.5}px solid {color};
        border-left: {size * 2}px solid transparent;
        transform: rotate(286deg);
      }}
      .star-text {{
        position: absolute;
        color: white;
        bottom: -10px; /* Adjust the vertical position of the text as needed */
        font-size: 12px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
      }}
    </style>
    </head>
    <body>
    <div class="star-container">
      <div class="five-point-star"></div>
      <div class="star-text">{Mw}</div>
    </div>
    </body>
    </html>
    """
    return html


def create_triangle_icon2(max_intensity, scaling_factor, font_size, font_family):
    if max_intensity < 3:
        border_color = "#e7edff"
        background_color = '#e7edff'  # cyan
        text_color = 'black'
    elif 3 <= max_intensity < 3.5:
        border_color = "#b1fff2"
        background_color = '#b1fff2'  # green
        text_color = 'black'
    elif 3.5 <= max_intensity < 4:
        border_color = "#7cffe9"
        background_color = '#7cffe9'  # Yellow  8ef1ff  00d1ef
        text_color = 'black'
    elif 4 <= max_intensity < 4.5:
        border_color = "#00d1ef"
        background_color = '#00d1ef'  # red
        text_color = 'black'
    elif 4.5 <= max_intensity < 5:
        border_color = "#efff91"
        background_color = '#efff91'  # red
        text_color = 'black'
    elif 5 <= max_intensity < 5.5:
        border_color = "#f8e29f"
        background_color = '#f8e29f'  # red
        text_color = 'black'
    elif 5.5 <= max_intensity < 6:
        border_color = "#f8c38d"
        background_color = '#f8c38d'  # red
        text_color = 'black'
    elif 6 <= max_intensity < 6.5:
        border_color = "#e68787"
        background_color = '#e68787'  # red
        text_color = 'white'
    elif 6.5 <= max_intensity < 7:
        border_color = "#b36189"
        background_color = '#b36189'  # red
        text_color = 'white'
    else:
        border_color = "#6c4259"
        background_color = '#6c4259'  # darkpurple #9300FF
        text_color = 'white'
        
    html = f"""
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Equilateral Triangle{max_intensity}</title>
    <style>
      .equilateral-triangle{max_intensity:} {{
        width: 0;
        height: 0;
        border-left: {25 * scaling_factor}px solid transparent;
        border-right: {25 * scaling_factor}px solid transparent;
        border-bottom: {43.3 * scaling_factor}px solid {border_color}; /* Hex color: {border_color} */
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
      }}
      .equilateral-triangle{max_intensity}::after {{
        content: "{max_intensity:.1f}";
        position: absolute;
        bottom: -{50 * scaling_factor}px; /* Adjust the vertical position of the text as needed */
        left: 50%;
        transform: translateX(-50%);
        color: {text_color}; /* Text color */
        font-size: {font_size}px; /* Font size */
        font-family: {font_family}; /* Font family */
      }}
    </style>
    </head>
    <body>
    <div class="equilateral-triangle{max_intensity}"></div>
    </body>
    </html>
    """
    return html


Mw = 4.5
center = (52.204793, 360.121558)
max_intensity = 6  # You can adjust this value to change the appearance of the triangle
scaling_factor = 0.7  # You can adjust this factor to scale the triangle
font_size = 16  # You can adjust the font size of the max_intensity
font_family = "Arial, sans-serif"  # You can adjust the font family of the max_intensity
star_color = "#FFA500"  # Hexadecimal color for orange
star_icon_size = 10




html = create_triangle_icon2(max_intensity, scaling_factor, font_size, font_family)
html2 = create_triangle_icon2(4, scaling_factor, font_size, font_family)
html_star = create_star_icon(star_color, star_icon_size, Mw)

m = Map(center=center, zoom=10)
icon = DivIcon(html=html, bg_pos=[0, 0], icon_size=[0, 0])
mark = Marker(location=center, icon=icon)
m.add_layer(mark)

icon2 = DivIcon(html=html2, bg_pos=[0, 0], icon_size=[0, 0])
mark2 = Marker(location=(52.414793, 360.431558), draggable=False, icon=icon2)
m.add_layer(mark2)


# Adding Star Marker
icon_star = DivIcon(html=html_star, bg_pos=[0, 0], icon_size=[0, 0])
mark_star = Marker(location=(52.404793, 360.421558), icon=icon_star)
m.add_layer(mark_star)
# Manipulate the legend
legend = LegendControl({"<3": "#e7edff", "3-3.5": "#b1fff2", "3.5-4": "#7cffe9", "4-4.5": "#00d1ef", "4.5-5": "#efff91",
                        "5-5.5": "#f8e29f", "5.5-6": "#f8c38d", "6-6.5": "#e68787", "6.5-7": "#b36189",
                        ">7": "#6c4259"}, title="IMI", position="topright")

m.add(legend)
m

and then when I execute these cells it doesn't move.

Cell2:

icon2 = DivIcon(html=html2, bg_pos=[0, 0], icon_size=[0, 0])
mark2 = Marker(location=(52.614793, 360.631558), draggable=False, icon=icon2)
m.add_layer(mark2)

but when I create a code that uses a function to update the map. it moves to the latest added marker.

here is the code: Cell1:

# Create a map
my_map = Map(center=[35.3021392, 51.6328143], zoom=6)

# Display the map
my_map

Cell2:

rom ipyleaflet import Map, Marker, Popup, DivIcon
from ipywidgets import HTML
import threading
import time

# Function to create HTML for triangle marker with intensity inside
def create_triangle_icon(max_intensity, border_color, background_color, text_color):
    html = f"""
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Equilateral Triangle</title>
    <style>
      .equilateral-triangle {{
        width: 0;
        height: 0;
        border-left: 25px solid transparent;
        border-right: 25px solid transparent;
        border-bottom: 43.3px solid {border_color}; /* Hex color: {border_color} */
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
      }}
      .equilateral-triangle::after {{
        content: "{max_intensity}";
        position: absolute;
        bottom: -50px; /* Adjust the vertical position of the text as needed */
        left: 50%;
        transform: translateX(-50%);
        color: {text_color}; /* Text color */
        font-size: 16px; /* Font size */
        font-family: Arial, sans-serif; /* Font family */
      }}
    </style>
    </head>
    <body>
    <div class="equilateral-triangle"></div>
    </body>
    </html>
    """
    return html

# Function to update the map with new markers
def update_map(data):
    all_channel_data = data['all_channel_data']
    max_intensity = max(channel['Intensity'] for channel in all_channel_data)
    
    if max_intensity < 3:
        border_color = "#e7edff"
        background_color = '#e7edff'  # cyan
        text_color = 'black'
    elif 3 <= max_intensity < 3.5:
        border_color = "#b1fff2"
        background_color = '#b1fff2'  # green
        text_color = 'black'
    elif 3.5 <= max_intensity < 4:
        border_color = "#7cffe9"
        background_color = '#7cffe9'  # Yellow  8ef1ff  00d1ef
        text_color = 'black'
    elif 4 <= max_intensity < 4.5:
        border_color = "#00d1ef"
        background_color = '#00d1ef'  # red
        text_color = 'black'
    elif 4.5 <= max_intensity < 5:
        border_color = "#efff91"
        background_color = '#efff91'  # red
        text_color = 'black'
    elif 5 <= max_intensity < 5.5:
        border_color = "#f8e29f"
        background_color = '#f8e29f'  # red
        text_color = 'black'
    elif 5.5 <= max_intensity < 6:
        border_color = "#f8c38d"
        background_color = '#f8c38d'  # red
        text_color = 'black'
    elif 6 <= max_intensity < 6.5:
        border_color = "#e68787"
        background_color = '#e68787'  # red
        text_color = 'white'
    elif 6.5 <= max_intensity < 7:
        border_color = "#b36189"
        background_color = '#b36189'  # red
        text_color = 'white'
    else:
        border_color = "#6c4259"
        background_color = '#6c4259'  # darkpurple #9300FF
        text_color = 'white'
    
    triangle_html = create_triangle_icon(str(round(max_intensity, 1)), border_color, background_color, text_color)
    
    marker = Marker(location=(float(data['latitude']), float(data['longitude'])))
    marker.icon = DivIcon(html=triangle_html, bg_pos=[0, 0], icon_size=[0, 0])
    
    popup_content = f"<b>Intensity:</b> {max_intensity:.1f}"
    popup = Popup(location=marker.location, child=HTML(value=popup_content), close_button=True, auto_close=False, close_on_escape_key=True)
    marker.popup = popup
    
    my_map.add(marker)



import random

# Simulate receiving new data and updating the map
def simulate_data():
    # Generate random latitude, longitude, and intensity values
    latitude = random.uniform(-90, 90)
    longitude = random.uniform(-180, 180)
    intensity = random.uniform(0, 10)
    
    data = {
        'latitude': latitude,
        'longitude': longitude,
        'all_channel_data': [{'Intensity': intensity}]
    }
    update_map(data)

# Simulate receiving new data every 3 seconds
while True:
    simulate_data()
    time.sleep(3)

I have no idea what to do here. I tried to split it into two cells but that didn't work. the code I wrote here is the split cells. I'm not familiar with Java script so I have no idea why it moves in one situation but it doesn't move in the other.

Can anybody help me?

1 Answer 1

1

Map moves/pans to the latest added marker because of the popup that is added to the marker. To prevent this move you have to use auto_pan=False argument when creating popup for marker (see https://ipyleaflet.readthedocs.io/en/latest/api_reference/index.html#ipyleaflet.leaflet.Popup).

Popup creation would then look like this:

popup = Popup(location=marker.location, child=HTML(value=popup_content), auto_pan=False, close_button=True, auto_close=False, close_on_escape_key=True)
1
  • thank you so much. this solved my problem. you are a god send my friend.
    – Shane roar
    Commented Mar 2 at 12:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.