plot-misc 2.0.3__tar.gz → 2.1.0__tar.gz

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.
Files changed (46) hide show
  1. plot_misc-2.1.0/MANIFEST.in +16 -0
  2. {plot_misc-2.0.3 → plot_misc-2.1.0}/PKG-INFO +22 -11
  3. {plot_misc-2.0.3 → plot_misc-2.1.0}/README.md +4 -2
  4. plot_misc-2.1.0/plot_misc/_version.py +1 -0
  5. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/barchart.py +24 -16
  6. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/examples.py +89 -0
  7. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/forest.py +6 -6
  8. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/heatmap.py +10 -2
  9. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/incidencematrix.py +33 -5
  10. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/machine_learning.py +1 -2
  11. plot_misc-2.1.0/plot_misc/survival.py +628 -0
  12. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/utils/colour.py +105 -8
  13. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/utils/formatting.py +48 -0
  14. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/utils/utils.py +41 -18
  15. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc.egg-info/PKG-INFO +22 -11
  16. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc.egg-info/SOURCES.txt +4 -0
  17. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc.egg-info/dependency_links.txt +0 -0
  18. plot_misc-2.1.0/plot_misc.egg-info/requires.txt +19 -0
  19. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc.egg-info/top_level.txt +0 -0
  20. {plot_misc-2.0.3 → plot_misc-2.1.0}/pyproject.toml +9 -13
  21. plot_misc-2.1.0/requirements-dev.txt +9 -0
  22. plot_misc-2.1.0/requirements.txt +9 -0
  23. plot_misc-2.0.3/plot_misc/_version.py +0 -1
  24. plot_misc-2.0.3/plot_misc.egg-info/requires.txt +0 -11
  25. {plot_misc-2.0.3 → plot_misc-2.1.0}/LICENSE +0 -0
  26. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/__init__.py +0 -0
  27. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/constants.py +0 -0
  28. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/errors.py +0 -0
  29. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/__init__.py +0 -0
  30. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/bar_points.tsv.gz +0 -0
  31. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/barchart.tsv.gz +0 -0
  32. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/calibration_bins.tsv.gz +0 -0
  33. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/calibration_data.tsv.gz +0 -0
  34. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/forest_data.tsv.gz +0 -0
  35. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/group_bar.tsv.gz +0 -0
  36. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/heatmap_data.tsv.gz +0 -0
  37. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/incidence_matrix_data.tsv.gz +0 -0
  38. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/lollipop_data.tsv.gz +0 -0
  39. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/mace_associations.tsv.gz +0 -0
  40. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/net_benefit.tsv.gz +0 -0
  41. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/string_data.txt +0 -0
  42. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/example_data/example_datasets/volcano.tsv.gz +0 -0
  43. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/piechart.py +0 -0
  44. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/utils/__init__.py +0 -0
  45. {plot_misc-2.0.3 → plot_misc-2.1.0}/plot_misc/volcano.py +0 -0
  46. {plot_misc-2.0.3 → plot_misc-2.1.0}/setup.cfg +0 -0
