scistackplotdb 0.1.44__tar.gz → 0.1.45__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.
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/PKG-INFO +5 -5
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/source.py +95 -7
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/.gitignore +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/README.md +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/pyproject.toml +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/__init__.py +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/_versioned.py +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/bundle_section.py +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/endpoint.py +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/hierarchy.py +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/load.py +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/presets.py +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/saved.py +0 -0
- {scistackplotdb-0.1.44 → scistackplotdb-0.1.45}/src/scistackplotdb/variants.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: scistackplotdb
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.45
|
|
4
4
|
Summary: scidb-backed plotting: load variables into long tables and plot them with scistackplot
|
|
5
5
|
Author: SciStack Contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -17,10 +17,10 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
17
17
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
18
18
|
Classifier: Typing :: Typed
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
|
-
Requires-Dist: sciduckdb==0.1.
|
|
21
|
-
Requires-Dist: scistack-db==0.1.
|
|
22
|
-
Requires-Dist: scistacklog==0.1.
|
|
23
|
-
Requires-Dist: scistackplot==0.1.
|
|
20
|
+
Requires-Dist: sciduckdb==0.1.45
|
|
21
|
+
Requires-Dist: scistack-db==0.1.45
|
|
22
|
+
Requires-Dist: scistacklog==0.1.45
|
|
23
|
+
Requires-Dist: scistackplot==0.1.45
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: matplotlib>=3.6; extra == 'dev'
|
|
26
26
|
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
@@ -818,9 +818,7 @@ class ScidbSource(BaseSource):
|
|
|
818
818
|
return frame, attached
|
|
819
819
|
|
|
820
820
|
for group in factor_variables:
|
|
821
|
-
|
|
822
|
-
variable = self._variable_frame(name)
|
|
823
|
-
source_column = self._factor_source_column(variable, group)
|
|
821
|
+
variable = self._variable_frame(group.variable)
|
|
824
822
|
factor = group.factor_name
|
|
825
823
|
if factor in frame.columns:
|
|
826
824
|
# Never merge over a column that is already there. pandas would
|
|
@@ -846,10 +844,7 @@ class ScidbSource(BaseSource):
|
|
|
846
844
|
f"attach one of its values to each row. Group by a variable "
|
|
847
845
|
f"recorded at or above the level of the data."
|
|
848
846
|
)
|
|
849
|
-
on =
|
|
850
|
-
right = self._pinned_variant(variable, group)
|
|
851
|
-
right = right.rename(columns={source_column: factor})
|
|
852
|
-
right = self._one_label_per_location(right, on, factor, group)
|
|
847
|
+
on, right = self._keyed_values(variable, group)
|
|
853
848
|
frame = frame.merge(right, on=on, how="left")
|
|
854
849
|
|
|
855
850
|
# A row the grouping variable says nothing about keeps its place and
|
|
@@ -895,6 +890,53 @@ class ScidbSource(BaseSource):
|
|
|
895
890
|
)
|
|
896
891
|
return frame, attached
|
|
897
892
|
|
|
893
|
+
def _keyed_values(self, variable_frame, group: FactorVariable):
|
|
894
|
+
"""``(on, right)``: one grouping's or covariate's values, pinned to its
|
|
895
|
+
variant, one per schema location, in a column named
|
|
896
|
+
``group.factor_name``; ``on`` = the schema keys it is recorded at.
|
|
897
|
+
|
|
898
|
+
The ONE loader behind both joins: a grouping variable merged onto the
|
|
899
|
+
long table (:meth:`_attach_factor_variables`) and a covariate merged
|
|
900
|
+
onto StatStudio's analysis rows (:meth:`covariate_values`), so "which
|
|
901
|
+
value does this location get" cannot mean two things.
|
|
902
|
+
"""
|
|
903
|
+
source_column = self._factor_source_column(variable_frame, group)
|
|
904
|
+
on = list(variable_frame.levels)
|
|
905
|
+
right = self._pinned_variant(variable_frame, group)
|
|
906
|
+
right = right.rename(columns={source_column: group.factor_name})
|
|
907
|
+
right = self._one_label_per_location(right, on, group.factor_name, group)
|
|
908
|
+
return on, right
|
|
909
|
+
|
|
910
|
+
def covariate_values(self, group: FactorVariable):
|
|
911
|
+
"""``(keys, frame)``: a numeric covariate for StatStudio's mixed model
|
|
912
|
+
(``scistackstats.tables.load_covariates``), keyed by the schema keys
|
|
913
|
+
it is recorded at. ``frame`` has ``[*keys, group.factor_name]``.
|
|
914
|
+
|
|
915
|
+
Joined per analysis ROW by the caller, after the figure's reduction,
|
|
916
|
+
so a covariate recorded below the rows' level is refused there with
|
|
917
|
+
the reason. A text column is refused here: a covariate is a number.
|
|
918
|
+
"""
|
|
919
|
+
import pandas as pd
|
|
920
|
+
|
|
921
|
+
variable = self._variable_frame(group.variable)
|
|
922
|
+
on, right = self._keyed_values(variable, group)
|
|
923
|
+
values = right[group.factor_name]
|
|
924
|
+
numeric = pd.to_numeric(values, errors="coerce")
|
|
925
|
+
if values.notna().any() and numeric.notna().sum() == 0:
|
|
926
|
+
raise ValueError(
|
|
927
|
+
f"{group.label} holds text, not numbers: a covariate is numeric "
|
|
928
|
+
f"(group by it instead)"
|
|
929
|
+
)
|
|
930
|
+
right = right.assign(**{group.factor_name: numeric})
|
|
931
|
+
Log.info(
|
|
932
|
+
"covariate %r: %d value(s) keyed by %s",
|
|
933
|
+
group.label,
|
|
934
|
+
int(numeric.notna().sum()),
|
|
935
|
+
on,
|
|
936
|
+
layer=LAYER,
|
|
937
|
+
)
|
|
938
|
+
return on, right
|
|
939
|
+
|
|
898
940
|
def _pinned_variant(self, variable_frame, group: FactorVariable):
|
|
899
941
|
"""The grouping variable's rows, narrowed to the pinned variant.
|
|
900
942
|
|
|
@@ -1748,6 +1790,52 @@ class ScidbSource(BaseSource):
|
|
|
1748
1790
|
)
|
|
1749
1791
|
return {"offered": offered, "rejected": rejected}
|
|
1750
1792
|
|
|
1793
|
+
def covariate_variables(self, measure: str) -> dict:
|
|
1794
|
+
"""Which VARIABLES may supply a numeric covariate for ``measure`` —
|
|
1795
|
+
the DAG canvas half of StatStudio's Add covariate picker.
|
|
1796
|
+
|
|
1797
|
+
:meth:`groupable_variables`' offers with the meaning of "numeric"
|
|
1798
|
+
turned around: a whole variable with numeric values and every wide
|
|
1799
|
+
table (its columns are :meth:`covariate_columns`' question) are
|
|
1800
|
+
offered; a categorical variable is refused, with the reason. The
|
|
1801
|
+
plotted variable's own columns are not offered: covariates are joined
|
|
1802
|
+
onto the analysis rows, where the measure's own fields are not
|
|
1803
|
+
carried.
|
|
1804
|
+
"""
|
|
1805
|
+
found = self.groupable_variables(measure)
|
|
1806
|
+
offered, rejected = [], dict(found["rejected"])
|
|
1807
|
+
for entry in found["offered"]:
|
|
1808
|
+
if entry.get("own"):
|
|
1809
|
+
continue
|
|
1810
|
+
if entry["kind"] == "categorical":
|
|
1811
|
+
rejected[entry["label"]] = "text values: a covariate is numeric (group by it instead)"
|
|
1812
|
+
continue
|
|
1813
|
+
offered.append(entry)
|
|
1814
|
+
Log.info("covariate_variables(%s): %d offered, %d rejected", measure, len(offered), len(rejected),
|
|
1815
|
+
layer=LAYER)
|
|
1816
|
+
return {"offered": offered, "rejected": rejected}
|
|
1817
|
+
|
|
1818
|
+
def covariate_columns(self, measure: str, variable: str) -> dict:
|
|
1819
|
+
"""Which COLUMNS of ``variable`` may be a covariate: the numeric ones
|
|
1820
|
+
(the mirror of :meth:`groupable_columns`, which offers the text
|
|
1821
|
+
ones). Same ``{"offered", "rejected"}`` shape, same type pre-filter."""
|
|
1822
|
+
rejected: dict[str, str] = {}
|
|
1823
|
+
offered: list[dict] = []
|
|
1824
|
+
types = data_column_types_for(self._db, variable)
|
|
1825
|
+
with Log.timer(f"covariate_columns({variable})", layer=LAYER):
|
|
1826
|
+
for column, data_type in types.items():
|
|
1827
|
+
label = f"{variable}.{column}"
|
|
1828
|
+
if is_container_type(data_type):
|
|
1829
|
+
continue
|
|
1830
|
+
shape = classify_value(sample_column_value(self._db, variable, column))
|
|
1831
|
+
if shape in (Shape.SERIES_1D, Shape.MATRIX_2D, Shape.UNKNOWN):
|
|
1832
|
+
continue
|
|
1833
|
+
if shape is Shape.CATEGORICAL:
|
|
1834
|
+
rejected[label] = "text column: a covariate is numeric (group by it instead)"
|
|
1835
|
+
continue
|
|
1836
|
+
offered.append(self._offer(variable, column, []))
|
|
1837
|
+
return {"offered": offered, "rejected": rejected}
|
|
1838
|
+
|
|
1751
1839
|
def _groupable_columns(
|
|
1752
1840
|
self,
|
|
1753
1841
|
variable: str,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|