TimeFeatures 2.0.0__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.
- {timefeatures-2.0.0/TimeFeatures.egg-info → timefeatures-2.1.0}/PKG-INFO +5 -2
- {timefeatures-2.0.0 → timefeatures-2.1.0}/README.md +4 -1
- {timefeatures-2.0.0 → timefeatures-2.1.0/TimeFeatures.egg-info}/PKG-INFO +5 -2
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/changes.rst +46 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/widgets/load-from-db.rst +40 -4
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/widgets/save-to-db.rst +41 -6
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/widgets/time-feature-constructor.rst +27 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/widgets/variable-dependency-graph.rst +17 -3
- {timefeatures-2.0.0 → timefeatures-2.1.0}/setup.py +1 -1
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_sources/changes.rst.txt +46 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_sources/widgets/load-from-db.rst.txt +40 -4
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_sources/widgets/save-to-db.rst.txt +41 -6
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_sources/widgets/time-feature-constructor.rst.txt +27 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_sources/widgets/variable-dependency-graph.rst.txt +17 -3
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/changes.html +46 -0
- timefeatures-2.1.0/timefeatures/help_html/objects.inv +0 -0
- timefeatures-2.1.0/timefeatures/help_html/searchindex.js +1 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/widgets/load-from-db.html +41 -4
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/widgets/save-to-db.html +45 -7
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/widgets/time-feature-constructor.html +25 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/widgets/variable-dependency-graph.html +19 -3
- timefeatures-2.1.0/timefeatures/widgets/icons/loaddatadb.svg +1 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/widgets/owloadfromdb.py +206 -7
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/widgets/owsavetodb.py +182 -146
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/widgets/owtimefeaturesconstructor.py +141 -26
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/widgets/owvardependencygraph.py +74 -34
- timefeatures-2.0.0/timefeatures/help_html/objects.inv +0 -0
- timefeatures-2.0.0/timefeatures/help_html/searchindex.js +0 -1
- timefeatures-2.0.0/timefeatures/widgets/icons/loaddatadb.svg +0 -1
- {timefeatures-2.0.0 → timefeatures-2.1.0}/LICENSE +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/MANIFEST.in +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/TimeFeatures.egg-info/SOURCES.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/TimeFeatures.egg-info/dependency_links.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/TimeFeatures.egg-info/entry_points.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/TimeFeatures.egg-info/requires.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/TimeFeatures.egg-info/top_level.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/Makefile +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/conf.py +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/index.rst +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/installation.rst +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/docs/requirements.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/imgs/installation.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/imgs/workflow.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/setup.cfg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/__init__.py +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help.py +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/.buildinfo +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_sources/index.rst.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_sources/installation.rst.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/alabaster.css +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/basic.css +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/custom.css +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/doctools.js +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/documentation_options.js +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/file.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/github-banner.svg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/language_data.js +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/minus.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/plus.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/pygments.css +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/searchtools.js +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_static/sphinx_highlight.js +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/genindex.html +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/index.html +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/installation.html +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/search.html +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/widgets/__init__.py +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/widgets/icons/graphgenerator.svg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/widgets/icons/savedatadb.svg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/widgets/icons/timefeature-xs.svg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/widgets/icons/timefeature.svg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TimeFeatures
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Timefeatures add-on for Orange 3 data mining software.
|
|
5
5
|
Home-page: https://github.com/alervgr/Orange-TimeFeatures
|
|
6
6
|
Author: Alejandro Rivas García
|
|
@@ -86,12 +86,15 @@ If using Anaconda Python distribution, simply run
|
|
|
86
86
|
pip install TimeFeatures
|
|
87
87
|
|
|
88
88
|
**Required Dependencies**:
|
|
89
|
+
|
|
89
90
|
* numpy>=1.22.4
|
|
90
91
|
* AnyQt>=0.2.0
|
|
91
|
-
* Orange3>=3.34.0
|
|
92
92
|
* PyQt5>=5.15.6
|
|
93
93
|
* PyQtWebEngine>=5.15.6
|
|
94
94
|
* scipy>=1.7.3
|
|
95
|
+
* SQLAlchemy>=1.4.0
|
|
96
|
+
* psycopg2-binary>=2.9.9
|
|
97
|
+
* PyMySQL>=1.0.0
|
|
95
98
|
* Orange3-Network>=1.8.0
|
|
96
99
|
|
|
97
100
|
Usage
|
|
@@ -42,12 +42,15 @@ If using Anaconda Python distribution, simply run
|
|
|
42
42
|
pip install TimeFeatures
|
|
43
43
|
|
|
44
44
|
**Required Dependencies**:
|
|
45
|
+
|
|
45
46
|
* numpy>=1.22.4
|
|
46
47
|
* AnyQt>=0.2.0
|
|
47
|
-
* Orange3>=3.34.0
|
|
48
48
|
* PyQt5>=5.15.6
|
|
49
49
|
* PyQtWebEngine>=5.15.6
|
|
50
50
|
* scipy>=1.7.3
|
|
51
|
+
* SQLAlchemy>=1.4.0
|
|
52
|
+
* psycopg2-binary>=2.9.9
|
|
53
|
+
* PyMySQL>=1.0.0
|
|
51
54
|
* Orange3-Network>=1.8.0
|
|
52
55
|
|
|
53
56
|
Usage
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TimeFeatures
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Timefeatures add-on for Orange 3 data mining software.
|
|
5
5
|
Home-page: https://github.com/alervgr/Orange-TimeFeatures
|
|
6
6
|
Author: Alejandro Rivas García
|
|
@@ -86,12 +86,15 @@ If using Anaconda Python distribution, simply run
|
|
|
86
86
|
pip install TimeFeatures
|
|
87
87
|
|
|
88
88
|
**Required Dependencies**:
|
|
89
|
+
|
|
89
90
|
* numpy>=1.22.4
|
|
90
91
|
* AnyQt>=0.2.0
|
|
91
|
-
* Orange3>=3.34.0
|
|
92
92
|
* PyQt5>=5.15.6
|
|
93
93
|
* PyQtWebEngine>=5.15.6
|
|
94
94
|
* scipy>=1.7.3
|
|
95
|
+
* SQLAlchemy>=1.4.0
|
|
96
|
+
* psycopg2-binary>=2.9.9
|
|
97
|
+
* PyMySQL>=1.0.0
|
|
95
98
|
* Orange3-Network>=1.8.0
|
|
96
99
|
|
|
97
100
|
Usage
|
|
@@ -22,6 +22,22 @@ Unreleased
|
|
|
22
22
|
- Workflow-persisted settings: ``selected_dataset`` and
|
|
23
23
|
``selected_class`` are ``Setting(..., schema_only=True)``, restored
|
|
24
24
|
as soon as the connection comes back up on reload.
|
|
25
|
+
- The Dataset combo is a ``ComboBoxSearch`` — type to filter when the
|
|
26
|
+
registry gets large.
|
|
27
|
+
- ``↻`` button next to the Dataset combo re-runs the listing without
|
|
28
|
+
dropping the connection (handy when something else just published a
|
|
29
|
+
new dataset). Auto-load is suppressed on Refresh so the user never
|
|
30
|
+
gets a Load they didn't ask for.
|
|
31
|
+
- ``Delete`` button drops the selected dataset's table and removes
|
|
32
|
+
its row in ``datasets``. Runs through a ``_DeleteDatasetWorker`` on
|
|
33
|
+
a background thread, guarded by a confirmation dialog. Idempotent:
|
|
34
|
+
re-deleting a missing table is a no-op thanks to
|
|
35
|
+
``DROP TABLE IF EXISTS``.
|
|
36
|
+
- **Auto-load** on workflow reopen: if the persisted
|
|
37
|
+
``selected_dataset`` is still on the server when the connection
|
|
38
|
+
succeeds and the listing returns, Load fires automatically — the
|
|
39
|
+
data flows out without a single click. The flag is cleared on
|
|
40
|
+
Refresh and on Delete to avoid surprises.
|
|
25
41
|
|
|
26
42
|
**Variable Dependency Graph**
|
|
27
43
|
|
|
@@ -31,6 +47,17 @@ Unreleased
|
|
|
31
47
|
reference the dependency. Plain (non-temporal) references default to
|
|
32
48
|
weight ``1``. The weights live in ``network.edges[0].edges.data``
|
|
33
49
|
and are consumable by any downstream Network widget.
|
|
50
|
+
- *New:* the graph is now **directed** (``DirectedEdges``). Previously
|
|
51
|
+
the sparse matrix was passed straight to ``Network`` which auto-wrapped
|
|
52
|
+
it as ``UndirectedEdges`` — a latent bug since A→B is not the same as
|
|
53
|
+
B→A in a dependency graph.
|
|
54
|
+
- *New:* nodes carry an extra ``expression`` meta (literal expression
|
|
55
|
+
text, empty for original variables) so the Network Explorer can show
|
|
56
|
+
the formula as the node label.
|
|
57
|
+
- *New:* ``Warning.no_derived`` fires when every input row is an
|
|
58
|
+
original variable — usually a sign the user wired the data output
|
|
59
|
+
of Time Features Constructor instead of the variable-definitions
|
|
60
|
+
one.
|
|
34
61
|
- Refactor: flattened the ``from_row_col`` / ``grafo`` decorator pattern
|
|
35
62
|
into a single, documented ``build_dependency_network`` function.
|
|
36
63
|
- Performance: O(n³) → O(n²) by precomputing a ``name → index`` map and
|
|
@@ -42,6 +69,16 @@ Unreleased
|
|
|
42
69
|
|
|
43
70
|
**Time Features Constructor**
|
|
44
71
|
|
|
72
|
+
- *New:* **chained descriptors**. A descriptor can now reference
|
|
73
|
+
another derived descriptor in its expression (e.g. ``X2 :=
|
|
74
|
+
shift(X1, -1)`` with ``X1`` itself defined a few rows above). The
|
|
75
|
+
widget topologically sorts the descriptors and cascades the
|
|
76
|
+
transforms — each step runs against the table state produced by
|
|
77
|
+
the previous one, so ``X2`` sees ``X1`` as a regular column.
|
|
78
|
+
Cycles (e.g. ``X1 := X2 + 1`` together with ``X2 := X1 + 1``) raise
|
|
79
|
+
a *Circular dependency between descriptors: X1, X2* error. Errors
|
|
80
|
+
during evaluation are reported per-descriptor so the failing row is
|
|
81
|
+
obvious.
|
|
45
82
|
- *Fixed (critical):* time-window functions used to lose context every
|
|
46
83
|
5 000 rows because Orange chunks tables during ``transform``. The
|
|
47
84
|
widget now caches the full source per ``FeatureFunc`` and returns the
|
|
@@ -68,6 +105,15 @@ Unreleased
|
|
|
68
105
|
|
|
69
106
|
**Save to DB**
|
|
70
107
|
|
|
108
|
+
- *New:* **write mode** selector with three options — *Create new*
|
|
109
|
+
(default, fail if the target exists), *Overwrite* (drop and
|
|
110
|
+
recreate the table and its ``datasets`` row), *Append* (keep
|
|
111
|
+
existing rows and add the new ones). Re-running a workflow no
|
|
112
|
+
longer breaks. The persisted ``write_mode`` Setting defaults to
|
|
113
|
+
``"create"`` so old workflows keep their previous behaviour. After
|
|
114
|
+
the upload, the widget runs ``SELECT COUNT(*)`` and rewrites the
|
|
115
|
+
``datasets`` row with the actual total, so the registry stays
|
|
116
|
+
accurate across appends.
|
|
71
117
|
- *New:* **MySQL support**. The connection panel now exposes a
|
|
72
118
|
database-type selector (PostgreSQL / MySQL). Per-dialect column
|
|
73
119
|
types and identifier quoting (``"name"`` vs ``\`name\```) live in
|
|
@@ -48,9 +48,21 @@ Controls
|
|
|
48
48
|
host/db (N datasets)", "Loaded <name> (N rows)"), error
|
|
49
49
|
("Connection failed: …", "Load failed: …").
|
|
50
50
|
* - Dataset
|
|
51
|
-
-
|
|
52
|
-
datetime DESC``. The most recent upload comes first; the
|
|
53
|
-
choice is restored when reopening a workflow.
|
|
51
|
+
- Searchable combo populated from ``SELECT * FROM datasets ORDER
|
|
52
|
+
BY datetime DESC``. The most recent upload comes first; the
|
|
53
|
+
last choice is restored when reopening a workflow. Type to
|
|
54
|
+
filter the visible items — handy when the registry grows large.
|
|
55
|
+
* - ↻ (Refresh)
|
|
56
|
+
- Small button to the right of the Dataset combo. Re-runs the
|
|
57
|
+
list query without dropping the connection. Useful if another
|
|
58
|
+
Orange canvas (or a parallel tool) just published a new
|
|
59
|
+
dataset while this widget was open.
|
|
60
|
+
* - Delete
|
|
61
|
+
- Drops the currently selected dataset's table from the database
|
|
62
|
+
and removes its row in ``datasets``. Gated by a confirmation
|
|
63
|
+
dialog — there is no Orange-side undo. The operation runs on a
|
|
64
|
+
background thread, so the canvas stays responsive even if the
|
|
65
|
+
table is large.
|
|
54
66
|
* - Dataset info
|
|
55
67
|
- Read-only block under the combo: save timestamp, row/column
|
|
56
68
|
counts and the original class column recorded by **Save to DB**.
|
|
@@ -60,7 +72,9 @@ Controls
|
|
|
60
72
|
choice, (2) the ``class_name`` stored in the ``datasets``
|
|
61
73
|
metadata, (3) ``(no class)`` if none of the above apply.
|
|
62
74
|
* - Load
|
|
63
|
-
- Triggers the actual download.
|
|
75
|
+
- Triggers the actual download. Skipped automatically on the
|
|
76
|
+
first connection after a workflow reopen if the persisted
|
|
77
|
+
dataset name is still available (see *Auto-load* below).
|
|
64
78
|
|
|
65
79
|
How it Works
|
|
66
80
|
------------
|
|
@@ -88,6 +102,28 @@ While any worker runs, the form controls (database type, connection
|
|
|
88
102
|
fields, **Connect**, **Load**, dataset and class combos) are
|
|
89
103
|
temporarily disabled and the status label keeps the user informed.
|
|
90
104
|
|
|
105
|
+
Auto-load
|
|
106
|
+
---------
|
|
107
|
+
|
|
108
|
+
When you reopen a workflow that already had a Load from DB widget with
|
|
109
|
+
a saved ``selected_dataset``, the widget fires Load automatically the
|
|
110
|
+
first time the dataset listing comes back successfully. The data flows
|
|
111
|
+
out of the **Data** output without a single click, mirroring how Orange
|
|
112
|
+
treats sources like **File** and **Datasets**.
|
|
113
|
+
|
|
114
|
+
Subtleties:
|
|
115
|
+
|
|
116
|
+
- Auto-load is a *one-shot* per widget lifetime. Manually clicking
|
|
117
|
+
**Refresh** clears the pending flag, so a Refresh never surprises
|
|
118
|
+
the user by loading something behind their back.
|
|
119
|
+
- If the persisted dataset no longer exists on the server (deleted
|
|
120
|
+
from outside, or the registry was wiped), the flag is cleared and
|
|
121
|
+
the widget just shows the available list — no error.
|
|
122
|
+
- If a different backend or set of credentials is restored, the user
|
|
123
|
+
still has to click **Connect** explicitly, just like in earlier
|
|
124
|
+
versions; auto-load happens *after* the first successful connection
|
|
125
|
+
+ listing.
|
|
126
|
+
|
|
91
127
|
Workflow Persistence
|
|
92
128
|
--------------------
|
|
93
129
|
|
|
@@ -59,6 +59,21 @@ TimeFeatures-specific controls:
|
|
|
59
59
|
- Destination table name. Validated against PostgreSQL identifier
|
|
60
60
|
rules (see *Validation* below); MySQL accepts a superset, so
|
|
61
61
|
the same rule is safe on both.
|
|
62
|
+
* - Mode
|
|
63
|
+
- Combo between the Table name and the Email fields:
|
|
64
|
+
|
|
65
|
+
- **Create new (fail if table exists)** — default, refuses to
|
|
66
|
+
touch an existing table or metadata row. Use this for first
|
|
67
|
+
uploads or when you want a clear error on accidental name
|
|
68
|
+
collisions.
|
|
69
|
+
- **Overwrite (drop and recreate)** — drops the existing data
|
|
70
|
+
table and the matching ``datasets`` row before uploading,
|
|
71
|
+
then recreates them. Re-running the workflow stops breaking.
|
|
72
|
+
- **Append (keep existing rows)** — adds rows to the existing
|
|
73
|
+
table (creating it if it doesn't exist). After the upload,
|
|
74
|
+
the widget runs ``SELECT COUNT(*)`` and rewrites the
|
|
75
|
+
``datasets`` row with the *actual* total row count, so the
|
|
76
|
+
registry stays accurate across repeated appends.
|
|
62
77
|
* - Email
|
|
63
78
|
- Optional notification address. A summary email is sent once the
|
|
64
79
|
upload finishes, including the table name, row / column counts,
|
|
@@ -79,12 +94,32 @@ When **Save** is clicked, the widget:
|
|
|
79
94
|
|
|
80
95
|
- converts the dataset to a pandas DataFrame with
|
|
81
96
|
``Orange.data.pandas_compat.table_to_frame(include_metas=True)``
|
|
82
|
-
and reorders the columns (class first, then metas in domain
|
|
83
|
-
then attributes) to match the existing schema convention;
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
97
|
+
and reorders the columns (class first, then metas in domain
|
|
98
|
+
order, then attributes) to match the existing schema convention;
|
|
99
|
+
- ensures the ``datasets`` metadata table exists;
|
|
100
|
+
- applies the mode-specific preparation:
|
|
101
|
+
|
|
102
|
+
- **create** — fail fast if a ``datasets`` row with this name
|
|
103
|
+
already exists.
|
|
104
|
+
- **overwrite** — ``DROP TABLE IF EXISTS`` on the target plus
|
|
105
|
+
``DELETE`` of the matching ``datasets`` row.
|
|
106
|
+
- **append** — leave everything in place; the upload itself will
|
|
107
|
+
create the table on the first chunk if it doesn't exist.
|
|
108
|
+
|
|
109
|
+
- writes the dataset in ``PANDAS_SQL_CHUNKSIZE`` chunks (default
|
|
110
|
+
``1 000``) via ``df.to_sql(..., method='multi')`` with the
|
|
111
|
+
``if_exists`` value tailored to the mode (see
|
|
112
|
+
``_pandas_if_exists`` for the exact table);
|
|
113
|
+
- runs ``SELECT COUNT(*)`` on the target table and re-inserts the
|
|
114
|
+
``datasets`` row with that real row count, so the registry stays
|
|
115
|
+
consistent even after multiple appends.
|
|
116
|
+
|
|
117
|
+
Everything happens inside a single SQLAlchemy transaction
|
|
118
|
+
(``engine.begin()``), so a mid-upload error rolls every step back on
|
|
119
|
+
PostgreSQL. MySQL auto-commits DDL (``DROP TABLE``, ``CREATE TABLE``),
|
|
120
|
+
so an Overwrite that crashes during the upload may leave you without
|
|
121
|
+
the original table — there's no way around that without engine-level
|
|
122
|
+
support.
|
|
88
123
|
|
|
89
124
|
While the worker runs, the widget's progress bar and status label are
|
|
90
125
|
updated through Qt signals; the **Save**, **Connect** and form controls
|
|
@@ -144,6 +144,33 @@ returns the appropriate slice for each chunk, so a call like
|
|
|
144
144
|
``shift(x, -20)`` keeps the right value across chunk boundaries even on
|
|
145
145
|
multi-million-row tables.
|
|
146
146
|
|
|
147
|
+
Chained descriptors
|
|
148
|
+
-------------------
|
|
149
|
+
|
|
150
|
+
Descriptors may reference each other. For example:
|
|
151
|
+
|
|
152
|
+
.. code-block:: python
|
|
153
|
+
|
|
154
|
+
X1 := shift(price, -1)
|
|
155
|
+
X2 := X1 + bias
|
|
156
|
+
|
|
157
|
+
When this happens, the widget topologically sorts the descriptors by
|
|
158
|
+
their dependencies and applies them in cascade — each transform step
|
|
159
|
+
runs against the table state produced by the previous step, so ``X2``
|
|
160
|
+
sees ``X1`` as if it were a regular source column.
|
|
161
|
+
|
|
162
|
+
- The order you click **New** in does not matter. Define ``X2`` before
|
|
163
|
+
``X1`` and the cascade still works.
|
|
164
|
+
- Cycles are detected: writing ``X1 := X2 + 1`` together with
|
|
165
|
+
``X2 := X1 + 1`` raises a *Circular dependency between descriptors:
|
|
166
|
+
X1, X2* error instead of producing garbage.
|
|
167
|
+
- Per-descriptor error reporting: if one expression fails (e.g.
|
|
168
|
+
``shift(unknown, -1)``), the error mentions the descriptor name so
|
|
169
|
+
you know which row to fix.
|
|
170
|
+
- Time-window correctness is preserved through the chain: a chained
|
|
171
|
+
``X2`` that reads ``X1`` over a window keeps producing the right
|
|
172
|
+
values even past Orange's 5 000-row chunk boundary.
|
|
173
|
+
|
|
147
174
|
Workflow persistence
|
|
148
175
|
--------------------
|
|
149
176
|
|
|
@@ -33,9 +33,9 @@ Outputs
|
|
|
33
33
|
- Description
|
|
34
34
|
* - Network
|
|
35
35
|
- ``orangecontrib.network.Network``
|
|
36
|
-
- A directed weighted graph. ``network.edges[0]
|
|
37
|
-
sparse adjacency matrix
|
|
38
|
-
weights described below.
|
|
36
|
+
- A **directed** weighted graph. ``network.edges[0]`` is a
|
|
37
|
+
``DirectedEdges`` instance whose sparse adjacency matrix carries
|
|
38
|
+
the per-edge weights described in *Edge Weights* below.
|
|
39
39
|
|
|
40
40
|
How It Works
|
|
41
41
|
------------
|
|
@@ -118,6 +118,11 @@ downstream styling:
|
|
|
118
118
|
* - ``var_type``
|
|
119
119
|
- Discrete
|
|
120
120
|
- ``Derived`` (has an expression) or ``Original`` (source feature).
|
|
121
|
+
* - ``expression``
|
|
122
|
+
- String
|
|
123
|
+
- The literal expression text for derived variables; empty for
|
|
124
|
+
original ones. Pick it as **Label** in Network Explorer to see
|
|
125
|
+
each derived node's formula directly on the graph.
|
|
121
126
|
|
|
122
127
|
Controls
|
|
123
128
|
--------
|
|
@@ -126,6 +131,15 @@ Controls
|
|
|
126
131
|
table. The widget also auto-regenerates whenever a valid input
|
|
127
132
|
arrives.
|
|
128
133
|
|
|
134
|
+
Warnings
|
|
135
|
+
--------
|
|
136
|
+
|
|
137
|
+
- *Input has no derived variables; the dependency graph is empty.*
|
|
138
|
+
Fires when every row of the configuration table is an original
|
|
139
|
+
variable (no ``Expression`` set). The output network has nodes but
|
|
140
|
+
no edges. Usually means you forgot to attach the second output of
|
|
141
|
+
**Time Features Constructor** instead of the data output.
|
|
142
|
+
|
|
129
143
|
Input Requirements
|
|
130
144
|
------------------
|
|
131
145
|
|
|
@@ -22,6 +22,22 @@ Unreleased
|
|
|
22
22
|
- Workflow-persisted settings: ``selected_dataset`` and
|
|
23
23
|
``selected_class`` are ``Setting(..., schema_only=True)``, restored
|
|
24
24
|
as soon as the connection comes back up on reload.
|
|
25
|
+
- The Dataset combo is a ``ComboBoxSearch`` — type to filter when the
|
|
26
|
+
registry gets large.
|
|
27
|
+
- ``↻`` button next to the Dataset combo re-runs the listing without
|
|
28
|
+
dropping the connection (handy when something else just published a
|
|
29
|
+
new dataset). Auto-load is suppressed on Refresh so the user never
|
|
30
|
+
gets a Load they didn't ask for.
|
|
31
|
+
- ``Delete`` button drops the selected dataset's table and removes
|
|
32
|
+
its row in ``datasets``. Runs through a ``_DeleteDatasetWorker`` on
|
|
33
|
+
a background thread, guarded by a confirmation dialog. Idempotent:
|
|
34
|
+
re-deleting a missing table is a no-op thanks to
|
|
35
|
+
``DROP TABLE IF EXISTS``.
|
|
36
|
+
- **Auto-load** on workflow reopen: if the persisted
|
|
37
|
+
``selected_dataset`` is still on the server when the connection
|
|
38
|
+
succeeds and the listing returns, Load fires automatically — the
|
|
39
|
+
data flows out without a single click. The flag is cleared on
|
|
40
|
+
Refresh and on Delete to avoid surprises.
|
|
25
41
|
|
|
26
42
|
**Variable Dependency Graph**
|
|
27
43
|
|
|
@@ -31,6 +47,17 @@ Unreleased
|
|
|
31
47
|
reference the dependency. Plain (non-temporal) references default to
|
|
32
48
|
weight ``1``. The weights live in ``network.edges[0].edges.data``
|
|
33
49
|
and are consumable by any downstream Network widget.
|
|
50
|
+
- *New:* the graph is now **directed** (``DirectedEdges``). Previously
|
|
51
|
+
the sparse matrix was passed straight to ``Network`` which auto-wrapped
|
|
52
|
+
it as ``UndirectedEdges`` — a latent bug since A→B is not the same as
|
|
53
|
+
B→A in a dependency graph.
|
|
54
|
+
- *New:* nodes carry an extra ``expression`` meta (literal expression
|
|
55
|
+
text, empty for original variables) so the Network Explorer can show
|
|
56
|
+
the formula as the node label.
|
|
57
|
+
- *New:* ``Warning.no_derived`` fires when every input row is an
|
|
58
|
+
original variable — usually a sign the user wired the data output
|
|
59
|
+
of Time Features Constructor instead of the variable-definitions
|
|
60
|
+
one.
|
|
34
61
|
- Refactor: flattened the ``from_row_col`` / ``grafo`` decorator pattern
|
|
35
62
|
into a single, documented ``build_dependency_network`` function.
|
|
36
63
|
- Performance: O(n³) → O(n²) by precomputing a ``name → index`` map and
|
|
@@ -42,6 +69,16 @@ Unreleased
|
|
|
42
69
|
|
|
43
70
|
**Time Features Constructor**
|
|
44
71
|
|
|
72
|
+
- *New:* **chained descriptors**. A descriptor can now reference
|
|
73
|
+
another derived descriptor in its expression (e.g. ``X2 :=
|
|
74
|
+
shift(X1, -1)`` with ``X1`` itself defined a few rows above). The
|
|
75
|
+
widget topologically sorts the descriptors and cascades the
|
|
76
|
+
transforms — each step runs against the table state produced by
|
|
77
|
+
the previous one, so ``X2`` sees ``X1`` as a regular column.
|
|
78
|
+
Cycles (e.g. ``X1 := X2 + 1`` together with ``X2 := X1 + 1``) raise
|
|
79
|
+
a *Circular dependency between descriptors: X1, X2* error. Errors
|
|
80
|
+
during evaluation are reported per-descriptor so the failing row is
|
|
81
|
+
obvious.
|
|
45
82
|
- *Fixed (critical):* time-window functions used to lose context every
|
|
46
83
|
5 000 rows because Orange chunks tables during ``transform``. The
|
|
47
84
|
widget now caches the full source per ``FeatureFunc`` and returns the
|
|
@@ -68,6 +105,15 @@ Unreleased
|
|
|
68
105
|
|
|
69
106
|
**Save to DB**
|
|
70
107
|
|
|
108
|
+
- *New:* **write mode** selector with three options — *Create new*
|
|
109
|
+
(default, fail if the target exists), *Overwrite* (drop and
|
|
110
|
+
recreate the table and its ``datasets`` row), *Append* (keep
|
|
111
|
+
existing rows and add the new ones). Re-running a workflow no
|
|
112
|
+
longer breaks. The persisted ``write_mode`` Setting defaults to
|
|
113
|
+
``"create"`` so old workflows keep their previous behaviour. After
|
|
114
|
+
the upload, the widget runs ``SELECT COUNT(*)`` and rewrites the
|
|
115
|
+
``datasets`` row with the actual total, so the registry stays
|
|
116
|
+
accurate across appends.
|
|
71
117
|
- *New:* **MySQL support**. The connection panel now exposes a
|
|
72
118
|
database-type selector (PostgreSQL / MySQL). Per-dialect column
|
|
73
119
|
types and identifier quoting (``"name"`` vs ``\`name\```) live in
|
|
@@ -48,9 +48,21 @@ Controls
|
|
|
48
48
|
host/db (N datasets)", "Loaded <name> (N rows)"), error
|
|
49
49
|
("Connection failed: …", "Load failed: …").
|
|
50
50
|
* - Dataset
|
|
51
|
-
-
|
|
52
|
-
datetime DESC``. The most recent upload comes first; the
|
|
53
|
-
choice is restored when reopening a workflow.
|
|
51
|
+
- Searchable combo populated from ``SELECT * FROM datasets ORDER
|
|
52
|
+
BY datetime DESC``. The most recent upload comes first; the
|
|
53
|
+
last choice is restored when reopening a workflow. Type to
|
|
54
|
+
filter the visible items — handy when the registry grows large.
|
|
55
|
+
* - ↻ (Refresh)
|
|
56
|
+
- Small button to the right of the Dataset combo. Re-runs the
|
|
57
|
+
list query without dropping the connection. Useful if another
|
|
58
|
+
Orange canvas (or a parallel tool) just published a new
|
|
59
|
+
dataset while this widget was open.
|
|
60
|
+
* - Delete
|
|
61
|
+
- Drops the currently selected dataset's table from the database
|
|
62
|
+
and removes its row in ``datasets``. Gated by a confirmation
|
|
63
|
+
dialog — there is no Orange-side undo. The operation runs on a
|
|
64
|
+
background thread, so the canvas stays responsive even if the
|
|
65
|
+
table is large.
|
|
54
66
|
* - Dataset info
|
|
55
67
|
- Read-only block under the combo: save timestamp, row/column
|
|
56
68
|
counts and the original class column recorded by **Save to DB**.
|
|
@@ -60,7 +72,9 @@ Controls
|
|
|
60
72
|
choice, (2) the ``class_name`` stored in the ``datasets``
|
|
61
73
|
metadata, (3) ``(no class)`` if none of the above apply.
|
|
62
74
|
* - Load
|
|
63
|
-
- Triggers the actual download.
|
|
75
|
+
- Triggers the actual download. Skipped automatically on the
|
|
76
|
+
first connection after a workflow reopen if the persisted
|
|
77
|
+
dataset name is still available (see *Auto-load* below).
|
|
64
78
|
|
|
65
79
|
How it Works
|
|
66
80
|
------------
|
|
@@ -88,6 +102,28 @@ While any worker runs, the form controls (database type, connection
|
|
|
88
102
|
fields, **Connect**, **Load**, dataset and class combos) are
|
|
89
103
|
temporarily disabled and the status label keeps the user informed.
|
|
90
104
|
|
|
105
|
+
Auto-load
|
|
106
|
+
---------
|
|
107
|
+
|
|
108
|
+
When you reopen a workflow that already had a Load from DB widget with
|
|
109
|
+
a saved ``selected_dataset``, the widget fires Load automatically the
|
|
110
|
+
first time the dataset listing comes back successfully. The data flows
|
|
111
|
+
out of the **Data** output without a single click, mirroring how Orange
|
|
112
|
+
treats sources like **File** and **Datasets**.
|
|
113
|
+
|
|
114
|
+
Subtleties:
|
|
115
|
+
|
|
116
|
+
- Auto-load is a *one-shot* per widget lifetime. Manually clicking
|
|
117
|
+
**Refresh** clears the pending flag, so a Refresh never surprises
|
|
118
|
+
the user by loading something behind their back.
|
|
119
|
+
- If the persisted dataset no longer exists on the server (deleted
|
|
120
|
+
from outside, or the registry was wiped), the flag is cleared and
|
|
121
|
+
the widget just shows the available list — no error.
|
|
122
|
+
- If a different backend or set of credentials is restored, the user
|
|
123
|
+
still has to click **Connect** explicitly, just like in earlier
|
|
124
|
+
versions; auto-load happens *after* the first successful connection
|
|
125
|
+
+ listing.
|
|
126
|
+
|
|
91
127
|
Workflow Persistence
|
|
92
128
|
--------------------
|
|
93
129
|
|
{timefeatures-2.0.0 → timefeatures-2.1.0}/timefeatures/help_html/_sources/widgets/save-to-db.rst.txt
RENAMED
|
@@ -59,6 +59,21 @@ TimeFeatures-specific controls:
|
|
|
59
59
|
- Destination table name. Validated against PostgreSQL identifier
|
|
60
60
|
rules (see *Validation* below); MySQL accepts a superset, so
|
|
61
61
|
the same rule is safe on both.
|
|
62
|
+
* - Mode
|
|
63
|
+
- Combo between the Table name and the Email fields:
|
|
64
|
+
|
|
65
|
+
- **Create new (fail if table exists)** — default, refuses to
|
|
66
|
+
touch an existing table or metadata row. Use this for first
|
|
67
|
+
uploads or when you want a clear error on accidental name
|
|
68
|
+
collisions.
|
|
69
|
+
- **Overwrite (drop and recreate)** — drops the existing data
|
|
70
|
+
table and the matching ``datasets`` row before uploading,
|
|
71
|
+
then recreates them. Re-running the workflow stops breaking.
|
|
72
|
+
- **Append (keep existing rows)** — adds rows to the existing
|
|
73
|
+
table (creating it if it doesn't exist). After the upload,
|
|
74
|
+
the widget runs ``SELECT COUNT(*)`` and rewrites the
|
|
75
|
+
``datasets`` row with the *actual* total row count, so the
|
|
76
|
+
registry stays accurate across repeated appends.
|
|
62
77
|
* - Email
|
|
63
78
|
- Optional notification address. A summary email is sent once the
|
|
64
79
|
upload finishes, including the table name, row / column counts,
|
|
@@ -79,12 +94,32 @@ When **Save** is clicked, the widget:
|
|
|
79
94
|
|
|
80
95
|
- converts the dataset to a pandas DataFrame with
|
|
81
96
|
``Orange.data.pandas_compat.table_to_frame(include_metas=True)``
|
|
82
|
-
and reorders the columns (class first, then metas in domain
|
|
83
|
-
then attributes) to match the existing schema convention;
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
97
|
+
and reorders the columns (class first, then metas in domain
|
|
98
|
+
order, then attributes) to match the existing schema convention;
|
|
99
|
+
- ensures the ``datasets`` metadata table exists;
|
|
100
|
+
- applies the mode-specific preparation:
|
|
101
|
+
|
|
102
|
+
- **create** — fail fast if a ``datasets`` row with this name
|
|
103
|
+
already exists.
|
|
104
|
+
- **overwrite** — ``DROP TABLE IF EXISTS`` on the target plus
|
|
105
|
+
``DELETE`` of the matching ``datasets`` row.
|
|
106
|
+
- **append** — leave everything in place; the upload itself will
|
|
107
|
+
create the table on the first chunk if it doesn't exist.
|
|
108
|
+
|
|
109
|
+
- writes the dataset in ``PANDAS_SQL_CHUNKSIZE`` chunks (default
|
|
110
|
+
``1 000``) via ``df.to_sql(..., method='multi')`` with the
|
|
111
|
+
``if_exists`` value tailored to the mode (see
|
|
112
|
+
``_pandas_if_exists`` for the exact table);
|
|
113
|
+
- runs ``SELECT COUNT(*)`` on the target table and re-inserts the
|
|
114
|
+
``datasets`` row with that real row count, so the registry stays
|
|
115
|
+
consistent even after multiple appends.
|
|
116
|
+
|
|
117
|
+
Everything happens inside a single SQLAlchemy transaction
|
|
118
|
+
(``engine.begin()``), so a mid-upload error rolls every step back on
|
|
119
|
+
PostgreSQL. MySQL auto-commits DDL (``DROP TABLE``, ``CREATE TABLE``),
|
|
120
|
+
so an Overwrite that crashes during the upload may leave you without
|
|
121
|
+
the original table — there's no way around that without engine-level
|
|
122
|
+
support.
|
|
88
123
|
|
|
89
124
|
While the worker runs, the widget's progress bar and status label are
|
|
90
125
|
updated through Qt signals; the **Save**, **Connect** and form controls
|
|
@@ -144,6 +144,33 @@ returns the appropriate slice for each chunk, so a call like
|
|
|
144
144
|
``shift(x, -20)`` keeps the right value across chunk boundaries even on
|
|
145
145
|
multi-million-row tables.
|
|
146
146
|
|
|
147
|
+
Chained descriptors
|
|
148
|
+
-------------------
|
|
149
|
+
|
|
150
|
+
Descriptors may reference each other. For example:
|
|
151
|
+
|
|
152
|
+
.. code-block:: python
|
|
153
|
+
|
|
154
|
+
X1 := shift(price, -1)
|
|
155
|
+
X2 := X1 + bias
|
|
156
|
+
|
|
157
|
+
When this happens, the widget topologically sorts the descriptors by
|
|
158
|
+
their dependencies and applies them in cascade — each transform step
|
|
159
|
+
runs against the table state produced by the previous step, so ``X2``
|
|
160
|
+
sees ``X1`` as if it were a regular source column.
|
|
161
|
+
|
|
162
|
+
- The order you click **New** in does not matter. Define ``X2`` before
|
|
163
|
+
``X1`` and the cascade still works.
|
|
164
|
+
- Cycles are detected: writing ``X1 := X2 + 1`` together with
|
|
165
|
+
``X2 := X1 + 1`` raises a *Circular dependency between descriptors:
|
|
166
|
+
X1, X2* error instead of producing garbage.
|
|
167
|
+
- Per-descriptor error reporting: if one expression fails (e.g.
|
|
168
|
+
``shift(unknown, -1)``), the error mentions the descriptor name so
|
|
169
|
+
you know which row to fix.
|
|
170
|
+
- Time-window correctness is preserved through the chain: a chained
|
|
171
|
+
``X2`` that reads ``X1`` over a window keeps producing the right
|
|
172
|
+
values even past Orange's 5 000-row chunk boundary.
|
|
173
|
+
|
|
147
174
|
Workflow persistence
|
|
148
175
|
--------------------
|
|
149
176
|
|
|
@@ -33,9 +33,9 @@ Outputs
|
|
|
33
33
|
- Description
|
|
34
34
|
* - Network
|
|
35
35
|
- ``orangecontrib.network.Network``
|
|
36
|
-
- A directed weighted graph. ``network.edges[0]
|
|
37
|
-
sparse adjacency matrix
|
|
38
|
-
weights described below.
|
|
36
|
+
- A **directed** weighted graph. ``network.edges[0]`` is a
|
|
37
|
+
``DirectedEdges`` instance whose sparse adjacency matrix carries
|
|
38
|
+
the per-edge weights described in *Edge Weights* below.
|
|
39
39
|
|
|
40
40
|
How It Works
|
|
41
41
|
------------
|
|
@@ -118,6 +118,11 @@ downstream styling:
|
|
|
118
118
|
* - ``var_type``
|
|
119
119
|
- Discrete
|
|
120
120
|
- ``Derived`` (has an expression) or ``Original`` (source feature).
|
|
121
|
+
* - ``expression``
|
|
122
|
+
- String
|
|
123
|
+
- The literal expression text for derived variables; empty for
|
|
124
|
+
original ones. Pick it as **Label** in Network Explorer to see
|
|
125
|
+
each derived node's formula directly on the graph.
|
|
121
126
|
|
|
122
127
|
Controls
|
|
123
128
|
--------
|
|
@@ -126,6 +131,15 @@ Controls
|
|
|
126
131
|
table. The widget also auto-regenerates whenever a valid input
|
|
127
132
|
arrives.
|
|
128
133
|
|
|
134
|
+
Warnings
|
|
135
|
+
--------
|
|
136
|
+
|
|
137
|
+
- *Input has no derived variables; the dependency graph is empty.*
|
|
138
|
+
Fires when every row of the configuration table is an original
|
|
139
|
+
variable (no ``Expression`` set). The output network has nodes but
|
|
140
|
+
no edges. Usually means you forgot to attach the second output of
|
|
141
|
+
**Time Features Constructor** instead of the data output.
|
|
142
|
+
|
|
129
143
|
Input Requirements
|
|
130
144
|
------------------
|
|
131
145
|
|