Source code for insarviz.view.InterferogramWidget

import pyqtgraph
import numpy as np
import datetime

from .__prelude__ import Qt, SELF, EACH
from .WidgetTree import Container, Leaf

def _to_date(time_stamp):
    return datetime.datetime.strftime(datetime.datetime.fromtimestamp(time_stamp), "%Y-%m-%d")

[docs] class InteractiveGraphItem(pyqtgraph.GraphItem): # Define signals for edge interactions sigEdgeClicked = Qt.Signal(object) # self, edge_index sigEdgeHovered = Qt.Signal(object) # self, edge_index def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.hovered_edge = None
[docs] def mouseClickEvent(self, ev): """Handle mouse clicks on edges""" if ev.button() == Qt.Qt.MouseButton.LeftButton: edge_idx = self._getEdgeAt(ev.pos()) if edge_idx is not None: ev.accept() self.sigEdgeClicked.emit(edge_idx) else: ev.ignore() else: ev.ignore()
[docs] def hoverEvent(self, ev): """Handle hover events on edges""" if ev.isExit(): self.hovered_edge = None self.update() return edge_idx = self._getEdgeAt(ev.pos()) if edge_idx != self.hovered_edge: self.hovered_edge = edge_idx self.update() if edge_idx is not None: self.sigEdgeHovered.emit(edge_idx)
[docs] def _getEdgeAt(self, pos): """Find which edge is at the given position""" if self.pos is None or self.adjacency is None: return None scene_pos = self.mapToScene(pos) click_point = pyqtgraph.Point(scene_pos) # Check each edge for i, edge in enumerate(self.adjacency): p1 = pyqtgraph.Point(self.mapToScene(pyqtgraph.Point(*self.pos[edge[0]]))) p2 = pyqtgraph.Point(self.mapToScene(pyqtgraph.Point(*self.pos[edge[1]]))) # Calculate distance from point to line segment dist = self._pointToLineDistance(click_point, p1, p2) # Use a tolerance of 5 pixels if dist < 5: return i return None
[docs] def _pointToLineDistance(self, point, line_p1, line_p2): """Calculate distance from point to line segment""" line_vec = line_p2 - line_p1 point_vec = point - line_p1 line_len2 = line_vec.dot(line_vec) if line_len2 == 0: return point_vec.length() t = max(0, min(1, point_vec.dot(line_vec) / line_len2)) projection = line_p1 + line_vec * t return (point - projection).length()
[docs] class InterferogramWidget(Qt.QWidget):
[docs] class Widgets: unwrapped_preview_label: Qt.QLabel wrapped_filtered_preview_label: Qt.QLabel aps_preview_label: Qt.QLabel
def __init__(self, interferogram): super().__init__() self.interferogram = interferogram wtree = Container(Qt.QHBoxLayout, (), [ Leaf(Qt.QLabel, (), id="unwrapped_preview_label"), Leaf(Qt.QLabel, (), id="wrapped_filtered_preview_label"), Leaf(Qt.QLabel, (), id="aps_preview_label"), Leaf(Qt.QWidget, (), id="interf_info"), (Leaf(Qt.QWidget, ()), {"stretch": 1}), ]) self.widgets = self.Widgets() wtree.create_in(self, self.widgets) info_layout = Qt.QFormLayout() info_layout.setAlignment(Qt.Qt.AlignVCenter) info_layout.addRow("Start date", Qt.QLabel(_to_date(interferogram.start_date))) info_layout.addRow("End date", Qt.QLabel(_to_date(interferogram.end_date))) self.widgets.interf_selection = Qt.QLabel("") info_layout.addRow("Selected", self.widgets.interf_selection) self.__set_selected() self.interferogram.dynamic_attribute("selected").value_changed.connect(self.__set_selected) self.widgets.interf_info.setLayout(info_layout) self.__update_preview() self.interferogram.wrapped_filtered_preview.ready.connect(self.__update_preview) self.interferogram.aps_preview.ready.connect(self.__update_preview) self.interferogram.unwrapped_preview.ready.connect(self.__update_preview) @Qt.Slot() def __set_selected(self): selected = self.interferogram.selected self.widgets.interf_selection.setText("Yes" if selected else "No") @Qt.Slot() def __update_preview(self): unwrapped_preview_image = self.interferogram.unwrapped_preview.latest() if unwrapped_preview_image is not None: h, w, _ = unwrapped_preview_image.shape data = Qt.QImage(bytes(unwrapped_preview_image.data), w, h, Qt.QImage.Format.Format_RGBA8888) self.widgets.unwrapped_preview_label.setPixmap(Qt.QPixmap.fromImage(data)) wrapped_filtered_preview_image = self.interferogram.wrapped_filtered_preview.latest() if wrapped_filtered_preview_image is not None: h, w, _ = wrapped_filtered_preview_image.shape data = Qt.QImage(bytes(wrapped_filtered_preview_image.data), w, h, Qt.QImage.Format.Format_RGBA8888) self.widgets.wrapped_filtered_preview_label.setPixmap(Qt.QPixmap.fromImage(data)) aps_preview_image = self.interferogram.aps_preview.latest() if aps_preview_image is not None: h, w, _ = aps_preview_image.shape data = Qt.QImage(bytes(aps_preview_image.data), w, h, Qt.QImage.Format.Format_RGBA8888) self.widgets.aps_preview_label.setPixmap(Qt.QPixmap.fromImage(data))
[docs] class InterferogramNetworkWidget(Qt.QWidget):
[docs] class Widgets: interfero_plot: pyqtgraph.PlotWidget interfero_scroll_area: Qt.QScrollArea
def __init__(self, network): super().__init__() self.network = network self.widgets = self.Widgets() wtree = Container(Qt.QHBoxLayout, (), [ Leaf(pyqtgraph.PlotWidget, (), id="interfero_plot"), Leaf(Qt.QScrollArea, (), id="interfero_scroll_area"), ]) wtree.create_in(self, self.widgets) scroll_wtree = Container(Qt.QVBoxLayout, (), []) self.widgets.interfero_scroll_area.setWidget(scroll_wtree.create(self.widgets)) self.widgets.interfero_scroll_area.setWidgetResizable(True) self.setWindowTitle(f"Interferogram from {network.base_url}") date_list = list(network.date_baselines.items()) date_indices = { date: i for i, (date, _) in enumerate(date_list) } pos = np.array(date_list) adj = np.array([ (date_indices[interf.start_date], date_indices[interf.end_date]) for interf in network.interferograms ]) self.graph_item = InteractiveGraphItem(pos = pos, adj = adj) self.graph_item.sigEdgeClicked.connect(self.__on_edge_clicked) time_line = pyqtgraph.InfiniteLine(pos = network.observed_timestamp, angle=90, movable=True) def on_time_moved(): network.observed_timestamp = time_line.getPos()[0] time_line.sigDragged.connect(on_time_moved) self._interferogram_selection = (SELF.interferograms / EACH(SELF.selected))[network] self._interferogram_selection.value_changed.connect(self.__update_interfero_list) self.__update_interfero_list() SELF.observed_timestamp[network].value_changed.connect(self.__update_interfero_list) self.widgets.interfero_plot.setAxisItems({"bottom": pyqtgraph.DateAxisItem(text='Date', units='yyyy-mm-dd')}) self.widgets.interfero_plot.addItem(self.graph_item) self.widgets.interfero_plot.addItem(time_line) def __on_edge_clicked(self, edge_idx): interf = self.network.interferograms[edge_idx] interf.selected = not interf.selected def __interf_color(self, interf, timestamp): if interf.selected: return (0,255,0,255,5) if interf.strides_date(timestamp): return (0,128,0,255,3) else: return (0,0,0,255,1) def __reset_colors(self): interf_colors = np.array([ self.__interf_color(interf, self.network.observed_timestamp) for interf in self.network.interferograms ], dtype=[('red', 'u1'), ('green', 'u1'), ('blue', 'u1'), ('alpha', 'u1'), ('width', 'f4')]) self.graph_item.setPen(interf_colors) @Qt.Slot() def __update_interfero_list(self): timestamp = self.network.observed_timestamp self.__reset_colors() layout = Qt.QVBoxLayout() for i in range(layout.count()): layout.takeAt(0).widget().deleteLater() # Show selected interferograms, always and before others selected_interferograms = [] striding_interferograms = [] for interf in self.network.interferograms: if interf.selected: selected_interferograms.append(interf) elif interf.strides_date(timestamp): striding_interferograms.append(interf) def mkGroupBox(title): return lambda: Qt.QGroupBox(title) selected_widget = [] if len(selected_interferograms) > 0: selected_widget = [ Container(Qt.QVBoxLayout, (), [ Leaf(InterferogramWidget, (interf, )) for interf in selected_interferograms ], widget_class = mkGroupBox("Selected")), ] list_wtree = Container(Qt.QVBoxLayout, (), selected_widget + [ Container(Qt.QVBoxLayout, (), [ Leaf(InterferogramWidget, (interf, )) for interf in striding_interferograms ], widget_class = mkGroupBox("Overlapping")), (Leaf(Qt.QWidget,()), {"stretch": 1}), ]) self.widgets.interfero_scroll_area.setWidget(list_wtree.create(self.widgets))