flimanalyzer 0.6.0__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.
- flim/__init__.py +2 -0
- flim/_version.py +5 -0
- flim/analysis/__init__.py +1 -0
- flim/analysis/ml/__init__.py +0 -0
- flim/analysis/ml/autoencoder.py +188 -0
- flim/analyzerapp.py +131 -0
- flim/batch.py +235 -0
- flim/configs/__init__.py +77 -0
- flim/configs/analysis.py +554 -0
- flim/configs/data.py +278 -0
- flim/configs/plot.py +543 -0
- flim/configs/workflow.py +204 -0
- flim/core/__init__.py +0 -0
- flim/core/calculator.py +0 -0
- flim/core/config.py +305 -0
- flim/core/execution.py +110 -0
- flim/core/fields.py +226 -0
- flim/core/filter.py +179 -0
- flim/core/graph.py +111 -0
- flim/core/headers.py +72 -0
- flim/core/importer.py +269 -0
- flim/core/parser.py +305 -0
- flim/core/paths.py +66 -0
- flim/core/prefect_server.py +152 -0
- flim/core/preprocessor.py +287 -0
- flim/core/registry.py +108 -0
- flim/core/runner.py +703 -0
- flim/core/schema.py +114 -0
- flim/core/settings.py +419 -0
- flim/core/tool.py +284 -0
- flim/core/tools.py +76 -0
- flim/core/types.py +113 -0
- flim/core/validation.py +272 -0
- flim/core/workflow.py +148 -0
- flim/gui/__init__.py +12 -0
- flim/gui/app.py +953 -0
- flim/gui/configdialog.py +495 -0
- flim/gui/datapanel.py +841 -0
- flim/gui/delimpanel.py +56 -0
- flim/gui/dialogs/__init__.py +473 -0
- flim/gui/dialogs/autoencoder.py +89 -0
- flim/gui/dialogs/categoryorder.py +130 -0
- flim/gui/dialogs/filter.py +86 -0
- flim/gui/dialogs/unpivot.py +72 -0
- flim/gui/dicttablepanel.py +178 -0
- flim/gui/editors.py +1578 -0
- flim/gui/events.py +162 -0
- flim/gui/icons.py +16 -0
- flim/gui/importdlg.py +391 -0
- flim/gui/listcontrol.py +472 -0
- flim/gui/macos.py +77 -0
- flim/gui/plotframe.py +73 -0
- flim/gui/progressdlg.py +290 -0
- flim/resources/aeaugment.png +0 -0
- flim/resources/aefeatureworkflow.png +0 -0
- flim/resources/aerun.png +0 -0
- flim/resources/aetrain.png +0 -0
- flim/resources/aetuneworkflow.png +0 -0
- flim/resources/barplot.png +0 -0
- flim/resources/boxplot.png +0 -0
- flim/resources/categorize.png +0 -0
- flim/resources/concatenate.png +0 -0
- flim/resources/fileopen.png +0 -0
- flim/resources/filter.png +0 -0
- flim/resources/flimanalyzer.ico +0 -0
- flim/resources/flimanalyzer.png +0 -0
- flim/resources/flirrplot.png +0 -0
- flim/resources/flirrworkflow.png +0 -0
- flim/resources/gmm.png +0 -0
- flim/resources/heatmap.png +0 -0
- flim/resources/histogram.png +0 -0
- flim/resources/import.png +0 -0
- flim/resources/kde.png +0 -0
- flim/resources/kmeans.png +0 -0
- flim/resources/ks.png +0 -0
- flim/resources/lineplot.png +0 -0
- flim/resources/merge.png +0 -0
- flim/resources/order.png +0 -0
- flim/resources/pairplot.png +0 -0
- flim/resources/pca.png +0 -0
- flim/resources/pivot.png +0 -0
- flim/resources/randomforest.png +0 -0
- flim/resources/relchange.png +0 -0
- flim/resources/scatter.png +0 -0
- flim/resources/seriesanalysis.png +0 -0
- flim/resources/sort.png +0 -0
- flim/resources/split.png +0 -0
- flim/resources/summary.png +0 -0
- flim/resources/swarmplot.png +0 -0
- flim/resources/unpivot.png +0 -0
- flim/resources/violinplot.png +0 -0
- flim/resources/workflow.png +0 -0
- flim/results.py +70 -0
- flim/tools/__init__.py +7 -0
- flim/tools/autoencoder.py +662 -0
- flim/tools/common.py +62 -0
- flim/tools/data.py +301 -0
- flim/tools/ml.py +311 -0
- flim/tools/plot.py +1439 -0
- flim/tools/statistics.py +348 -0
- flim/utils.py +43 -0
- flim/workflow/__init__.py +3 -0
- flim/workflow/aefeature.py +145 -0
- flim/workflow/aetune.py +163 -0
- flim/workflow/basicflow.py +99 -0
- flimanalyzer-0.6.0.dist-info/METADATA +262 -0
- flimanalyzer-0.6.0.dist-info/RECORD +110 -0
- flimanalyzer-0.6.0.dist-info/WHEEL +4 -0
- flimanalyzer-0.6.0.dist-info/entry_points.txt +5 -0
- flimanalyzer-0.6.0.dist-info/licenses/LICENSE +19 -0
flim/configs/data.py
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""Configs of the Data tools."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Literal, Optional, Union
|
|
4
|
+
|
|
5
|
+
from pydantic import Field, field_validator, model_validator
|
|
6
|
+
|
|
7
|
+
from flim.core.config import (
|
|
8
|
+
AllFeatures,
|
|
9
|
+
BaseConfig,
|
|
10
|
+
CategoryColumn,
|
|
11
|
+
FeatureColumn,
|
|
12
|
+
TaskConfig,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DataTaskConfig(TaskConfig):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CategoryOrderConfig(DataTaskConfig):
|
|
21
|
+
"""Order of the values of category columns; the columns are sorted by them."""
|
|
22
|
+
|
|
23
|
+
legacy_keys = {"categories": None}
|
|
24
|
+
legacy_dropped = frozenset({"inplace"})
|
|
25
|
+
hidden_fields = frozenset({"grouping", "features"})
|
|
26
|
+
|
|
27
|
+
categories: dict[CategoryColumn, list[Any]] = Field(
|
|
28
|
+
default={},
|
|
29
|
+
title="Value order",
|
|
30
|
+
description="For each category column, its values in the order to use.",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def _from_legacy(cls, params):
|
|
35
|
+
# legacy: {column: {"values": [...], "sort": ...}}; only the values are used
|
|
36
|
+
categories = params.pop("categories", {}) or {}
|
|
37
|
+
return {
|
|
38
|
+
"categories": {
|
|
39
|
+
col: list(spec.get("values", [])) for col, spec in categories.items()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
def _to_legacy(self):
|
|
44
|
+
return {
|
|
45
|
+
"categories": {
|
|
46
|
+
col: {"values": list(values), "sort": "custom"}
|
|
47
|
+
for col, values in self.categories.items()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ConcatConfig(DataTaskConfig):
|
|
53
|
+
legacy_keys = {"mode": None}
|
|
54
|
+
legacy_dropped = frozenset({"source_suffix"}) # unused
|
|
55
|
+
hidden_fields = frozenset({"grouping", "features"})
|
|
56
|
+
|
|
57
|
+
mode: Literal["vertical", "horizontal"] = Field(
|
|
58
|
+
default="vertical",
|
|
59
|
+
title="Direction",
|
|
60
|
+
description="Append the rows of the tables below each other, or their columns"
|
|
61
|
+
" side by side.",
|
|
62
|
+
json_schema_extra={
|
|
63
|
+
"labels": {
|
|
64
|
+
"vertical": "Rows (stack below)",
|
|
65
|
+
"horizontal": "Columns (side by side)",
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
numbers_only: bool = Field(
|
|
70
|
+
default=False,
|
|
71
|
+
title="Numeric columns only",
|
|
72
|
+
description="Columns: append only the numeric columns of the other tables.",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def _from_legacy(cls, params):
|
|
77
|
+
# legacy "type" is the "Horizontal Concatenate" checkbox
|
|
78
|
+
if "type" in params:
|
|
79
|
+
return {"mode": "horizontal" if params.pop("type") else "vertical"}
|
|
80
|
+
return {}
|
|
81
|
+
|
|
82
|
+
def _to_legacy(self):
|
|
83
|
+
return {"type": self.mode == "horizontal"}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def range_of_legacy(spec: dict) -> dict:
|
|
87
|
+
"""low, high and dropna of a plugin's range filter; infinite: no limit."""
|
|
88
|
+
low, high = spec.get("rangelow"), spec.get("rangehigh")
|
|
89
|
+
return {
|
|
90
|
+
"low": None if low is None or low == float("-inf") else low,
|
|
91
|
+
"high": None if high is None or high == float("inf") else high,
|
|
92
|
+
"dropna": spec.get("dropna", True),
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class RangeSettings(BaseConfig):
|
|
97
|
+
"""Rows whose value lies outside [low, high] are dropped; empty: no limit."""
|
|
98
|
+
|
|
99
|
+
low: Optional[float] = Field(default=None, title="Low")
|
|
100
|
+
high: Optional[float] = Field(default=None, title="High")
|
|
101
|
+
dropna: bool = Field(
|
|
102
|
+
default=True,
|
|
103
|
+
title="Drop missing",
|
|
104
|
+
description="Also drop rows without a value.",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
@model_validator(mode="after")
|
|
108
|
+
def _check_range(self):
|
|
109
|
+
if self.low is not None and self.high is not None and self.low > self.high:
|
|
110
|
+
raise ValueError(f"low ({self.low}) > high ({self.high})")
|
|
111
|
+
return self
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class FilterConfig(DataTaskConfig):
|
|
115
|
+
legacy_keys = {"range_filters": None}
|
|
116
|
+
legacy_dropped = frozenset({"use", "inplace", "show_dropped"}) # unused
|
|
117
|
+
hidden_fields = frozenset({"grouping", "features"})
|
|
118
|
+
|
|
119
|
+
category_filters: dict[CategoryColumn, list[Any]] = Field(
|
|
120
|
+
default={},
|
|
121
|
+
title="Category values to keep",
|
|
122
|
+
description="For each category column, the values whose rows are kept.",
|
|
123
|
+
)
|
|
124
|
+
range_filters: dict[FeatureColumn, RangeSettings] = Field(
|
|
125
|
+
default={},
|
|
126
|
+
title="Range filters",
|
|
127
|
+
description=(
|
|
128
|
+
"Check the columns to filter: rows outside [low, high] are dropped (empty:"
|
|
129
|
+
" no limit)."
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
@field_validator("range_filters", mode="before")
|
|
134
|
+
@classmethod
|
|
135
|
+
def _filters_from_list(cls, filters):
|
|
136
|
+
"""A list of columns: filters without limits (dropping missing values)."""
|
|
137
|
+
if isinstance(filters, (list, tuple)):
|
|
138
|
+
return {f: {} for f in filters}
|
|
139
|
+
return filters
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def _from_legacy(cls, params):
|
|
143
|
+
# the plugin: a list of {"name", "rangelow", "rangehigh", "selected", ...};
|
|
144
|
+
# it applied the selected ones
|
|
145
|
+
filters = {}
|
|
146
|
+
for spec in params.pop("range_filters", []) or []:
|
|
147
|
+
if spec.get("selected", True):
|
|
148
|
+
filters[spec["name"]] = RangeSettings(**range_of_legacy(spec))
|
|
149
|
+
return {"range_filters": filters}
|
|
150
|
+
|
|
151
|
+
def _to_legacy(self):
|
|
152
|
+
inf = float("inf")
|
|
153
|
+
return {
|
|
154
|
+
"range_filters": [
|
|
155
|
+
{
|
|
156
|
+
"name": column,
|
|
157
|
+
"rangelow": -inf if r.low is None else r.low,
|
|
158
|
+
"rangehigh": inf if r.high is None else r.high,
|
|
159
|
+
"allowedmin": None,
|
|
160
|
+
"allowedmax": None,
|
|
161
|
+
"selected": True,
|
|
162
|
+
"dropna": r.dropna,
|
|
163
|
+
}
|
|
164
|
+
for column, r in self.range_filters.items()
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class MergeConfig(DataTaskConfig):
|
|
170
|
+
legacy_keys = {"how": None, "on": None}
|
|
171
|
+
legacy_dropped = frozenset({"left_index", "right_index"})
|
|
172
|
+
hidden_fields = frozenset({"grouping", "features"})
|
|
173
|
+
|
|
174
|
+
how: Literal["inner", "outer", "left", "right"] = Field(
|
|
175
|
+
default="inner",
|
|
176
|
+
title="Join",
|
|
177
|
+
description=(
|
|
178
|
+
"inner: rows in both tables; outer: in either; left/right: all rows of"
|
|
179
|
+
" that table."
|
|
180
|
+
),
|
|
181
|
+
)
|
|
182
|
+
on: Optional[list[CategoryColumn]] = Field(
|
|
183
|
+
default=None,
|
|
184
|
+
title="Merge on",
|
|
185
|
+
description="Columns to merge on; automatic: the category columns both have.",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
@classmethod
|
|
189
|
+
def _from_legacy(cls, params):
|
|
190
|
+
how = params.pop("how", "")
|
|
191
|
+
return {"how": how} if how else {} # legacy default "" fails in pandas
|
|
192
|
+
|
|
193
|
+
def _to_legacy(self):
|
|
194
|
+
return {"how": self.how}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class PivotConfig(DataTaskConfig):
|
|
198
|
+
"""Pivots the ``grouping`` columns."""
|
|
199
|
+
|
|
200
|
+
grouping: list[CategoryColumn] = Field(
|
|
201
|
+
default=["Treatment"],
|
|
202
|
+
title="Columns to pivot",
|
|
203
|
+
description="Their values become columns; the other category columns stay rows.",
|
|
204
|
+
)
|
|
205
|
+
features: Union[list[FeatureColumn], AllFeatures] = Field(
|
|
206
|
+
default="all", title="Features"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
class SortConfig(DataTaskConfig):
|
|
211
|
+
"""Sorts by the ``features`` columns."""
|
|
212
|
+
|
|
213
|
+
hidden_fields = frozenset({"grouping"})
|
|
214
|
+
|
|
215
|
+
features: Union[list[FeatureColumn], AllFeatures] = Field(
|
|
216
|
+
default=[], title="Sort by", description="The columns to sort by, in order."
|
|
217
|
+
)
|
|
218
|
+
ascending: bool = Field(default=True, title="Ascending")
|
|
219
|
+
ignore_index: bool = Field(
|
|
220
|
+
default=True,
|
|
221
|
+
title="Renumber rows",
|
|
222
|
+
description="Number the sorted rows 0, 1, ...",
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class SplitConfig(DataTaskConfig):
|
|
227
|
+
"""Splits a table by the values of the ``grouping`` columns."""
|
|
228
|
+
|
|
229
|
+
hidden_fields = frozenset({"features"})
|
|
230
|
+
|
|
231
|
+
grouping: list[CategoryColumn] = Field(
|
|
232
|
+
default=[],
|
|
233
|
+
title="Split by",
|
|
234
|
+
description="A table for each combination of the values of these columns.",
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
@field_validator("grouping")
|
|
238
|
+
@classmethod
|
|
239
|
+
def _some_columns(cls, grouping):
|
|
240
|
+
if not grouping:
|
|
241
|
+
raise ValueError("Select the columns to split by")
|
|
242
|
+
return grouping
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class UnpivotConfig(DataTaskConfig):
|
|
246
|
+
"""Moves one level (line) of the columns' headers into a category column: the
|
|
247
|
+
inverse of Pivot. E.g. the level Treatment of ``"FLIRR\\nctrl"``,
|
|
248
|
+
``"FLIRR\\nDox15"``: a column Treatment (ctrl, Dox15) and a column FLIRR."""
|
|
249
|
+
|
|
250
|
+
legacy_keys = {"category_name": None}
|
|
251
|
+
legacy_dropped = frozenset({"feature_name"}) # now named by the other levels
|
|
252
|
+
hidden_fields = frozenset({"grouping"})
|
|
253
|
+
|
|
254
|
+
features: Union[list[FeatureColumn], AllFeatures] = Field(
|
|
255
|
+
default="all", title="Columns", description="The columns to unpivot."
|
|
256
|
+
)
|
|
257
|
+
level: str = Field(
|
|
258
|
+
default="",
|
|
259
|
+
title="Level",
|
|
260
|
+
description=(
|
|
261
|
+
"The header line that becomes a category column; empty: the last. The"
|
|
262
|
+
" other lines name the value columns."
|
|
263
|
+
),
|
|
264
|
+
)
|
|
265
|
+
category_name: Optional[str] = Field(
|
|
266
|
+
default=None,
|
|
267
|
+
title="Category column",
|
|
268
|
+
description="Name of the new category column; empty: the level's name.",
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
@classmethod
|
|
272
|
+
def _from_legacy(cls, params):
|
|
273
|
+
# "Category" (the plugin's default name): the level's name
|
|
274
|
+
name = params.pop("category_name", None)
|
|
275
|
+
return {"category_name": None if name in (None, "", "Category") else name}
|
|
276
|
+
|
|
277
|
+
def _to_legacy(self):
|
|
278
|
+
return {"category_name": self.category_name or "Category"}
|