In my map visualizer with PyQT5 using Folium I have a data_provider for testing purposes. When it updates ship coordinates and heading, the map needs to update which causes flashing. import io import sys import folium from PyQt5.QtGui import QRegion from PyQt5.QtCore import QRect, QTimer from PyQt5 import QtWidgets, QtWebEngineWidgets class Map(QtWidgets.QWidget): """ Updates the map's location and heading based on parameters. Places a circular map inside a frame with a circular alarm mask. """ triggered = False def __init__(self) -> None: super().__init__() self.map = None self.init_ui() def init_ui(self) -> None: # Create layout self.layout = QtWidgets.QVBoxLayout(self) self.setLayout(self.layout) # Create a parent frame for the circular map self.frame = QtWidgets.QWidget(self) self.frame.setFixedSize(310, 310) self.frame.setStyleSheet( "border: 5px solid black; border-radius: 155px;") self.frame.setGeometry(145, 10, 310, 310) self.layout.addWidget(self.frame) # Add the WebEngineView for the map inside the frame self.map_view = QtWebEngineWidgets.QWebEngineView(self.frame) self.map_view.setFixedSize(300, 300) self.map_view.setGeometry(5, 5, 300, 300) # Apply a circular mask to the map view circular_region = QRegion(QRect(0, 0, self.map_view.width(), self.map_view.height()), QRegion.Ellipse) self.map_view.setMask(circular_region) # Create buttons and input fields self.control_layout = QtWidgets.QHBoxLayout() self.layout.addLayout(self.control_layout) self.lat_input = QtWidgets.QLineEdit(self) self.lat_input.setPlaceholderText("Latitude") self.control_layout.addWidget(self.lat_input) self.lon_input = QtWidgets.QLineEdit(self) self.lon_input.setPlaceholderText("Longitude") self.control_layout.addWidget(self.lon_input) self.heading_input = QtWidgets.QLineEdit(self) self.heading_input.setPlaceholderText("Heading (degrees)") self.control_layout.addWidget(self.heading_input) self.update_button = QtWidgets.QPushButton("Update Location", self) self.update_button.clicked.connect(self.update_location) self.control_layout.addWidget(self.update_button) self.update_button = QtWidgets.QPushButton("Test", self) self.update_button.clicked.connect(self.data_provider) self.control_layout.addWidget(self.update_button) self.trigger_button = QtWidgets.QPushButton("Trigger Frame Color", self) self.trigger_button.clicked.connect(self.trigger_frame) self.control_layout.addWidget(self.trigger_button) self.example_continous_data = [ (40.851, 29.041, 311, [(40.85851, 29.04981, 1)]), (40.852, 29.042, 312, [(40.85852, 29.04982, 2)]), (40.853, 29.043, 313, [(40.85853, 29.04983, 3)]), (40.854, 29.044, 314, [(40.85854, 29.04984, 4)]), (40.855, 29.045, 315, [(40.85855, 29.04985, 5)]), (40.856, 29.046, 316, [(40.85856, 29.04986, 6)]), (40.857, 29.047, 317, [(40.85857, 29.04987, 7)]), (40.858, 29.048, 318, [(40.85858, 29.04988, 8)]), (40.859, 29.049, 319, [(40.85859, 29.04989, 9)]) ] self.data_index = 0 def data_provider(self) -> None: """Update the map with the next data point every second.""" if self.data_index < len(self.example_continous_data): latitude, longitude, degree, dangerous_areas = \ self.example_continous_data[self.data_index] self.create_map(latitude, longitude, degree, dangerous_areas) self.data_index += 1 else: self.data_index = 0 self.timer2 = QTimer() self.timer2.timeout.connect(self.data_provider) self.timer2.start(1000) def create_map(self, latitude, longitude, heading, dangerous_areas) -> None: """ Create or update a Folium map centered on the given location with a heading arrow. """ self.map = folium.Map( location=[latitude, longitude], zoom_start=14, tiles="OpenStreetMap", attribution_control=False, zoom_control=True ) folium.TileLayer("OpenSeaMap", name="OpenSeaMap").add_to(self.map) # Custom CSS for circular map and repositioned controls circular_css = """ <style> .leaflet-top.leaflet-left { left: 24%; /* Adjust horizontal positioning of controls */ top: 90%; /* Adjust vertical positioning of controls */ transform: translate(-24%, -90%); position: absolute; z-index: 1000;/*Ensure controls are visible above the map*/ } </style> """ # Inject the custom CSS into the map HTML self.map.get_root().header.add_child(folium.Element(circular_css)) # Add a ship marker with an arrow to indicate heading size = 22 arrow_icon = folium.DivIcon(html=f""" <div style="transform: rotate({heading}deg);\ font-size: {size}px; color: red;"> ➤ </div> """) marker = folium.Marker( location=[latitude, longitude], icon=arrow_icon, tooltip=f"{latitude}, {longitude}, {heading}°" ) marker.add_to(self.map) # Add dangerous areas for lat, lon, depth in dangerous_areas: circle = folium.Circle( location=[lat, lon], radius=100, color="red", fill=True, fill_color="red", fill_opacity=0.5, tooltip=f"Depth: {depth}m" ) circle.add_to(self.map) self.render_map() def render_map(self) -> None: # Save map to memory data = io.BytesIO() self.map.save(data, close_file=False) # Display the map in the WebEngineView self.map_view.setHtml(data.getvalue().decode()) data.close() def update_location(self) -> None: """Update the map's location and heading based on user input.""" try: latitude = float(self.lat_input.text()) longitude = float(self.lon_input.text()) heading = float(self.heading_input.text()) self.create_map(latitude, longitude, heading, []) except ValueError: QtWidgets.QMessageBox.critical(self, "Error", "Invalid latitude, longitude, or heading") def update_frame_style(self) -> None: """Update the frame style based on the `triggered` variable.""" red = "border: 5px solid red; border-radius: 155px;" black = "border: 5px solid black; border-radius: 155px;" if self.triggered: # create a loop to blink the frame in parallel self.timer = QTimer() self.timer.timeout.connect(self.update_frame_style) self.timer.start(1000) if self.frame.styleSheet() == red: self.frame.setStyleSheet(black) else: self.frame.setStyleSheet(red) else: # reset the frame to black self.frame.setStyleSheet(black) def trigger_frame(self) -> None: """Toggle the frame color based on an external trigger.""" self.triggered = not self.triggered self.update_frame_style() class MainWindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Dynamic Location Update with Heading") self.resize(600, 600) self.setCentralWidget(Map()) if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) main_window = Map() main_window.show() sys.exit(app.exec_()) Continue reading...