Coverage for src/gncpy/plotting.py: 55%
44 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-13 06:15 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-13 06:15 +0000
1"""Defines utility functions for plotting routines."""
2import numpy as np
3from numpy.linalg import eigh
4import numpy.random as rnd
5import matplotlib.pyplot as plt
8def calc_error_ellipse(cov, n_sig):
9 """Calculates parameters for an error ellipse.
11 This calucates the error ellipse for a given sigma
12 number according to :cite:`Hoover1984_AlgorithmsforConfidenceCirclesandEllipses`.
14 Parameters
15 ----------
16 cov : 2 x 2 numpy array
17 covariance matrix.
18 n_sig : float
19 Sigma number, must be positive.
21 Returns
22 -------
23 width : float
24 The width of the ellipse
25 height :float
26 The height of the ellipse
27 angle : float
28 The rotation angle in degrees of the semi-major axis. Measured up from
29 the positive x-axis.
30 """
31 # get and sort eigne values
32 vals, vecs = eigh(cov)
33 order = vals.argsort()[::-1]
34 vals = vals[order]
35 vecs = vecs[:, order]
37 # find rotation angle from positive x-axis, and width/height
38 angle = 180 / np.pi * np.arctan2(*vecs[:, 0][::-1])
39 width, height = 2 * n_sig * np.sqrt(vals)
41 return 2 * width, 2 * height, angle
44def init_plotting_opts(
45 f_hndl=None,
46 lgnd_loc=None,
47 sig_bnd=1,
48 time_vec=None,
49 true_states=None,
50 rng=rnd.default_rng(1),
51 meas_inds=None,
52 marker="o",
53 ttl_fontsize=12,
54 ttl_fontstyle="normal",
55 ttl_fontfamily="sans-serif",
56 ax_fontsize=10,
57 ax_fontstyle="normal",
58 ax_fontfamily="sans-serif",
59):
60 """Processes common plotting options in a common interface.
62 Parameters
63 ----------
64 f_hndl : matplotlib figure, optional
65 Current to figure to plot on. Pass None to create a new figure. The
66 default is None.
67 lgnd_loc : string, optional
68 Location of the legend. Set to none to skip creating a legend. The
69 default is None.
70 sig_bnd : int, optional
71 If set and the covariances are saved, the sigma bounds are scaled by
72 this number and plotted for each track. The default is 1.
73 time_vec : list, optional
74 List of time values. The default is None.
75 true_states : list, optional
76 Each element is a N x 1 numpy array representing the true state.
77 If not given true states are not plotted. The default is None.
78 rng : numpy random generator, optional
79 For generating random numbers. The default is rnd.default_rng(1).
80 meas_inds : list, optional
81 List of indices in the measurement vector to plot if this is specified
82 all available measurements will be plotted. Note, x-axis is first, then
83 y-axis. Also note, if gating is on then gated measurements will not be
84 plotted. The default is None.
85 marker : string, optional
86 Shape to use as a marker, can be any valid value used by matplotlib.
87 The default is 'o'.
88 ttl_fontsize : int, optional
89 Title font size. The default is 12.
90 ttl_fontstyle : string, optional
91 Matplotlib font style for the title. The default is 'normal'.
92 ttl_fontfamily : string, optional
93 Matplotlib font family for the title. The default is 'sans-serif'.
94 ax_fontsize : int, optional
95 Axis label font size. The default is 10.
96 ax_fontstyle : string, optional
97 Matplotlib font style for the axis label. The default is 'normal'.
98 ax_fontfamily : string, optional
99 Matplotlib font family for the axis label. The default is 'sans-serif'.
101 Returns
102 -------
103 opts : dict
104 Plotting options with default values where custom ones were not specified.
105 """
106 opts = {}
108 opts["f_hndl"] = f_hndl
109 opts["lgnd_loc"] = lgnd_loc
111 opts["sig_bnd"] = sig_bnd
112 opts["time_vec"] = time_vec
113 opts["true_states"] = true_states
114 opts["rng"] = rng
115 opts["meas_inds"] = meas_inds
117 opts["marker"] = marker
119 opts["ttl_fontsize"] = ttl_fontsize
120 opts["ttl_fontstyle"] = ttl_fontstyle
121 opts["ttl_fontfamily"] = ttl_fontfamily
123 opts["ax_fontsize"] = ax_fontsize
124 opts["ax_fontstyle"] = ax_fontstyle
125 opts["ax_fontfamily"] = ax_fontfamily
127 return opts
130def set_title_label(
131 fig, ax_num, opts, ttl=None, x_lbl=None, y_lbl=None, z_lbl=None, use_local=False
132):
133 """Sets the figure/window title, and axis labels with the given options.
135 Parameters
136 ----------
137 fig : matplot figure object
138 Current figure to edit.
139 ax_num : int
140 Index into the axes object to modify.
141 opts : dict
142 Standard dictionary from :func:`.plotting.init_plotting_opts`.
143 ttl : string, optional
144 Title string to use. This is set to the proper size, family, and
145 style. It also becomes the window title. The default is None.
146 x_lbl : string, optional
147 Label for the x-axis. This is set to the proper size, family, and
148 style. The default is None.
149 y_lbl : string, optional
150 Label for the y-axis. This is set to the proper size, family, and
151 style. The default is None.
152 z_lbl : string, optional
153 Label for the z-axis. This is set to the proper size, family, and
154 style. The default is None.
155 use_local : bool, optional
156 Flag indicating if the local title or suptitle should be set. The
157 default is False.
159 Returns
160 -------
161 None.
162 """
163 if ttl is not None:
164 if use_local:
165 fig.axes[ax_num].set_title(
166 ttl,
167 fontsize=opts["ttl_fontsize"],
168 fontstyle=opts["ttl_fontstyle"],
169 fontfamily=opts["ttl_fontfamily"],
170 )
171 else:
172 fig.suptitle(
173 ttl,
174 fontsize=opts["ttl_fontsize"],
175 fontstyle=opts["ttl_fontstyle"],
176 fontfamily=opts["ttl_fontfamily"],
177 )
178 if fig.canvas.manager is not None:
179 fig.canvas.manager.set_window_title(ttl)
181 if x_lbl is not None:
182 fig.axes[ax_num].set_xlabel(
183 x_lbl,
184 fontsize=opts["ax_fontsize"],
185 fontstyle=opts["ax_fontstyle"],
186 fontfamily=opts["ax_fontfamily"],
187 )
188 if y_lbl is not None:
189 fig.axes[ax_num].set_ylabel(
190 y_lbl,
191 fontsize=opts["ax_fontsize"],
192 fontstyle=opts["ax_fontstyle"],
193 fontfamily=opts["ax_fontfamily"],
194 )
195 if z_lbl is not None:
196 fig.axes[ax_num].set_zlabel(
197 z_lbl,
198 fontsize=opts["ax_fontsize"],
199 fontstyle=opts["ax_fontstyle"],
200 fontfamily=opts["ax_fontfamily"],
201 )
204def get_cmap(n, name="Dark2"):
205 """Returns a function that generates a color map.
207 Returns a function thata maps each index in 0, 1, ..., n-1 to a distinct
208 RGB color; the keyword argument name must be a standard mpl colormap name.
210 Parameters
211 ----------
212 n : int
213 Number of colors in the map.
214 name : string
215 name of the colormap, valid for `pyplot.cm.get_cmap` function
216 """
217 return plt.cm.get_cmap(name, n)