TimeFeatures 2.0.0__tar.gz → 2.1.1__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.1}/PKG-INFO +42 -25
- timefeatures-2.1.1/README.md +101 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1/TimeFeatures.egg-info}/PKG-INFO +42 -25
- {timefeatures-2.0.0 → timefeatures-2.1.1}/TimeFeatures.egg-info/SOURCES.txt +10 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/changes.rst +48 -2
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/conf.py +6 -2
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/index.rst +9 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/widgets/load-from-db.rst +45 -4
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/widgets/save-to-db.rst +46 -6
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/widgets/time-feature-constructor.rst +32 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/widgets/variable-dependency-graph.rst +22 -3
- timefeatures-2.1.1/imgs/installation.png +0 -0
- timefeatures-2.1.1/imgs/widgets/owloadfromdb.png +0 -0
- timefeatures-2.1.1/imgs/widgets/owsavetodb.png +0 -0
- timefeatures-2.1.1/imgs/widgets/owtimefeaturesconstructor.png +0 -0
- timefeatures-2.1.1/imgs/widgets/owvariabledependencygraph.png +0 -0
- timefeatures-2.1.1/imgs/workflow.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/setup.py +12 -2
- timefeatures-2.1.1/timefeatures/__init__.py +5 -0
- timefeatures-2.1.1/timefeatures/__version__.py +3 -0
- timefeatures-2.1.1/timefeatures/help_html/.buildinfo +4 -0
- timefeatures-2.1.1/timefeatures/help_html/_images/owloadfromdb.png +0 -0
- timefeatures-2.1.1/timefeatures/help_html/_images/owsavetodb.png +0 -0
- timefeatures-2.1.1/timefeatures/help_html/_images/owtimefeaturesconstructor.png +0 -0
- timefeatures-2.1.1/timefeatures/help_html/_images/owvariabledependencygraph.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_sources/changes.rst.txt +48 -2
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_sources/index.rst.txt +9 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_sources/widgets/load-from-db.rst.txt +45 -4
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_sources/widgets/save-to-db.rst.txt +46 -6
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_sources/widgets/time-feature-constructor.rst.txt +32 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_sources/widgets/variable-dependency-graph.rst.txt +22 -3
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/documentation_options.js +1 -1
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/changes.html +50 -4
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/genindex.html +2 -2
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/index.html +8 -2
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/installation.html +2 -2
- timefeatures-2.1.1/timefeatures/help_html/objects.inv +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/search.html +2 -2
- timefeatures-2.1.1/timefeatures/help_html/searchindex.js +1 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/widgets/load-from-db.html +49 -6
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/widgets/save-to-db.html +53 -9
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/widgets/time-feature-constructor.html +33 -2
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/widgets/variable-dependency-graph.html +27 -5
- timefeatures-2.1.1/timefeatures/widgets/icons/loaddatadb.svg +1 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/widgets/owloadfromdb.py +206 -7
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/widgets/owsavetodb.py +182 -146
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/widgets/owtimefeaturesconstructor.py +141 -26
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/widgets/owvardependencygraph.py +74 -34
- timefeatures-2.0.0/README.md +0 -84
- timefeatures-2.0.0/imgs/installation.png +0 -0
- timefeatures-2.0.0/imgs/workflow.png +0 -0
- timefeatures-2.0.0/timefeatures/__init__.py +0 -0
- 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.1}/LICENSE +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/MANIFEST.in +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/TimeFeatures.egg-info/dependency_links.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/TimeFeatures.egg-info/entry_points.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/TimeFeatures.egg-info/requires.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/TimeFeatures.egg-info/top_level.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/Makefile +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/installation.rst +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/docs/requirements.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/setup.cfg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help.py +0 -0
- /timefeatures-2.0.0/timefeatures/help_html/.buildinfo → /timefeatures-2.1.1/timefeatures/help_html/.buildinfo.bak +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_sources/installation.rst.txt +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/alabaster.css +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/basic.css +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/custom.css +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/doctools.js +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/file.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/github-banner.svg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/language_data.js +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/minus.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/plus.png +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/pygments.css +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/searchtools.js +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/help_html/_static/sphinx_highlight.js +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/widgets/__init__.py +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/widgets/icons/graphgenerator.svg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/widgets/icons/savedatadb.svg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/timefeatures/widgets/icons/timefeature-xs.svg +0 -0
- {timefeatures-2.0.0 → timefeatures-2.1.1}/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.1
|
|
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
|
|
@@ -42,15 +42,37 @@ Dynamic: provides-extra
|
|
|
42
42
|
Dynamic: requires-dist
|
|
43
43
|
Dynamic: summary
|
|
44
44
|
|
|
45
|
-
Orange3 TimeFeatures
|
|
46
|
-
===============
|
|
45
|
+
# Orange3 TimeFeatures
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
[](https://pypi.org/project/TimeFeatures/)
|
|
48
|
+
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
49
|
+
[](https://www.python.org/downloads/)
|
|
50
|
+
[](https://orangedatamining.com/)
|
|
51
|
+
|
|
52
|
+
TimeFeatures is an add-on for [Orange] 3 data mining software for generating synthetic data using datasets with time series, generating graphs of relationships between the generated variables, and includes widgets to save and load data and configuration tables from a database.
|
|
49
53
|
|
|
50
54
|
[Orange]: https://orangedatamining.com/
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
## Features
|
|
57
|
+
|
|
58
|
+
- 🕐 **7 time-window functions** — `shift`, `sum`, `mean`, `min`, `max`, `count`, `sd` with full chunk-boundary correctness
|
|
59
|
+
- 🔗 **Chained descriptors** — derived variables can reference each other; topological sort resolves the evaluation order automatically
|
|
60
|
+
- 🛡️ **Secure evaluation** — expressions run in a restricted `eval` sandbox (`__builtins__` replaced, curated whitelist only)
|
|
61
|
+
- 🗄️ **PostgreSQL & MySQL** — persist and reload datasets via SQLAlchemy with dialect-agnostic SQL generation
|
|
62
|
+
- 📊 **Directed weighted dependency graphs** — edge weights reflect temporal window size; visualise in Network Explorer
|
|
63
|
+
- ⚡ **Bulk upload performance** — pandas `DataFrame.to_sql` with chunked multi-row INSERTs
|
|
64
|
+
- 💾 **Workflow persistence** — variable definitions survive save/reload without clicking Send first
|
|
65
|
+
|
|
66
|
+
## Widgets
|
|
67
|
+
|
|
68
|
+
| Widget | Description |
|
|
69
|
+
|---|---|
|
|
70
|
+
| **Time Features Constructor** | Defines new variables from existing ones using Python-style expressions and time-window functions. Supports chained descriptors with automatic topological sorting. |
|
|
71
|
+
| **Variable Dependency Graph** | Builds a directed, weighted dependency graph from the variable definitions. Edge weights summarise how far back or forward in time each variable looks. |
|
|
72
|
+
| **Save to DB** | Persists the resulting dataset to a SQL database (PostgreSQL or MySQL), with full SQL-injection defences, three write modes (create / overwrite / append) and an optional completion email. |
|
|
73
|
+
| **Load from DB** | Lists datasets previously stored by Save to DB and pulls the chosen one back into Orange, optionally marking the class column directly so no Select Columns widget is needed. |
|
|
74
|
+
|
|
75
|
+
## Installation
|
|
54
76
|
|
|
55
77
|
### Orange add-on installer
|
|
56
78
|
|
|
@@ -64,21 +86,10 @@ To install the add-on with pip use
|
|
|
64
86
|
|
|
65
87
|
pip install TimeFeatures
|
|
66
88
|
|
|
67
|
-
To install the add-on from source, run
|
|
68
|
-
|
|
69
|
-
python setup.py install
|
|
70
|
-
|
|
71
|
-
To register this add-on with Orange, but keep the code in the development directory (do not copy it to
|
|
72
|
-
Python's site-packages directory), run
|
|
73
|
-
|
|
74
|
-
python setup.py develop
|
|
75
|
-
|
|
76
|
-
You can also run
|
|
89
|
+
To install the add-on from source in editable mode, run
|
|
77
90
|
|
|
78
91
|
pip install -e .
|
|
79
92
|
|
|
80
|
-
which is sometimes preferable as you can *pip uninstall* packages later.
|
|
81
|
-
|
|
82
93
|
### Anaconda
|
|
83
94
|
|
|
84
95
|
If using Anaconda Python distribution, simply run
|
|
@@ -86,16 +97,18 @@ If using Anaconda Python distribution, simply run
|
|
|
86
97
|
pip install TimeFeatures
|
|
87
98
|
|
|
88
99
|
**Required Dependencies**:
|
|
100
|
+
|
|
89
101
|
* numpy>=1.22.4
|
|
90
102
|
* AnyQt>=0.2.0
|
|
91
|
-
* Orange3>=3.34.0
|
|
92
103
|
* PyQt5>=5.15.6
|
|
93
104
|
* PyQtWebEngine>=5.15.6
|
|
94
105
|
* scipy>=1.7.3
|
|
106
|
+
* SQLAlchemy>=1.4.0
|
|
107
|
+
* psycopg2-binary>=2.9.9
|
|
108
|
+
* PyMySQL>=1.0.0
|
|
95
109
|
* Orange3-Network>=1.8.0
|
|
96
110
|
|
|
97
|
-
Usage
|
|
98
|
-
-----
|
|
111
|
+
## Usage
|
|
99
112
|
|
|
100
113
|
After the installation, the widgets from this add-on are registered with Orange. To run Orange from the terminal,
|
|
101
114
|
use
|
|
@@ -108,21 +121,25 @@ or
|
|
|
108
121
|
|
|
109
122
|
New widgets are in the toolbox bar under Time-Features section.
|
|
110
123
|
|
|
111
|
-
Documentation
|
|
112
|
-
-------------
|
|
124
|
+
## Documentation
|
|
113
125
|
|
|
114
126
|
The add-on includes Sphinx documentation for each widget. Orange resolves the
|
|
115
127
|
local HTML pages through its internal Help panel, not through an internet URL.
|
|
116
128
|
To rebuild the documentation locally, run
|
|
117
129
|
|
|
118
130
|
pip install -e ".[docs]"
|
|
131
|
+
python -m sphinx -b html docs docs/build/html
|
|
132
|
+
|
|
133
|
+
The bundled in-app help is pre-built under `timefeatures/help_html/`. To
|
|
134
|
+
regenerate it (e.g. after editing the `.rst` files), run
|
|
135
|
+
|
|
119
136
|
python -m sphinx -b html docs timefeatures/help_html
|
|
120
137
|
|
|
121
138
|
Use the widget help action in Orange to open the corresponding page inside the
|
|
122
139
|
Orange Help window.
|
|
123
140
|
|
|
124
|
-
Workflow Example
|
|
125
|
-
|
|
141
|
+
## Workflow Example
|
|
142
|
+
|
|
126
143
|
This is an example of how you can use this add-on.
|
|
127
144
|
|
|
128
145
|

|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Orange3 TimeFeatures
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/TimeFeatures/)
|
|
4
|
+
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
[](https://orangedatamining.com/)
|
|
7
|
+
|
|
8
|
+
TimeFeatures is an add-on for [Orange] 3 data mining software for generating synthetic data using datasets with time series, generating graphs of relationships between the generated variables, and includes widgets to save and load data and configuration tables from a database.
|
|
9
|
+
|
|
10
|
+
[Orange]: https://orangedatamining.com/
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- 🕐 **7 time-window functions** — `shift`, `sum`, `mean`, `min`, `max`, `count`, `sd` with full chunk-boundary correctness
|
|
15
|
+
- 🔗 **Chained descriptors** — derived variables can reference each other; topological sort resolves the evaluation order automatically
|
|
16
|
+
- 🛡️ **Secure evaluation** — expressions run in a restricted `eval` sandbox (`__builtins__` replaced, curated whitelist only)
|
|
17
|
+
- 🗄️ **PostgreSQL & MySQL** — persist and reload datasets via SQLAlchemy with dialect-agnostic SQL generation
|
|
18
|
+
- 📊 **Directed weighted dependency graphs** — edge weights reflect temporal window size; visualise in Network Explorer
|
|
19
|
+
- ⚡ **Bulk upload performance** — pandas `DataFrame.to_sql` with chunked multi-row INSERTs
|
|
20
|
+
- 💾 **Workflow persistence** — variable definitions survive save/reload without clicking Send first
|
|
21
|
+
|
|
22
|
+
## Widgets
|
|
23
|
+
|
|
24
|
+
| Widget | Description |
|
|
25
|
+
|---|---|
|
|
26
|
+
| **Time Features Constructor** | Defines new variables from existing ones using Python-style expressions and time-window functions. Supports chained descriptors with automatic topological sorting. |
|
|
27
|
+
| **Variable Dependency Graph** | Builds a directed, weighted dependency graph from the variable definitions. Edge weights summarise how far back or forward in time each variable looks. |
|
|
28
|
+
| **Save to DB** | Persists the resulting dataset to a SQL database (PostgreSQL or MySQL), with full SQL-injection defences, three write modes (create / overwrite / append) and an optional completion email. |
|
|
29
|
+
| **Load from DB** | Lists datasets previously stored by Save to DB and pulls the chosen one back into Orange, optionally marking the class column directly so no Select Columns widget is needed. |
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
### Orange add-on installer
|
|
34
|
+
|
|
35
|
+
Install from Orange add-on installer through Options -> Add-ons.
|
|
36
|
+
|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
### Using pip
|
|
40
|
+
|
|
41
|
+
To install the add-on with pip use
|
|
42
|
+
|
|
43
|
+
pip install TimeFeatures
|
|
44
|
+
|
|
45
|
+
To install the add-on from source in editable mode, run
|
|
46
|
+
|
|
47
|
+
pip install -e .
|
|
48
|
+
|
|
49
|
+
### Anaconda
|
|
50
|
+
|
|
51
|
+
If using Anaconda Python distribution, simply run
|
|
52
|
+
|
|
53
|
+
pip install TimeFeatures
|
|
54
|
+
|
|
55
|
+
**Required Dependencies**:
|
|
56
|
+
|
|
57
|
+
* numpy>=1.22.4
|
|
58
|
+
* AnyQt>=0.2.0
|
|
59
|
+
* PyQt5>=5.15.6
|
|
60
|
+
* PyQtWebEngine>=5.15.6
|
|
61
|
+
* scipy>=1.7.3
|
|
62
|
+
* SQLAlchemy>=1.4.0
|
|
63
|
+
* psycopg2-binary>=2.9.9
|
|
64
|
+
* PyMySQL>=1.0.0
|
|
65
|
+
* Orange3-Network>=1.8.0
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
After the installation, the widgets from this add-on are registered with Orange. To run Orange from the terminal,
|
|
70
|
+
use
|
|
71
|
+
|
|
72
|
+
orange-canvas
|
|
73
|
+
|
|
74
|
+
or
|
|
75
|
+
|
|
76
|
+
python3 -m Orange.canvas
|
|
77
|
+
|
|
78
|
+
New widgets are in the toolbox bar under Time-Features section.
|
|
79
|
+
|
|
80
|
+
## Documentation
|
|
81
|
+
|
|
82
|
+
The add-on includes Sphinx documentation for each widget. Orange resolves the
|
|
83
|
+
local HTML pages through its internal Help panel, not through an internet URL.
|
|
84
|
+
To rebuild the documentation locally, run
|
|
85
|
+
|
|
86
|
+
pip install -e ".[docs]"
|
|
87
|
+
python -m sphinx -b html docs docs/build/html
|
|
88
|
+
|
|
89
|
+
The bundled in-app help is pre-built under `timefeatures/help_html/`. To
|
|
90
|
+
regenerate it (e.g. after editing the `.rst` files), run
|
|
91
|
+
|
|
92
|
+
python -m sphinx -b html docs timefeatures/help_html
|
|
93
|
+
|
|
94
|
+
Use the widget help action in Orange to open the corresponding page inside the
|
|
95
|
+
Orange Help window.
|
|
96
|
+
|
|
97
|
+
## Workflow Example
|
|
98
|
+
|
|
99
|
+
This is an example of how you can use this add-on.
|
|
100
|
+
|
|
101
|
+

|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: TimeFeatures
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.1
|
|
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
|
|
@@ -42,15 +42,37 @@ Dynamic: provides-extra
|
|
|
42
42
|
Dynamic: requires-dist
|
|
43
43
|
Dynamic: summary
|
|
44
44
|
|
|
45
|
-
Orange3 TimeFeatures
|
|
46
|
-
===============
|
|
45
|
+
# Orange3 TimeFeatures
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
[](https://pypi.org/project/TimeFeatures/)
|
|
48
|
+
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
49
|
+
[](https://www.python.org/downloads/)
|
|
50
|
+
[](https://orangedatamining.com/)
|
|
51
|
+
|
|
52
|
+
TimeFeatures is an add-on for [Orange] 3 data mining software for generating synthetic data using datasets with time series, generating graphs of relationships between the generated variables, and includes widgets to save and load data and configuration tables from a database.
|
|
49
53
|
|
|
50
54
|
[Orange]: https://orangedatamining.com/
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
## Features
|
|
57
|
+
|
|
58
|
+
- 🕐 **7 time-window functions** — `shift`, `sum`, `mean`, `min`, `max`, `count`, `sd` with full chunk-boundary correctness
|
|
59
|
+
- 🔗 **Chained descriptors** — derived variables can reference each other; topological sort resolves the evaluation order automatically
|
|
60
|
+
- 🛡️ **Secure evaluation** — expressions run in a restricted `eval` sandbox (`__builtins__` replaced, curated whitelist only)
|
|
61
|
+
- 🗄️ **PostgreSQL & MySQL** — persist and reload datasets via SQLAlchemy with dialect-agnostic SQL generation
|
|
62
|
+
- 📊 **Directed weighted dependency graphs** — edge weights reflect temporal window size; visualise in Network Explorer
|
|
63
|
+
- ⚡ **Bulk upload performance** — pandas `DataFrame.to_sql` with chunked multi-row INSERTs
|
|
64
|
+
- 💾 **Workflow persistence** — variable definitions survive save/reload without clicking Send first
|
|
65
|
+
|
|
66
|
+
## Widgets
|
|
67
|
+
|
|
68
|
+
| Widget | Description |
|
|
69
|
+
|---|---|
|
|
70
|
+
| **Time Features Constructor** | Defines new variables from existing ones using Python-style expressions and time-window functions. Supports chained descriptors with automatic topological sorting. |
|
|
71
|
+
| **Variable Dependency Graph** | Builds a directed, weighted dependency graph from the variable definitions. Edge weights summarise how far back or forward in time each variable looks. |
|
|
72
|
+
| **Save to DB** | Persists the resulting dataset to a SQL database (PostgreSQL or MySQL), with full SQL-injection defences, three write modes (create / overwrite / append) and an optional completion email. |
|
|
73
|
+
| **Load from DB** | Lists datasets previously stored by Save to DB and pulls the chosen one back into Orange, optionally marking the class column directly so no Select Columns widget is needed. |
|
|
74
|
+
|
|
75
|
+
## Installation
|
|
54
76
|
|
|
55
77
|
### Orange add-on installer
|
|
56
78
|
|
|
@@ -64,21 +86,10 @@ To install the add-on with pip use
|
|
|
64
86
|
|
|
65
87
|
pip install TimeFeatures
|
|
66
88
|
|
|
67
|
-
To install the add-on from source, run
|
|
68
|
-
|
|
69
|
-
python setup.py install
|
|
70
|
-
|
|
71
|
-
To register this add-on with Orange, but keep the code in the development directory (do not copy it to
|
|
72
|
-
Python's site-packages directory), run
|
|
73
|
-
|
|
74
|
-
python setup.py develop
|
|
75
|
-
|
|
76
|
-
You can also run
|
|
89
|
+
To install the add-on from source in editable mode, run
|
|
77
90
|
|
|
78
91
|
pip install -e .
|
|
79
92
|
|
|
80
|
-
which is sometimes preferable as you can *pip uninstall* packages later.
|
|
81
|
-
|
|
82
93
|
### Anaconda
|
|
83
94
|
|
|
84
95
|
If using Anaconda Python distribution, simply run
|
|
@@ -86,16 +97,18 @@ If using Anaconda Python distribution, simply run
|
|
|
86
97
|
pip install TimeFeatures
|
|
87
98
|
|
|
88
99
|
**Required Dependencies**:
|
|
100
|
+
|
|
89
101
|
* numpy>=1.22.4
|
|
90
102
|
* AnyQt>=0.2.0
|
|
91
|
-
* Orange3>=3.34.0
|
|
92
103
|
* PyQt5>=5.15.6
|
|
93
104
|
* PyQtWebEngine>=5.15.6
|
|
94
105
|
* scipy>=1.7.3
|
|
106
|
+
* SQLAlchemy>=1.4.0
|
|
107
|
+
* psycopg2-binary>=2.9.9
|
|
108
|
+
* PyMySQL>=1.0.0
|
|
95
109
|
* Orange3-Network>=1.8.0
|
|
96
110
|
|
|
97
|
-
Usage
|
|
98
|
-
-----
|
|
111
|
+
## Usage
|
|
99
112
|
|
|
100
113
|
After the installation, the widgets from this add-on are registered with Orange. To run Orange from the terminal,
|
|
101
114
|
use
|
|
@@ -108,21 +121,25 @@ or
|
|
|
108
121
|
|
|
109
122
|
New widgets are in the toolbox bar under Time-Features section.
|
|
110
123
|
|
|
111
|
-
Documentation
|
|
112
|
-
-------------
|
|
124
|
+
## Documentation
|
|
113
125
|
|
|
114
126
|
The add-on includes Sphinx documentation for each widget. Orange resolves the
|
|
115
127
|
local HTML pages through its internal Help panel, not through an internet URL.
|
|
116
128
|
To rebuild the documentation locally, run
|
|
117
129
|
|
|
118
130
|
pip install -e ".[docs]"
|
|
131
|
+
python -m sphinx -b html docs docs/build/html
|
|
132
|
+
|
|
133
|
+
The bundled in-app help is pre-built under `timefeatures/help_html/`. To
|
|
134
|
+
regenerate it (e.g. after editing the `.rst` files), run
|
|
135
|
+
|
|
119
136
|
python -m sphinx -b html docs timefeatures/help_html
|
|
120
137
|
|
|
121
138
|
Use the widget help action in Orange to open the corresponding page inside the
|
|
122
139
|
Orange Help window.
|
|
123
140
|
|
|
124
|
-
Workflow Example
|
|
125
|
-
|
|
141
|
+
## Workflow Example
|
|
142
|
+
|
|
126
143
|
This is an example of how you can use this add-on.
|
|
127
144
|
|
|
128
145
|

|
|
@@ -21,9 +21,15 @@ docs/widgets/time-feature-constructor.rst
|
|
|
21
21
|
docs/widgets/variable-dependency-graph.rst
|
|
22
22
|
imgs/installation.png
|
|
23
23
|
imgs/workflow.png
|
|
24
|
+
imgs/widgets/owloadfromdb.png
|
|
25
|
+
imgs/widgets/owsavetodb.png
|
|
26
|
+
imgs/widgets/owtimefeaturesconstructor.png
|
|
27
|
+
imgs/widgets/owvariabledependencygraph.png
|
|
24
28
|
timefeatures/__init__.py
|
|
29
|
+
timefeatures/__version__.py
|
|
25
30
|
timefeatures/help.py
|
|
26
31
|
timefeatures/help_html/.buildinfo
|
|
32
|
+
timefeatures/help_html/.buildinfo.bak
|
|
27
33
|
timefeatures/help_html/changes.html
|
|
28
34
|
timefeatures/help_html/genindex.html
|
|
29
35
|
timefeatures/help_html/index.html
|
|
@@ -31,6 +37,10 @@ timefeatures/help_html/installation.html
|
|
|
31
37
|
timefeatures/help_html/objects.inv
|
|
32
38
|
timefeatures/help_html/search.html
|
|
33
39
|
timefeatures/help_html/searchindex.js
|
|
40
|
+
timefeatures/help_html/_images/owloadfromdb.png
|
|
41
|
+
timefeatures/help_html/_images/owsavetodb.png
|
|
42
|
+
timefeatures/help_html/_images/owtimefeaturesconstructor.png
|
|
43
|
+
timefeatures/help_html/_images/owvariabledependencygraph.png
|
|
34
44
|
timefeatures/help_html/_sources/changes.rst.txt
|
|
35
45
|
timefeatures/help_html/_sources/index.rst.txt
|
|
36
46
|
timefeatures/help_html/_sources/installation.rst.txt
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
2.1.1 — 2026-06-09
|
|
5
|
+
-------------------
|
|
6
6
|
|
|
7
7
|
**Load from DB (new widget)**
|
|
8
8
|
|
|
@@ -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
|
|
@@ -10,7 +10,11 @@ sys.path.insert(0, str(ROOT))
|
|
|
10
10
|
project = "TimeFeatures"
|
|
11
11
|
author = "Alejandro Rivas Garcia"
|
|
12
12
|
copyright = "2026, Alejandro Rivas Garcia"
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
# Read version from the single source of truth.
|
|
15
|
+
_version_globals = {}
|
|
16
|
+
exec((ROOT / "timefeatures" / "__version__.py").read_text(encoding="utf-8"), _version_globals)
|
|
17
|
+
release = _version_globals["__version__"]
|
|
14
18
|
version = ".".join(release.split(".")[:2])
|
|
15
19
|
|
|
16
20
|
# -- General configuration ------------------------------------------------
|
|
@@ -47,7 +51,7 @@ html_theme_options = {
|
|
|
47
51
|
"description": (
|
|
48
52
|
"Time-series feature engineering for Orange3: build derived "
|
|
49
53
|
"variables, visualise their dependencies, and persist data to "
|
|
50
|
-
"PostgreSQL."
|
|
54
|
+
"PostgreSQL or MySQL."
|
|
51
55
|
),
|
|
52
56
|
"github_user": "alervgr",
|
|
53
57
|
"github_repo": "Orange-TimeFeatures",
|
|
@@ -81,11 +81,20 @@ Project
|
|
|
81
81
|
Building this documentation
|
|
82
82
|
---------------------------
|
|
83
83
|
|
|
84
|
+
**Development build** (for previewing locally):
|
|
85
|
+
|
|
84
86
|
.. code-block:: bash
|
|
85
87
|
|
|
86
88
|
pip install -e ".[docs]"
|
|
87
89
|
python -m sphinx -b html docs docs/build/html
|
|
88
90
|
|
|
91
|
+
**In-app help** (bundled with the wheel so Orange's Help panel works
|
|
92
|
+
offline):
|
|
93
|
+
|
|
94
|
+
.. code-block:: bash
|
|
95
|
+
|
|
96
|
+
python -m sphinx -b html docs timefeatures/help_html
|
|
97
|
+
|
|
89
98
|
The HTML build is also bundled with the wheel so Orange's in-app help
|
|
90
99
|
panel can resolve every widget's *Help* action without internet
|
|
91
100
|
access.
|
|
@@ -7,6 +7,11 @@ connects to a SQL database, lists the datasets previously persisted by
|
|
|
7
7
|
``Table`` — optionally marking the class column on the fly so no
|
|
8
8
|
**Select Columns** widget is needed downstream.
|
|
9
9
|
|
|
10
|
+
.. figure:: ../../imgs/widgets/owloadfromdb.png
|
|
11
|
+
:alt: Load from DB widget interface.
|
|
12
|
+
|
|
13
|
+
The Load from DB widget.
|
|
14
|
+
|
|
10
15
|
Inputs
|
|
11
16
|
------
|
|
12
17
|
|
|
@@ -48,9 +53,21 @@ Controls
|
|
|
48
53
|
host/db (N datasets)", "Loaded <name> (N rows)"), error
|
|
49
54
|
("Connection failed: …", "Load failed: …").
|
|
50
55
|
* - Dataset
|
|
51
|
-
-
|
|
52
|
-
datetime DESC``. The most recent upload comes first; the
|
|
53
|
-
choice is restored when reopening a workflow.
|
|
56
|
+
- Searchable combo populated from ``SELECT * FROM datasets ORDER
|
|
57
|
+
BY datetime DESC``. The most recent upload comes first; the
|
|
58
|
+
last choice is restored when reopening a workflow. Type to
|
|
59
|
+
filter the visible items — handy when the registry grows large.
|
|
60
|
+
* - ↻ (Refresh)
|
|
61
|
+
- Small button to the right of the Dataset combo. Re-runs the
|
|
62
|
+
list query without dropping the connection. Useful if another
|
|
63
|
+
Orange canvas (or a parallel tool) just published a new
|
|
64
|
+
dataset while this widget was open.
|
|
65
|
+
* - Delete
|
|
66
|
+
- Drops the currently selected dataset's table from the database
|
|
67
|
+
and removes its row in ``datasets``. Gated by a confirmation
|
|
68
|
+
dialog — there is no Orange-side undo. The operation runs on a
|
|
69
|
+
background thread, so the canvas stays responsive even if the
|
|
70
|
+
table is large.
|
|
54
71
|
* - Dataset info
|
|
55
72
|
- Read-only block under the combo: save timestamp, row/column
|
|
56
73
|
counts and the original class column recorded by **Save to DB**.
|
|
@@ -60,7 +77,9 @@ Controls
|
|
|
60
77
|
choice, (2) the ``class_name`` stored in the ``datasets``
|
|
61
78
|
metadata, (3) ``(no class)`` if none of the above apply.
|
|
62
79
|
* - Load
|
|
63
|
-
- Triggers the actual download.
|
|
80
|
+
- Triggers the actual download. Skipped automatically on the
|
|
81
|
+
first connection after a workflow reopen if the persisted
|
|
82
|
+
dataset name is still available (see *Auto-load* below).
|
|
64
83
|
|
|
65
84
|
How it Works
|
|
66
85
|
------------
|
|
@@ -88,6 +107,28 @@ While any worker runs, the form controls (database type, connection
|
|
|
88
107
|
fields, **Connect**, **Load**, dataset and class combos) are
|
|
89
108
|
temporarily disabled and the status label keeps the user informed.
|
|
90
109
|
|
|
110
|
+
Auto-load
|
|
111
|
+
---------
|
|
112
|
+
|
|
113
|
+
When you reopen a workflow that already had a Load from DB widget with
|
|
114
|
+
a saved ``selected_dataset``, the widget fires Load automatically the
|
|
115
|
+
first time the dataset listing comes back successfully. The data flows
|
|
116
|
+
out of the **Data** output without a single click, mirroring how Orange
|
|
117
|
+
treats sources like **File** and **Datasets**.
|
|
118
|
+
|
|
119
|
+
Subtleties:
|
|
120
|
+
|
|
121
|
+
- Auto-load is a *one-shot* per widget lifetime. Manually clicking
|
|
122
|
+
**Refresh** clears the pending flag, so a Refresh never surprises
|
|
123
|
+
the user by loading something behind their back.
|
|
124
|
+
- If the persisted dataset no longer exists on the server (deleted
|
|
125
|
+
from outside, or the registry was wiped), the flag is cleared and
|
|
126
|
+
the widget just shows the available list — no error.
|
|
127
|
+
- If a different backend or set of credentials is restored, the user
|
|
128
|
+
still has to click **Connect** explicitly, just like in earlier
|
|
129
|
+
versions; auto-load happens *after* the first successful connection
|
|
130
|
+
+ listing.
|
|
131
|
+
|
|
91
132
|
Workflow Persistence
|
|
92
133
|
--------------------
|
|
93
134
|
|
|
@@ -7,6 +7,11 @@ database. Two dialects are supported out of the box:
|
|
|
7
7
|
- **PostgreSQL** — through ``psycopg2``.
|
|
8
8
|
- **MySQL** — through ``pymysql``.
|
|
9
9
|
|
|
10
|
+
.. figure:: ../../imgs/widgets/owsavetodb.png
|
|
11
|
+
:alt: Save to DB widget interface.
|
|
12
|
+
|
|
13
|
+
The Save to DB widget.
|
|
14
|
+
|
|
10
15
|
Both drivers are reached via **SQLAlchemy**, which keeps the SQL
|
|
11
16
|
generation, identifier quoting and type rendering dialect-agnostic. The
|
|
12
17
|
actual upload uses a `pandas <https://pandas.pydata.org/>`_ DataFrame
|
|
@@ -59,6 +64,21 @@ TimeFeatures-specific controls:
|
|
|
59
64
|
- Destination table name. Validated against PostgreSQL identifier
|
|
60
65
|
rules (see *Validation* below); MySQL accepts a superset, so
|
|
61
66
|
the same rule is safe on both.
|
|
67
|
+
* - Mode
|
|
68
|
+
- Combo between the Table name and the Email fields:
|
|
69
|
+
|
|
70
|
+
- **Create new (fail if table exists)** — default, refuses to
|
|
71
|
+
touch an existing table or metadata row. Use this for first
|
|
72
|
+
uploads or when you want a clear error on accidental name
|
|
73
|
+
collisions.
|
|
74
|
+
- **Overwrite (drop and recreate)** — drops the existing data
|
|
75
|
+
table and the matching ``datasets`` row before uploading,
|
|
76
|
+
then recreates them. Re-running the workflow stops breaking.
|
|
77
|
+
- **Append (keep existing rows)** — adds rows to the existing
|
|
78
|
+
table (creating it if it doesn't exist). After the upload,
|
|
79
|
+
the widget runs ``SELECT COUNT(*)`` and rewrites the
|
|
80
|
+
``datasets`` row with the *actual* total row count, so the
|
|
81
|
+
registry stays accurate across repeated appends.
|
|
62
82
|
* - Email
|
|
63
83
|
- Optional notification address. A summary email is sent once the
|
|
64
84
|
upload finishes, including the table name, row / column counts,
|
|
@@ -79,12 +99,32 @@ When **Save** is clicked, the widget:
|
|
|
79
99
|
|
|
80
100
|
- converts the dataset to a pandas DataFrame with
|
|
81
101
|
``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
|
-
|
|
102
|
+
and reorders the columns (class first, then metas in domain
|
|
103
|
+
order, then attributes) to match the existing schema convention;
|
|
104
|
+
- ensures the ``datasets`` metadata table exists;
|
|
105
|
+
- applies the mode-specific preparation:
|
|
106
|
+
|
|
107
|
+
- **create** — fail fast if a ``datasets`` row with this name
|
|
108
|
+
already exists.
|
|
109
|
+
- **overwrite** — ``DROP TABLE IF EXISTS`` on the target plus
|
|
110
|
+
``DELETE`` of the matching ``datasets`` row.
|
|
111
|
+
- **append** — leave everything in place; the upload itself will
|
|
112
|
+
create the table on the first chunk if it doesn't exist.
|
|
113
|
+
|
|
114
|
+
- writes the dataset in ``PANDAS_SQL_CHUNKSIZE`` chunks (default
|
|
115
|
+
``1 000``) via ``df.to_sql(..., method='multi')`` with the
|
|
116
|
+
``if_exists`` value tailored to the mode (see
|
|
117
|
+
``_pandas_if_exists`` for the exact table);
|
|
118
|
+
- runs ``SELECT COUNT(*)`` on the target table and re-inserts the
|
|
119
|
+
``datasets`` row with that real row count, so the registry stays
|
|
120
|
+
consistent even after multiple appends.
|
|
121
|
+
|
|
122
|
+
Everything happens inside a single SQLAlchemy transaction
|
|
123
|
+
(``engine.begin()``), so a mid-upload error rolls every step back on
|
|
124
|
+
PostgreSQL. MySQL auto-commits DDL (``DROP TABLE``, ``CREATE TABLE``),
|
|
125
|
+
so an Overwrite that crashes during the upload may leave you without
|
|
126
|
+
the original table — there's no way around that without engine-level
|
|
127
|
+
support.
|
|
88
128
|
|
|
89
129
|
While the worker runs, the widget's progress bar and status label are
|
|
90
130
|
updated through Qt signals; the **Save**, **Connect** and form controls
|