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/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from ._version import __version__
|
plot_misc/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '2.0.2'
|
plot_misc/barchart.py
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Bar chart plotting tools using matplotlib.
|
|
3
|
+
|
|
4
|
+
This module provides a collection of flexible bar chart functions based on
|
|
5
|
+
`matplotlib`, including standard, grouped, stacked, and subtotal bar plots.
|
|
6
|
+
These functions offer fine control over visual elements such as bar width,
|
|
7
|
+
transparency, edge colouring, error bars, and group positioning.
|
|
8
|
+
|
|
9
|
+
Functions
|
|
10
|
+
---------
|
|
11
|
+
bar(data, label, column, ...)
|
|
12
|
+
Plot a standard bar chart from a single column of values.
|
|
13
|
+
|
|
14
|
+
stack_bar(data, label, columns, ...)
|
|
15
|
+
Plot a stacked bar chart from multiple columns in a DataFrame.
|
|
16
|
+
|
|
17
|
+
subtotal_bar(data, label, total_col, subtotal_col, ...)
|
|
18
|
+
Plot a bar chart of totals with optionally overlaid subtotals.
|
|
19
|
+
|
|
20
|
+
group_bar(data, label, columns, ...)
|
|
21
|
+
Plot a grouped bar chart with multiple bars per group, optionally
|
|
22
|
+
with error bars.
|
|
23
|
+
"""
|
|
24
|
+
import matplotlib.pyplot as plt
|
|
25
|
+
import pandas as pd
|
|
26
|
+
import numpy as np
|
|
27
|
+
from plot_misc.utils.utils import _update_kwargs
|
|
28
|
+
from plot_misc.errors import (
|
|
29
|
+
is_type,
|
|
30
|
+
is_df,
|
|
31
|
+
Error_MSG,
|
|
32
|
+
)
|
|
33
|
+
from typing import Any, Optional
|
|
34
|
+
from plot_misc.constants import Real
|
|
35
|
+
|
|
36
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
37
|
+
def bar(data:pd.DataFrame, label:str, column:str,
|
|
38
|
+
error_max:str | None = None, error_min:str | None = None,
|
|
39
|
+
colours:list[str]=['tab:blue', 'tab:pink'], transparency:float=0.7,
|
|
40
|
+
wd:Real=1.0, edgecolour:str='black',
|
|
41
|
+
horizontal:bool = False, figsize:tuple[Real,Real] = (2,2),
|
|
42
|
+
ax:plt.Axes | None = None,
|
|
43
|
+
kwargs_bar:dict[str, Any] | None = None,
|
|
44
|
+
kwargs_error:dict[str, Any] | None = None,
|
|
45
|
+
) -> tuple[plt.Figure, plt.Axes]:
|
|
46
|
+
"""
|
|
47
|
+
Plot a vertical or horizontal bar chart with optional error bars.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
data : `pd.DataFrame`
|
|
52
|
+
DataFrame containing bar heights and axis labels.
|
|
53
|
+
label : `str`
|
|
54
|
+
The column name for the axes labels.
|
|
55
|
+
column : `str`
|
|
56
|
+
The column name for the bar height values.
|
|
57
|
+
error_max : `str`, default `NoneType`
|
|
58
|
+
column name for the upper value of the error line segment.
|
|
59
|
+
error_min : ``str` default `NoneType`
|
|
60
|
+
column name for the lower value of the error line segment.
|
|
61
|
+
colours : `list` [`str`], default ['tab:blue', 'tab:pink']
|
|
62
|
+
Colours for the bars; recycled if shorter than the number of bars.
|
|
63
|
+
transparency : `float`, default 0.7
|
|
64
|
+
Alpha transparency level for the bars (0 to 1).
|
|
65
|
+
wd : `float` or `int`, default 1.0
|
|
66
|
+
The bar width.
|
|
67
|
+
edgecolour : `str`, default `black`
|
|
68
|
+
The bar edgecolour.
|
|
69
|
+
horizontal : `bool`, default `False`
|
|
70
|
+
Whether plot a horizontal bar chart.
|
|
71
|
+
ax : `plt.ax`, default `NoneType`
|
|
72
|
+
The pyplot.axes object.
|
|
73
|
+
figsize : `tuple` [`float`, `float`], default (2, 2),
|
|
74
|
+
The figure size in inches, when ax is set to None.
|
|
75
|
+
kwargs_bar : `any`
|
|
76
|
+
Arbitrary keyword arguments for `ax.bar` or `ax.barh`.
|
|
77
|
+
kwargs_error : `any`
|
|
78
|
+
Arbitrary keyword arguments for `ax.hlines` or `ax.vlines`.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
fig : plt.Figure
|
|
83
|
+
Matplotlib figure object.
|
|
84
|
+
ax : plt.Axes
|
|
85
|
+
Matplotlib axes with the rendered bar plot.
|
|
86
|
+
"""
|
|
87
|
+
# check input
|
|
88
|
+
is_df(data)
|
|
89
|
+
is_type(label, str)
|
|
90
|
+
is_type(column, str)
|
|
91
|
+
is_type(colours, list)
|
|
92
|
+
is_type(transparency, float)
|
|
93
|
+
is_type(wd, (float, int))
|
|
94
|
+
is_type(edgecolour, str)
|
|
95
|
+
is_type(horizontal, bool)
|
|
96
|
+
is_type(ax, (type(None), plt.Axes))
|
|
97
|
+
is_type(error_min, (type(None), str))
|
|
98
|
+
is_type(error_max, (type(None), str))
|
|
99
|
+
is_type(kwargs_bar, (type(None), dict))
|
|
100
|
+
is_type(kwargs_error, (type(None), dict))
|
|
101
|
+
# ### should we create a figure and axis
|
|
102
|
+
if ax is None:
|
|
103
|
+
f, ax = plt.subplots(figsize=figsize)
|
|
104
|
+
else:
|
|
105
|
+
f = ax.figure
|
|
106
|
+
# mapping None to empty dicts
|
|
107
|
+
kwargs_bar = kwargs_bar or {}
|
|
108
|
+
kwargs_error = kwargs_error or {}
|
|
109
|
+
# ### check input
|
|
110
|
+
if any(data.isna().any()):
|
|
111
|
+
raise ValueError(Error_MSG.MISSING_DF.format('data'))
|
|
112
|
+
# ### get labels
|
|
113
|
+
labels = data[label]
|
|
114
|
+
# ### plotting
|
|
115
|
+
if horizontal == False:
|
|
116
|
+
# plotting vertical bar chart
|
|
117
|
+
new_kwargs = _update_kwargs(update_dict=kwargs_bar,
|
|
118
|
+
edgecolor=edgecolour,
|
|
119
|
+
width=wd, color=colours,
|
|
120
|
+
alpha=transparency,
|
|
121
|
+
zorder=2,
|
|
122
|
+
)
|
|
123
|
+
bars = ax.bar(labels, height=data[column], **new_kwargs,
|
|
124
|
+
)
|
|
125
|
+
else:
|
|
126
|
+
# plotting horizontal bar chart
|
|
127
|
+
new_kwargs = _update_kwargs(update_dict=kwargs_bar,
|
|
128
|
+
edgecolor=edgecolour,
|
|
129
|
+
height=wd, color=colours,
|
|
130
|
+
alpha=transparency,
|
|
131
|
+
zorder=2,
|
|
132
|
+
)
|
|
133
|
+
bars = ax.barh(labels, width=data[column], **new_kwargs,
|
|
134
|
+
)
|
|
135
|
+
# do we need to plot error bars
|
|
136
|
+
if error_min is not None or error_max is not None:
|
|
137
|
+
# finding the mid points of the bars and
|
|
138
|
+
# initialising the bounds, allowing for one-sided limits.
|
|
139
|
+
if horizontal == False:
|
|
140
|
+
min_l = [b.get_y() + b.get_height() for b in bars]
|
|
141
|
+
max_l = min_l.copy()
|
|
142
|
+
else:
|
|
143
|
+
min_l = [b.get_x() + b.get_width() for b in bars]
|
|
144
|
+
max_l = min_l.copy()
|
|
145
|
+
# setting columns values
|
|
146
|
+
try:
|
|
147
|
+
min_l = data[error_min].to_list()
|
|
148
|
+
except KeyError:
|
|
149
|
+
pass
|
|
150
|
+
try:
|
|
151
|
+
max_l = data[error_max].to_list()
|
|
152
|
+
except KeyError:
|
|
153
|
+
pass
|
|
154
|
+
# the actual plotting
|
|
155
|
+
new_kwargs_error = _update_kwargs(update_dict=kwargs_error,
|
|
156
|
+
color='black',
|
|
157
|
+
zorder=1,
|
|
158
|
+
)
|
|
159
|
+
if horizontal == False:
|
|
160
|
+
mids = [b.get_x() + b.get_width() / 2 for b in bars]
|
|
161
|
+
ax.vlines(mids, min_l, max_l, **new_kwargs_error,)
|
|
162
|
+
else:
|
|
163
|
+
mids = [b.get_y() + b.get_height() / 2 for b in bars]
|
|
164
|
+
ax.hlines(mids, min_l, max_l, **new_kwargs_error,)
|
|
165
|
+
# removing spines
|
|
166
|
+
ax.spines['top'].set_visible(False)
|
|
167
|
+
ax.spines['right'].set_visible(False)
|
|
168
|
+
# return
|
|
169
|
+
return f, ax
|
|
170
|
+
|
|
171
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
172
|
+
def stack_bar(data:pd.DataFrame, label:str, columns:list[str],
|
|
173
|
+
colours:list[str]=['tab:blue', 'tab:pink'],
|
|
174
|
+
transparency:float=0.7, wd:Real=1.0, edgecolour:str='black',
|
|
175
|
+
horizontal:bool = False, figsize:tuple[Real,Real] = (2,2),
|
|
176
|
+
ax:plt.Axes | None = None, **kwargs:Optional[Any],
|
|
177
|
+
) -> tuple[plt.Figure, plt.Axes]:
|
|
178
|
+
"""
|
|
179
|
+
Plot a stacked bar chart with each bar divided into segments.
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
data : `pd.DataFrame`
|
|
184
|
+
DataFrame containing bar segment values and axis labels.
|
|
185
|
+
label : `str`
|
|
186
|
+
Column name used for bar labels.
|
|
187
|
+
columns : `list` [`str`]
|
|
188
|
+
Column names representing bar segments to stack.
|
|
189
|
+
colours : `list` [`str`]
|
|
190
|
+
List of colours for each stack segment.
|
|
191
|
+
transparency : `float`, default 0.7
|
|
192
|
+
Degree of transparency, between 0 and 1 (solid).
|
|
193
|
+
wd : `float` or `int`, default 1.0
|
|
194
|
+
The bar width.
|
|
195
|
+
edgecolour : `str`, default `black`
|
|
196
|
+
Colour for bar borders.
|
|
197
|
+
horizontal : `bool`, default `False`
|
|
198
|
+
Whether plot a horizontal barchart.
|
|
199
|
+
ax : `plt.ax`, default `NoneType`
|
|
200
|
+
The pyplot.axes object.
|
|
201
|
+
figsize : `tuple` [`float`, `float`], default (2, 2),
|
|
202
|
+
The figure size in inches, when ax is set to None.
|
|
203
|
+
kwargs : `any`
|
|
204
|
+
Arbitrary keyword arguments for `ax.bar` or `ax.barh`.
|
|
205
|
+
|
|
206
|
+
Returns
|
|
207
|
+
-------
|
|
208
|
+
fig : plt.Figure
|
|
209
|
+
Matplotlib figure object.
|
|
210
|
+
ax : plt.Axes
|
|
211
|
+
Axes with the stacked bar chart.
|
|
212
|
+
"""
|
|
213
|
+
# ### check input
|
|
214
|
+
is_df(data)
|
|
215
|
+
is_type(label, str)
|
|
216
|
+
is_type(columns, list)
|
|
217
|
+
is_type(colours, list)
|
|
218
|
+
is_type(transparency, float)
|
|
219
|
+
is_type(wd, (float, int))
|
|
220
|
+
is_type(edgecolour, str)
|
|
221
|
+
is_type(horizontal, bool)
|
|
222
|
+
is_type(ax, (type(None), plt.Axes))
|
|
223
|
+
# ### should we create a figure and axis
|
|
224
|
+
if ax is None:
|
|
225
|
+
f, ax = plt.subplots(figsize=figsize)
|
|
226
|
+
else:
|
|
227
|
+
f = ax.figure
|
|
228
|
+
# ### should not be any missings
|
|
229
|
+
# NOTE consider making this into a function
|
|
230
|
+
if any(data.isna().any()):
|
|
231
|
+
raise ValueError(Error_MSG.MISSING_DF.format('data'))
|
|
232
|
+
# make sure we have sufficient colours
|
|
233
|
+
if len(columns) != len(colours):
|
|
234
|
+
raise AttributeError('The number of columns ({0}) does not match the '
|
|
235
|
+
'number of colours ({1}).'.format(
|
|
236
|
+
len(columns), len(colours)))
|
|
237
|
+
# get labels
|
|
238
|
+
labels = data[label]
|
|
239
|
+
# get columns
|
|
240
|
+
fields=columns
|
|
241
|
+
# actual plotting
|
|
242
|
+
left = len(data) * [0]
|
|
243
|
+
for idx, name in enumerate(fields):
|
|
244
|
+
if horizontal == False:
|
|
245
|
+
# plotting vertical bar chart
|
|
246
|
+
new_kwargs = _update_kwargs(update_dict=kwargs,
|
|
247
|
+
edgecolor=edgecolour,
|
|
248
|
+
width=wd, color=colours[idx],
|
|
249
|
+
alpha=transparency,
|
|
250
|
+
)
|
|
251
|
+
ax.bar(labels, height=data[name], bottom=left, **new_kwargs,
|
|
252
|
+
)
|
|
253
|
+
else:
|
|
254
|
+
# horizontal bar chart
|
|
255
|
+
new_kwargs = _update_kwargs(update_dict=kwargs, edgecolor=edgecolour,
|
|
256
|
+
height=wd, color=colours[idx],
|
|
257
|
+
alpha=transparency,
|
|
258
|
+
)
|
|
259
|
+
ax.barh(labels, width=data[name], left=left, **new_kwargs,
|
|
260
|
+
)
|
|
261
|
+
# update the locations
|
|
262
|
+
left = left + data[name]
|
|
263
|
+
# removing spines
|
|
264
|
+
ax.spines['right'].set_visible(False)
|
|
265
|
+
ax.spines['top'].set_visible(False)
|
|
266
|
+
# returns
|
|
267
|
+
return f, ax
|
|
268
|
+
|
|
269
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
270
|
+
def subtotal_bar(data:pd.DataFrame, label:str, total_col:str,
|
|
271
|
+
subtotal_col: str | None = None,
|
|
272
|
+
colours:tuple[str,str]=('grey','tab:blue'),
|
|
273
|
+
transparency:tuple[float,float]=(0.7,0.9),
|
|
274
|
+
wd:tuple[float,float]=(1,0.6),
|
|
275
|
+
edgecolour:tuple[str,str]=('black', 'black'),
|
|
276
|
+
zorder:tuple[int,int] = (2,3),
|
|
277
|
+
horizontal:bool=False,
|
|
278
|
+
figsize:tuple[Real,Real] = (2,2),
|
|
279
|
+
ax:plt.Axes | None = None,
|
|
280
|
+
total_kwargs_dict:dict[str,Any] | None = None,
|
|
281
|
+
subtotal_kwargs_dict:dict[str, Any] | None = None,
|
|
282
|
+
) -> tuple[plt.Figure,plt.Axes]:
|
|
283
|
+
"""
|
|
284
|
+
Plot total bars with overlaid subtotal bars (e.g., for highlighting).
|
|
285
|
+
|
|
286
|
+
Parameters
|
|
287
|
+
----------
|
|
288
|
+
data : `pd.DataFrame`
|
|
289
|
+
The input data containing total and (optionally) subtotal values.
|
|
290
|
+
label : `str`
|
|
291
|
+
Column name for axis labels.
|
|
292
|
+
total_col : `str`
|
|
293
|
+
Column containing values for the base (total) bars.
|
|
294
|
+
subtotal_col : `str` or `None`, default `NoneType`
|
|
295
|
+
Column containing values for (smaller) overlaid subtotal bars.
|
|
296
|
+
colours : `tuple` [`str`,`str`], default ("grey", "tab:blue")
|
|
297
|
+
Colours for the total and subtotal bars.
|
|
298
|
+
transparency : `tuple` [`float`,`float`], default (0.7, 0.9)
|
|
299
|
+
Alpha levels for bars.
|
|
300
|
+
wd : `tuple` [`real`,`real`], default (1.0, 0.6)
|
|
301
|
+
The bar widths.
|
|
302
|
+
edgecolour : `tuple` [`str`,`str`], default ("black", "black")
|
|
303
|
+
The bar edgecolours.
|
|
304
|
+
horizontal : `bool`, default `False`
|
|
305
|
+
Whether plot a horizontal bar chart.
|
|
306
|
+
zorder : `tuple` [`int`,`int`], default (2,3)
|
|
307
|
+
The order the total and subtotal bars are plotted.
|
|
308
|
+
figsize : `tuple` [`float`, `float`], default (2, 2),
|
|
309
|
+
The figure size in inches, when ax is set to None.
|
|
310
|
+
ax : `plt.Axes` or `None`, default `None`
|
|
311
|
+
The pyplot.axes object.
|
|
312
|
+
total_kwargs_dict : `dict` [`str`,`any`] or `None`, default None
|
|
313
|
+
Additional arguments passed to barchart.bar().
|
|
314
|
+
subtotal_kwargs_dict : `dict` [`str`,`any`] or `None`, default None
|
|
315
|
+
Additional arguments passed to barchart.bar().
|
|
316
|
+
|
|
317
|
+
Returns
|
|
318
|
+
-------
|
|
319
|
+
fig : plt.Figure
|
|
320
|
+
Matplotlib figure object.
|
|
321
|
+
ax : plt.Axes
|
|
322
|
+
Axes with the plotted bars.
|
|
323
|
+
|
|
324
|
+
Notes
|
|
325
|
+
-----
|
|
326
|
+
Plot total bars with overlaid subtotal bars (e.g., for highlighting).
|
|
327
|
+
"""
|
|
328
|
+
# ### check input
|
|
329
|
+
is_df(data)
|
|
330
|
+
is_type(label, str)
|
|
331
|
+
is_type(ax, (type(None), plt.Axes))
|
|
332
|
+
is_type(total_col, str)
|
|
333
|
+
is_type(subtotal_col, (str, type(None)))
|
|
334
|
+
is_type(zorder, tuple)
|
|
335
|
+
is_type(colours, tuple)
|
|
336
|
+
is_type(transparency, tuple)
|
|
337
|
+
is_type(wd, tuple)
|
|
338
|
+
is_type(edgecolour, tuple)
|
|
339
|
+
is_type(horizontal, bool)
|
|
340
|
+
is_type(total_kwargs_dict, (dict,type(None)))
|
|
341
|
+
is_type(subtotal_kwargs_dict, (dict,type(None)))
|
|
342
|
+
# ### should we create a figure and axis
|
|
343
|
+
if ax is None:
|
|
344
|
+
f, ax = plt.subplots(figsize=figsize)
|
|
345
|
+
else:
|
|
346
|
+
f = ax.figure
|
|
347
|
+
# mapping None to empty dicts
|
|
348
|
+
total_kwargs_dict = total_kwargs_dict or {}
|
|
349
|
+
subtotal_kwargs_dict = subtotal_kwargs_dict or {}
|
|
350
|
+
# get labels
|
|
351
|
+
labels = data[label]
|
|
352
|
+
# counts
|
|
353
|
+
total = data[total_col]
|
|
354
|
+
# #### plot total
|
|
355
|
+
# checking whether something is passed to kwargs_bar
|
|
356
|
+
new_total_kwargs_bar = _update_kwargs(
|
|
357
|
+
update_dict = total_kwargs_dict,
|
|
358
|
+
zorder=zorder[0],
|
|
359
|
+
)
|
|
360
|
+
bar(
|
|
361
|
+
pd.DataFrame({total_col:total, label:labels}),
|
|
362
|
+
ax=ax,
|
|
363
|
+
label=label,
|
|
364
|
+
column=total_col,
|
|
365
|
+
colours=[colours[0]],
|
|
366
|
+
transparency=transparency[0],
|
|
367
|
+
wd=wd[0],
|
|
368
|
+
edgecolour=edgecolour[0],
|
|
369
|
+
horizontal=horizontal,
|
|
370
|
+
kwargs_bar=new_total_kwargs_bar,
|
|
371
|
+
)
|
|
372
|
+
# plot subtotal
|
|
373
|
+
if not subtotal_col is None:
|
|
374
|
+
subtotal = data[subtotal_col]
|
|
375
|
+
# updating kwargs
|
|
376
|
+
new_subtotal_kwargs_bar = _update_kwargs(
|
|
377
|
+
update_dict = subtotal_kwargs_dict,
|
|
378
|
+
zorder=zorder[1],
|
|
379
|
+
)
|
|
380
|
+
bar(
|
|
381
|
+
pd.DataFrame({subtotal_col:subtotal, label:labels}),
|
|
382
|
+
ax=ax,
|
|
383
|
+
label=label,
|
|
384
|
+
column=subtotal_col,
|
|
385
|
+
colours=[colours[1]],
|
|
386
|
+
transparency=transparency[1],
|
|
387
|
+
wd=wd[1],
|
|
388
|
+
edgecolour=edgecolour[1],
|
|
389
|
+
horizontal=horizontal,
|
|
390
|
+
kwargs_bar = new_subtotal_kwargs_bar,
|
|
391
|
+
)
|
|
392
|
+
# removing spines
|
|
393
|
+
ax.spines['top'].set_visible(False)
|
|
394
|
+
ax.spines['right'].set_visible(False)
|
|
395
|
+
# return
|
|
396
|
+
return f, ax
|
|
397
|
+
|
|
398
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
399
|
+
def group_bar(data:pd.DataFrame, label:str, columns:list[str],
|
|
400
|
+
errors_max:list[str] | None = None,
|
|
401
|
+
errors_min:list[str] | None = None,
|
|
402
|
+
colours:list[str]=['tab:blue', 'tab:pink'],
|
|
403
|
+
transparency:float=0.7,
|
|
404
|
+
wd:Real=1.0, edgecolour:str='black',
|
|
405
|
+
bar_spacing:Real = 0, group_spacing:Real = 1,
|
|
406
|
+
horizontal:bool = False, figsize:tuple[Real,Real] = (2,2),
|
|
407
|
+
ax:plt.Axes | None = None,
|
|
408
|
+
kwargs_bar:dict[str, Any] | None = None,
|
|
409
|
+
kwargs_error:dict[str, Any] | None = None,
|
|
410
|
+
) -> tuple[plt.Figure,plt.Axes]:
|
|
411
|
+
"""
|
|
412
|
+
Plot a grouped bar chart with optional error bars.
|
|
413
|
+
|
|
414
|
+
The function expects the data organised in a wide format where the
|
|
415
|
+
unique group names are provides one time in the `label` column and the
|
|
416
|
+
values which should be plotted
|
|
417
|
+
(e.g. the values for `day 0`, `day 10`, `day 25`) provided as multiple
|
|
418
|
+
column names.
|
|
419
|
+
|
|
420
|
+
Parameters
|
|
421
|
+
----------
|
|
422
|
+
data : `pd.DataFrame`
|
|
423
|
+
DataFrame with a group label column and multiple value columns.
|
|
424
|
+
label : `str`
|
|
425
|
+
Column name for group labels.
|
|
426
|
+
column : `list` [`str`]
|
|
427
|
+
Value columns to plot as grouped bars.
|
|
428
|
+
errors_max : `list` [`str`] or `None`, default `NoneType`
|
|
429
|
+
Column names in `data` containing the upper values of the error bars.
|
|
430
|
+
Should be structured similarly to `columns` if used.
|
|
431
|
+
errors_min : `list` [`str`] or `None` default `NoneType`
|
|
432
|
+
Column names in `data` containing the lower values of the error bars.
|
|
433
|
+
colours : `list` [`str`], default ['tab:blue', 'tab:pink']
|
|
434
|
+
Colours for the bars. Recycled if fewer colours than `columns`.
|
|
435
|
+
transparency : `float`, default 0.7
|
|
436
|
+
Alpha of the bar fill.
|
|
437
|
+
wd : `float` or `int`, default 1.0
|
|
438
|
+
The bar widths.
|
|
439
|
+
edgecolour : `str`, default `black`
|
|
440
|
+
The bar edge colours.
|
|
441
|
+
horizontal : `bool`, default `False`
|
|
442
|
+
Whether plot a horizontal barchart.
|
|
443
|
+
ax : `plt.ax`, default `NoneType`
|
|
444
|
+
The pyplot.axes object.
|
|
445
|
+
figsize : `tuple` [`float`, `float`], default (2, 2),
|
|
446
|
+
The figure size in inches, when ax is set to None.
|
|
447
|
+
kwargs_bar : `any`
|
|
448
|
+
Keyword arguments passed to `kwargs_bar` in barchart.bar().
|
|
449
|
+
kwargs_error : `any`
|
|
450
|
+
Keyword arguments passed to `kwargs_error` in barchart.bar().
|
|
451
|
+
|
|
452
|
+
Returns
|
|
453
|
+
-------
|
|
454
|
+
fig : plt.Figure
|
|
455
|
+
The matplotlib Figure object.
|
|
456
|
+
ax : plt.Axes
|
|
457
|
+
The matplotlib Axes object with the plot.
|
|
458
|
+
"""
|
|
459
|
+
# constants
|
|
460
|
+
OFFSET_COL = "__offset__"
|
|
461
|
+
# check input - most will be done by bar, just keeping the minimum
|
|
462
|
+
is_df(data)
|
|
463
|
+
is_type(columns, list)
|
|
464
|
+
is_type(errors_max, (type(None),list))
|
|
465
|
+
is_type(errors_min, (type(None),list))
|
|
466
|
+
is_type(horizontal, bool)
|
|
467
|
+
is_type(ax, (type(None), plt.Axes))
|
|
468
|
+
is_type(kwargs_bar, (type(None), dict))
|
|
469
|
+
is_type(kwargs_error, (type(None), dict))
|
|
470
|
+
# ### should we create a figure and axis
|
|
471
|
+
if ax is None:
|
|
472
|
+
f, ax = plt.subplots(figsize=figsize)
|
|
473
|
+
else:
|
|
474
|
+
f = ax.figure
|
|
475
|
+
# ### prepare the loop
|
|
476
|
+
# the number of bars for each group
|
|
477
|
+
n_bars = len(columns)
|
|
478
|
+
# the number of groups
|
|
479
|
+
base = np.arange(data.shape[0]) * group_spacing
|
|
480
|
+
# the total width of all the bars in a single group
|
|
481
|
+
spacing_per_bar = bar_spacing * wd
|
|
482
|
+
total_spacing = spacing_per_bar * (n_bars - 1)
|
|
483
|
+
# the group labels
|
|
484
|
+
label_values = data[label]
|
|
485
|
+
# the tick positions
|
|
486
|
+
group_width = wd * n_bars + total_spacing
|
|
487
|
+
tick_pos = base + (group_width - wd) / 2
|
|
488
|
+
# looping
|
|
489
|
+
df_offset = data.copy()
|
|
490
|
+
for i, column in enumerate(columns):
|
|
491
|
+
# the location of the bar
|
|
492
|
+
offset = base + i * (wd + spacing_per_bar)
|
|
493
|
+
df_offset[OFFSET_COL] = offset
|
|
494
|
+
# cycling the colours
|
|
495
|
+
col = colours[i % len(colours)]
|
|
496
|
+
# the limits
|
|
497
|
+
err_max = errors_max[i] if errors_max else None
|
|
498
|
+
err_min = errors_min[i] if errors_min else None
|
|
499
|
+
_ = bar(
|
|
500
|
+
data=df_offset,
|
|
501
|
+
label=OFFSET_COL,
|
|
502
|
+
column=column,
|
|
503
|
+
error_max=err_max,
|
|
504
|
+
error_min=err_min,
|
|
505
|
+
colours=[col],
|
|
506
|
+
transparency=transparency,
|
|
507
|
+
wd=wd,
|
|
508
|
+
edgecolour=edgecolour,
|
|
509
|
+
horizontal=horizontal,
|
|
510
|
+
figsize=figsize,
|
|
511
|
+
ax=ax,
|
|
512
|
+
kwargs_bar=kwargs_bar,
|
|
513
|
+
kwargs_error=kwargs_error,
|
|
514
|
+
)
|
|
515
|
+
# labels
|
|
516
|
+
if not horizontal:
|
|
517
|
+
ax.set_xticks(tick_pos)
|
|
518
|
+
ax.set_xticklabels(label_values)
|
|
519
|
+
else:
|
|
520
|
+
ax.set_yticks(tick_pos)
|
|
521
|
+
ax.set_yticklabels(label_values)
|
|
522
|
+
# return
|
|
523
|
+
return f, ax
|
plot_misc/constants.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Named constants for use throughout the plot-misc package.
|
|
3
|
+
|
|
4
|
+
This module provides collections of string constants grouped by their
|
|
5
|
+
functional context. These constants are intended to ensure consistency
|
|
6
|
+
in labelling, plotting, and data management across modules.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
11
|
+
CLASS_NAME = '__CLASS_NAME'
|
|
12
|
+
|
|
13
|
+
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
14
|
+
# an alias to int or float type hint
|
|
15
|
+
Real = int | float
|
|
16
|
+
|
|
17
|
+
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
18
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
19
|
+
# Forest plot
|
|
20
|
+
class ForestNames(object):
|
|
21
|
+
"""
|
|
22
|
+
Constants used by forest.py
|
|
23
|
+
"""
|
|
24
|
+
s_col = 's_col'
|
|
25
|
+
c_col = 'c_col'
|
|
26
|
+
a_col = 'a_col'
|
|
27
|
+
g_col = 'g_col'
|
|
28
|
+
y_col = 'y_axis'
|
|
29
|
+
forest_data = 'data'
|
|
30
|
+
strata_del = 'strata_del'
|
|
31
|
+
group_del = 'group_del'
|
|
32
|
+
order_col = 'order'
|
|
33
|
+
min = 'min'
|
|
34
|
+
max = 'max'
|
|
35
|
+
mean = 'mean'
|
|
36
|
+
fontweight = 'bold'
|
|
37
|
+
kwargs = 'kwargs'
|
|
38
|
+
span = 'span'
|
|
39
|
+
ESTIMATE = 'estimate'
|
|
40
|
+
LOWER_BOUND = 'lower_bound'
|
|
41
|
+
UPPER_BOUND = 'upper_bound'
|
|
42
|
+
PVALUE = 'p-value'
|
|
43
|
+
CI = 'confidence_interval'
|
|
44
|
+
data_table = 'data_table'
|
|
45
|
+
EmpericalSupport_Coverage = 'coverage'
|
|
46
|
+
EmpericalSupport_Compatability = 'compatibility'
|
|
47
|
+
EmpericalSupportResults = 'results_'
|
|
48
|
+
|
|
49
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
50
|
+
# Utils Names
|
|
51
|
+
class UtilsNames(object):
|
|
52
|
+
"""
|
|
53
|
+
Constants used by utils.utils.py
|
|
54
|
+
"""
|
|
55
|
+
value_input = 'curated_matrix_value'
|
|
56
|
+
annot_input = 'curated_matrix_annotation'
|
|
57
|
+
annot_star = 'matrix_star'
|
|
58
|
+
annot_pval = 'matrix_pvalue'
|
|
59
|
+
annot_effect = 'matrix_point_estimate'
|
|
60
|
+
value_point = 'curated_matrix_point_estimate_value'
|
|
61
|
+
value_original = 'crude_point_estimate'
|
|
62
|
+
source_data = 'source_data'
|
|
63
|
+
mat_point = 'point'
|
|
64
|
+
mat_pvalue = 'pvalue'
|
|
65
|
+
mat_index = 'id'
|
|
66
|
+
mat_exposure = 'exposure'
|
|
67
|
+
mat_outcome = 'outcome'
|
|
68
|
+
mat_exposure_list = ['IL2ra', 'IP10', 'SCF', 'TRAIL']
|
|
69
|
+
mat_outcome_list = ['HDL-C', 'LDL-C']
|
|
70
|
+
mat_annot_star = 'star'
|
|
71
|
+
mat_annot_pval = 'pvalues'
|
|
72
|
+
mat_annot_point = 'point_estimates'
|
|
73
|
+
mat_annot_none = '`NoneType`'
|
|
74
|
+
roc_false_positive = 'false_positive'
|
|
75
|
+
roc_sensitivity = 'sensitivity'
|
|
76
|
+
roc_threshold = 'threshold'
|
|
77
|
+
|
|
78
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
79
|
+
class NamesDecisionCurves(object):
|
|
80
|
+
'''
|
|
81
|
+
Names used by the DecisionCurve class in machine_learning.py
|
|
82
|
+
'''
|
|
83
|
+
TP_RATE = 'True positive rate'
|
|
84
|
+
FP_RATE = 'False positive rate'
|
|
85
|
+
THRESHOLD = 'Threshold'
|
|
86
|
+
ALL_MODEL = 'All model'
|
|
87
|
+
NONE_MODEL = 'None model'
|
|
88
|
+
MODEL = 'model'
|
|
89
|
+
NETBENEFIT = 'Net benefit'
|
|
90
|
+
HARM = 'harm'
|
|
91
|
+
COL = 'col'
|
|
92
|
+
LTY = 'lty'
|
|
93
|
+
|
|
94
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
95
|
+
class NamesIncidenceMatrix(object):
|
|
96
|
+
"""
|
|
97
|
+
Names used by incidencematrix.py
|
|
98
|
+
"""
|
|
99
|
+
AXIS_X = 'x'
|
|
100
|
+
AXIS_Y = 'y'
|
|
101
|
+
AXIS_B = 'both'
|
|
102
|
+
GRID_POS_B = 'centre'
|
|
103
|
+
GRID_POS_O = 'outline'
|
|
104
|
+
|
|
105
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
106
|
+
class NamesMachineLearnig(object):
|
|
107
|
+
'''
|
|
108
|
+
Names used by machinelearning.py
|
|
109
|
+
'''
|
|
110
|
+
DATA = 'data'
|
|
111
|
+
CI_COLOUR = 'ci_colour'
|
|
112
|
+
CI_LINEWIDTH = 'ci_linewidth'
|
|
113
|
+
DOT_COLOUR = 'dot_colour'
|
|
114
|
+
DOT_MARKER = 'dot_marker'
|
|
115
|
+
LINE_COLOUR = 'line_colour'
|
|
116
|
+
LINE_LINEWIDTH = 'line_linewidth'
|
|
117
|
+
LINE_LINESTYLE = 'line_linestyle'
|
|
118
|
+
|