Coverage for cc_modules/cc_trackerhelpers.py: 42%
53 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
1#!/usr/bin/env python
3"""
4camcops_server/cc_modules/cc_trackerhelpers.py
6===============================================================================
8 Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
9 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
11 This file is part of CamCOPS.
13 CamCOPS is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
18 CamCOPS is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
26===============================================================================
28**Helper representations for trackers.**
30"""
32from enum import Enum
33from typing import List, Optional
35import numpy as np
38DEFAULT_TRACKER_ASPECT_RATIO = 2.0 # width / height
41class LabelAlignment(Enum):
42 """
43 Enum representing figure label alignment.
44 """
46 center = "center"
47 top = "top"
48 bottom = "bottom"
49 baseline = "baseline"
52class TrackerLabel(object):
53 """
54 Representation of a label on a
55 :class:`camcops_server.cc_modules.cc_tracker.Tracker` figure.
56 """
58 def __init__(
59 self,
60 y: float,
61 label: str,
62 vertical_alignment: LabelAlignment = LabelAlignment.center,
63 ):
64 """
65 Args:
66 y: Y axis (vertical) position
67 label: text for label
68 vertical_alignment: :class:`LabelAlignment` enum
69 """
70 self.y = y
71 self.label = label
72 self.vertical_alignment = vertical_alignment
74 def __str__(self) -> str:
75 return f"{self.y}: {self.label}"
78class TrackerAxisTick(object):
79 """
80 Representation of a Y-axis tick mark and associated label on a
81 :class:`camcops_server.cc_modules.cc_tracker.Tracker` figure.
82 """
84 def __init__(self, y: float, label: str):
85 self.y = y
86 self.label = label
89class TrackerInfo(object):
90 """
91 Tasks return one or more of these (one for each tracker to be shown), from
92 which :class:`camcops_server.cc_modules.cc_tracker.Tracker` displays are
93 created.
94 """
96 def __init__(
97 self,
98 value: float,
99 plot_label: str = None,
100 axis_label: str = None,
101 axis_min: float = None,
102 axis_max: float = None,
103 axis_ticks: Optional[List[TrackerAxisTick]] = None,
104 horizontal_lines: Optional[List[float]] = None,
105 horizontal_labels: Optional[List[TrackerLabel]] = None,
106 aspect_ratio: Optional[float] = DEFAULT_TRACKER_ASPECT_RATIO,
107 ):
108 """
109 Args:
110 value: numerical value
111 plot_label: label for the whole plot
112 axis_label: label for the Y axis
113 axis_min: minimum value for the Y axis
114 axis_max: maximum value for the Y axis
115 axis_ticks: optional list of :class:`TrackerAxisTick` objects
116 describing where to put tick marks/labels on the Y axis
117 horizontal_lines: optional list of y values at which to draw
118 horizontal (dotted) lines
119 horizontal_labels: optional list of :class:`TrackerLabel` objects
120 indicating which additional labels to place on the main plot
121 (such as: to describe the meaning of the horizontal lines)
122 aspect_ratio: optional aspect ratio (width / height)
123 """
124 self.value = value
125 self.plot_label = plot_label
126 self.axis_label = axis_label
127 self.axis_min = axis_min
128 self.axis_max = axis_max
129 self.axis_ticks = axis_ticks or []
130 self.horizontal_lines = horizontal_lines or []
131 self.horizontal_labels = horizontal_labels or []
132 self.aspect_ratio = aspect_ratio
135def equally_spaced_ndarray(
136 start: float, stop: float, num: int, endpoint: bool = True
137) -> np.ndarray:
138 """
139 Produces equally spaced numbers. See
140 https://stackoverflow.com/questions/477486/how-to-use-a-decimal-range-step-value.
142 Args:
143 start: starting value
144 stop: stopping value
145 num: number of values to return
146 endpoint: include the endpoint?
148 Returns:
149 list of floats
151 """ # noqa
152 return np.linspace(start, stop, num, endpoint=endpoint, dtype=float)
155def equally_spaced_float(
156 start: float, stop: float, num: int, endpoint: bool = True
157) -> List[float]:
158 """
159 Returns a float equivalent of :func:`equally_spaced_float` (q.v.).
160 """
161 return list(equally_spaced_ndarray(start, stop, num, endpoint=endpoint))
164def equally_spaced_int(
165 start: int, stop: int, step: int, endpoint: bool = True
166) -> List[int]:
167 """
168 Almost a synonym for :func:`range`!
170 Args:
171 start: starting value
172 stop: stopping value (INCLUSIVE if endpoint is True)
173 step: step size
174 endpoint: bool
176 Returns:
177 list of integers
178 """
179 if endpoint:
180 if start <= stop: # normal
181 range_stop = stop + 1
182 else: # counting backwards: start > stop
183 range_stop = stop - 1
184 else:
185 range_stop = stop
186 return list(range(start, range_stop, step))
189def regular_tracker_axis_ticks_float(
190 start: float, stop: float, num: int, endpoint: bool = True
191) -> List[TrackerAxisTick]:
192 """
193 Args:
194 start: starting value
195 stop: stopping value
196 num: number of values to return
197 endpoint: include the endpoint?
199 Returns:
200 a list of simple numerical TrackerAxisTick objects
202 """
203 ticks = [] # type: List[TrackerAxisTick]
204 for val in equally_spaced_ndarray(start, stop, num, endpoint=endpoint):
205 ticks.append(TrackerAxisTick(val, str(val)))
206 return ticks
209def regular_tracker_axis_ticks_int(
210 start: int, stop: int, step: int, endpoint: bool = True
211) -> List[TrackerAxisTick]:
212 """
213 Args:
214 start: starting value
215 stop: stopping value
216 step: step size
217 endpoint: include the endpoint?
219 Returns:
220 a list of simple numerical TrackerAxisTick objects
222 """
223 ticks = [] # type: List[TrackerAxisTick]
224 for val in equally_spaced_int(start, stop, step, endpoint=endpoint):
225 ticks.append(TrackerAxisTick(val, str(val)))
226 return ticks