ModulePlottingUtilities

Module containing some useful functions for generating various plots. It exists mostly to avoid cluttering the main plotting module.

Created in November 2024

@author: André Kalouguine + Stefan Haessler + Anthony Guillaume

  1"""
  2Module containing some useful functions for generating various plots.
  3It exists mostly to avoid cluttering the main plotting module.
  4
  5Created in November 2024
  6
  7@author: André Kalouguine + Stefan Haessler + Anthony Guillaume
  8"""
  9# %% Module imports
 10import weakref
 11import numpy as np
 12import colorcet as cc
 13import matplotlib.pyplot as plt
 14
 15import ARTcore.ModuleProcessing as mp
 16import ARTcore.ModuleGeometry as mgeo
 17import ARTcore.ModuleProcessing as mp
 18
 19
 20# %% Definition of observer class to make plots interactive
 21class Observable():
 22    """
 23    Observer class to make several plots interactive simultaneously.
 24    It encapsulates a single value.
 25    When it's modified, it notifies all registered observers.
 26    """
 27    def __init__(self, value):
 28        self._value = value
 29        self._observers = set()
 30        self._calculation = set()
 31    
 32    def register_calculation(self, callback):
 33        """
 34        Register a calculation to be performed when the value is modified before notifying the observers.
 35        For instance, this can be used to perform the ray tracing calculation when the value is modified.
 36        The other callbacks will be notified after the calculation is performed and will update the plots.
 37        """
 38        self._calculation.add(callback)
 39
 40    def unregister_calculation(self, callback):
 41        self._calculation.discard(callback)
 42    
 43    @property
 44    def value(self):
 45        return self._value
 46    
 47    @value.setter
 48    def value(self, new_value):
 49        self._value = new_value
 50        for callback in self._calculation:
 51            callback(new_value)
 52        self.notify(new_value)
 53    
 54    def register(self, callback):
 55        self._observers.add(callback)
 56
 57    def unregister(self, callback):
 58        self._observers.discard(callback)
 59
 60    def notify(self, event):
 61        for callback in self._observers:
 62            callback(event)
 63
 64
 65# %% Utility functions
 66def generate_distinct_colors(num_colors):
 67    """
 68    Utility function to generate a list of distinct colors for plotting.
 69
 70    Parameters
 71    ----------
 72        num_colors : int
 73            The number of colors to generate.
 74
 75    Returns
 76    -------
 77        distinct_colors : list
 78            List of distinct colors.
 79    """
 80    # Get a color palette from colorcet
 81    palette = cc.glasbey
 82
 83    # Make sure the number of colors does not exceed the palette length
 84    num_colors = min(num_colors, len(palette))
 85
 86    # Slice the palette to get the desired number of colors
 87    distinct_colors = palette[:num_colors]
 88
 89    return distinct_colors
 90
 91
 92def _getDetectorPoints(RayListAnalysed, Detector) -> tuple[np.ndarray, np.ndarray, float, float]:
 93    """
 94    Prepare the ray impact points on the detector in a format used for the plotting,
 95    and along the way also calculate the "spotsize" of this point-cloud on the detector.
 96
 97    Parameters
 98    ----------
 99        RayListAnalysed : list(Ray)
100            A list of objects of the ModuleOpticalRay.Ray-class.
101
102        Detector : Detector
103            An object of the ModuleDetector.Detector-class.
104
105    Returns
106    -------
107        DectectorPoint2D_Xcoord : np.ndarray with x-coordinates
108
109        DectectorPoint2D_Ycoord : np.ndarray with y-coordinates
110
111        FocalSpotSize : float
112
113        SpotSizeSD : float
114    """
115
116    Points2D = Detector.get_2D_points(RayListAnalysed)
117    Points2D -= np.mean(Points2D, axis=1)  # Centering the points
118    X = Points2D[0][:,0] * 1e3 # To convert to µm
119    Y = Points2D[0][:,1] * 1e3 # To convert to µm
120
121    FocalSpotSize = float(mgeo.DiameterPointArray(Points2D[0]))
122    SpotSizeSD = mp.StandardDeviation(Points2D[0])
123    return X, Y, FocalSpotSize, SpotSizeSD
124
125def show():
126    plt.show(block=False)
class Observable:
22class Observable():
23    """
24    Observer class to make several plots interactive simultaneously.
25    It encapsulates a single value.
26    When it's modified, it notifies all registered observers.
27    """
28    def __init__(self, value):
29        self._value = value
30        self._observers = set()
31        self._calculation = set()
32    
33    def register_calculation(self, callback):
34        """
35        Register a calculation to be performed when the value is modified before notifying the observers.
36        For instance, this can be used to perform the ray tracing calculation when the value is modified.
37        The other callbacks will be notified after the calculation is performed and will update the plots.
38        """
39        self._calculation.add(callback)
40
41    def unregister_calculation(self, callback):
42        self._calculation.discard(callback)
43    
44    @property
45    def value(self):
46        return self._value
47    
48    @value.setter
49    def value(self, new_value):
50        self._value = new_value
51        for callback in self._calculation:
52            callback(new_value)
53        self.notify(new_value)
54    
55    def register(self, callback):
56        self._observers.add(callback)
57
58    def unregister(self, callback):
59        self._observers.discard(callback)
60
61    def notify(self, event):
62        for callback in self._observers:
63            callback(event)

Observer class to make several plots interactive simultaneously. It encapsulates a single value. When it's modified, it notifies all registered observers.

Observable(value)
28    def __init__(self, value):
29        self._value = value
30        self._observers = set()
31        self._calculation = set()
def register_calculation(self, callback):
33    def register_calculation(self, callback):
34        """
35        Register a calculation to be performed when the value is modified before notifying the observers.
36        For instance, this can be used to perform the ray tracing calculation when the value is modified.
37        The other callbacks will be notified after the calculation is performed and will update the plots.
38        """
39        self._calculation.add(callback)

Register a calculation to be performed when the value is modified before notifying the observers. For instance, this can be used to perform the ray tracing calculation when the value is modified. The other callbacks will be notified after the calculation is performed and will update the plots.

def unregister_calculation(self, callback):
41    def unregister_calculation(self, callback):
42        self._calculation.discard(callback)
value
44    @property
45    def value(self):
46        return self._value
def register(self, callback):
55    def register(self, callback):
56        self._observers.add(callback)
def unregister(self, callback):
58    def unregister(self, callback):
59        self._observers.discard(callback)
def notify(self, event):
61    def notify(self, event):
62        for callback in self._observers:
63            callback(event)
def generate_distinct_colors(num_colors):
67def generate_distinct_colors(num_colors):
68    """
69    Utility function to generate a list of distinct colors for plotting.
70
71    Parameters
72    ----------
73        num_colors : int
74            The number of colors to generate.
75
76    Returns
77    -------
78        distinct_colors : list
79            List of distinct colors.
80    """
81    # Get a color palette from colorcet
82    palette = cc.glasbey
83
84    # Make sure the number of colors does not exceed the palette length
85    num_colors = min(num_colors, len(palette))
86
87    # Slice the palette to get the desired number of colors
88    distinct_colors = palette[:num_colors]
89
90    return distinct_colors

Utility function to generate a list of distinct colors for plotting.

Parameters

num_colors : int
    The number of colors to generate.

Returns

distinct_colors : list
    List of distinct colors.
def show():
126def show():
127    plt.show(block=False)