plot-misc 2.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plot_misc/__init__.py +1 -0
- plot_misc/_version.py +1 -0
- plot_misc/barchart.py +523 -0
- plot_misc/constants.py +118 -0
- plot_misc/errors.py +328 -0
- plot_misc/example_data/__init__.py +1 -0
- plot_misc/example_data/example_datasets/bar_points.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/barchart.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/calibration_bins.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/calibration_data.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/forest_data.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/group_bar.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/heatmap_data.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/incidence_matrix_data.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/lollipop_data.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/mace_associations.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/net_benefit.tsv.gz +0 -0
- plot_misc/example_data/example_datasets/string_data.txt +1 -0
- plot_misc/example_data/example_datasets/volcano.tsv.gz +0 -0
- plot_misc/example_data/examples.py +637 -0
- plot_misc/forest.py +1478 -0
- plot_misc/heatmap.py +369 -0
- plot_misc/incidencematrix.py +394 -0
- plot_misc/machine_learning.py +1143 -0
- plot_misc/piechart.py +197 -0
- plot_misc/utils/__init__.py +1 -0
- plot_misc/utils/colour.py +171 -0
- plot_misc/utils/formatting.py +369 -0
- plot_misc/utils/utils.py +1151 -0
- plot_misc/volcano.py +203 -0
- plot_misc-2.0.2.dist-info/METADATA +107 -0
- plot_misc-2.0.2.dist-info/RECORD +35 -0
- plot_misc-2.0.2.dist-info/WHEEL +5 -0
- plot_misc-2.0.2.dist-info/licenses/LICENSE +18 -0
- plot_misc-2.0.2.dist-info/top_level.txt +1 -0
plot_misc/errors.py
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides utility functions and error classes to support safe and
|
|
3
|
+
consistent handling of inputs throughout the plot-misc codebase. It includes
|
|
4
|
+
mechanisms for enforcing type constraints, checking object shapes and content,
|
|
5
|
+
and raising informative exceptions when expectations are not met.
|
|
6
|
+
|
|
7
|
+
Classes
|
|
8
|
+
-------
|
|
9
|
+
InputValidationError
|
|
10
|
+
A custom exception raised when validation of a parameter fails.
|
|
11
|
+
|
|
12
|
+
Error_MSG
|
|
13
|
+
A container of templated error messages for validation routines.
|
|
14
|
+
|
|
15
|
+
Functions
|
|
16
|
+
---------
|
|
17
|
+
is_type(param, types, param_name=None)
|
|
18
|
+
Verifies that a parameter is an instance of a given type or set of types.
|
|
19
|
+
|
|
20
|
+
is_df(df)
|
|
21
|
+
Confirms whether an object is a pandas DataFrame.
|
|
22
|
+
|
|
23
|
+
are_columns_in_df(df, expected_columns, warning=False)
|
|
24
|
+
Checks that specific column names exist in a DataFrame.
|
|
25
|
+
|
|
26
|
+
is_series_type(column, types)
|
|
27
|
+
Confirms all elements of a Series or DataFrame match a specified type.
|
|
28
|
+
|
|
29
|
+
same_len(object1, object2, object_names=None)
|
|
30
|
+
Validates that two objects have the same length.
|
|
31
|
+
|
|
32
|
+
string_to_list(object)
|
|
33
|
+
Wraps strings in a list; leaves other objects unchanged.
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
import inspect
|
|
38
|
+
import warnings
|
|
39
|
+
import pandas as pd
|
|
40
|
+
from typing import (
|
|
41
|
+
Any,
|
|
42
|
+
Type,
|
|
43
|
+
Set,
|
|
44
|
+
)
|
|
45
|
+
from packaging import version
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
49
|
+
class InputValidationError(Exception):
|
|
50
|
+
"""
|
|
51
|
+
Custom exception for signalling input validation failures.
|
|
52
|
+
"""
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
56
|
+
# error messages
|
|
57
|
+
class Error_MSG(object):
|
|
58
|
+
"""
|
|
59
|
+
Container for predefined error message templates.
|
|
60
|
+
|
|
61
|
+
Attributes
|
|
62
|
+
----------
|
|
63
|
+
MISSING_DF : str
|
|
64
|
+
Message template for missing values in a DataFrame.
|
|
65
|
+
INVALID_STRING : str
|
|
66
|
+
Message for invalid string values.
|
|
67
|
+
INVALID_EXACT_LENGTH : str
|
|
68
|
+
Message for enforcing exact list or array length.
|
|
69
|
+
"""
|
|
70
|
+
MISSING_DF = '`{}` contains missing values.'
|
|
71
|
+
INVALID_STRING = '`{}` should be limited to `{}`.'
|
|
72
|
+
INVALID_EXACT_LENGTH = '`{}` needs to contain exactly {} elements, not {}.'
|
|
73
|
+
|
|
74
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
75
|
+
def _get_param_name(param:Any) -> str | None:
|
|
76
|
+
"""
|
|
77
|
+
Attempt to infer the variable name of a parameter from the caller's scope.
|
|
78
|
+
"""
|
|
79
|
+
frame = inspect.currentframe().f_back.f_back
|
|
80
|
+
param_names =\
|
|
81
|
+
[name for name, value in frame.f_locals.items() if value is param]
|
|
82
|
+
return param_names[0] if param_names else None
|
|
83
|
+
|
|
84
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
85
|
+
def is_type(param: Any, types: tuple[Type] | Type,
|
|
86
|
+
param_name: str | None = None,) -> bool:
|
|
87
|
+
"""
|
|
88
|
+
Checks if a given parameter matches any of the supplied types
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
param : `any`
|
|
93
|
+
Object to test.
|
|
94
|
+
types: `type` or `tuple` [`type`]
|
|
95
|
+
Expected type(s) of the object.
|
|
96
|
+
param_name : `str` or `None`
|
|
97
|
+
Name of the parameter. Will attempt to infer the parameter name if set
|
|
98
|
+
to `NoneType`.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
bool
|
|
103
|
+
True if type matches.
|
|
104
|
+
|
|
105
|
+
Raises
|
|
106
|
+
------
|
|
107
|
+
InputValidationError
|
|
108
|
+
If the parameter does not match any of the expected types.
|
|
109
|
+
"""
|
|
110
|
+
if not isinstance(param, types):
|
|
111
|
+
if param_name is None:
|
|
112
|
+
param_name = _get_param_name(param)
|
|
113
|
+
else:
|
|
114
|
+
warnings.warn('`param_name` will be depricated.',
|
|
115
|
+
DeprecationWarning,
|
|
116
|
+
stacklevel=2,
|
|
117
|
+
)
|
|
118
|
+
raise InputValidationError(
|
|
119
|
+
f"Expected any of [{types}], "
|
|
120
|
+
f"got {type(param)}; Please see parameter: `{param_name}`."
|
|
121
|
+
)
|
|
122
|
+
return True
|
|
123
|
+
|
|
124
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
125
|
+
def is_df(df: Any) -> bool:
|
|
126
|
+
"""
|
|
127
|
+
Check if objects is a pd.DataFrame.
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
df : `Any`
|
|
132
|
+
Object to test.
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
bool
|
|
137
|
+
True if the object is a DataFrame.
|
|
138
|
+
|
|
139
|
+
Raises
|
|
140
|
+
------
|
|
141
|
+
InputValidationError
|
|
142
|
+
If the object is not a DataFrame.
|
|
143
|
+
"""
|
|
144
|
+
return is_type(df, pd.DataFrame)
|
|
145
|
+
|
|
146
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
147
|
+
# NOTE add test for expected_columns being a str and that it raises an error
|
|
148
|
+
# with the intact tsring rather than each letter individually.
|
|
149
|
+
def are_columns_in_df(
|
|
150
|
+
df: pd.DataFrame, expected_columns: list[str] | str, warning: bool=False,
|
|
151
|
+
) -> bool:
|
|
152
|
+
"""
|
|
153
|
+
Check if all expected columns are present in a given pandas.DataFrame.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
df : `pandas.DataFrame`
|
|
158
|
+
DataFrame to test.
|
|
159
|
+
expected_columns: `str` or `list` [`str`]
|
|
160
|
+
Expected column name(s). For easy of use any `None` entries will be
|
|
161
|
+
filtered out before applying the test.
|
|
162
|
+
warning : bool, default False
|
|
163
|
+
raises a warning instead of an error.
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
bool
|
|
168
|
+
True if all columns are present, False if missing and `warning=True`.
|
|
169
|
+
|
|
170
|
+
Raises
|
|
171
|
+
------
|
|
172
|
+
InputValidationError
|
|
173
|
+
If any columns are missing and `warning=False`.
|
|
174
|
+
"""
|
|
175
|
+
# constant
|
|
176
|
+
message = "The following columns are missing from the pandas.DataFrame: {}"
|
|
177
|
+
res = True
|
|
178
|
+
# filtering out any potential None names
|
|
179
|
+
expected_columns = string_to_list(expected_columns)
|
|
180
|
+
expected_columns = [c for c in expected_columns if c is not None]
|
|
181
|
+
# tests
|
|
182
|
+
expected_columns_set: Set[str] = set(expected_columns) if isinstance(
|
|
183
|
+
expected_columns, list
|
|
184
|
+
) else set([expected_columns])
|
|
185
|
+
missing_columns = expected_columns_set - set(df.columns)
|
|
186
|
+
# return
|
|
187
|
+
if missing_columns:
|
|
188
|
+
if warning == False:
|
|
189
|
+
raise InputValidationError(
|
|
190
|
+
message.format(missing_columns)
|
|
191
|
+
)
|
|
192
|
+
else:
|
|
193
|
+
warnings.warn(
|
|
194
|
+
message.format(missing_columns)
|
|
195
|
+
)
|
|
196
|
+
res = False
|
|
197
|
+
return res
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
201
|
+
def is_series_type(column: pd.Series | pd.DataFrame, types: tuple[Type] | Type,
|
|
202
|
+
) -> bool:
|
|
203
|
+
"""
|
|
204
|
+
Check whether each element of a Series or DataFrame matches a given type.
|
|
205
|
+
|
|
206
|
+
Parameters
|
|
207
|
+
----------
|
|
208
|
+
column : `pd.Series` or `pd.DataFrame`
|
|
209
|
+
Data structure to validate.
|
|
210
|
+
types : `type` or `tuple` [`tupe`]
|
|
211
|
+
Allowed types for individual elements.
|
|
212
|
+
|
|
213
|
+
Returns
|
|
214
|
+
-------
|
|
215
|
+
bool
|
|
216
|
+
True if all elements match given types.
|
|
217
|
+
|
|
218
|
+
Raises
|
|
219
|
+
------
|
|
220
|
+
InputValidationError
|
|
221
|
+
If any element fails the type check.
|
|
222
|
+
|
|
223
|
+
Notes
|
|
224
|
+
-----
|
|
225
|
+
Instead of testing the dtypes, the function will look over each
|
|
226
|
+
element and test these individually.
|
|
227
|
+
"""
|
|
228
|
+
# check input
|
|
229
|
+
is_type(column, (pd.DataFrame, pd.Series))
|
|
230
|
+
# run tests
|
|
231
|
+
if isinstance(column, pd.Series):
|
|
232
|
+
[is_type(col, types) for col in column]
|
|
233
|
+
elif isinstance(column, pd.DataFrame):
|
|
234
|
+
if version.parse('2.0.3') <= version.parse(pd.__version__):
|
|
235
|
+
# iteritems got depricated.
|
|
236
|
+
column.iteritems = column.items
|
|
237
|
+
for _, col in column.items():
|
|
238
|
+
[is_type(co, types) for co in col]
|
|
239
|
+
# return
|
|
240
|
+
return True
|
|
241
|
+
|
|
242
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
243
|
+
def same_len(object1: Any, object2: Any, object_names: list[str] | None = None,
|
|
244
|
+
) -> bool:
|
|
245
|
+
"""
|
|
246
|
+
Assert that two objects have the same length.
|
|
247
|
+
|
|
248
|
+
Parameters
|
|
249
|
+
----------
|
|
250
|
+
object1 : Any
|
|
251
|
+
First object.
|
|
252
|
+
object2 : Any
|
|
253
|
+
Second object.
|
|
254
|
+
object_names : list of str, optional
|
|
255
|
+
Names of the two objects (for error message).
|
|
256
|
+
|
|
257
|
+
Returns
|
|
258
|
+
-------
|
|
259
|
+
bool
|
|
260
|
+
True if lengths match.
|
|
261
|
+
|
|
262
|
+
Notes
|
|
263
|
+
-----
|
|
264
|
+
both object1 and object2 should have a `len` method.
|
|
265
|
+
|
|
266
|
+
Raises
|
|
267
|
+
------
|
|
268
|
+
ValueError
|
|
269
|
+
If lengths do not match or `object_names` is invalid.
|
|
270
|
+
"""
|
|
271
|
+
n1 = len(object1)
|
|
272
|
+
n2 = len(object2)
|
|
273
|
+
if object_names is None:
|
|
274
|
+
object_names = ['object1', 'object2']
|
|
275
|
+
elif len(object_names) !=2:
|
|
276
|
+
raise ValueError('`object_names` should be `NoneType` or contain '
|
|
277
|
+
'two strings')
|
|
278
|
+
# the actual test
|
|
279
|
+
if n1 != n2:
|
|
280
|
+
raise ValueError("The length of `{0}`: {1}, does not match the length "
|
|
281
|
+
"of `{2}`: {3}.".format(object_names[0], n1,
|
|
282
|
+
object_names[1], n2)
|
|
283
|
+
)
|
|
284
|
+
return True
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
288
|
+
def string_to_list(object:Any) -> Any | list[str]:
|
|
289
|
+
"""
|
|
290
|
+
Checks if `object` is a string and wraps this in a list, returns the
|
|
291
|
+
original object if it is not a string.
|
|
292
|
+
|
|
293
|
+
Parameters
|
|
294
|
+
----------
|
|
295
|
+
object : Any
|
|
296
|
+
Object to check.
|
|
297
|
+
|
|
298
|
+
Returns
|
|
299
|
+
-------
|
|
300
|
+
list[str] or Any
|
|
301
|
+
List if input is string; otherwise the input unchanged.
|
|
302
|
+
"""
|
|
303
|
+
if isinstance(object, str):
|
|
304
|
+
return [object]
|
|
305
|
+
else:
|
|
306
|
+
return object
|
|
307
|
+
|
|
308
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
309
|
+
def number_to_list(object:Any) -> Any | list[str]:
|
|
310
|
+
"""
|
|
311
|
+
Checks if `object` is a float or int and wraps this in a list, returns the
|
|
312
|
+
original object if it is not a string.
|
|
313
|
+
|
|
314
|
+
Parameters
|
|
315
|
+
----------
|
|
316
|
+
object : Any
|
|
317
|
+
Object to check.
|
|
318
|
+
|
|
319
|
+
Returns
|
|
320
|
+
-------
|
|
321
|
+
list[str] or Any
|
|
322
|
+
List if input is string; otherwise the input unchanged.
|
|
323
|
+
"""
|
|
324
|
+
if isinstance(object, (int, float)):
|
|
325
|
+
return [object]
|
|
326
|
+
else:
|
|
327
|
+
return object
|
|
328
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
an example data string
|
|
Binary file
|