Coverage for cc_modules/cc_trackerhelpers.py : 41%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python
3"""
4camcops_server/cc_modules/cc_trackerhelpers.py
6===============================================================================
8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com).
10 This file is part of CamCOPS.
12 CamCOPS is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
17 CamCOPS is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
25===============================================================================
27**Helper representations for trackers.**
29"""
31from enum import Enum
32from typing import List, Optional
34import numpy as np
37DEFAULT_TRACKER_ASPECT_RATIO = 2.0 # width / height
40class LabelAlignment(Enum):
41 """
42 Enum representing figure label alignment.
43 """
44 center = "center"
45 top = "top"
46 bottom = "bottom"
47 baseline = "baseline"
50class TrackerLabel(object):
51 """
52 Representation of a label on a
53 :class:`camcops_server.cc_modules.cc_tracker.Tracker` figure.
54 """
55 def __init__(self,
56 y: float,
57 label: str,
58 vertical_alignment: LabelAlignment = LabelAlignment.center):
59 """
60 Args:
61 y: Y axis (vertical) position
62 label: text for label
63 vertical_alignment: :class:`LabelAlignment` enum
64 """
65 self.y = y
66 self.label = label
67 self.vertical_alignment = vertical_alignment
70class TrackerAxisTick(object):
71 """
72 Representation of a Y-axis tick mark and associated label on a
73 :class:`camcops_server.cc_modules.cc_tracker.Tracker` figure.
74 """
75 def __init__(self, y: float, label: str):
76 self.y = y
77 self.label = label
80class TrackerInfo(object):
81 """
82 Tasks return one or more of these (one for each tracker to be shown), from
83 which :class:`camcops_server.cc_modules.cc_tracker.Tracker` displays are
84 created.
85 """
86 def __init__(self,
87 value: float,
88 plot_label: str = None,
89 axis_label: str = None,
90 axis_min: float = None,
91 axis_max: float = None,
92 axis_ticks: Optional[List[TrackerAxisTick]] = None,
93 horizontal_lines: Optional[List[float]] = None,
94 horizontal_labels: Optional[List[TrackerLabel]] = None,
95 aspect_ratio: Optional[float] = DEFAULT_TRACKER_ASPECT_RATIO):
96 """
97 Args:
98 value: numerical value
99 plot_label: label for the whole plot
100 axis_label: label for the Y axis
101 axis_min: minimum value for the Y axis
102 axis_max: maximum value for the Y axis
103 axis_ticks: optional list of :class:`TrackerAxisTick` objects
104 describing where to put tick marks/labels on the Y axis
105 horizontal_lines: optional list of y values at which to draw
106 horizontal (dotted) lines
107 horizontal_labels: optional list of :class:`TrackerLabel` objects
108 indicating which additional labels to place on the main plot
109 (such as: to describe the meaning of the horizontal lines)
110 aspect_ratio: optional aspect ratio (width / height)
111 """
112 self.value = value
113 self.plot_label = plot_label
114 self.axis_label = axis_label
115 self.axis_min = axis_min
116 self.axis_max = axis_max
117 self.axis_ticks = axis_ticks or []
118 self.horizontal_lines = horizontal_lines or []
119 self.horizontal_labels = horizontal_labels or []
120 self.aspect_ratio = aspect_ratio
123def equally_spaced_ndarray(start: float, stop: float, num: int,
124 endpoint: bool = True) -> np.ndarray:
125 """
126 Produces equally spaced numbers. See
127 https://stackoverflow.com/questions/477486/how-to-use-a-decimal-range-step-value.
129 Args:
130 start: starting value
131 stop: stopping value
132 num: number of values to return
133 endpoint: include the endpoint?
135 Returns:
136 list of floats
138 """ # noqa
139 return np.linspace(start, stop, num, endpoint=endpoint, dtype=float)
142def equally_spaced_float(start: float, stop: float, num: int,
143 endpoint: bool = True) -> List[float]:
144 """
145 Returns a float equivalent of :func:`equally_spaced_float` (q.v.).
146 """
147 return list(equally_spaced_ndarray(start, stop, num, endpoint=endpoint))
150def equally_spaced_int(start: int, stop: int, step: int,
151 endpoint: bool = True) -> List[int]:
152 """
153 Almost a synonym for :func:`range`!
155 Args:
156 start: starting value
157 stop: stopping value (INCLUSIVE if endpoint is True)
158 step: step size
159 endpoint: bool
161 Returns:
162 list of integers
163 """
164 if endpoint:
165 if start <= stop: # normal
166 range_stop = stop + 1
167 else: # counting backwards: start > stop
168 range_stop = stop - 1
169 else:
170 range_stop = stop
171 return list(range(start, range_stop, step))
174def regular_tracker_axis_ticks_float(
175 start: float, stop: float, num: int,
176 endpoint: bool = True) -> List[TrackerAxisTick]:
177 """
178 Args:
179 start: starting value
180 stop: stopping value
181 num: number of values to return
182 endpoint: include the endpoint?
184 Returns:
185 a list of simple numerical TrackerAxisTick objects
187 """
188 ticks = [] # type: List[TrackerAxisTick]
189 for val in equally_spaced_ndarray(start, stop, num, endpoint=endpoint):
190 ticks.append(TrackerAxisTick(val, str(val)))
191 return ticks
194def regular_tracker_axis_ticks_int(
195 start: int, stop: int, step: int,
196 endpoint: bool = True) -> List[TrackerAxisTick]:
197 """
198 Args:
199 start: starting value
200 stop: stopping value
201 step: step size
202 endpoint: include the endpoint?
204 Returns:
205 a list of simple numerical TrackerAxisTick objects
207 """
208 ticks = [] # type: List[TrackerAxisTick]
209 for val in equally_spaced_int(start, stop, step, endpoint=endpoint):
210 ticks.append(TrackerAxisTick(val, str(val)))
211 return ticks