mergeron_extra 2024.739099.2__tar.gz → 2024.739099.6__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.
- {mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/PKG-INFO +1 -1
- {mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/pyproject.toml +1 -1
- {mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/src/mergeron_extra/__init__.py +8 -1
- {mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/src/mergeron_extra/proportions_tests.py +7 -10
- {mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/src/mergeron_extra/xlsxw_helper.py +39 -31
- {mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/README.rst +0 -0
- {mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/src/mergeron_extra/tol_colors.py +0 -0
|
@@ -4,7 +4,7 @@ description = "Tools for users of the mergeron package."
|
|
|
4
4
|
authors = ["Murthy Kambhampaty <smk@capeconomics.com>"]
|
|
5
5
|
license = "MIT"
|
|
6
6
|
readme = "README.rst"
|
|
7
|
-
version = "2024.739099.
|
|
7
|
+
version = "2024.739099.6"
|
|
8
8
|
|
|
9
9
|
classifiers = [
|
|
10
10
|
"Development Status :: 4 - Beta",
|
{mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/src/mergeron_extra/__init__.py
RENAMED
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
|
+
from numpy.typing import NDArray
|
|
6
7
|
|
|
7
8
|
_PKG_NAME: str = Path(__file__).parent.stem
|
|
8
9
|
|
|
@@ -19,5 +20,11 @@ If the subdirectory doesn't exist, it is created on package invocation.
|
|
|
19
20
|
if not DATA_DIR.is_dir():
|
|
20
21
|
DATA_DIR.mkdir(parents=False)
|
|
21
22
|
|
|
23
|
+
np.set_printoptions(precision=24, floatmode="fixed")
|
|
22
24
|
|
|
23
|
-
np.
|
|
25
|
+
type ArrayBoolean = NDArray[np.bool_]
|
|
26
|
+
type ArrayFloat = NDArray[np.half | np.single | np.double]
|
|
27
|
+
type ArrayINT = NDArray[np.intp]
|
|
28
|
+
|
|
29
|
+
type ArrayDouble = NDArray[np.double]
|
|
30
|
+
type ArrayBIGINT = NDArray[np.int64]
|
|
@@ -9,23 +9,20 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
from collections.abc import Sequence
|
|
11
11
|
from dataclasses import dataclass
|
|
12
|
-
from typing import Literal
|
|
12
|
+
from typing import Literal
|
|
13
13
|
|
|
14
14
|
import numpy as np
|
|
15
|
-
from numpy.typing import NBitBase, NDArray
|
|
16
15
|
from scipy.optimize import OptimizeResult, root # type: ignore
|
|
17
16
|
from scipy.stats import beta, chi2, norm # type: ignore
|
|
18
17
|
|
|
19
|
-
from . import
|
|
18
|
+
from . import VERSION, ArrayDouble, ArrayINT
|
|
20
19
|
|
|
21
20
|
__version__ = VERSION
|
|
22
21
|
|
|
23
|
-
TI = TypeVar("TI", bound=NBitBase)
|
|
24
|
-
|
|
25
22
|
|
|
26
23
|
def propn_ci(
|
|
27
|
-
_npos: ArrayINT
|
|
28
|
-
_nobs: ArrayINT
|
|
24
|
+
_npos: ArrayINT | int = 4,
|
|
25
|
+
_nobs: ArrayINT | int = 10,
|
|
29
26
|
/,
|
|
30
27
|
*,
|
|
31
28
|
alpha: float = 0.05,
|
|
@@ -127,7 +124,7 @@ def propn_ci(
|
|
|
127
124
|
|
|
128
125
|
|
|
129
126
|
def propn_ci_multinomial(
|
|
130
|
-
_counts:
|
|
127
|
+
_counts: ArrayINT,
|
|
131
128
|
/,
|
|
132
129
|
*,
|
|
133
130
|
alpha: float = 0.05,
|
|
@@ -438,7 +435,7 @@ def _propn_diff_chisq_mn(
|
|
|
438
435
|
|
|
439
436
|
|
|
440
437
|
def propn_diff_ci_multinomial(
|
|
441
|
-
_counts:
|
|
438
|
+
_counts: ArrayINT, /, *, alpha: float = 0.05
|
|
442
439
|
) -> ArrayDouble:
|
|
443
440
|
"""Estimate confidence intervals of pair-wise differences in multinomial proportions
|
|
444
441
|
|
|
@@ -480,7 +477,7 @@ class MultinomialPropnsTest:
|
|
|
480
477
|
|
|
481
478
|
|
|
482
479
|
def propn_test_multinomial(
|
|
483
|
-
_counts:
|
|
480
|
+
_counts: ArrayINT, /, *, alpha: float = 0.05
|
|
484
481
|
) -> MultinomialPropnsTest:
|
|
485
482
|
"""Chi-square test for homogeneity of differences in multinomial proportions.
|
|
486
483
|
|
{mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/src/mergeron_extra/xlsxw_helper.py
RENAMED
|
@@ -27,15 +27,16 @@ from collections.abc import Sequence
|
|
|
27
27
|
from typing import Any, ClassVar, Literal, TypeAlias, TypedDict
|
|
28
28
|
|
|
29
29
|
import numpy as np
|
|
30
|
-
import xlsxwriter # type: ignore
|
|
31
30
|
from aenum import Enum, extend_enum, unique # type: ignore
|
|
32
31
|
from numpy.typing import NDArray
|
|
32
|
+
from xlsxwriter.format import Format
|
|
33
|
+
from xlsxwriter.workbook import Workbook
|
|
34
|
+
from xlsxwriter.worksheet import Worksheet
|
|
33
35
|
|
|
34
36
|
from . import VERSION
|
|
35
37
|
|
|
36
38
|
__version__ = VERSION
|
|
37
39
|
|
|
38
|
-
Workbook = xlsxwriter.Workbook
|
|
39
40
|
|
|
40
41
|
XLBorderType: TypeAlias = Literal[
|
|
41
42
|
"none",
|
|
@@ -132,7 +133,7 @@ class CFmtVal(TypedDict, total=False):
|
|
|
132
133
|
|
|
133
134
|
|
|
134
135
|
@unique
|
|
135
|
-
class CFmt(
|
|
136
|
+
class CFmt(Enum): # type: ignore
|
|
136
137
|
"""
|
|
137
138
|
Cell format enums for xlsxwriter Format objects.
|
|
138
139
|
|
|
@@ -194,7 +195,7 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
194
195
|
HDR_BORDER: ClassVar = TOP_BORDER | BOTTOM_BORDER
|
|
195
196
|
|
|
196
197
|
@classmethod
|
|
197
|
-
def add_new(
|
|
198
|
+
def add_new(cls, _fmt_name: str, _xlsx_fmt_dict: CFmtVal, /) -> CFmt:
|
|
198
199
|
"""
|
|
199
200
|
Add new :class:`CFmt` object to instance.
|
|
200
201
|
|
|
@@ -204,9 +205,9 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
204
205
|
Name of new member to be added to :class:`CFmt`
|
|
205
206
|
_xlsx_fmt_dict
|
|
206
207
|
Any valid argument to :code:`xlsxwriter.Workbook.add_format()`, or union of
|
|
207
|
-
same with one or more :class:`CFmt` objects, e.g.,
|
|
208
|
-
:code:`CFmt.HDR_BORDER | CFmt.HDR_FILL` or
|
|
209
|
-
:code:`CFmt.HDR_BORDER | {"pattern": 1, "bg_color": "f2f2f2"}`
|
|
208
|
+
same with the value of one or more :class:`CFmt` objects, e.g.,
|
|
209
|
+
:code:`CFmt.HDR_BORDER.value | CFmt.HDR_FILL.value` or
|
|
210
|
+
:code:`CFmt.HDR_BORDER.value | {"pattern": 1, "bg_color": "f2f2f2"}`
|
|
210
211
|
|
|
211
212
|
Returns
|
|
212
213
|
-------
|
|
@@ -214,11 +215,11 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
214
215
|
|
|
215
216
|
"""
|
|
216
217
|
|
|
217
|
-
return extend_enum(
|
|
218
|
+
return extend_enum(cls, _fmt_name, _xlsx_fmt_dict) # type: ignore
|
|
218
219
|
|
|
219
220
|
@classmethod
|
|
220
221
|
def ensure_cell_format_spec_tuple(
|
|
221
|
-
|
|
222
|
+
cls, _cell_format: Sequence[CFmt | Sequence[CFmt]], /
|
|
222
223
|
) -> bool:
|
|
223
224
|
"""
|
|
224
225
|
Test that a given format specification is a tuple of :class:`CFmt` enums
|
|
@@ -242,7 +243,7 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
242
243
|
|
|
243
244
|
for _cf in _cell_format:
|
|
244
245
|
if isinstance(_cf, tuple):
|
|
245
|
-
|
|
246
|
+
cls.ensure_cell_format_spec_tuple(_cf)
|
|
246
247
|
|
|
247
248
|
if not (isinstance(_cf, CFmt),):
|
|
248
249
|
raise ValueError(
|
|
@@ -254,11 +255,11 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
254
255
|
|
|
255
256
|
@classmethod
|
|
256
257
|
def xl_fmt(
|
|
257
|
-
|
|
258
|
-
_xl_book:
|
|
258
|
+
cls,
|
|
259
|
+
_xl_book: Workbook,
|
|
259
260
|
_cell_fmt: Sequence[CFmt | Sequence[CFmt]] | CFmt | None,
|
|
260
261
|
/,
|
|
261
|
-
) ->
|
|
262
|
+
) -> Format:
|
|
262
263
|
"""
|
|
263
264
|
Return :code:`xlsxwriter` :code:`Format` object given a :class:`CFmt` enum, or tuple thereof.
|
|
264
265
|
|
|
@@ -274,7 +275,7 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
274
275
|
------
|
|
275
276
|
ValueError
|
|
276
277
|
If format specification is not one of None, a :class:`CFmt` enum, or
|
|
277
|
-
a :code:`
|
|
278
|
+
a :code:`Format` object
|
|
278
279
|
|
|
279
280
|
Returns
|
|
280
281
|
-------
|
|
@@ -282,20 +283,20 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
282
283
|
|
|
283
284
|
"""
|
|
284
285
|
|
|
285
|
-
if isinstance(_cell_fmt,
|
|
286
|
+
if isinstance(_cell_fmt, Format):
|
|
286
287
|
return _cell_fmt
|
|
287
288
|
elif _cell_fmt is None:
|
|
288
289
|
return _xl_book.add_format(CFmt.XL_DEFAULT.value)
|
|
289
290
|
|
|
290
291
|
_cell_fmt_dict: CFmtVal = {}
|
|
291
292
|
if isinstance(_cell_fmt, Sequence):
|
|
292
|
-
|
|
293
|
+
cls.ensure_cell_format_spec_tuple(_cell_fmt)
|
|
293
294
|
for _cf in _cell_fmt:
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
295
|
+
if isinstance(_cf, Sequence):
|
|
296
|
+
for _cfi in _cf:
|
|
297
|
+
_cell_fmt_dict |= _cfi.value
|
|
298
|
+
else:
|
|
299
|
+
_cell_fmt_dict |= _cf.value
|
|
299
300
|
elif isinstance(_cell_fmt, CFmt):
|
|
300
301
|
_cell_fmt_dict = _cell_fmt.value
|
|
301
302
|
else:
|
|
@@ -305,7 +306,7 @@ class CFmt(dict, Enum): # type: ignore
|
|
|
305
306
|
|
|
306
307
|
|
|
307
308
|
def write_header(
|
|
308
|
-
_xl_sheet:
|
|
309
|
+
_xl_sheet: Worksheet,
|
|
309
310
|
/,
|
|
310
311
|
*,
|
|
311
312
|
center_header: str | None = None,
|
|
@@ -348,7 +349,7 @@ def write_header(
|
|
|
348
349
|
|
|
349
350
|
|
|
350
351
|
def write_footer(
|
|
351
|
-
_xl_sheet:
|
|
352
|
+
_xl_sheet: Worksheet,
|
|
352
353
|
/,
|
|
353
354
|
*,
|
|
354
355
|
center_footer: str | None = None,
|
|
@@ -392,8 +393,8 @@ def write_footer(
|
|
|
392
393
|
|
|
393
394
|
|
|
394
395
|
def array_to_sheet(
|
|
395
|
-
_xl_book:
|
|
396
|
-
_xl_sheet:
|
|
396
|
+
_xl_book: Workbook,
|
|
397
|
+
_xl_sheet: Worksheet,
|
|
397
398
|
_data_table: Sequence[Any] | NDArray[Any],
|
|
398
399
|
_row_id: int,
|
|
399
400
|
_col_id: int = 0,
|
|
@@ -498,6 +499,7 @@ def array_to_sheet(
|
|
|
498
499
|
_num_cols = len(_data_table[0])
|
|
499
500
|
_right_column_id = _col_id + _num_cols
|
|
500
501
|
|
|
502
|
+
_cell_format: Sequence[CFmt | Sequence[CFmt]]
|
|
501
503
|
if isinstance(cell_format, Sequence):
|
|
502
504
|
if _num_rows > 1 and ragged_flag:
|
|
503
505
|
raise ValueError(
|
|
@@ -512,10 +514,11 @@ def array_to_sheet(
|
|
|
512
514
|
elif isinstance(cell_format, CFmt):
|
|
513
515
|
_cell_format = (cell_format,) * len(_data_table[0])
|
|
514
516
|
else:
|
|
515
|
-
_cell_format = (CFmt.XL_DEFAULT,) * len(_data_table[0])
|
|
517
|
+
_cell_format = (CFmt.XL_DEFAULT,) * len(_data_table[0]) # pyright: ignore
|
|
516
518
|
|
|
517
519
|
# construct vector of xlslwrter.format.Format objects
|
|
518
520
|
_wbk_formats = tuple(CFmt.xl_fmt(_xl_book, _cf) for _cf in _cell_format)
|
|
521
|
+
_wbk_formats_greened = _wbk_formats
|
|
519
522
|
if _num_rows > 1:
|
|
520
523
|
_wbk_formats_greened = (
|
|
521
524
|
tuple(
|
|
@@ -536,6 +539,7 @@ def array_to_sheet(
|
|
|
536
539
|
for _ci, _cv in enumerate(_rv):
|
|
537
540
|
_cf = _wbk_fmt_tuple[_ci]
|
|
538
541
|
scalar_to_sheet(
|
|
542
|
+
_xl_book,
|
|
539
543
|
_xl_sheet,
|
|
540
544
|
_row_id + _ri,
|
|
541
545
|
_col_id + _ci,
|
|
@@ -550,7 +554,8 @@ def array_to_sheet(
|
|
|
550
554
|
|
|
551
555
|
|
|
552
556
|
def scalar_to_sheet(
|
|
553
|
-
|
|
557
|
+
_xl_book: Workbook,
|
|
558
|
+
_xl_sheet: Worksheet,
|
|
554
559
|
_cell_addr_0: str | int = "A1",
|
|
555
560
|
/,
|
|
556
561
|
*_s2s_args: Any,
|
|
@@ -591,9 +596,9 @@ def scalar_to_sheet(
|
|
|
591
596
|
|
|
592
597
|
"""
|
|
593
598
|
|
|
594
|
-
_cell_addr: tuple[
|
|
595
|
-
_cell_val: Any
|
|
596
|
-
_cell_fmt:
|
|
599
|
+
_cell_addr: tuple[str] | tuple[int, int]
|
|
600
|
+
_cell_val: Any
|
|
601
|
+
_cell_fmt: CFmt | Sequence[CFmt] | None
|
|
597
602
|
|
|
598
603
|
if isinstance(_cell_addr_0, str):
|
|
599
604
|
if len(_s2s_args) not in (1, 2):
|
|
@@ -603,6 +608,7 @@ def scalar_to_sheet(
|
|
|
603
608
|
_cell_fmt = _s2s_args[1] if len(_s2s_args) == 2 else None
|
|
604
609
|
elif isinstance(_cell_addr_0, int):
|
|
605
610
|
if len(_s2s_args) not in (2, 3) or not isinstance(_s2s_args[0], int):
|
|
611
|
+
print(repr(_s2s_args))
|
|
606
612
|
raise ValueError("Incorrect/incomplete specification for Excel cell data.")
|
|
607
613
|
_cell_addr = (_cell_addr_0, _s2s_args[0])
|
|
608
614
|
_cell_val = _s2s_args[1]
|
|
@@ -615,7 +621,9 @@ def scalar_to_sheet(
|
|
|
615
621
|
if np.ndim(_cell_val) or _cell_val in (np.inf, -np.inf, np.nan)
|
|
616
622
|
else (*_cell_addr, _cell_val)
|
|
617
623
|
)
|
|
618
|
-
_write_args = (
|
|
624
|
+
_write_args = (
|
|
625
|
+
(*_write_args, CFmt.xl_fmt(_xl_book, _cell_fmt)) if _cell_fmt else _write_args
|
|
626
|
+
)
|
|
619
627
|
|
|
620
628
|
if empty_as_blank and (_cell_val is None or _cell_val == ""):
|
|
621
629
|
_xl_sheet.write_blank(*_write_args)
|
|
File without changes
|
{mergeron_extra-2024.739099.2 → mergeron_extra-2024.739099.6}/src/mergeron_extra/tol_colors.py
RENAMED
|
File without changes
|