Skip to main content
 首页 » 编程设计

python之使用小部件更新 Gmaps + Jupyter 中的标记

2024年11月24日39qlqwjy

我正在研究 gmaps,我正在尝试使用 widgets.button 刷新 gmap 标记,但是当我单击按钮时无法刷新 map 。 也许是一个简单的问题,但我试了几个小时却无法解决。 遵循我的代码。

from IPython.display import display 
import ipywidgets as widgets 
 
import gmaps 
gmaps.configure(api_key='') 
 
 
class AcledExplorer(object): 
    """ 
    Jupyter widget for exploring the ACLED dataset. 
 
    The user uses the slider to choose a year. This renders 
    a heatmap of civilian victims in that year. 
    """ 
 
    def __init__(self): 
        self.marker_locations = [(None, None)] 
        self._slider = None 
        self._slider2 = None 
        title_widget = widgets.HTML( 
            '<h3>MY TEST, my test</h3>' 
            '<h4>test1 <a href="https://www.test.com/">ACLED project</a></h4>' 
        ) 
 
        map_figure = self._render_map(-15.7934036, -47.8823172) 
        control = self._render_control() 
        self._container = widgets.VBox([title_widget, control, map_figure]) 
 
    def render(self): 
        display(self._container) 
 
    def on_button_clicked(self, b): 
        latitude = self.FloatSlider1.value 
        longitude = self.FloatSlider2.value 
        print("Button clicked.") 
        self.markers = gmaps.marker_layer([(latitude, longitude)]) 
        return self._container 
 
    def _render_control(self): 
 
        """ Render the widgets """ 
 
        self.FloatSlider1 = widgets.FloatSlider( 
        value=-15.8, 
        min=-34, 
        max=4.5, 
        step=0.2, 
        description='Latitude:', 
        disabled=False, 
        continuous_update=False, 
        orientation='horizontal', 
        readout=True, 
        readout_format='.1f', 
    ) 
        self.FloatSlider2 = widgets.FloatSlider( 
        value=-47.9, 
        min=-74, 
        max=-33, 
        step=0.2, 
        description='Longitude:', 
        disabled=False, 
        continuous_update=False, 
        orientation='horizontal', 
        readout=True, 
        readout_format='.1f', 
    ) 
        self.button = widgets.Button( 
            description="Plot!" 
        ) 
 
        self.button.on_click(self.on_button_clicked) 
 
        controls = widgets.VBox( 
        [self.FloatSlider1, self.FloatSlider2, self.button]) 
        return controls 
 
    def _render_map(self, latitude, longitude): 
        """ Render the initial map """ 
        self.marker_locations = [(latitude, longitude)] 
        brasilia_coordinates = (-15.7934036, -47.8823172) 
 
        fig = gmaps.figure(center=brasilia_coordinates, zoom_level=3) 
        self.markers = gmaps.marker_layer(self.marker_locations) 
        fig.add_layer(self.markers) 
        return fig 
 
 
AcledExplorer().render() 

在将值从 slider 链接到按钮后,我开始创建小部件。单击按钮时我需要刷新标记位置。

在函数 on_button_click 中,我可以看到纬度和经度的新闻值是从 slider 获取的,所以我正在更新 self.marker,也许我的错误留在这里。

请您参考如下方法:

你的代码有问题

在 on_button_click 中,您实际上并没有更新标记层。你目前写:

self.markers = gmaps.marker_layer([(latitude, longitude)]) 

但这只是设置了您的类的 markers 属性。您真正想要做的是改变标记层中的标记集。您可以做的最简单的更改是将该行更改为:

self.markers.markers = [gmaps.Marker(location=(latitude, longitude))] 

这会改变标记层的 markers 属性——基本上是标记列表。每次按下 plot 时,它都会破坏 map 上的标记,并在更新后的位置用新标记替换它。

改进您的解决方案

使用像 marker_layer 这样的高级工厂方法可以掩盖 jupyter-gmaps 如何在内部使用小部件。为了让它更容易理解,让我们介绍一个创建 gmaps.Marker 对象的 _create_marker() 方法:

def _create_marker(self, latitude, longitude): 
    return gmaps.Marker(location=(latitude, longitude)) 

我们现在可以在初始渲染中使用它:

def _render_map(self, latitude, longitude): 
    """ Render the initial map """ 
    brasilia_coordinates = (-15.7934036, -47.8823172) 
 
    fig = gmaps.figure(center=brasilia_coordinates, zoom_level=3) 
    self.marker_layer = gmaps.Markers() 
    initial_marker = self._create_marker(latitude, longitude) 
    self.marker_layer.markers = [initial_marker]  # set the first marker 
    fig.add_layer(self.marker_layer) 
    return fig 

请注意,我已将 self.markers 重命名为 self.marker_layer 以表明它是一个层。

最后,现在是更新代码:

def on_button_clicked(self, _): 
    latitude = self.FloatSlider1.value 
    longitude = self.FloatSlider2.value 
 
    # look how closely the following two lines match the construction code 
    new_marker = self._create_marker(latitude, longitude) 
    self.marker_layer.markers = [new_marker]