@@ -0,0 +1,16 @@
1
+ # include top-level metadata
2
+ include README.md LICENSE
3
+ include requirements.txt
4
+ include requirements-dev.txt
5
+
6
+ # ship the example datasets explicitly
7
+ recursive-include plot_misc/example_data/example_datasets *.tsv.gz *.txt
8
+
9
+ # drop these
10
+ prune tests
11
+ prune resources
12
+
13
+ # drop the rest
14
+ global-exclude .*
15
+ global-exclude *.py[cod]
16
+ global-exclude __pycache__/*
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plot-misc
3
- Version: 2.0.3
3
+ Version: 2.1.0
4
4
  Summary: Various plotting templates built on top of matplotlib
5
5
  Author-email: A Floriaan Schmidt <floriaanschmidt@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://gitlab.com/SchmidtAF/plot-misc
8
+ Project-URL: Documentation, https://schmidtaf.gitlab.io/plot-misc/
8
9
  Classifier: Programming Language :: Python
9
10
  Classifier: Programming Language :: Python :: 3
10
11
  Classifier: Programming Language :: Python :: 3.10
@@ -14,20 +15,30 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
14
15
  Requires-Python: <3.13,>=3.10
15
16
  Description-Content-Type: text/markdown
16
17
  License-File: LICENSE
17
- Requires-Dist: numpy
18
- Requires-Dist: pandas
19
- Requires-Dist: matplotlib
20
- Requires-Dist: seaborn
21
- Requires-Dist: scipy
22
- Requires-Dist: scikit-learn
23
- Requires-Dist: adjustText
18
+ Requires-Dist: pandas>=1.3
19
+ Requires-Dist: numpy>=1.21
20
+ Requires-Dist: matplotlib>=3.5
21
+ Requires-Dist: seaborn>=0.11
22
+ Requires-Dist: scipy>=1.5
23
+ Requires-Dist: statsmodels>=0.1
24
+ Requires-Dist: scikit-learn>=1.4
25
+ Requires-Dist: adjustText>=1.3
24
26
  Provides-Extra: dev
27
+ Requires-Dist: python-build; extra == "dev"
25
28
  Requires-Dist: twine; extra == "dev"
26
- Requires-Dist: build; extra == "dev"
29
+ Requires-Dist: setuptools; extra == "dev"
30
+ Requires-Dist: wheel; extra == "dev"
31
+ Requires-Dist: pytest>=6; extra == "dev"
32
+ Requires-Dist: pytest-mock>=3; extra == "dev"
33
+ Requires-Dist: pytest-dependency>=0.5; extra == "dev"
34
+ Requires-Dist: bump2version>=1; extra == "dev"
35
+ Requires-Dist: jupyter; extra == "dev"
27
36
  Dynamic: license-file
28
37
 
38
+ <img src="https://schmidtaf.gitlab.io/plot-misc/_images/icon.png" alt="plot-misc icon" width="250"/>
39
+
29
40
  # A collection of plotting functions
30
- __version__: `2.0.3`
41
+ __version__: `2.1.0`
31
42
 
32
43
  This repository collects plotting modules written on top of `matplotlib`.
33
44
  The functions are intended to set up light-touch, basic illustrations that
@@ -60,7 +71,7 @@ To install from this channel, run:
60
71
 
61
72
 
62
73
  ```sh
63
- conda install afschmidt::plot_misc
74
+ conda install afschmidt::plot-misc
64
75
  ```
65
76
 
66
77
  ### Installation using gitlab
@@ -1,5 +1,7 @@
1
+ <img src="https://schmidtaf.gitlab.io/plot-misc/_images/icon.png" alt="plot-misc icon" width="250"/>
2
+
1
3
  # A collection of plotting functions
2
- __version__: `2.0.3`
4
+ __version__: `2.1.0`
3
5
 
4
6
  This repository collects plotting modules written on top of `matplotlib`.
5
7
  The functions are intended to set up light-touch, basic illustrations that
@@ -32,7 +34,7 @@ To install from this channel, run:
32
34
 
33
35
 
34
36
  ```sh
35
- conda install afschmidt::plot_misc
37
+ conda install afschmidt::plot-misc
36
38
  ```
37
39
 
38
40
  ### Installation using gitlab
@@ -0,0 +1 @@
1
+ __version__ = '2.1.0'
@@ -21,9 +21,9 @@ group_bar(data, label, columns, ...)
21
21
  Plot a grouped bar chart with multiple bars per group, optionally
22
22
  with error bars.
23
23
  """
24
- import matplotlib.pyplot as plt
25
24
  import pandas as pd
26
25
  import numpy as np
26
+ import matplotlib.pyplot as plt
27
27
  from plot_misc.utils.utils import _update_kwargs
28
28
  from plot_misc.errors import (
29
29
  is_type,
@@ -56,7 +56,7 @@ def bar(data:pd.DataFrame, label:str, column:str,
56
56
  The column name for the bar height values.
57
57
  error_max : `str`, default `NoneType`
58
58
  column name for the upper value of the error line segment.
59
- error_min : ``str` default `NoneType`
59
+ error_min : `str`, default `NoneType`
60
60
  column name for the lower value of the error line segment.
61
61
  colours : `list` [`str`], default ['tab:blue', 'tab:pink']
62
62
  Colours for the bars; recycled if shorter than the number of bars.
@@ -83,6 +83,14 @@ def bar(data:pd.DataFrame, label:str, column:str,
83
83
  Matplotlib figure object.
84
84
  ax : plt.Axes
85
85
  Matplotlib axes with the rendered bar plot.
86
+
87
+ Notes
88
+ -----
89
+ This function is essentially a helper function for the more complicated
90
+ bar charts in this module and simply wraps matplotlib's bar function.
91
+ It is included as a public function to allow people to use the same
92
+ interface when working with plot-misc. If one is exclusively looking to
93
+ use `bar` it is advisable to simply revert to matplotlib's offering.
86
94
  """
87
95
  # check input
88
96
  is_df(data)
@@ -235,30 +243,30 @@ def stack_bar(data:pd.DataFrame, label:str, columns:list[str],
235
243
  'number of colours ({1}).'.format(
236
244
  len(columns), len(colours)))
237
245
  # get labels
238
- labels = data[label]
246
+ # labels = data[label]
239
247
  # get columns
240
248
  fields=columns
241
249
  # actual plotting
242
250
  left = len(data) * [0]
243
251
  for idx, name in enumerate(fields):
252
+ new_kwargs = _update_kwargs(update_dict=kwargs,
253
+ edgecolor=edgecolour,
254
+ color=colours[idx],
255
+ alpha=transparency,
256
+ )
244
257
  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,
258
+ new_kwargs = _update_kwargs(new_kwargs, bottom=left,
250
259
  )
251
- ax.bar(labels, height=data[name], bottom=left, **new_kwargs,
252
- )
253
260
  else:
254
- # horizontal bar chart
255
- new_kwargs = _update_kwargs(update_dict=kwargs, edgecolor=edgecolour,
256
- height=wd, color=colours[idx],
257
- alpha=transparency,
261
+ new_kwargs = _update_kwargs(new_kwargs, left=left,
258
262
  )
259
- ax.barh(labels, width=data[name], left=left, **new_kwargs,
263
+ # The actual plotting
264
+ # NOTE adding wd here because it bar assigns it to either width or
265
+ # height depending on horizontal.
266
+ _, ax = bar(data=data, label=label, column=name, horizontal=horizontal,
267
+ wd=wd, ax=ax, kwargs_bar=new_kwargs,
260
268
  )
261
- # update the locations
269
+ # updating the coordinate where the last bar stops
262
270
  left = left + data[name]
263
271
  # removing spines
264
272
  ax.spines['right'].set_visible(False)
@@ -635,3 +635,92 @@ def load_mace_associations(**kwargs):
635
635
  )
636
636
  # return
637
637
  return df
638
+
639
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
640
+ def create_survival_data(nrows:int = 50,
641
+ survival_rate:float = 0.02,
642
+ ci_width:float=0.15,
643
+ random_seed:int = 42,
644
+ initial_n:int = 1000) -> pd.DataFrame:
645
+ """
646
+ Create pilot survival analysis data for testing.
647
+
648
+ Parameters
649
+ ----------
650
+ nrows : int, default 50
651
+ Number of time points to generate
652
+ random_seed : int, default 42
653
+ Random seed for reproducibility
654
+ initial_n : int, default 1000
655
+ Initial number of subjects at risk at time zero
656
+
657
+ Returns
658
+ -------
659
+ pd.DataFrame
660
+ DataFrame with survival data including survival estimates,
661
+ confidence intervals, and at-risk counts
662
+ """
663
+ np.random.seed(random_seed)
664
+
665
+ # Create time points
666
+ time_points = np.linspace(0, 100, nrows)
667
+
668
+ # Generate decreasing survival function with some noise
669
+ base_survival = np.exp(-time_points * survival_rate) # Exponential decay
670
+ noise = np.random.normal(0, 0.01, nrows)
671
+ survival = np.clip(base_survival + noise, 0, 1)
672
+
673
+ # Ensure monotonic decrease
674
+ survival = np.minimum.accumulate(survival)
675
+
676
+ # Generate confidence intervals
677
+ ci_width = ci_width * survival # CI width proportional to survival
678
+ lower_ci = np.clip(survival - ci_width, 0, 1)
679
+ upper_ci = np.clip(survival + ci_width, 0, 1)
680
+
681
+ # Generate at-risk numbers directly from survival probabilities
682
+ at_risk = (survival * initial_n).astype(int)
683
+
684
+ # Create DataFrame
685
+ df = pd.DataFrame({
686
+ 'survival_estimate': survival,
687
+ 'lower_ci_95': lower_ci,
688
+ 'upper_ci_95': upper_ci,
689
+ 'at_risk': at_risk,
690
+ 'time': time_points
691
+ })
692
+
693
+ df.set_index('time', inplace=True)
694
+ return df
695
+
696
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
697
+ @dataset
698
+ def load_survival_table(**kwargs):
699
+ """
700
+ Returns a survival table with information on the `time` (in days) an event
701
+ occured the cummulative events per discordancy group. The time per year
702
+ is provided as the time_format column.
703
+
704
+ Returns
705
+ -------
706
+ pd.DataFrame
707
+ """
708
+ # data
709
+ table = pd.DataFrame(
710
+ {
711
+ 'time': [0, 365, 730, 1095, 1461, 1826, 2191, 2556, 2922, 3287,
712
+ 3652, 4017, 4383, 4748, 5113, 5478],
713
+ 'Not Discordant': ['268,196', '263,426', '258,484', '254,009',
714
+ '249,315', '244,907', '240,562', '236,574',
715
+ '233,347', '230,368', '227,648', '224,916',
716
+ '222,169', '172,545', '95,987', '15,280'],
717
+ 'Discordant': ['5,749', '5,629', '5,494', '5,374',
718
+ '5,245', '5,129', '5,029', '4,935',
719
+ '4,863', '4,777', '4,714', '4,634',
720
+ '4,558', '3,586', '2,030', '346'],
721
+ 'time_format': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
722
+ }, **kwargs,
723
+ )
724
+ # return
725
+ return table
726
+
@@ -394,9 +394,9 @@ class ForestPlot(object):
394
394
  - 'max' : float
395
395
  The upper bound of the span in data coordinates.
396
396
  - 'kwargs' : dict
397
- A dictionary of keyword arguments to be passed to the span plotting
398
- function (e.g., `ax.axhspan()`), such as `facecolor`, `alpha`,
399
- `zorder`, etc.
397
+ A dictionary of keyword arguments to be passed to the span plotting
398
+ function (e.g., `ax.axhspan()`), such as `facecolor`, `alpha`,
399
+ `zorder`, etc.
400
400
 
401
401
  Notes
402
402
  -----
@@ -1000,15 +1000,15 @@ class EmpericalSupport(object):
1000
1000
  -----
1001
1001
  This implementation is based on the concept of compatibility (or
1002
1002
  confidence) curves, which visualise the range of parameter values supported
1003
- by the data across a continuum of alpha levels [1]_, [2]_.
1003
+ by the data across a continuum of alpha levels [ES1]_, [ES2]_.
1004
1004
 
1005
1005
  References
1006
1006
  ----------
1007
- .. [1] Amrhein, V., Greenland, S., & McShane, B. B. (2019).
1007
+ .. [ES1] Amrhein, V., Greenland, S., & McShane, B. B. (2019).
1008
1008
  Scientists rise up against statistical significance.
1009
1009
  *Nature*, 567(7748), 305–307. https://doi.org/10.1038/d41586-019-00857-9
1010
1010
 
1011
- .. [2] Van der Burg, S. H., & Gelman, A. (2020).
1011
+ .. [ES2] Van der Burg, S. H., & Gelman, A. (2020).
1012
1012
  Empirical support plots and compatibility intervals.
1013
1013
  *BMC Medical Research Methodology*, 20, Article 109.
1014
1014
  https://doi.org/10.1186/s12874-020-01105-9
@@ -28,7 +28,9 @@ from the example published in the official matplotlib gallery [1]_.
28
28
 
29
29
  References
30
30
  ----------
31
- .. [1] https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html
31
+ .. [1] Matplotlib contributors. "Creating annotated heatmaps."
32
+ Matplotlib Gallery.
33
+ https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html
32
34
  """
33
35
 
34
36
  # modules
@@ -105,7 +107,13 @@ def heatmap(data:pd.DataFrame | np.ndarray, row_labels:list[str] | np.ndarray,
105
107
  The returned objects can be used to annotate the cells using for example
106
108
  `annotate_heatmap`.
107
109
 
108
- This function is adapted from the matplotlib gallery example [1]_.
110
+ This function is adapted from the matplotlib gallery example [HM1]_.
111
+
112
+ References
113
+ ----------
114
+ .. [HM1] Matplotlib contributors. "Creating annotated heatmaps."
115
+ Matplotlib Gallery.
116
+ https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html
109
117
  """
110
118
 
111
119
  # create a axes if needed
@@ -61,6 +61,8 @@ def draw_incidencematrix(
61
61
  margins:tuple[float,float] | None = None,
62
62
  grid_position:Literal['outline', 'centre'] | None = 'centre',
63
63
  ax:plt.Axes | None = None,
64
+ x_coords:list[Real] | None = None,
65
+ y_coords:list[Real] | None = None,
64
66
  break_limits:tuple[float, float] = (-np.inf, np.inf),
65
67
  size_data: pd.DataFrame | None = None,
66
68
  transparency_data: pd.DataFrame | None = None,
@@ -119,6 +121,14 @@ def draw_incidencematrix(
119
121
  ax : `plt.axes` or `None`, default `None`
120
122
  If provided, the plot is drawn on this axis. Otherwise, a new figure
121
123
  and axis are created.
124
+ x_coords : `list` [`real`] or `None`, default `None`
125
+ An optional list of x-coordinates to use for plotting the dots.
126
+ If `None`, dots are spaced evenly. Length must match number of
127
+ rows in `data`.
128
+ y_coords : `list` [`real`] or `None`, default `None`
129
+ An optional list of y-coordinates to use for plotting the dots.
130
+ If `None`, dots are spaced evenly. Length must match number of
131
+ columns in `data`.
122
132
  break_limits : `tuple` [`float`, `float`], default (-np.inf, np.inf)
123
133
  Lower and upper bounds for the first and final break. Used to define
124
134
  open-ended ranges in dot colouring. Currently only uses the lower
@@ -148,8 +158,9 @@ def draw_incidencematrix(
148
158
 
149
159
  Missing or non-matching entries in the input matrix will be ignored.
150
160
  """
151
- SHAPE_ERR = ('`data` and `{0}` should have the same shapes '
161
+ SHAPE_ERR1 = ('`data` and `{0}` should have the same shapes '
152
162
  'not: {1} and {2}, respectively.')
163
+ SHAPE_ERR2 = ('Length of {0}: {1} must match number of {2}: {3}.')
153
164
  # check inputs
154
165
  is_type(dot_size, list)
155
166
  is_type(dot_colour, list)
@@ -159,6 +170,8 @@ def draw_incidencematrix(
159
170
  is_type(grid_position, (str, type(None)))
160
171
  is_type(size_data, (type(None), pd.DataFrame))
161
172
  is_type(transparency_data, (type(None), pd.DataFrame))
173
+ is_type(x_coords, (type(None), list))
174
+ is_type(y_coords, (type(None), list))
162
175
  # check literals
163
176
  EXP_GRID = [NamesIM.GRID_POS_B, NamesIM.GRID_POS_O]
164
177
  if grid_position is not None and not grid_position in EXP_GRID:
@@ -168,11 +181,11 @@ def draw_incidencematrix(
168
181
  # make sure all the data have the same shape
169
182
  if size_data is not None and data.shape != size_data.shape:
170
183
  raise IndexError(
171
- SHAPE_ERR.format('size_data', data.shape, size_data.shape
184
+ SHAPE_ERR1.format('size_data', data.shape, size_data.shape
172
185
  ))
173
186
  if transparency_data is not None and data.shape != transparency_data.shape:
174
187
  raise IndexError(
175
- SHAPE_ERR.format('transparency_data', data.shape,
188
+ SHAPE_ERR1.format('transparency_data', data.shape,
176
189
  transparency_data.shape
177
190
  ))
178
191
  # transpose - hack to make the output match the input row,col and order.
@@ -221,9 +234,24 @@ def draw_incidencematrix(
221
234
  dot_transparency_arr = _map_attributes(
222
235
  transparency_input, new_dot_transparency,
223
236
  break_limits=break_limits)
224
- # the x and y coordinates
237
+ # All for user supplied coordinates and check these match the data shape
225
238
  M, N = data.shape
226
- x, y = np.meshgrid(np.arange(M), np.arange(N))
239
+ if x_coords is not None:
240
+ x_coords_ = np.asarray(x_coords)
241
+ if len(x_coords_) != M:
242
+ raise ValueError(SHAPE_ERR2.format('x_coords', len(x_coords_),
243
+ 'rows', M))
244
+ else:
245
+ x_coords_ = np.arange(M)
246
+ if y_coords is not None:
247
+ y_coords_ = np.asarray(y_coords)
248
+ if len(y_coords_) != N:
249
+ raise ValueError(SHAPE_ERR2.format('y_coords', len(y_coords_),
250
+ 'columns', N))
251
+ else:
252
+ y_coords_ = np.arange(N)
253
+ # get the actual coordinates
254
+ x, y = np.meshgrid(x_coords_, y_coords_)
227
255
  xv = x.T.ravel()
228
256
  yv = y.T.ravel()
229
257
  col_flat = dot_colours_arr.ravel()
@@ -79,7 +79,7 @@ def lollipop(values:np.ndarray, labels:np.ndarray,
79
79
  ax:plt.Axes | None=None,
80
80
  kwargs_lines_dict:dict[Any,Any] | None=None,
81
81
  kwargs_plot_dict:dict[Any,Any] | None=None,
82
- ) -> tuple[plt.Axes, plt.Figure]:
82
+ ) -> tuple[plt.Figure, plt.Axes]:
83
83
  """
84
84
  Plots a lollipop chart.
85
85
 
@@ -960,7 +960,6 @@ class DecisionCurve(object):
960
960
  self.NET_BENEFIT = results
961
961
  self.CALCULATED=True
962
962
  # \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
963
- # NOTE add smoother paramter to allow for a different smoothing function.
964
963
  def plot(self,
965
964
  ax: plt.Axes | None = None,
966
965
  col_dict: dict[str,str] | None = None,