TimeFeatures 1.0.18__tar.gz → 2.0.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-1.0.18/TimeFeatures.egg-info → timefeatures-2.0.0}/PKG-INFO +3 -1
- {timefeatures-1.0.18 → timefeatures-2.0.0/TimeFeatures.egg-info}/PKG-INFO +3 -1
- {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/SOURCES.txt +11 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/requires.txt +2 -0
- timefeatures-2.0.0/docs/changes.rst +121 -0
- timefeatures-2.0.0/docs/conf.py +62 -0
- timefeatures-2.0.0/docs/index.rst +97 -0
- timefeatures-2.0.0/docs/installation.rst +103 -0
- timefeatures-2.0.0/docs/widgets/load-from-db.rst +136 -0
- timefeatures-2.0.0/docs/widgets/save-to-db.rst +185 -0
- timefeatures-2.0.0/docs/widgets/time-feature-constructor.rst +182 -0
- timefeatures-2.0.0/docs/widgets/variable-dependency-graph.rst +160 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/setup.py +3 -1
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/.buildinfo +1 -1
- timefeatures-2.0.0/timefeatures/help_html/_sources/changes.rst.txt +121 -0
- timefeatures-2.0.0/timefeatures/help_html/_sources/index.rst.txt +97 -0
- timefeatures-2.0.0/timefeatures/help_html/_sources/installation.rst.txt +103 -0
- timefeatures-2.0.0/timefeatures/help_html/_sources/widgets/load-from-db.rst.txt +136 -0
- timefeatures-2.0.0/timefeatures/help_html/_sources/widgets/save-to-db.rst.txt +185 -0
- timefeatures-2.0.0/timefeatures/help_html/_sources/widgets/time-feature-constructor.rst.txt +182 -0
- timefeatures-2.0.0/timefeatures/help_html/_sources/widgets/variable-dependency-graph.rst.txt +160 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/alabaster.css +6 -1
- timefeatures-2.0.0/timefeatures/help_html/changes.html +241 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/genindex.html +42 -27
- timefeatures-2.0.0/timefeatures/help_html/index.html +226 -0
- timefeatures-2.0.0/timefeatures/help_html/installation.html +231 -0
- timefeatures-2.0.0/timefeatures/help_html/objects.inv +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/search.html +59 -44
- timefeatures-2.0.0/timefeatures/help_html/searchindex.js +1 -0
- timefeatures-2.0.0/timefeatures/help_html/widgets/load-from-db.html +261 -0
- timefeatures-2.0.0/timefeatures/help_html/widgets/save-to-db.html +318 -0
- timefeatures-2.0.0/timefeatures/help_html/widgets/time-feature-constructor.html +321 -0
- timefeatures-2.0.0/timefeatures/help_html/widgets/variable-dependency-graph.html +308 -0
- timefeatures-2.0.0/timefeatures/widgets/icons/loaddatadb.svg +1 -0
- timefeatures-2.0.0/timefeatures/widgets/owloadfromdb.py +553 -0
- timefeatures-2.0.0/timefeatures/widgets/owsavetodb.py +850 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/owtimefeaturesconstructor.py +8 -6
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/owvardependencygraph.py +58 -9
- timefeatures-1.0.18/docs/conf.py +0 -26
- timefeatures-1.0.18/docs/index.rst +0 -37
- timefeatures-1.0.18/docs/widgets/save-to-db.rst +0 -70
- timefeatures-1.0.18/docs/widgets/time-feature-constructor.rst +0 -100
- timefeatures-1.0.18/docs/widgets/variable-dependency-graph.rst +0 -66
- timefeatures-1.0.18/timefeatures/help_html/_sources/index.rst.txt +0 -37
- timefeatures-1.0.18/timefeatures/help_html/_sources/widgets/save-to-db.rst.txt +0 -70
- timefeatures-1.0.18/timefeatures/help_html/_sources/widgets/time-feature-constructor.rst.txt +0 -100
- timefeatures-1.0.18/timefeatures/help_html/_sources/widgets/variable-dependency-graph.rst.txt +0 -66
- timefeatures-1.0.18/timefeatures/help_html/index.html +0 -135
- timefeatures-1.0.18/timefeatures/help_html/objects.inv +0 -6
- timefeatures-1.0.18/timefeatures/help_html/searchindex.js +0 -1
- timefeatures-1.0.18/timefeatures/help_html/widgets/save-to-db.html +0 -185
- timefeatures-1.0.18/timefeatures/help_html/widgets/time-feature-constructor.html +0 -219
- timefeatures-1.0.18/timefeatures/help_html/widgets/variable-dependency-graph.html +0 -181
- timefeatures-1.0.18/timefeatures/widgets/owsavetodb.py +0 -401
- {timefeatures-1.0.18 → timefeatures-2.0.0}/LICENSE +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/MANIFEST.in +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/README.md +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/dependency_links.txt +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/entry_points.txt +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/top_level.txt +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/docs/Makefile +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/docs/requirements.txt +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/imgs/installation.png +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/imgs/workflow.png +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/setup.cfg +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/__init__.py +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help.py +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/basic.css +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/custom.css +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/doctools.js +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/documentation_options.js +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/file.png +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/github-banner.svg +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/language_data.js +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/minus.png +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/plus.png +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/pygments.css +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/searchtools.js +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/sphinx_highlight.js +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/__init__.py +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/icons/graphgenerator.svg +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/icons/savedatadb.svg +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/icons/timefeature-xs.svg +0 -0
- {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/icons/timefeature.svg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TimeFeatures
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.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
|
|
@@ -23,7 +23,9 @@ Requires-Dist: AnyQt>=0.2.0
|
|
|
23
23
|
Requires-Dist: PyQt5>=5.15.6
|
|
24
24
|
Requires-Dist: PyQtWebEngine>=5.15.6
|
|
25
25
|
Requires-Dist: scipy>=1.7.3
|
|
26
|
+
Requires-Dist: SQLAlchemy>=1.4.0
|
|
26
27
|
Requires-Dist: psycopg2-binary>=2.9.9
|
|
28
|
+
Requires-Dist: PyMySQL>=1.0.0
|
|
27
29
|
Requires-Dist: Orange3-Network>=1.8.0
|
|
28
30
|
Provides-Extra: docs
|
|
29
31
|
Requires-Dist: Sphinx>=7.0; extra == "docs"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TimeFeatures
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.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
|
|
@@ -23,7 +23,9 @@ Requires-Dist: AnyQt>=0.2.0
|
|
|
23
23
|
Requires-Dist: PyQt5>=5.15.6
|
|
24
24
|
Requires-Dist: PyQtWebEngine>=5.15.6
|
|
25
25
|
Requires-Dist: scipy>=1.7.3
|
|
26
|
+
Requires-Dist: SQLAlchemy>=1.4.0
|
|
26
27
|
Requires-Dist: psycopg2-binary>=2.9.9
|
|
28
|
+
Requires-Dist: PyMySQL>=1.0.0
|
|
27
29
|
Requires-Dist: Orange3-Network>=1.8.0
|
|
28
30
|
Provides-Extra: docs
|
|
29
31
|
Requires-Dist: Sphinx>=7.0; extra == "docs"
|
|
@@ -10,9 +10,12 @@ TimeFeatures.egg-info/entry_points.txt
|
|
|
10
10
|
TimeFeatures.egg-info/requires.txt
|
|
11
11
|
TimeFeatures.egg-info/top_level.txt
|
|
12
12
|
docs/Makefile
|
|
13
|
+
docs/changes.rst
|
|
13
14
|
docs/conf.py
|
|
14
15
|
docs/index.rst
|
|
16
|
+
docs/installation.rst
|
|
15
17
|
docs/requirements.txt
|
|
18
|
+
docs/widgets/load-from-db.rst
|
|
16
19
|
docs/widgets/save-to-db.rst
|
|
17
20
|
docs/widgets/time-feature-constructor.rst
|
|
18
21
|
docs/widgets/variable-dependency-graph.rst
|
|
@@ -21,12 +24,17 @@ imgs/workflow.png
|
|
|
21
24
|
timefeatures/__init__.py
|
|
22
25
|
timefeatures/help.py
|
|
23
26
|
timefeatures/help_html/.buildinfo
|
|
27
|
+
timefeatures/help_html/changes.html
|
|
24
28
|
timefeatures/help_html/genindex.html
|
|
25
29
|
timefeatures/help_html/index.html
|
|
30
|
+
timefeatures/help_html/installation.html
|
|
26
31
|
timefeatures/help_html/objects.inv
|
|
27
32
|
timefeatures/help_html/search.html
|
|
28
33
|
timefeatures/help_html/searchindex.js
|
|
34
|
+
timefeatures/help_html/_sources/changes.rst.txt
|
|
29
35
|
timefeatures/help_html/_sources/index.rst.txt
|
|
36
|
+
timefeatures/help_html/_sources/installation.rst.txt
|
|
37
|
+
timefeatures/help_html/_sources/widgets/load-from-db.rst.txt
|
|
30
38
|
timefeatures/help_html/_sources/widgets/save-to-db.rst.txt
|
|
31
39
|
timefeatures/help_html/_sources/widgets/time-feature-constructor.rst.txt
|
|
32
40
|
timefeatures/help_html/_sources/widgets/variable-dependency-graph.rst.txt
|
|
@@ -43,14 +51,17 @@ timefeatures/help_html/_static/plus.png
|
|
|
43
51
|
timefeatures/help_html/_static/pygments.css
|
|
44
52
|
timefeatures/help_html/_static/searchtools.js
|
|
45
53
|
timefeatures/help_html/_static/sphinx_highlight.js
|
|
54
|
+
timefeatures/help_html/widgets/load-from-db.html
|
|
46
55
|
timefeatures/help_html/widgets/save-to-db.html
|
|
47
56
|
timefeatures/help_html/widgets/time-feature-constructor.html
|
|
48
57
|
timefeatures/help_html/widgets/variable-dependency-graph.html
|
|
49
58
|
timefeatures/widgets/__init__.py
|
|
59
|
+
timefeatures/widgets/owloadfromdb.py
|
|
50
60
|
timefeatures/widgets/owsavetodb.py
|
|
51
61
|
timefeatures/widgets/owtimefeaturesconstructor.py
|
|
52
62
|
timefeatures/widgets/owvardependencygraph.py
|
|
53
63
|
timefeatures/widgets/icons/graphgenerator.svg
|
|
64
|
+
timefeatures/widgets/icons/loaddatadb.svg
|
|
54
65
|
timefeatures/widgets/icons/savedatadb.svg
|
|
55
66
|
timefeatures/widgets/icons/timefeature-xs.svg
|
|
56
67
|
timefeatures/widgets/icons/timefeature.svg
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Changelog
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
Unreleased
|
|
5
|
+
----------
|
|
6
|
+
|
|
7
|
+
**Load from DB (new widget)**
|
|
8
|
+
|
|
9
|
+
- Lists every dataset registered in the ``datasets`` metadata table
|
|
10
|
+
via SQLAlchemy and pulls the selected one back into Orange as an
|
|
11
|
+
``Orange.data.Table`` using ``pandas.read_sql`` +
|
|
12
|
+
``Orange.data.pandas_compat.table_from_frame``.
|
|
13
|
+
- Offers a Class column combo populated from the dataset's columns,
|
|
14
|
+
pre-selected with the user's persisted choice or the ``class_name``
|
|
15
|
+
recorded by Save to DB. The output ``Table`` already exposes the
|
|
16
|
+
chosen column as ``domain.class_var``, so no Select Columns widget
|
|
17
|
+
is needed downstream.
|
|
18
|
+
- Same dialect selector (PostgreSQL / MySQL), connection-status
|
|
19
|
+
label and ``QThread`` worker pattern as Save to DB. Both the
|
|
20
|
+
metadata listing and the actual table read happen off the GUI
|
|
21
|
+
thread.
|
|
22
|
+
- Workflow-persisted settings: ``selected_dataset`` and
|
|
23
|
+
``selected_class`` are ``Setting(..., schema_only=True)``, restored
|
|
24
|
+
as soon as the connection comes back up on reload.
|
|
25
|
+
|
|
26
|
+
**Variable Dependency Graph**
|
|
27
|
+
|
|
28
|
+
- *New:* edges now carry **numeric weights** equal to the largest
|
|
29
|
+
``|argument|`` among the temporal calls (``shift``, ``sum``, ``mean``,
|
|
30
|
+
``count``, ``min``, ``max``, ``sd``) in the source expression that
|
|
31
|
+
reference the dependency. Plain (non-temporal) references default to
|
|
32
|
+
weight ``1``. The weights live in ``network.edges[0].edges.data``
|
|
33
|
+
and are consumable by any downstream Network widget.
|
|
34
|
+
- Refactor: flattened the ``from_row_col`` / ``grafo`` decorator pattern
|
|
35
|
+
into a single, documented ``build_dependency_network`` function.
|
|
36
|
+
- Performance: O(n³) → O(n²) by precomputing a ``name → index`` map and
|
|
37
|
+
using a ``set`` to dedupe dependencies.
|
|
38
|
+
- Bugfix: an ``IndexError`` was raised when the input domain had a
|
|
39
|
+
single column. The widget now checks ``len(domain) >= 2`` before
|
|
40
|
+
reading the second column.
|
|
41
|
+
- Removed 65 lines of dead commented-out code.
|
|
42
|
+
|
|
43
|
+
**Time Features Constructor**
|
|
44
|
+
|
|
45
|
+
- *Fixed (critical):* time-window functions used to lose context every
|
|
46
|
+
5 000 rows because Orange chunks tables during ``transform``. The
|
|
47
|
+
widget now caches the full source per ``FeatureFunc`` and returns the
|
|
48
|
+
right slice for each chunk, so ``shift(x, -20)`` is correct across
|
|
49
|
+
chunk boundaries on datasets of any size.
|
|
50
|
+
- *Fixed:* "Variables to generate" was being cleared after every Send
|
|
51
|
+
and on every input change, so workflow save / reload lost the
|
|
52
|
+
definitions. Storage moved from ``ContextSetting`` to
|
|
53
|
+
``Setting(..., schema_only=True)`` (matching upstream Orange v4) and
|
|
54
|
+
the editor is now restored from the persisted descriptors on every
|
|
55
|
+
input. The legacy context handler stays around to migrate old
|
|
56
|
+
workflows.
|
|
57
|
+
- Each **Send** re-transforms the *original* input table instead of the
|
|
58
|
+
cumulative output, removing the implicit "consume on Send" semantics
|
|
59
|
+
and the duplicate-name errors that came with it.
|
|
60
|
+
- ``eval`` hardened: ``__builtins__`` replaced with an empty dict in
|
|
61
|
+
the expression evaluator. Only the curated whitelist
|
|
62
|
+
(safe builtins + ``math`` + selected ``random`` / ``numpy``
|
|
63
|
+
helpers) is exposed.
|
|
64
|
+
- Refactor: ``modificar_expression`` collapsed from 7 near-identical
|
|
65
|
+
loops to a single regex-driven pass.
|
|
66
|
+
- Bugfix: ``FeatureEditor.editorData`` returned the variable name as
|
|
67
|
+
the expression.
|
|
68
|
+
|
|
69
|
+
**Save to DB**
|
|
70
|
+
|
|
71
|
+
- *New:* **MySQL support**. The connection panel now exposes a
|
|
72
|
+
database-type selector (PostgreSQL / MySQL). Per-dialect column
|
|
73
|
+
types and identifier quoting (``"name"`` vs ``\`name\```) live in
|
|
74
|
+
a ``_Dialect`` abstraction.
|
|
75
|
+
- *Performance:* uploads now go through
|
|
76
|
+
``Orange.data.pandas_compat.table_to_frame`` +
|
|
77
|
+
``DataFrame.to_sql(method='multi', chunksize=1000)`` over a
|
|
78
|
+
SQLAlchemy engine. The old row-per-INSERT loop is gone — typical
|
|
79
|
+
speedups are 50-100×, especially over the network. Identifier
|
|
80
|
+
quoting and per-column DDL types are emitted by the SQLAlchemy
|
|
81
|
+
dialect (``DOUBLE_PRECISION`` on PostgreSQL, ``DOUBLE`` on MySQL,
|
|
82
|
+
``DATETIME`` instead of ``TIMESTAMP`` on MySQL to dodge the 2038
|
|
83
|
+
cap, ``VARCHAR(255)`` / ``TEXT`` everywhere else).
|
|
84
|
+
- *UX:* the upload runs in a background ``QThread`` (``_UploadWorker``),
|
|
85
|
+
so the canvas stays interactive on long writes. A status label under
|
|
86
|
+
the connection box reports *Not connected* / *Connected to … : …* /
|
|
87
|
+
*Uploading rows N/M…* / *Upload completed in Xs* / *Upload failed:
|
|
88
|
+
…* with colour cues. **Save**, **Connect** and the form fields are
|
|
89
|
+
disabled while the worker runs and re-enabled on success or
|
|
90
|
+
failure; the widget aborts the thread cleanly on close.
|
|
91
|
+
- *Fixed (critical):* SQL injection in the metadata ``INSERT``. The
|
|
92
|
+
query is now fully parametrised.
|
|
93
|
+
- Added an identifier whitelist
|
|
94
|
+
(``^[A-Za-z_][A-Za-z0-9_]{0,62}$``) and a ``quote_ident`` helper that
|
|
95
|
+
wraps identifiers with PostgreSQL-standard double quotes (with any
|
|
96
|
+
internal ``"`` doubled). Used in every ``CREATE TABLE`` / ``INSERT
|
|
97
|
+
INTO`` that touches user-supplied names.
|
|
98
|
+
- Replaced ``psycopg2`` with ``psycopg2-binary`` in the install
|
|
99
|
+
requirements so installation works on macOS, Linux and Windows
|
|
100
|
+
without a C compiler.
|
|
101
|
+
- ``setup.py`` now declares ``install_requires``; ``pip install`` was
|
|
102
|
+
previously not pulling in any runtime dependency.
|
|
103
|
+
|
|
104
|
+
Testing
|
|
105
|
+
-------
|
|
106
|
+
|
|
107
|
+
The widget suite grew to **92 tests**, covering:
|
|
108
|
+
|
|
109
|
+
- Unit tests for ``modificar_expression``, the time-window helpers,
|
|
110
|
+
``_sanitize_name`` / ``_expression_or_none`` and ``_temporal_weights``.
|
|
111
|
+
- A regression test for the 5 000-row chunk bug
|
|
112
|
+
(``shift(x, -20)`` over a 12 000-row table).
|
|
113
|
+
- ``eval``-safety tests asserting that ``__import__`` / ``open`` raise
|
|
114
|
+
``NameError`` while ``sqrt`` / ``abs`` still resolve.
|
|
115
|
+
- Widget-level tests (via ``Orange.widgets.tests.base.WidgetTest``) for
|
|
116
|
+
descriptor persistence, including an end-to-end
|
|
117
|
+
``settingsHandler.pack_data`` / ``stored_settings=`` round-trip that
|
|
118
|
+
mirrors what Orange does when saving and reopening a ``.ows`` file.
|
|
119
|
+
- Edge-weight tests covering single calls, three-argument families,
|
|
120
|
+
mixed temporal / non-temporal references, max across multiple calls,
|
|
121
|
+
and per-dependency independence.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Sphinx configuration for TimeFeatures."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
7
|
+
sys.path.insert(0, str(ROOT))
|
|
8
|
+
|
|
9
|
+
# -- Project information --------------------------------------------------
|
|
10
|
+
project = "TimeFeatures"
|
|
11
|
+
author = "Alejandro Rivas Garcia"
|
|
12
|
+
copyright = "2026, Alejandro Rivas Garcia"
|
|
13
|
+
release = "1.0.18"
|
|
14
|
+
version = ".".join(release.split(".")[:2])
|
|
15
|
+
|
|
16
|
+
# -- General configuration ------------------------------------------------
|
|
17
|
+
extensions = [
|
|
18
|
+
# Auto-generate :ref: labels from section titles so we can write
|
|
19
|
+
# `:ref:`Edge Weights`` instead of declaring labels by hand.
|
|
20
|
+
"sphinx.ext.autosectionlabel",
|
|
21
|
+
# Link to Orange / NumPy / SciPy reference docs.
|
|
22
|
+
"sphinx.ext.intersphinx",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
# Prefix labels with the document name so two pages can share the same
|
|
26
|
+
# section title (e.g. "Usage Example") without clashing.
|
|
27
|
+
autosectionlabel_prefix_document = True
|
|
28
|
+
|
|
29
|
+
intersphinx_mapping = {
|
|
30
|
+
"python": ("https://docs.python.org/3", None),
|
|
31
|
+
"numpy": ("https://numpy.org/doc/stable/", None),
|
|
32
|
+
"scipy": ("https://docs.scipy.org/doc/scipy/", None),
|
|
33
|
+
"orange": ("https://orange3.readthedocs.io/projects/orange-data-mining-library/en/latest/", None),
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
templates_path = ["_templates"]
|
|
37
|
+
exclude_patterns = ["build", "Thumbs.db", ".DS_Store"]
|
|
38
|
+
|
|
39
|
+
language = "en"
|
|
40
|
+
|
|
41
|
+
# -- HTML output ----------------------------------------------------------
|
|
42
|
+
html_theme = "alabaster"
|
|
43
|
+
html_static_path = []
|
|
44
|
+
html_title = "TimeFeatures documentation"
|
|
45
|
+
html_short_title = "TimeFeatures"
|
|
46
|
+
html_theme_options = {
|
|
47
|
+
"description": (
|
|
48
|
+
"Time-series feature engineering for Orange3: build derived "
|
|
49
|
+
"variables, visualise their dependencies, and persist data to "
|
|
50
|
+
"PostgreSQL."
|
|
51
|
+
),
|
|
52
|
+
"github_user": "alervgr",
|
|
53
|
+
"github_repo": "Orange-TimeFeatures",
|
|
54
|
+
"github_banner": True,
|
|
55
|
+
"show_powered_by": False,
|
|
56
|
+
"fixed_sidebar": True,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Default replacements for any RST file (no need to redeclare per page).
|
|
60
|
+
rst_prolog = """
|
|
61
|
+
.. |addon| replace:: TimeFeatures
|
|
62
|
+
"""
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
TimeFeatures
|
|
2
|
+
============
|
|
3
|
+
|
|
4
|
+
|addon| is an `Orange3 <https://orangedatamining.com/>`_ add-on for
|
|
5
|
+
time-series feature engineering. It ships four widgets that work
|
|
6
|
+
together to define, visualise, persist and re-load derived variables
|
|
7
|
+
built on top of an existing dataset.
|
|
8
|
+
|
|
9
|
+
.. list-table::
|
|
10
|
+
:header-rows: 1
|
|
11
|
+
:widths: 30 70
|
|
12
|
+
|
|
13
|
+
* - Widget
|
|
14
|
+
- What it does
|
|
15
|
+
* - :doc:`widgets/time-feature-constructor`
|
|
16
|
+
- Defines new variables from existing ones using Python-style
|
|
17
|
+
expressions and time-window functions (``shift``, ``sum``,
|
|
18
|
+
``mean``, ``min``, ``max``, ``sd``, ``count``).
|
|
19
|
+
* - :doc:`widgets/variable-dependency-graph`
|
|
20
|
+
- Builds a directed, **weighted** dependency graph from the
|
|
21
|
+
resulting variable / expression table. Edge weights summarise
|
|
22
|
+
how far back or forward in time each variable looks.
|
|
23
|
+
* - :doc:`widgets/save-to-db`
|
|
24
|
+
- Persists the resulting dataset to a SQL database (PostgreSQL
|
|
25
|
+
or MySQL), with full SQL-injection defences and an optional
|
|
26
|
+
completion email.
|
|
27
|
+
* - :doc:`widgets/load-from-db`
|
|
28
|
+
- Lists the datasets previously stored by Save to DB and pulls
|
|
29
|
+
the chosen one back into Orange, optionally marking the class
|
|
30
|
+
column directly so no Select Columns widget is needed.
|
|
31
|
+
|
|
32
|
+
.. _workflow:
|
|
33
|
+
|
|
34
|
+
Workflow
|
|
35
|
+
--------
|
|
36
|
+
|
|
37
|
+
A typical pipeline:
|
|
38
|
+
|
|
39
|
+
.. code-block:: text
|
|
40
|
+
|
|
41
|
+
File → Time Features Constructor → ┬→ <downstream models>
|
|
42
|
+
└→ Variable Dependency Graph
|
|
43
|
+
↓
|
|
44
|
+
Network Explorer
|
|
45
|
+
|
|
46
|
+
The **Time Features Constructor** outputs both the transformed data
|
|
47
|
+
(top arrow) and the variable / expression definition table (bottom
|
|
48
|
+
arrow). Feed the latter into the **Variable Dependency Graph** to
|
|
49
|
+
visualise the dependencies, and send the data into **Save to DB** if
|
|
50
|
+
you want to keep it in a database.
|
|
51
|
+
|
|
52
|
+
Getting started
|
|
53
|
+
---------------
|
|
54
|
+
|
|
55
|
+
.. toctree::
|
|
56
|
+
:maxdepth: 2
|
|
57
|
+
|
|
58
|
+
installation
|
|
59
|
+
|
|
60
|
+
.. _widgets:
|
|
61
|
+
|
|
62
|
+
Widgets
|
|
63
|
+
-------
|
|
64
|
+
|
|
65
|
+
.. toctree::
|
|
66
|
+
:maxdepth: 1
|
|
67
|
+
|
|
68
|
+
widgets/time-feature-constructor
|
|
69
|
+
widgets/variable-dependency-graph
|
|
70
|
+
widgets/save-to-db
|
|
71
|
+
widgets/load-from-db
|
|
72
|
+
|
|
73
|
+
Project
|
|
74
|
+
-------
|
|
75
|
+
|
|
76
|
+
.. toctree::
|
|
77
|
+
:maxdepth: 1
|
|
78
|
+
|
|
79
|
+
changes
|
|
80
|
+
|
|
81
|
+
Building this documentation
|
|
82
|
+
---------------------------
|
|
83
|
+
|
|
84
|
+
.. code-block:: bash
|
|
85
|
+
|
|
86
|
+
pip install -e ".[docs]"
|
|
87
|
+
python -m sphinx -b html docs docs/build/html
|
|
88
|
+
|
|
89
|
+
The HTML build is also bundled with the wheel so Orange's in-app help
|
|
90
|
+
panel can resolve every widget's *Help* action without internet
|
|
91
|
+
access.
|
|
92
|
+
|
|
93
|
+
Indices
|
|
94
|
+
-------
|
|
95
|
+
|
|
96
|
+
* :ref:`genindex`
|
|
97
|
+
* :ref:`search`
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Installation
|
|
2
|
+
============
|
|
3
|
+
|
|
4
|
+
|addon| is an Orange3 add-on, so it requires a working Orange3
|
|
5
|
+
installation in the same Python environment.
|
|
6
|
+
|
|
7
|
+
From PyPI
|
|
8
|
+
---------
|
|
9
|
+
|
|
10
|
+
.. code-block:: bash
|
|
11
|
+
|
|
12
|
+
pip install TimeFeatures
|
|
13
|
+
|
|
14
|
+
This pulls in every runtime dependency, including the precompiled
|
|
15
|
+
``psycopg2-binary`` wheel so the **Save to DB** widget works on macOS,
|
|
16
|
+
Linux and Windows without a C toolchain.
|
|
17
|
+
|
|
18
|
+
From source
|
|
19
|
+
-----------
|
|
20
|
+
|
|
21
|
+
.. code-block:: bash
|
|
22
|
+
|
|
23
|
+
git clone https://github.com/alervgr/Orange-TimeFeatures.git
|
|
24
|
+
cd Orange-TimeFeatures
|
|
25
|
+
pip install -e .
|
|
26
|
+
|
|
27
|
+
The ``-e`` flag installs in *editable* mode so changes to the source
|
|
28
|
+
tree are picked up on the next Orange restart without reinstalling.
|
|
29
|
+
|
|
30
|
+
Inside Orange
|
|
31
|
+
-------------
|
|
32
|
+
|
|
33
|
+
|addon| also installs through Orange's GUI:
|
|
34
|
+
|
|
35
|
+
1. Open Orange.
|
|
36
|
+
2. Go to **Options → Add-ons…**.
|
|
37
|
+
3. Tick **TimeFeatures** in the list and confirm.
|
|
38
|
+
4. Restart Orange. The new widgets appear under the **Time-Features**
|
|
39
|
+
toolbox section.
|
|
40
|
+
|
|
41
|
+
.. image:: https://github.com/alervgr/Orange-TimeFeatures/blob/main/imgs/installation.png?raw=true
|
|
42
|
+
:alt: TimeFeatures in Orange's Add-on installer.
|
|
43
|
+
|
|
44
|
+
Anaconda
|
|
45
|
+
--------
|
|
46
|
+
|
|
47
|
+
The same ``pip install TimeFeatures`` command works inside a Conda
|
|
48
|
+
environment as long as Orange3 is installed there.
|
|
49
|
+
|
|
50
|
+
Dependencies
|
|
51
|
+
------------
|
|
52
|
+
|
|
53
|
+
|addon| declares the following runtime dependencies (see
|
|
54
|
+
``setup.py``):
|
|
55
|
+
|
|
56
|
+
.. list-table::
|
|
57
|
+
:header-rows: 1
|
|
58
|
+
|
|
59
|
+
* - Package
|
|
60
|
+
- Minimum version
|
|
61
|
+
- Used by
|
|
62
|
+
* - ``numpy``
|
|
63
|
+
- 1.22.4
|
|
64
|
+
- All widgets.
|
|
65
|
+
* - ``scipy``
|
|
66
|
+
- 1.7.3
|
|
67
|
+
- Sparse adjacency matrices in the dependency graph.
|
|
68
|
+
* - ``PyQt5``
|
|
69
|
+
- 5.15.6
|
|
70
|
+
- Widget UI.
|
|
71
|
+
* - ``AnyQt``
|
|
72
|
+
- 0.2.0
|
|
73
|
+
- Qt abstraction used by Orange.
|
|
74
|
+
* - ``SQLAlchemy``
|
|
75
|
+
- 1.4.0
|
|
76
|
+
- Dialect-agnostic SQL toolkit used by **Save to DB**.
|
|
77
|
+
* - ``psycopg2-binary``
|
|
78
|
+
- 2.9.9
|
|
79
|
+
- PostgreSQL driver for **Save to DB**.
|
|
80
|
+
* - ``PyMySQL``
|
|
81
|
+
- 1.0.0
|
|
82
|
+
- MySQL driver for **Save to DB**.
|
|
83
|
+
* - ``Orange3-Network``
|
|
84
|
+
- 1.8.0
|
|
85
|
+
- ``Network`` type produced by **Variable Dependency Graph**.
|
|
86
|
+
|
|
87
|
+
Orange3 itself is intentionally left out of the requirements list — the
|
|
88
|
+
host application provides it.
|
|
89
|
+
|
|
90
|
+
Running tests
|
|
91
|
+
-------------
|
|
92
|
+
|
|
93
|
+
The test suite uses ``unittest`` and lives under
|
|
94
|
+
``timefeatures/widgets/tests/``. From a checkout:
|
|
95
|
+
|
|
96
|
+
.. code-block:: bash
|
|
97
|
+
|
|
98
|
+
pip install -e .
|
|
99
|
+
python -m unittest discover -v timefeatures/widgets/tests
|
|
100
|
+
|
|
101
|
+
The widget-level tests inherit from ``Orange.widgets.tests.base.WidgetTest``
|
|
102
|
+
and therefore require Qt; a virtual display (``Xvfb``) is enough on a
|
|
103
|
+
headless CI worker.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Load from DB
|
|
2
|
+
============
|
|
3
|
+
|
|
4
|
+
The **Load from DB** widget is the inverse of :doc:`save-to-db`. It
|
|
5
|
+
connects to a SQL database, lists the datasets previously persisted by
|
|
6
|
+
**Save to DB**, and pulls the selected one back into Orange as a
|
|
7
|
+
``Table`` — optionally marking the class column on the fly so no
|
|
8
|
+
**Select Columns** widget is needed downstream.
|
|
9
|
+
|
|
10
|
+
Inputs
|
|
11
|
+
------
|
|
12
|
+
|
|
13
|
+
This widget has no input signals.
|
|
14
|
+
|
|
15
|
+
Outputs
|
|
16
|
+
-------
|
|
17
|
+
|
|
18
|
+
.. list-table::
|
|
19
|
+
:header-rows: 1
|
|
20
|
+
|
|
21
|
+
* - Signal
|
|
22
|
+
- Type
|
|
23
|
+
- Description
|
|
24
|
+
* - Data
|
|
25
|
+
- ``Orange.data.Table``
|
|
26
|
+
- The loaded dataset. If the user picks a class column, the
|
|
27
|
+
resulting domain already exposes it as the class variable; all
|
|
28
|
+
other columns stay in ``domain.attributes`` and the metas
|
|
29
|
+
declared in the SQL schema (if any) remain as ``domain.metas``.
|
|
30
|
+
|
|
31
|
+
Controls
|
|
32
|
+
--------
|
|
33
|
+
|
|
34
|
+
.. list-table::
|
|
35
|
+
:header-rows: 1
|
|
36
|
+
|
|
37
|
+
* - Field
|
|
38
|
+
- Description
|
|
39
|
+
* - Database type
|
|
40
|
+
- Combo box at the top of the connection box. Pick **PostgreSQL**
|
|
41
|
+
or **MySQL**. The driver and quoting rules adapt automatically
|
|
42
|
+
through the same :class:`_Dialect` abstraction the **Save to
|
|
43
|
+
DB** widget uses.
|
|
44
|
+
* - Connection status
|
|
45
|
+
- Small label under the connection box. Shows three states:
|
|
46
|
+
neutral ("Not connected", "Connecting…", "Listing datasets…",
|
|
47
|
+
"Loading <name>…"), success ("Connected to PostgreSQL:
|
|
48
|
+
host/db (N datasets)", "Loaded <name> (N rows)"), error
|
|
49
|
+
("Connection failed: …", "Load failed: …").
|
|
50
|
+
* - Dataset
|
|
51
|
+
- Combo populated from ``SELECT * FROM datasets ORDER BY
|
|
52
|
+
datetime DESC``. The most recent upload comes first; the last
|
|
53
|
+
choice is restored when reopening a workflow.
|
|
54
|
+
* - Dataset info
|
|
55
|
+
- Read-only block under the combo: save timestamp, row/column
|
|
56
|
+
counts and the original class column recorded by **Save to DB**.
|
|
57
|
+
* - Class column
|
|
58
|
+
- Combo with every column of the selected dataset plus a
|
|
59
|
+
``(no class)`` sentinel. Defaults to (1) the user's persisted
|
|
60
|
+
choice, (2) the ``class_name`` stored in the ``datasets``
|
|
61
|
+
metadata, (3) ``(no class)`` if none of the above apply.
|
|
62
|
+
* - Load
|
|
63
|
+
- Triggers the actual download.
|
|
64
|
+
|
|
65
|
+
How it Works
|
|
66
|
+
------------
|
|
67
|
+
|
|
68
|
+
When the **Connect** button is clicked, the widget validates the
|
|
69
|
+
connection through ``OWBaseSql`` (the same path Save to DB uses) and
|
|
70
|
+
then spawns a background ``QThread`` that runs a
|
|
71
|
+
``_ListDatasetsWorker``. The worker queries the ``datasets`` metadata
|
|
72
|
+
table via SQLAlchemy and emits the result back to the GUI thread.
|
|
73
|
+
|
|
74
|
+
Selecting a dataset triggers a tiny ``SELECT * FROM <name> LIMIT 0``
|
|
75
|
+
to fetch the column list — this is cheap enough to run synchronously
|
|
76
|
+
because the server only returns the column header.
|
|
77
|
+
|
|
78
|
+
When **Load** is clicked, a ``_LoadTableWorker`` runs
|
|
79
|
+
``pandas.read_sql("SELECT * FROM <name>", engine)`` on a background
|
|
80
|
+
thread, returning a DataFrame that the GUI thread converts into an
|
|
81
|
+
``Orange.data.Table`` with
|
|
82
|
+
``Orange.data.pandas_compat.table_from_frame``. If the user picked a
|
|
83
|
+
class column, the helper ``_build_domain_with_class`` rebuilds the
|
|
84
|
+
domain so that column becomes ``domain.class_var`` and the rest of the
|
|
85
|
+
columns stay in ``domain.attributes``.
|
|
86
|
+
|
|
87
|
+
While any worker runs, the form controls (database type, connection
|
|
88
|
+
fields, **Connect**, **Load**, dataset and class combos) are
|
|
89
|
+
temporarily disabled and the status label keeps the user informed.
|
|
90
|
+
|
|
91
|
+
Workflow Persistence
|
|
92
|
+
--------------------
|
|
93
|
+
|
|
94
|
+
Two ``Setting``\\s are persisted with the workflow:
|
|
95
|
+
|
|
96
|
+
- ``selected_dataset`` — the name picked in the Dataset combo.
|
|
97
|
+
- ``selected_class`` — the name picked in the Class combo
|
|
98
|
+
(``""`` means "no class").
|
|
99
|
+
|
|
100
|
+
Both are declared as ``Setting(..., schema_only=True)``, mirroring the
|
|
101
|
+
**Time Features Constructor** convention: the values live in the
|
|
102
|
+
``.ows`` file but never become global defaults. On reopening a
|
|
103
|
+
workflow, the widget restores the choices as soon as the connection
|
|
104
|
+
succeeds and the dataset list arrives.
|
|
105
|
+
|
|
106
|
+
Usage Example
|
|
107
|
+
-------------
|
|
108
|
+
|
|
109
|
+
Round-tripping a dataset through the database:
|
|
110
|
+
|
|
111
|
+
1. In one Orange workflow, attach a **File** widget to **Save to DB**
|
|
112
|
+
and upload the data with a chosen table name.
|
|
113
|
+
2. In another workflow (or the same one), drop a **Load from DB**
|
|
114
|
+
widget.
|
|
115
|
+
3. Pick the database type, fill in the connection fields, and click
|
|
116
|
+
**Connect**.
|
|
117
|
+
4. Pick the dataset in the Dataset combo. The info block shows the
|
|
118
|
+
timestamp and the original class.
|
|
119
|
+
5. Override the Class column if you want a different target, or leave
|
|
120
|
+
the default to keep the original one.
|
|
121
|
+
6. Click **Load**. The table flows out of the **Data** output ready
|
|
122
|
+
for any downstream Orange widget — no **Select Columns** in
|
|
123
|
+
between.
|
|
124
|
+
|
|
125
|
+
Requirements
|
|
126
|
+
------------
|
|
127
|
+
|
|
128
|
+
|addon| brings every dependency the widget needs:
|
|
129
|
+
|
|
130
|
+
.. code-block:: text
|
|
131
|
+
|
|
132
|
+
SQLAlchemy>=1.4.0 # dialect-agnostic SQL toolkit
|
|
133
|
+
psycopg2-binary>=2.9.9 # PostgreSQL driver
|
|
134
|
+
PyMySQL>=1.0.0 # MySQL driver
|
|
135
|
+
|
|
136
|
+
``pandas`` itself is a transitive dependency of Orange3.
|