From 7dec54fa1c9d66c5d7b504fbcf4521dfc5dd3b8e Mon Sep 17 00:00:00 2001 From: Pim Nelissen Date: Tue, 10 Mar 2026 20:45:35 +0100 Subject: [PATCH] update plotter to add direction of travel arrow and detector info --- src/pg_rad/plotting/landscape_plotter.py | 37 +++++++++++++++++++++++- src/pg_rad/plotting/result_plotter.py | 31 ++++++++++++++++---- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/pg_rad/plotting/landscape_plotter.py b/src/pg_rad/plotting/landscape_plotter.py index 4a990f3..aebfc36 100644 --- a/src/pg_rad/plotting/landscape_plotter.py +++ b/src/pg_rad/plotting/landscape_plotter.py @@ -69,7 +69,7 @@ class LandscapeSlicePlotter: ax.set_ylabel("Y [m]") ax.set_title(f"Landscape (top-down, z = {self.z})") - def _draw_path(self, ax, landscape): + def _draw_path(self, ax, landscape: Landscape): if landscape.path.z <= self.z: ax.plot( landscape.path.x_list, @@ -79,6 +79,9 @@ class LandscapeSlicePlotter: markersize=3, linewidth=1 ) + if len(landscape.path.x_list) >= 2: + ax = self._draw_path_direction_arrow(ax, landscape.path) + else: logger.warning( "Path is above the slice height z." @@ -113,3 +116,35 @@ class LandscapeSlicePlotter: f"Source {s.name} is above slice height z." "It will not show on the plot." ) + + def _draw_path_direction_arrow(self, ax, path) -> Axes: + inset_ax = ax.inset_axes([0.8, 0.1, 0.15, 0.15]) + + x_start, y_start = path.x_list[0], path.y_list[0] + x_end, y_end = path.x_list[1], path.y_list[1] + + dx = x_end - x_start + dy = y_end - y_start + + if path.opposite_direction: + dx = -dx + dy = -dy + + length = 10 + dx_norm = dx / (dx**2 + dy**2)**0.5 * length + dy_norm = dy / (dx**2 + dy**2)**0.5 * length + + inset_ax.arrow( + 0, 0, + dx_norm, dy_norm, + head_width=5, head_length=5, + fc='red', ec='red', + zorder=4, linewidth=1 + ) + + inset_ax.set_xlim(-2*length, 2*length) + inset_ax.set_ylim(-2*length, 2*length) + inset_ax.set_title("Direction", fontsize=8) + inset_ax.set_xticks([]) + inset_ax.set_yticks([]) + return ax diff --git a/src/pg_rad/plotting/result_plotter.py b/src/pg_rad/plotting/result_plotter.py index 51ba366..bcd4a65 100644 --- a/src/pg_rad/plotting/result_plotter.py +++ b/src/pg_rad/plotting/result_plotter.py @@ -16,10 +16,10 @@ class ResultPlotter: fig = plt.figure(figsize=(12, 10), constrained_layout=True) fig.suptitle(self.landscape.name) gs = GridSpec( - 3, + 4, 2, width_ratios=[0.5, 0.5], - height_ratios=[0.7, 0.15, 0.15], + height_ratios=[0.7, 0.1, 0.1, 0.1], hspace=0.2) ax1 = fig.add_subplot(gs[0, 0]) @@ -32,9 +32,11 @@ class ResultPlotter: self._draw_table(ax3) ax4 = fig.add_subplot(gs[2, :]) - self._draw_source_table(ax4) + self._draw_detector_table(ax4) + + ax5 = fig.add_subplot(gs[3, :]) + self._draw_source_table(ax5) - plt.tight_layout() plt.show() def _plot_landscape(self, ax, z): @@ -57,7 +59,26 @@ class ResultPlotter: cols = ('Parameter', 'Value') data = [ ["Air density (kg/m^3)", round(self.landscape.air_density, 3)], - ["Total path length (m)", round(self.landscape.path.length, 3)] + ["Total path length (m)", round(self.landscape.path.length, 3)], + ] + + ax.table( + cellText=data, + colLabels=cols, + loc='center' + ) + + return ax + + def _draw_detector_table(self, ax): + det = self.landscape.detector + print(det) + ax.set_axis_off() + ax.set_title('Detector') + cols = ('Parameter', 'Value') + data = [ + ["Name", det.name], + ["Type", det.efficiency], ] ax.table(