From 9923b2ef27d72811daf3ba757529bad6e7a8a639 Mon Sep 17 00:00:00 2001 From: Carlos Sevilla Salcedo <22427519+sevisal@users.noreply.github.com> Date: Mon, 3 Jul 2023 09:45:38 +0200 Subject: [PATCH] Css data flow selection (#107) * Reupload integral plugin * argopt plugin * Css user interaction for Bayesian Optimisation (#91) * Display for less than 3 parameters * Added current selection * DoubleClick for editing * Change plugin readable name In order to avoid confusions with the Optimisation plugin, changed naming to indicate it referes to the ui. * Added icon to GUI window * Fix more than 2 variables error * Minor aesthetic changes * Css bayesian optimisation (#98) * added re-attempt of env and pybullet * ongoing pybullet/arg population changes * added pybullet stubs * added credit to stubs * added gui/headless choice function * added environment module tag to XML parser * added pybullet config file * renamed Environment module to remove plural * added types and ABC for env modules * removed renamed scripts * modified run pipeline for pybullet * moved relative to absolute converter to import helper * added half-cheetah model * pybullet loading and running working * added half cheetah example with mass * added option to set gravity * removed requirement for data * removed data loading for pybullet example script * added __getattr__ function to access all pybullet methods from ENV class * added option parsing * Change progressTracker to treeview * Correct icon * WIP: editing option parsing * option mods - not yet working * arg passing without kwords to pybul from xml * cleaned imports * renamed depreciated setup file * removed old setup file * cleaned up main __init__ file * added matplotlib to pyproject.toml * Add pytest structure (#56) Co-authored-by: Teemu Ruokolainen * Add cli (#57) * working cli * Update readme * Update readme Co-authored-by: Teemu Ruokolainen * Cm package restructuring (#54) * moved py files to src/vai_labs for packaging * added vscode config to gitignore * updated package name in run_pipeline * fixed pyproject matplotlib import * fixed path for import helper * updated project version for PYPI * updated readme and pyproject.toml * fixed README typo * removed depreciated setup script * fixed path in import_helper.py * Update README.md Updated repo name in README * moved README images * Update README image paths * Remove readme.md.bak (#58) Co-authored-by: Teemu Ruokolainen * Cm name updates (#59) * updated naming and paths for projects * merged README files * updated README naming * update import names in README * updated example links * updated missed readme names * find-replace aidesign refs -> vai_lab * renamed files containing old ai_design name * renamed test file * Css-gui_bugFixing (#60) * Adjust aidCanvas' buttons' size * Correctly resize lower buttons' sizes * Resize buttons, pad radio frame, correct click on in or out * Fix issue with data path * Fix upload data mattrix path * moved test script Co-authored-by: cam586 * Fix repository url in readme and pyproject.toml (#63) * added opencv & pytest (#62) * Clean up lingering/duplicate files. (#64) Co-authored-by: Teemu Ruokolainen * Added debug option (#65) * add debug option to core,GUI * Update test_launch.py Add test_launch() function for pytest discovery Co-authored-by: teemu * Added CI Test using Github Actions (#66) * add debug option to core,GUI * Update test_launch.py Add test_launch() function for pytest discovery * added initial actions yaml * testing now triggered on PR * removed testing for python3.7 * added option for manually running actions * added workflow_dispatch options * temp removal of PR trigger * testing using push trigger * removed incorrect pytest dir * added env variable for GUI testing * added virtual display for GUI testing * removed old yml tag * install virtual display with existing action * fixed yml syntax * fixed xvfb syntax * removed old xvfb tags * update to node.js 16 * test pip caching * removed cache test * fixed cov file path * removed testing for python3.7 * install virtual display with existing action * update to node.js 16 * fixed cov file path * changed trigger condition to pull request * renamed tests package * added programming language classifiers * changed trigger to PR * added test and version shields * fixed README typo * gitignore any venv * removed unneeded tk dep from toml * simplified test call * testing manual workflow trigger * added workflow_dispatch options * re-added pull_request trigger Co-authored-by: teemu * Remove flit from readme (#67) Co-authored-by: Teemu Ruokolainen * Cm fix readme img path (#68) * fixed readme image paths * updated version number * Css fix pluginarchitecture diagram (#69) * Include plugin diagram * Delete old verion * Update plugin diagram * Update plugin diagram * Add white filling to squares for dark mode * fixed contribute urls Co-authored-by: cam586 * Add rough sphinx documentation (#74) * Add autogen docsting sphinx docs * ReadTheDocs * Building version * Change index page title * Add github actions workflow * Update README * Add pip install . to documentation.yml * Add README.md as a page in documentation * Add sphinx-apidoc command to readme; gitignore generated rst files * Update readme sphinx commands * Update readme * Add comments * Update commands in documentation workflow * Fix typo in .gitignore * Remove _static folder from config to remove warning message * Specify python=3.10 for workflow * Remove pip install sphinx-apidoc, no such package * Update readme * added docs build badge to readme * fixed error-causing docstring Co-authored-by: Teemu Ruokolainen Co-authored-by: chris * Cm test docs (#76) * edited branch name for doc building * test actions * added jekyll options * removed settings * fixed gh pages deployment * Cm add docs (#77) * changed copyright year * updated readme headings * moved tutorials from readme to docs * removed tutorials from readme * added getting started page to index toc * Update python=3.8 to python=3.10 in readme * Cm feature add tests (#80) * bumped version number * add pilot example test * simplified core.py * improved naming and docs in core * progress tracker. -> * added example script iteration * fixed loop error msg in COre * updated progress tracker naming (#71) * fixed for loop logic and error handling in core (#72) * Cm fix tracker loops (#73) * fixed for loop logic and error handling in core * fixed tracker dict population for loops * Fix Progess Tracker naming Removing Initialiser name requirement from Progress Tracker * Remove Canvas if there are no ccordinates * Fixing last fix. Correctly read modules inside loop * Fix error with coordinates case * minor typo fix in core * renamed .s variable to .xml_handler for readability * fixed xml_handler naming in GUI_Core * Trying to fix coordinates case * moved avail_plugins to init * Display treeview for no-coordinates case (need fixes)) * FIX - Consistent input and output naming issue * Functioning progress tracker for coord and no coord * Fixed list plugin options issues * Minor fixes to test usability * changed avail plugins options to readable names * removed private and test files from avail_plugins * removed old xml files, mod pybullet * Fix parent issue * fixed pybullet and canvas gui-test issues * fixed pytest errors (except manual plugin) * changed sklearn->scikit-learn in toml * added pybullet to toml * Remove testing file * test fix with scalar * translate boolean literals * removed python 3.8,3.9 * added param to ridge example * removed closed check from core * switced core check to _debug --------- Co-authored-by: Carlos Sevilla Salcedo --------- Co-authored-by: Carlos Sevilla Salcedo * Fix examples path in README.md * Another bad examples path * update conda env part in README.md * fixed calls to undefined parent (#90) * Added Bayesian Optimisation plugin * Fix merge errors * Remove old run file * Modify plugin types * Addoptions to BO * Css feature trying to catch errors (#94) * Move Modelling plugins functions to template * Add clsutering methods to template * Change function doc * Move DataProcessing plugins functions to template * Update pipeline for testing * Update init * Fix conflicts * Add DecisionMaking plugin template * Fixing issues with Optimisation module * Fixed errors passing params to BO * Changed plugin Template to work for BO params Still need to fix issue when running the BO * BO suggests points correctly * Change xml_handler naming Change xml_handler naming to fit with the other UIs * Typo correction * Added bayes_opt optimisation plugin * Modify integral to simpson * Fixed issue with UI --------- Co-authored-by: cam586 Co-authored-by: teemu Co-authored-by: Teemu Ruokolainen Co-authored-by: Richard Darst * Fix issue with example * Added basic dataFlow selection * Fixed issue with module list * Remove option of data self-looping * Add plugin's data input to XML * Fixed error with ridge regression * Added new data reading option * Fix minor errors * Define data communication Redifined data passing and reading between different modules. `vai_lab_core` now stores all output data for each module and could be accessible by any module. Not tested on loops. * Fixed issue duplicated module entries Still need to fix issue with module name reading. * Fixed names used to define input * Clean some example files * Remove testing print * Add output module as editable * Include a checklist for output data * Fixed issue with output update * Write output data in XML file working * Include output path for outdata * Storing output in file * Fix space reading * Allow one or more stored module output * Update XML examples to dataflow * Store relative path * Add option of relative or absolute path * Allow relative path * Change input data definition to optionmenu * By default store output of last module * Update example coordinates * Improve look of output data's optionmenu * Fix issue with path * Fix error with pybullet * Add an output file to create results folder * add: fail-fast false * Fix issue with files * Fix issue with debug * Fix issue with exceptions * Fixed issue with CanvasInput It was not loading the data passed by the Initialiser * Fixed issue with draging states * Improve style of UserInteraction plugins Changed treeview to fill the area next to the canvas and move the scrollbar along with the selected row * Fixed issue with testers * rm: tk from deps * merge main * merge main * rm: obsolete workflow files * tr: merge main * Remove files from a different branch * DEL: .DS_Store files, updated .gitignore accordingly --------- Co-authored-by: cam586 Co-authored-by: teemu Co-authored-by: Teemu Ruokolainen Co-authored-by: Richard Darst --- .github/workflows/pytest.yml | 1 + .gitignore | 5 +- pyproject.toml | 3 +- src/vai_lab/Core/vai_lab_core.py | 42 ++- src/vai_lab/Data/Data_core.py | 7 +- src/vai_lab/Data/xml_handler.py | 32 ++- .../DataProcessing/DataProcessing_core.py | 3 +- .../plugins/kbinsdiscretizer.py | 2 +- src/vai_lab/DecisionMaking/Modelling_core.py | 29 --- src/vai_lab/DecisionMaking/__init__.py | 2 +- src/vai_lab/GUI/GUI_core.py | 3 +- .../Modelling/plugins/knnclassifier.py | 2 +- .../Modelling/plugins/ridgeregression.py | 6 +- .../UserInteraction/plugins/CanvasInput.py | 165 +++++++----- .../UserInteraction/plugins/ManualInput.py | 5 +- src/vai_lab/_import_helper.py | 2 +- src/vai_lab/_plugin_templates.py | 38 ++- .../CsFA/fulldata/CsFA_T300_above.csv | 1 + .../CsMA/fulldata/CsMA_T300_above.csv | 1 + .../FAMA/fulldata/FAMA_T300_above.csv | 1 + .../crystalDesign/phasestability/Readme | 16 ++ .../crystalDesign/phasestability/template.csv | 16 ++ src/vai_lab/examples/results/output.pkl | Bin 0 -> 6665 bytes src/vai_lab/examples/state-action/X_data.csv | 122 ++++----- .../xml_files/KNN-classification_demo.xml | 27 +- src/vai_lab/examples/xml_files/SVR_demo.xml | 25 +- .../examples/xml_files/canvas_demo.xml | 34 ++- .../xml_files/k-mean_clustering_demo.xml | 27 +- .../xml_files/logistic_regression_demo.xml | 42 --- .../xml_files/pybullet_env_example.xml | 18 +- .../xml_files/random_forest_class_demo.xml | 25 +- .../examples/xml_files/regression_demo.xml | 20 +- .../xml_files/ridge-scalar-ridge_demo.xml | 35 ++- .../xml_files/ridge_regression_demo.xml | 22 +- .../examples/xml_files/scalar_demo.xml | 27 +- .../examples/xml_files/scaler-lasso_demo.xml | 28 +- .../examples/xml_files/user_feedback_demo.xml | 31 --- .../xml_files/user_feedback_demo2.xml | 46 ++++ src/vai_lab/run_pipeline.py | 2 +- src/vai_lab/utils/plugins/MainPage.py | 4 +- src/vai_lab/utils/plugins/aidCanvas.py | 14 +- src/vai_lab/utils/plugins/dataLoader.py | 8 + src/vai_lab/utils/plugins/pluginCanvas.py | 244 +++++++++++++++--- tests/test_launch.py | 1 + 44 files changed, 778 insertions(+), 406 deletions(-) delete mode 100644 src/vai_lab/DecisionMaking/Modelling_core.py create mode 100644 src/vai_lab/examples/crystalDesign/phasestability/CsFA/fulldata/CsFA_T300_above.csv create mode 100644 src/vai_lab/examples/crystalDesign/phasestability/CsMA/fulldata/CsMA_T300_above.csv create mode 100644 src/vai_lab/examples/crystalDesign/phasestability/FAMA/fulldata/FAMA_T300_above.csv create mode 100644 src/vai_lab/examples/crystalDesign/phasestability/Readme create mode 100644 src/vai_lab/examples/crystalDesign/phasestability/template.csv create mode 100644 src/vai_lab/examples/results/output.pkl delete mode 100644 src/vai_lab/examples/xml_files/logistic_regression_demo.xml delete mode 100644 src/vai_lab/examples/xml_files/user_feedback_demo.xml create mode 100644 src/vai_lab/examples/xml_files/user_feedback_demo2.xml diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index ec4eaf1d..ea62fcce 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -23,6 +23,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.10", "3.11"] + fail-fast: false steps: - uses: actions/checkout@v3 diff --git a/.gitignore b/.gitignore index 0e6e69c7..d80f36db 100644 --- a/.gitignore +++ b/.gitignore @@ -145,4 +145,7 @@ dmypy.json .pyre/ # pytype static type analyzer -.pytype/ \ No newline at end of file +.pytype/ + +# Ignore Mac DS_Store files +.DS_Store diff --git a/pyproject.toml b/pyproject.toml index 91fa8f7f..f1c9a7c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,8 +28,7 @@ dependencies = [ "matplotlib >= 3.5.0", "opencv-python >= 4.6.0.65", "pybullet >= 3.2.5", - "attrs >= 23.1.0", - "tk >= 0.1.0" + "attrs >= 23.1.0" ] [project.optional-dependencies] diff --git a/src/vai_lab/Core/vai_lab_core.py b/src/vai_lab/Core/vai_lab_core.py index fd65ea49..a2aeca8b 100644 --- a/src/vai_lab/Core/vai_lab_core.py +++ b/src/vai_lab/Core/vai_lab_core.py @@ -2,8 +2,9 @@ from sys import exit from os.path import join from typing import Dict, List, Tuple, Union +import pickle -from vai_lab._import_helper import import_module +from vai_lab._import_helper import import_module, rel_to_abs from vai_lab._plugin_helpers import PluginSpecs from vai_lab._types import ModuleInterface, PluginSpecsInterface from vai_lab.GUI.GUI_core import GUI @@ -13,7 +14,8 @@ class Core: def __init__(self) -> None: - self.data = Data() + self.data = {} + self.data['Initialiser'] = Data() self._xml_handler = XML_handler() self._avail_plugins: PluginSpecsInterface = PluginSpecs() @@ -33,7 +35,6 @@ def _launch(self): self.load_config_file(gui_output["xml_filename"]) except: raise Exception("No XML File Selected. Cannot Run Pipeline") - self._load_data() def load_config_file(self, filename: Union[str,List,Tuple]): """Loads XML file into XML_handler object. @@ -46,10 +47,15 @@ def load_config_file(self, filename: Union[str,List,Tuple]): self._xml_handler.load_XML(filedir) self._initialised = True - def _load_data(self) -> None: + def _load_data(self, module = 'Initialiser') -> None: """Loads data from XML file into Data object""" - init_data_fn = self._xml_handler.data_to_load - self.data.import_data_from_config(init_data_fn) + init_data_fn = self._xml_handler.data_to_load(module) + if module not in self.data.keys(): + self.data[module] = Data() + if isinstance(init_data_fn, str): + self.data[module].import_existing_data(init_data_fn, self.data) + elif isinstance(init_data_fn, dict): + self.data[module].import_data_from_config(init_data_fn) def _execute_module(self, specs): """Executes named module with given options @@ -60,7 +66,8 @@ def _execute_module(self, specs): mod: ModuleInterface = import_module(globals(), specs["module_type"]).__call__() mod._debug = self._debug mod.set_avail_plugins(self._avail_plugins) - mod.set_data_in(self.data) + self._load_data(specs["name"]) + mod.set_data_in(self.data[specs["name"]]) mod.set_options(specs) print("\t"*self.loop_level + specs["module_type"] @@ -68,7 +75,7 @@ def _execute_module(self, specs): + "processing..." ) mod.launch() - self.data = mod.get_result() + self.data[specs["name"]] = mod.get_result() def _execute_loop(self, specs): if hasattr(self,"_execute_{}_loop".format(specs["type"])): @@ -90,9 +97,17 @@ def _execute_entry_point(self, specs): pass def _execute_exit_point(self, specs): - """Placeholder: Will parse the Output module when ready""" - pass - + """ Runs the Output module """ + if all(k in specs['plugin']['options'] for k in ('outdata', 'outpath')): + data_out = {} + if type(specs['plugin']['options']['outdata']) is list: + for module in specs['plugin']['options']['outdata']: + data_out[module] = self.data[module] + elif type(specs['plugin']['options']['outdata']) is str: + data_out[specs['plugin']['options']['outdata']] = self.data[specs['plugin']['options']['outdata']] + + with open(rel_to_abs(specs['plugin']['options']['outpath']), 'wb') as handle: + pickle.dump(data_out, handle, protocol=pickle.HIGHEST_PROTOCOL) def _parse_loop_condition(self, condition): try: condition = int(condition) @@ -102,7 +117,7 @@ def _parse_loop_condition(self, condition): except: print("Condition \"{0}\" cannot be parsed".format(condition)) print( - "Other formats in in development. Only ranged for loops are working currently") + "Other formats in development. Only ranged for loops are working currently") def _execute_for_loop(self, specs): condition = self._parse_loop_condition(specs["condition"]) @@ -169,7 +184,8 @@ def run(self): if not self._initialised: self._initialise_with_gui() print("Running pipeline...") - self._load_data() + if len(self._xml_handler.loaded_modules) > 0: + self._load_data() self._init_status(self._xml_handler.loaded_modules) self._execute(self._xml_handler.loaded_modules) diff --git a/src/vai_lab/Data/Data_core.py b/src/vai_lab/Data/Data_core.py index 327ba0fe..fccb1c43 100644 --- a/src/vai_lab/Data/Data_core.py +++ b/src/vai_lab/Data/Data_core.py @@ -92,8 +92,7 @@ def import_data(self: DataT, :param filename: str, filename of file to be loaded :param data_name: str, name of class variable data will be loaded to """ - filename = rel_to_abs(filename).replace( - "\\", "/").replace("/", path.sep) + filename = rel_to_abs(filename) ext = self._get_ext(filename) getattr(self, "_import_{0}".format(ext))(filename, data_name) @@ -101,6 +100,10 @@ def import_data_from_config(self: DataT, config: dict) -> None: for c in config.keys(): self.import_data(config[c], c) + def import_existing_data(self: DataT, config: dict, data: DataT) -> None: + for item in data[config].keys(): + self.data[item] = data[config][item] + def append_data_column(self: DataT, col_name: str, data=None) -> None: self.data[col_name] = data diff --git a/src/vai_lab/Data/xml_handler.py b/src/vai_lab/Data/xml_handler.py index 6d2c323c..b3ebeae3 100644 --- a/src/vai_lab/Data/xml_handler.py +++ b/src/vai_lab/Data/xml_handler.py @@ -178,7 +178,7 @@ def _load_data(self, element: ET.Element, parent: dict) -> None: "class": "data", "to_load": {}} for child in element: - assert "file" in child.attrib or "folder" in child.attrib,\ + assert "file" in child.attrib or "folder" in child.attrib or "module" in child.attrib,\ str("XML Parse Error \ \n\tA path to data file must be specified. \ \n\t{0} does not contain the \"file\" tag. \ @@ -198,6 +198,9 @@ def _load_data(self, element: ET.Element, parent: dict) -> None: .format(self._check_filename_abs_rel(child.attrib["folder"]))) parent[data_name]["to_load"][child.tag] = child.attrib["folder"] + if "module" in child.attrib: + parent[data_name]["to_load"] = child.attrib["module"] + def _load_exit_point(self, element: ET.Element, parent: dict) -> None: """Parses tags associated with output and appends to parent dict :param elem: xml.etree.ElementTree.Element to be parsed @@ -267,11 +270,12 @@ def _parse_text_to_list(self, element: ET.Element) -> List: :returns out: list containing parsed text data """ if element.text is not None: - new = element.text.strip().replace(" ", "") + new = element.text.strip() out: List[Any] = new.split("\n") raw_elem_text = str() for idx in range(0, len(out)): + out[idx] = " ".join(out[idx].split()) raw_elem_text = (raw_elem_text+"\n{}").format(out[idx]) if "[" in out[idx] and "]" in out[idx]: out[idx] = literal_eval(out[idx]) @@ -499,15 +503,23 @@ def append_input_data(self, if input_data_elem is None: input_data_elem = ET.SubElement(xml_parent, "inputdata") + data_name_elem = input_data_elem.find("./"+data_name) + if data_name_elem is not None: + input_data_elem.remove(data_name_elem) + plugin_elem = ET.SubElement(input_data_elem, data_name) if save_dir_as_relative: data_dir = data_dir.replace(self.lib_base_path, "./") data_dir = data_dir.replace("\\", "/") - plugin_elem.set('file', data_dir) + if path.exists(path.dirname(data_dir)): + plugin_elem.set('file', data_dir) + else: + plugin_elem.set('module', data_dir) def append_plugin_to_module(self, plugin_type: str, plugin_options: dict, + plugin_data: str, xml_parent: Union[ET.Element, str], overwrite_existing: Union[bool, int] = False ): @@ -515,6 +527,7 @@ def append_plugin_to_module(self, :param plugin_type: string type of plugin to be loaded into module :param plugin_options: dict where keys & values are options & values + :param plugin_data: string type of data to be used as input :param xml_parent: dict OR str. If string given, parent elem is found via search, Otherwise, plugin appeneded directly @@ -531,6 +544,8 @@ def append_plugin_to_module(self, if plugin_elem is None: plugin_elem = ET.SubElement(xml_parent, "plugin") plugin_elem.set('type', plugin_type) + if plugin_data is not None and len(plugin_data) > 0: + self.append_input_data('X', plugin_data, xml_parent, False) self._add_plugin_options(plugin_elem, plugin_options) def append_pipeline_module(self, @@ -562,6 +577,7 @@ def append_pipeline_module(self, if plugin_type != None: self.append_plugin_to_module(plugin_type, plugin_options, + parents[0], new_mod, 0 ) @@ -609,9 +625,9 @@ def append_pipeline_loop(self, xml_parent_element.append(new_loop) - def _get_init_data_structure(self) -> Dict[str, Any]: + def _get_data_structure(self, module) -> Dict[str, Any]: data_struct = self._find_dict_with_key_val_pair( - self.loaded_modules, + self.loaded_modules[module], "class", "data") assert len(data_struct) < 2, \ @@ -624,9 +640,9 @@ def _get_init_data_structure(self) -> Dict[str, Any]: out = {"to_load": {}} return out - @property - def data_to_load(self) -> Dict[str, str]: - return (self._get_init_data_structure()["to_load"]) + #@property + def data_to_load(self, module='Initialiser') -> Dict[str, str]: + return self._get_data_structure(module)["to_load"] # Use case examples: diff --git a/src/vai_lab/DataProcessing/DataProcessing_core.py b/src/vai_lab/DataProcessing/DataProcessing_core.py index ae681db3..666e2a2d 100644 --- a/src/vai_lab/DataProcessing/DataProcessing_core.py +++ b/src/vai_lab/DataProcessing/DataProcessing_core.py @@ -32,8 +32,7 @@ def launch(self) -> None: self._plugin.set_data_in(self._data_in) self._plugin.configure(self._module_config["plugin"]) self._plugin.fit() - self.output_data = self._data_in.copy() - self.output_data = self._plugin.transform(self.output_data) + self.output_data = self._plugin.transform(self._data_in) def get_result(self) -> DataInterface: return self.output_data diff --git a/src/vai_lab/DataProcessing/plugins/kbinsdiscretizer.py b/src/vai_lab/DataProcessing/plugins/kbinsdiscretizer.py index bcc13b9a..a844db5e 100644 --- a/src/vai_lab/DataProcessing/plugins/kbinsdiscretizer.py +++ b/src/vai_lab/DataProcessing/plugins/kbinsdiscretizer.py @@ -8,7 +8,7 @@ _PLUGIN_REQUIRED_SETTINGS = {"Data": "str"} # type:ignore _PLUGIN_OPTIONAL_SETTINGS = {"n_bins": "int"} # type:ignore _PLUGIN_REQUIRED_DATA = {} # type:ignore -_PLUGIN_OPTIONAL_DATA = {"X","Y","X_tst", 'Y_tst'} # type:ignore +_PLUGIN_OPTIONAL_DATA = {"X","Y","X_tst","Y_tst"} # type:ignore class KBinsDiscretizer(DataProcessingT): """ diff --git a/src/vai_lab/DecisionMaking/Modelling_core.py b/src/vai_lab/DecisionMaking/Modelling_core.py deleted file mode 100644 index 97a81d24..00000000 --- a/src/vai_lab/DecisionMaking/Modelling_core.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -class Modelling(object): - def __init__(self): - self.node_name = None - self.plugin_name = None - self.output_data = None - - def set_input_data(self, data): - self.input_data = data - - def set_target_data(self, data): - self.target_data = data - - def _load_plugin(self): - pass - - def set_plugin_name(self, plugin_name): - self.plugin_name = plugin_name - self._load_plugin() - - def set_options(self, options): - self.options = options - - def solve(self): - # send the input data to the modelling plugin and assign it to an output property - pass - - def get_result(self): - return self.output_data diff --git a/src/vai_lab/DecisionMaking/__init__.py b/src/vai_lab/DecisionMaking/__init__.py index 99e78a66..77990d09 100644 --- a/src/vai_lab/DecisionMaking/__init__.py +++ b/src/vai_lab/DecisionMaking/__init__.py @@ -4,4 +4,4 @@ Let's look for a more automatic way of doing this when we have more modules """ -from .Modelling_core import Modelling +from .DecisionMaking_core import DecisionMaking diff --git a/src/vai_lab/GUI/GUI_core.py b/src/vai_lab/GUI/GUI_core.py index 3fa6f524..bb3f3c3b 100644 --- a/src/vai_lab/GUI/GUI_core.py +++ b/src/vai_lab/GUI/GUI_core.py @@ -11,7 +11,8 @@ class GUI(tk.Tk): """ TODO: This structure still needs serious overhaul. - TODO: By having the TKinter controller as in the main GUI module, we are locked to using TKinter which defeats the purpose of being modular. This class needs to only be calling the plugins themselves, not acting as a controller. + TODO: By having the TKinter controller as in the main GUI module, we are locked to using TKinter which defeats the purpose of being modular. + This class needs to only be calling the plugins themselves, not acting as a controller. """ def __init__(self, *args, **kwargs): diff --git a/src/vai_lab/Modelling/plugins/knnclassifier.py b/src/vai_lab/Modelling/plugins/knnclassifier.py index 9ae82293..3a56f8ec 100644 --- a/src/vai_lab/Modelling/plugins/knnclassifier.py +++ b/src/vai_lab/Modelling/plugins/knnclassifier.py @@ -11,7 +11,7 @@ _PLUGIN_OPTIONAL_DATA = {"X_tst", 'Y_tst'} # type:ignore -class KNNclassifier(ModellingPluginTClass): +class KNNClassifier(ModellingPluginTClass): """ Classifier implementing the k-nearest neighbors vote """ diff --git a/src/vai_lab/Modelling/plugins/ridgeregression.py b/src/vai_lab/Modelling/plugins/ridgeregression.py index ee0a234b..6578c83d 100644 --- a/src/vai_lab/Modelling/plugins/ridgeregression.py +++ b/src/vai_lab/Modelling/plugins/ridgeregression.py @@ -1,8 +1,8 @@ from vai_lab._plugin_templates import ModellingPluginT from sklearn.linear_model import Ridge as model -_PLUGIN_READABLE_NAMES = {"Ridge": "default", - "RidgeRegression": "alias"} # type:ignore +_PLUGIN_READABLE_NAMES = {"RidgeRegression": "default", + "Ridge": "alias"} # type:ignore _PLUGIN_MODULE_OPTIONS = {"Type": "regression"} # type:ignore _PLUGIN_REQUIRED_SETTINGS = {} # type:ignore _PLUGIN_OPTIONAL_SETTINGS = {"alpha": "float"} # type:ignore @@ -20,4 +20,4 @@ def __init__(self): Passes `globals` dict of all current variables """ super().__init__(globals()) - self.clf = model() \ No newline at end of file + self.clf = model() diff --git a/src/vai_lab/UserInteraction/plugins/CanvasInput.py b/src/vai_lab/UserInteraction/plugins/CanvasInput.py index 30256eaa..e521ff37 100644 --- a/src/vai_lab/UserInteraction/plugins/CanvasInput.py +++ b/src/vai_lab/UserInteraction/plugins/CanvasInput.py @@ -11,7 +11,7 @@ import pandas as pd import math -_PLUGIN_READABLE_NAMES = {"canvas": "default", +_PLUGIN_READABLE_NAMES = {"CanvasInput": "default", "state-action": "alias", "robot": "alias"} # type:ignore _PLUGIN_MODULE_OPTIONS = {"layer_priority": 2, "required_children": None} # type:ignore @@ -32,7 +32,6 @@ def __init__(self, parent, controller, config: dict): self.notebook = ttk.Notebook(self) self.notebook.grid(row=0, column=0, columnspan=7, rowspan=12, pady=15) - self.frame: List[tk.Frame] = [] self.tree: List[ttk.Treeview] = [] self.canvas: List[tk.Canvas] = [] self.draw: List[tk.StringVar] = [] @@ -84,6 +83,8 @@ def _load_classes_from_data(self): if not all(islist): self._class_list = [list(self._class_list)] + frame: List[tk.Frame] = [] + self.out_data = {} self.out_data[0] = {} for ii in np.arange(len(self._class_list)): @@ -94,9 +95,8 @@ def _load_classes_from_data(self): self.out_data[ii][self._class_list[ii][k]] = [] for ii in np.arange(len(self.out_data)): - self.frame.append(tk.Frame(self, bg=self.parent['bg'])) - self.frame[-1].grid(row=0, column=0, sticky="nsew", pady=15) - # if self._class_list[ii][0].split('_')[1] == 'a': + frame.append(tk.Frame(self, bg=self.parent['bg'])) + frame[-1].grid(row=0, column=0, sticky="nsew", pady=(15,0)) if self._class_list[ii][0].split('_')[1] == 'a': self.type.append('Rotating') self.clock.append(tk.StringVar()) @@ -105,13 +105,18 @@ def _load_classes_from_data(self): self.type.append('Sliding') self.clock.append(-1) self.notebook.add( - self.frame[-1], + frame[-1], text='Object ' + str(ii) + ' - ' + self.type[-1]) - + + # Frames for canvas, treeview and buttons + frame1 = tk.Frame(frame[-1], bg=self.parent['bg']) + frame2 = tk.Frame(frame[-1], bg=self.parent['bg']) + frame3 = tk.Frame(frame[-1], bg=self.parent['bg']) + frame4 = tk.Frame(frame[-1], bg=self.parent['bg']) # Create a canvas widget self.width, self.height = 600, 600 self.canvas.append(tk.Canvas( - self.frame[-1], width=self.width, + frame1, width=self.width, height=self.height, background="white")) self.canvas[-1].grid(row=0, column=0, columnspan=4, rowspan=2) self.canvas[-1].bind('', self.draw_dot) @@ -124,64 +129,61 @@ def _load_classes_from_data(self): self.state.append(tk.StringVar()) self.state[ii].set('state') # Buttons under the canvas - self.button_draw = tk.Radiobutton( - self.frame[-1], text='Draw', fg='white', bg=self.parent['bg'], + tk.Radiobutton( + frame4, text='Draw', fg='white', bg=self.parent['bg'], height=3, width=20, var=self.draw[ii], selectcolor='black', value='draw').grid(column=4, row=3) - self.button_drag = tk.Radiobutton( - self.frame[-1], text='Move', fg='white', bg=self.parent['bg'], + tk.Radiobutton( + frame4, text='Move', fg='white', bg=self.parent['bg'], height=3, width=20, var=self.draw[ii], selectcolor='black', value='drag').grid(column=5, row=3) - self.clock_arc = tk.Radiobutton( - self.frame[-1], text='Clockwise', fg='white', bg=self.parent['bg'], + tk.Radiobutton( + frame4, text='Clockwise', fg='white', bg=self.parent['bg'], height=3, width=20, var=self.clock[ii], selectcolor='black', value='clock').grid(column=6, row=3) - self.countclock_arc = tk.Radiobutton( - self.frame[-1], text='Counterclockwise', fg='white', bg=self.parent['bg'], + tk.Radiobutton( + frame4, text='Counterclockwise', fg='white', bg=self.parent['bg'], height=3, width=20, var=self.clock[ii], selectcolor='black', value='countclock').grid(column=7, row=3) # self.button_edit = tk.Radiobutton( - # self.frame[-1], text = 'Edit', fg = 'white', bg = self.parent['bg'], + # frame[-1], text = 'Edit', fg = 'white', bg = self.parent['bg'], # height = 3, width = 20, var = self.draw[ii], # selectcolor = 'black', value = 'edit').grid(column = 6,row = 3) - self.button_save = tk.Button( - self.frame[-1], text='Save', fg='white', bg=self.parent['bg'], + tk.Button( + frame3, text='Save', fg='white', bg=self.parent['bg'], height=3, width=20, command=self.save_file).grid(column=1, row=3) - self.button_upload = tk.Button( - self.frame[-1], text='Upload coordinates', fg='white', + tk.Button( + frame3, text='Upload coordinates', fg='white', bg=self.parent['bg'], height=3, width=20, command=self.upload_sa).grid(column=0, row=3) - self.button_reset = tk.Button( - self.frame[-1], text='Reset', fg='white', + tk.Button( + frame3, text='Reset', fg='white', bg=self.parent['bg'], height=3, width=20, command=self.reset).grid(column=2, row=3) - button_main = tk.Button( - self.frame[-1], text="Done", fg='white', + tk.Button( + frame3, text="Done", fg='white', bg=self.parent['bg'], height=3, width=20, command=self.check_quit).grid(column=3, row=3) style = ttk.Style() style.configure( - "Treeview", background='white', foreground='white', + "Treeview", background='white', foreground='black', rowheight=25, fieldbackground='white', font=self.controller.pages_font) style.configure("Treeview.Heading", font=self.controller.pages_font) style.map('Treeview', background=[('selected', 'grey')]) - tree_frame = tk.Frame(self.frame[-1]) - tree_frame.grid(row=0, column=4, columnspan=3, rowspan=10) - - tree_scrollx = tk.Scrollbar(tree_frame, orient='horizontal') + tree_scrollx = tk.Scrollbar(frame2, orient='horizontal') tree_scrollx.pack(side=tk.BOTTOM, fill=tk.X) - tree_scrolly = tk.Scrollbar(tree_frame) + tree_scrolly = tk.Scrollbar(frame2) tree_scrolly.pack(side=tk.RIGHT, fill=tk.Y) self.tree.append(ttk.Treeview( - tree_frame, + frame2, yscrollcommand=tree_scrolly.set, xscrollcommand=tree_scrollx.set)) - self.tree[-1].pack() + self.tree[-1].pack(fill='both', expand=True) tree_scrollx.config(command=self.tree[-1].xview) tree_scrolly.config(command=self.tree[-1].yview) @@ -221,6 +223,22 @@ def _load_classes_from_data(self): # Define double-click on row action self.tree[-1].bind("", self.OnDoubleClick) + + frame1.grid(column=0, row=0, sticky="nsew", padx=2, pady=2) + frame2.grid(column=1, row=0, sticky="nsew", padx=2, pady=2) + frame3.grid(column=0, row=1, sticky="nswe") + frame4.grid(column=1, row=1, sticky="nsew") + + # self.frame2.grid_columnconfigure(tuple(range(2)), weight=1) + # self.frame2.grid_columnconfigure(1, weight=1) + # frame3.grid_columnconfigure(tuple(range(2)), weight=2) + # # frame3.grid_columnconfigure(2, weight=2) + # self.frame4.grid_columnconfigure(tuple(range(2)), weight=2) + # self.frame4.grid_columnconfigure(2, weight=2) + + # Load input data + if not self._data_in["X"].empty: + self.load_data(self._data_in["X"].values, True) def draw_dot(self, event): @@ -262,6 +280,7 @@ def draw_dot(self, event): self.out_data[ii])[n, :].astype(int)), tags=tag) self.tree[ii].selection_set(str(n)) + self.tree[ii].yview_moveto(int(n) / (len(self.tree[ii].get_children()))) else: self.tree[ii].insert( parent='', index='end', iid=0, text=1, @@ -269,7 +288,7 @@ def draw_dot(self, event): self.out_data[ii])[0, :].astype(int)), tags=('even',)) self.tree[ii].selection_set(str(0)) - + self.tree[ii].yview_moveto(0) elif self.state[ii].get() == 'action': if self.clock[ii].get() == 'clock': start = self.out_data[ii]['state_a'][-1] @@ -313,6 +332,7 @@ def draw_dot(self, event): self.out_data[ii])[n, :].astype(int)), tags=tag) self.tree[ii].selection_set(str(n)) + self.tree[ii].yview_moveto(int(n) / (len(self.tree[ii].get_children()))) else: self.tree[ii].insert( parent='', index='end', iid=0, text=1, @@ -320,7 +340,7 @@ def draw_dot(self, event): self.out_data[ii])[0, :].astype(int)), tags=('even',)) self.tree[ii].selection_set(str(0)) - + self.tree[ii].yview_moveto(0) elif self.state[ii].get() == 'action': self.canvas[ii].create_line( self.out_data[ii]['state_x'][-1], @@ -340,7 +360,7 @@ def draw_dot(self, event): def on_drag(self, event): ii = self.notebook.index(self.notebook.select()) - if self.draw[ii].get() == 'drag' and self.canvas[ii].selected: + if self.draw[ii].get() == 'drag' and self.canvas[ii].selected and len(self.canvas[ii].gettags("current")) > 0: # move the selected item n = int(self.canvas[ii].gettags("current")[0].split('-')[1]) @@ -416,6 +436,7 @@ def on_drag(self, event): values=tuple(self.dict2mat( self.out_data[ii])[n, :].astype(int))) self.tree[ii].selection_set(str(n)) + self.tree[ii].yview_moveto(int(n) / (len(self.tree[ii].get_children()))) def checkered(self, line_distance): @@ -554,9 +575,46 @@ def OnDoubleClick(self, event): y=y + pady, anchor=tk.W, width=width) - def upload_sa(self): + def load_data(self, data, read = False): ii = self.notebook.index(self.notebook.select()) + self.draw[ii].set('drag') + for point in data: + if read: # Not elegant at all, just to omit the header. + if isinstance(point, str): + sx, sy, ax, ay = point.split() + elif isinstance(point, (list, np.ndarray)): + sx, sy, ax, ay = point + # Draw an oval in the given coordinates + self.canvas[ii].create_oval( + float(sx)-3, float(sy)-3, float(sx)+3, float(sy)+3, + fill="black", width=0, + tags=("state"+str(ii)+"-" + str(len( + self.out_data[ii]['state_x'])))) + self.canvas[ii].create_line( + float(sx), float(sy), float(ax), float(ay), + fill="red", arrow=tk.LAST, + tags=("action"+str(ii)+"-" + str(len( + self.out_data[ii]['action_x'])))) + self.out_data[ii]['state_x'].append(sx) + self.out_data[ii]['state_y'].append(sy) + self.out_data[ii]['action_x'].append(ax) + self.out_data[ii]['action_y'].append(ay) + self.tree[ii].insert( + parent='', index='end', + iid=len(self.out_data[ii]['action_x'])-1, + text=len(self.out_data[ii]['action_x']), + values=tuple(self.dict2mat( + self.out_data[ii]) + [len(self.out_data[ii] + ['action_x'])-1, :].astype(int))) + sel_item = len(self.out_data[ii]['action_x'])-1 + self.tree[ii].selection_set(str(sel_item)) + self.tree[ii].yview_moveto(int(sel_item) / (len(self.tree[ii].get_children()))) + else: + read = True + + def upload_sa(self): filename = askopenfilename(initialdir=os.getcwd(), title='Select a file', defaultextension='.txt', @@ -565,38 +623,7 @@ def upload_sa(self): ('All Files', '*.*')]) if filename is not None: data = open(filename, 'r') - read = False - self.draw[ii].set('drag') - for n, point in enumerate(data): - if read: # Not elegant at all, just to omit the header. - i, sx, sy, ax, ay = point.split() - # Draw an oval in the given coordinates - self.canvas[ii].create_oval( - float(sx)-3, float(sy)-3, float(sx)+3, float(sy)+3, - fill="black", width=0, - tags=("state-" + str(len( - self.out_data[ii]['state_x'])))) - self.canvas[ii].create_line( - float(sx), float(sy), float(ax), float(ay), - fill="red", arrow=tk.LAST, - tags=("action"+str(ii)+"-" + str(len( - self.out_data[ii]['action_x'])))) - self.out_data[ii]['state_x'].append(sx) - self.out_data[ii]['state_y'].append(sy) - self.out_data[ii]['action_x'].append(ax) - self.out_data[ii]['action_y'].append(ay) - self.tree.insert( - parent='', index='end', - iid=len(self.out_data[ii]['action_x'])-1, - text=len(self.out_data[ii]['action_x']), - values=tuple(self.dict2mat( - self.out_data[ii]) - [len(self.out_data[ii] - ['action_x'])-1, :].astype(int))) - self.tree.selection_set(str(len( - self.out_data[ii]['action_x'])-1)) - else: - read = True + self.load_data(data) def reset(self): diff --git a/src/vai_lab/UserInteraction/plugins/ManualInput.py b/src/vai_lab/UserInteraction/plugins/ManualInput.py index 9e6a40e9..b3d7ac1b 100644 --- a/src/vai_lab/UserInteraction/plugins/ManualInput.py +++ b/src/vai_lab/UserInteraction/plugins/ManualInput.py @@ -12,7 +12,7 @@ from tkinter import messagebox, ttk from tkinter.filedialog import asksaveasfile -_PLUGIN_READABLE_NAMES = {"manual": "default", +_PLUGIN_READABLE_NAMES = {"ManualInput": "default", "binary": "alias", "classification": "alias"} # type:ignore _PLUGIN_MODULE_OPTIONS = {"layer_priority": 2, @@ -212,7 +212,7 @@ def _load_classes_from_data(self): # Select the current row self.tree.selection_set(str(int(0))) - + self.tree.yview_moveto(0) # Define double-click on row action self.tree.bind("", self.OnDoubleClick) @@ -302,6 +302,7 @@ def forward_back(self, image_number): " Forward button to continue to the next image in the folder." self.tree.selection_set(str(int(image_number-1))) + self.tree.yview_moveto(int(image_number-1) / (len(self.tree.get_children()))) # Print the corresponding image self.resizing((0, 0)) diff --git a/src/vai_lab/_import_helper.py b/src/vai_lab/_import_helper.py index e083a007..e56d2118 100644 --- a/src/vai_lab/_import_helper.py +++ b/src/vai_lab/_import_helper.py @@ -40,7 +40,7 @@ def rel_to_abs(filename: str) -> str: If relative, converts path to absolute by appending to base directory """ if filename[0] == ".": - filename = path.join(get_lib_parent_dir(), filename) + filename = path.normpath(path.join(get_lib_parent_dir(), filename)) elif filename[0] == "/" or (filename[0].isalpha() and filename[0].isupper()): filename = filename return filename \ No newline at end of file diff --git a/src/vai_lab/_plugin_templates.py b/src/vai_lab/_plugin_templates.py index 2973574c..98d289d4 100644 --- a/src/vai_lab/_plugin_templates.py +++ b/src/vai_lab/_plugin_templates.py @@ -113,6 +113,12 @@ def _parse_options_dict(self,options_dict:Dict): val = int(val) cleaned_opts.append(val) options_dict[key] = cleaned_opts + elif type(val) == str and val.lower() in ('y', 'yes', 't', 'true', 'on'): + options_dict[key] = True + elif type(val) == str and val.lower() in ('n', 'no', 'f', 'false', 'off'): + options_dict[key] = False + elif type(val) == str and val.lower() in ('none'): + options_dict[key] = None return options_dict def _clean_options(self): @@ -120,7 +126,7 @@ def _clean_options(self): and modifies DataInterface in-place str options which only contain numeric data are converted to float OR int """ - self._parse_options_dict(self._config["options"]) + return self._parse_options_dict(self._config["options"]) def _test(self, data: DataInterface) -> DataInterface: """Run debug tests on data operations @@ -185,13 +191,13 @@ def fit(self): self.proc.set_params(**cleaned_options) except Exception as exc: print('The plugin encountered an error on the parameters of ' - +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+exc+'.') + +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+str(exc)+'.') raise try: self.proc.fit(self.X) except Exception as exc: print('The plugin encountered an error when fitting ' - +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+exc+'.') + +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+str(exc)+'.') raise def transform(self, data: DataInterface) -> DataInterface: @@ -199,14 +205,14 @@ def transform(self, data: DataInterface) -> DataInterface: data.append_data_column("X", pd.DataFrame(self.proc.transform(self.X))) except Exception as exc: print('The plugin encountered an error when transforming the data with ' - +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+exc+'.') + +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+str(exc)+'.') raise if self.X_tst is not None: try: data.append_data_column("X_test", pd.DataFrame(self.proc.transform(self.X_tst))) except Exception as exc: print('The plugin encountered an error when transforming the data with ' - +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+exc+'.') + +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+str(exc)+'.') raise return data @@ -221,13 +227,13 @@ def solve(self): self.clf.set_params(**self._config["options"]) except Exception as exc: print('The plugin encountered an error on the parameters of ' - +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+exc+'.') + +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+str(exc)+'.') raise try: self.clf.fit(self.X, self.Y) except Exception as exc: print('The plugin encountered an error when fitting ' - +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+exc+'.') + +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+str(exc)+'.') raise def predict(self, data): @@ -242,7 +248,7 @@ def predict(self, data): return self.clf.predict(data) except Exception as exc: print('The plugin encountered an error when predicting with ' - +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+exc+'.') + +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+': '+str(exc)+'.') raise def score(self, X, Y, sample_weight): @@ -280,6 +286,22 @@ def predict_proba(self, data): +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+'.') raise +class DecisionMakingPluginT(PluginTemplate, ABC): + def __init__(self, plugin_globals: dict) -> None: + super().__init__(plugin_globals) + + def configure(self, config: dict): + """Extended from PluginTemplate.configure""" + super().configure(config) + try: + self.BO = self.model(**self._clean_options()) + except Exception as exc: + print('The plugin encountered an error on the parameters of ' + +str(list(self._PLUGIN_READABLE_NAMES.keys())[list(self._PLUGIN_READABLE_NAMES.values()).index('default')])+'.') + raise + if type(self.X) is None and type(self.Y) is None: + print('Invalid Data name. Indicate whether to use `X` or `Y`') + class UI(PluginTemplate, ABC): @property diff --git a/src/vai_lab/examples/crystalDesign/phasestability/CsFA/fulldata/CsFA_T300_above.csv b/src/vai_lab/examples/crystalDesign/phasestability/CsFA/fulldata/CsFA_T300_above.csv new file mode 100644 index 00000000..12a64d5c --- /dev/null +++ b/src/vai_lab/examples/crystalDesign/phasestability/CsFA/fulldata/CsFA_T300_above.csv @@ -0,0 +1 @@ +Cs,MA,FA,dEmix (ev/f.u.),TdSmix (ev/f.u.),dGmix (ev/f.u.) 1.00,0.00,0.00,0.000,0.000,0.000 0.92,0.00,0.08,0.043,0.007,0.036 0.92,0.00,0.08,0.053,0.007,0.046 0.88,0.00,0.13,0.055,0.010,0.045 0.88,0.00,0.13,0.033,0.010,0.023 0.83,0.00,0.17,0.090,0.012,0.078 0.83,0.00,0.17,0.089,0.012,0.077 0.75,0.00,0.25,0.041,0.015,0.026 0.75,0.00,0.25,0.038,0.015,0.023 0.73,0.00,0.28,0.020,0.015,0.005 0.73,0.00,0.28,0.017,0.016,0.001 0.67,0.00,0.33,0.011,0.016,-0.005 0.67,0.00,0.33,0.008,0.016,-0.008 0.65,0.00,0.35,0.000,0.017,-0.017 0.65,0.00,0.35,0.000,0.017,-0.017 0.63,0.00,0.38,-0.043,0.017,-0.060 0.63,0.00,0.38,-0.048,0.017,-0.065 0.58,0.00,0.42,-0.011,0.018,-0.029 0.58,0.00,0.42,-0.004,0.018,-0.022 0.50,0.00,0.50,-0.047,0.018,-0.065 0.50,0.00,0.50,-0.027,0.018,-0.045 0.42,0.00,0.58,-0.052,0.018,-0.070 0.42,0.00,0.58,-0.045,0.018,-0.063 0.38,0.00,0.63,-0.095,0.017,-0.112 0.38,0.00,0.63,-0.100,0.017,-0.117 0.33,0.00,0.67,-0.083,0.016,-0.099 0.33,0.00,0.67,-0.088,0.016,-0.104 0.25,0.00,0.75,-0.137,0.015,-0.152 0.25,0.00,0.75,-0.142,0.015,-0.157 0.17,0.00,0.83,-0.085,0.012,-0.097 0.17,0.00,0.83,-0.091,0.012,-0.103 0.13,0.00,0.88,-0.069,0.010,-0.079 0.13,0.00,0.88,-0.074,0.010,-0.084 0.08,0.00,0.92,-0.110,0.007,-0.117 0.08,0.00,0.92,-0.115,0.007,-0.122 0.00,0.00,1.00,0.000,0.000,0.000 \ No newline at end of file diff --git a/src/vai_lab/examples/crystalDesign/phasestability/CsMA/fulldata/CsMA_T300_above.csv b/src/vai_lab/examples/crystalDesign/phasestability/CsMA/fulldata/CsMA_T300_above.csv new file mode 100644 index 00000000..f2358371 --- /dev/null +++ b/src/vai_lab/examples/crystalDesign/phasestability/CsMA/fulldata/CsMA_T300_above.csv @@ -0,0 +1 @@ +Cs,MA,FA,dEmix (ev/f.u.),TdSmix (ev/f.u.),dGmix (ev/f.u.) 1.00,0.00,0.00,0.000,0.000,0.000 0.92,0.08,0.00,0.054,0.007,0.047 0.88,0.12,0.00,0.043,0.010,0.033 0.88,0.12,0.00,0.058,0.010,0.048 0.75,0.25,0.00,0.044,0.015,0.029 0.67,0.33,0.00,0.053,0.016,0.037 0.63,0.37,0.00,0.024,0.017,0.007 0.63,0.37,0.00,0.026,0.017,0.009 0.50,0.50,0.00,0.016,0.018,-0.002 0.50,0.50,0.00,0.037,0.018,0.019 0.42,0.58,0.00,0.012,0.018,-0.006 0.42,0.58,0.00,0.027,0.018,0.009 0.38,0.62,0.00,0.001,0.017,-0.016 0.38,0.62,0.00,0.003,0.017,-0.014 0.33,0.67,0.00,0.029,0.016,0.013 0.33,0.67,0.00,0.031,0.016,0.015 0.25,0.75,0.00,0.005,0.015,-0.010 0.25,0.75,0.00,0.005,0.015,-0.010 0.17,0.83,0.00,-0.016,0.012,-0.028 0.17,0.83,0.00,-0.013,0.012,-0.025 0.13,0.87,0.00,-0.038,0.010,-0.048 0.13,0.87,0.00,-0.026,0.010,-0.036 0.08,0.92,0.00,-0.014,0.007,-0.021 0.08,0.92,0.00,-0.045,0.007,-0.052 0.00,1.00,0.00,0.000,0.000,0.000 \ No newline at end of file diff --git a/src/vai_lab/examples/crystalDesign/phasestability/FAMA/fulldata/FAMA_T300_above.csv b/src/vai_lab/examples/crystalDesign/phasestability/FAMA/fulldata/FAMA_T300_above.csv new file mode 100644 index 00000000..2ffcec7e --- /dev/null +++ b/src/vai_lab/examples/crystalDesign/phasestability/FAMA/fulldata/FAMA_T300_above.csv @@ -0,0 +1 @@ +Cs,MA,FA,dEmix (ev/f.u.),TdSmix (ev/f.u.),dGmix (ev/f.u.) 0,0,1,0.000,0.000,0.000 0,0.08,0.92,-0.172,0.007,-0.179 0,0.08,0.92,-0.137,0.007,-0.144 0,0.13,0.88,-0.193,0.010,-0.203 0,0.13,0.88,-0.161,0.010,-0.171 0,0.17,0.83,-0.201,0.012,-0.213 0,0.17,0.83,-0.167,0.012,-0.179 0,0.25,0.75,-0.180,0.015,-0.195 0,0.25,0.75,-0.148,0.015,-0.163 0,0.33,0.67,-0.143,0.016,-0.159 0,0.33,0.67,-0.125,0.016,-0.141 0,0.42,0.58,-0.138,0.018,-0.156 0,0.42,0.58,-0.136,0.018,-0.154 0,0.5,0.5,-0.138,0.018,-0.156 0,0.5,0.5,-0.094,0.018,-0.112 0,0.58,0.42,-0.087,0.018,-0.105 0,0.58,0.42,-0.115,0.018,-0.133 0,0.63,0.38,-0.113,0.017,-0.130 0,0.63,0.38,-0.106,0.017,-0.123 0,0.67,0.33,-0.089,0.016,-0.105 0,0.67,0.33,-0.080,0.016,-0.096 0,0.75,0.25,-0.080,0.015,-0.095 0,0.75,0.25,-0.067,0.015,-0.082 0,0.83,0.17,-0.057,0.012,-0.069 0,0.83,0.17,-0.049,0.012,-0.061 0,0.88,0.13,-0.032,0.010,-0.042 0,0.88,0.13,-0.040,0.010,-0.050 0,0.92,0.08,-0.031,0.007,-0.038 0,0.92,0.08,-0.035,0.007,-0.042 0,1,0,0.000,0.000,0.000 \ No newline at end of file diff --git a/src/vai_lab/examples/crystalDesign/phasestability/Readme b/src/vai_lab/examples/crystalDesign/phasestability/Readme new file mode 100644 index 00000000..d1942c91 --- /dev/null +++ b/src/vai_lab/examples/crystalDesign/phasestability/Readme @@ -0,0 +1,16 @@ +1. Folders correspond to the following binary alloys + + (Cs,FA)PbI3 + (FA,MA)PbI3 + (Cs,MA)PbI3 + +2. fulldata - all the data points for the binary alloys +3. *.csv file naming - alloyname_temp.csv + + example: + CsFA_T300_above.csv - enthalpy data for (Cs,FA)PbI3 alloy at T = 300 K. + + Note: + For T = 300 K, T300_above represents the choice of the reference (pure phase) crystal structure at 300 K. Please refer figure 3 in Energy. Environ. Sci. 12 1341 2019 (DOI:10.1039/c8ee03051k) + +4. Data format - {Composition, dE_mix (in eV/formula unit), T*dS_mix (eV/fu), dG_mix (eV/fu)} diff --git a/src/vai_lab/examples/crystalDesign/phasestability/template.csv b/src/vai_lab/examples/crystalDesign/phasestability/template.csv new file mode 100644 index 00000000..1613e8b5 --- /dev/null +++ b/src/vai_lab/examples/crystalDesign/phasestability/template.csv @@ -0,0 +1,16 @@ +Cs,MA,FA,Free energy +0,0.75,0.25,3360.98951 +0,0.25,0.75,2703.2987 +0,1,0,4826.95325 +0,0,1,1066.41486 +0,0.5,0.5,2874.82457 +0.25,0.25,0.5,536.95459 +0.25,0.5,0.25,1633.79642 +0.25,0.75,0,3501.47038 +0.25,0,0.75,192.08462 +0.5,0.5,0,1846.26203 +0.5,0,0.5,408.12527 +0.5,0.25,0.25,2389.18803 +0.75,0.25,0,152.62719 +0.75,0,0.25,422.88636 +1,0,0,2017.8144 diff --git a/src/vai_lab/examples/results/output.pkl b/src/vai_lab/examples/results/output.pkl new file mode 100644 index 0000000000000000000000000000000000000000..c89ae4a91cc3acd3c4ce0c1ee30b78cbfe3ae253 GIT binary patch literal 6665 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 literal 0 HcmV?d00001 diff --git a/src/vai_lab/examples/state-action/X_data.csv b/src/vai_lab/examples/state-action/X_data.csv index a33f8ae8..b10f8298 100644 --- a/src/vai_lab/examples/state-action/X_data.csv +++ b/src/vai_lab/examples/state-action/X_data.csv @@ -1,61 +1,61 @@ -State_x ,State_y ,Action_x ,Action_y -0.9671880089819392 ,0.4380968121803849 ,0.4984887549541376 ,0.9322726736376392 -0.7643188319722541 ,0.01231887020330591 ,0.9830931007621688 ,0.8522744809601737 -0.9237525748244838 ,0.11898284551274751 ,0.9924417893483648 ,0.25218680355486556 -0.9792179211485214 ,0.6255946427530268 ,0.3431932557012749 ,0.22506274930650727 -0.7535567846092962 ,0.24123313933735335 ,0.018579652407582636 ,0.8800662109032867 -0.3437925770776318 ,0.07699836482205524 ,0.4728350987688088 ,0.7662442031942271 -0.9172917672442188 ,0.9662772820792992 ,0.18452917862354012 ,0.24925132769402703 -0.3558655691713499 ,0.7314046169290214 ,0.6292458753640825 ,0.7281748531672392 -0.05455147830497775 ,0.15032095601880535 ,0.000742940145887161 ,0.0263197539225396 -0.12794977066232505 ,0.49156583621314887 ,0.10202991264566497 ,0.5301707346161213 -0.536257172265748 ,0.7996784991300683 ,0.9172832910459607 ,0.8776049102983675 -0.6599930891873356 ,0.09321141488037277 ,0.1482680061282743 ,0.3125012812415898 -0.23424261012475522 ,0.55511448517851 ,0.013046984000703254 ,0.34234482093755003 -0.7101280593659418 ,0.37479280138602833 ,0.27362008914570524 ,0.682871585689911 -0.421235878074406 ,0.3116126920265224 ,0.02583910127018263 ,0.5547669223178248 -0.34286708741990113 ,0.21179048991267835 ,0.32716029003021707 ,0.4890251672215029 -0.5189154708727883 ,0.5461829716414196 ,0.016511407532504907 ,0.9121837468923465 -0.5631894552042326 ,0.3325024218489049 ,0.9161226750644361 ,0.22983791939614862 -0.49074103400728974 ,0.524449286501952 ,0.7100987717394524 ,0.21311227550583367 -0.42488315106570407 ,0.8449397402408293 ,0.5834117468530966 ,0.535672046560473 -0.3192056373096188 ,0.851494347175034 ,0.13184467127491017 ,0.23424731183882164 -0.41787827702876124 ,0.7045916830745 ,0.3297951468894895 ,0.806647258078522 -0.017145552002915787 ,0.10061912324474898 ,0.9024866878930592 ,0.3440758374198163 -0.438299588339767 ,0.6335190171928938 ,0.19639432578427918 ,0.9921209657903454 -0.7419383944302453 ,0.6611922350606557 ,0.06827617632578975 ,0.1127204989170465 -0.6272401825306418 ,0.9286242708669664 ,0.6533329448337888 ,0.3681024165243707 -0.9924588758607049 ,0.867934944378779 ,0.9502383116354627 ,0.44763906453714963 -0.6814344435878125 ,0.08375304244682025 ,0.3479481173938417 ,0.5482785322145338 -0.1050339978746333 ,0.7584944915035335 ,0.7585866415821404 ,0.351215896269197 -0.12658825210891933 ,0.0732871690467427 ,0.5535637694702159 ,0.6312631154416452 -0.7422778633830742 ,0.8789197110172094 ,0.4615899023589518 ,0.47150569972602174 -0.060643318283553405 ,0.7178088837302014 ,0.702272065932264 ,0.38390413101856535 -0.8191895410512178 ,0.3634229938710849 ,0.42135628539750447 ,0.2727994683499393 -0.9999199411408117 ,0.8684190230298257 ,0.2596353916370152 ,0.7818544450839995 -0.4309294603116195 ,0.1621914263062164 ,0.19093665617217148 ,0.2629780574128501 -0.6769153420880742 ,0.25354748987282205 ,0.41826407613880523 ,0.5105298249146336 -0.6973003602191449 ,0.6705192894977414 ,0.8987394761400211 ,0.4890113703300386 -0.24062711159874495 ,0.5047811254637201 ,0.7732363361216537 ,0.847096699066319 -0.7652673533252651 ,0.3180290726747005 ,0.233764403225033 ,0.13733508395405847 -0.20599356053214612 ,0.4693193853964881 ,0.9884067295994179 ,0.14179763257150835 -0.6230605269306876 ,0.37226905005157285 ,0.8375513460804126 ,0.47522858272099777 -0.13169282511385816 ,0.3507415100597824 ,0.2685222265975922 ,0.30877628171800475 -0.12253840357227408 ,0.8734014654383687 ,0.8028293377767859 ,0.8342239310648731 -0.3325029621446359 ,0.04003932588687398 ,0.12709466197531627 ,0.6662216171464865 -0.04245689148699905 ,0.9570047234482667 ,0.43227208799454175 ,0.3865771351092523 -0.2028627113720355 ,0.42487299763806974 ,0.6634501230665879 ,0.42138481640595493 -0.7302574619774882 ,0.7445376224867151 ,0.21713246315756352 ,0.3434198127813938 -0.6365439014447486 ,0.25606444854559063 ,0.5537129809489818 ,0.1629672057071535 -0.7000014791771763 ,0.5979649835252617 ,0.03838676802768348 ,0.9121462360882062 -0.3886002445513097 ,0.977242303405838 ,0.2705691672546615 ,0.9513765865234916 -0.6473604202902449 ,0.28350244814093783 ,0.08775351900953965 ,0.6312290476710444 -0.6990859986824999 ,0.032529525745985444 ,0.5598806306599382 ,0.2896794051531735 -0.9730538815643153 ,0.5161662313731986 ,0.8374231998423672 ,0.41418214281430754 -0.31942545883706497 ,0.47600176099408975 ,0.9147675682128449 ,0.2758930549358044 -0.9906583523353286 ,0.08568211061940656 ,0.18753616812160567 ,0.7573360865775085 -0.06608602930280472 ,0.740352078456626 ,0.6784709775636907 ,0.37006251016903113 -0.48699741570742805 ,0.5692196155586737 ,0.9431057810851509 ,0.4807794949611165 -0.6052645403989522 ,0.1991049312114247 ,0.18358768708081097 ,0.3520418987936338 -0.4376150973891353 ,0.07995788691173977 ,0.18067397841443167 ,0.23594549880692017 -0.31292316838092515 ,0.45870340272609433 ,0.973868440052966 ,0.280301692602244 +State_x,State_y,Action_x,Action_y +580.3128053891636,262.85808730823095,299.09325297248256,559.3636041825836 +458.5912991833525,7.39132212198354,589.8558604573013,511.3646885761042 +554.2515448946903,71.38970730764851,595.4650736090189,151.3120821329193 +587.5307526891128,375.3567856518161,205.91595342076494,135.0376495839043 +452.13407076557775,144.73988360241196,11.147791444549561,528.0397265419721 +206.27554624657907,46.199018893233124,283.7010592612853,459.74652191653627 +550.3750603465313,579.7663692475795,110.71750717412405,149.5507966164162 +213.51934150280997,438.8427701574128,377.5475252184495,436.9049119003435 +32.730886982986625,90.19257361128318,0.44576408753226,15.791852353523762 +76.76986239739499,294.9395017278893,61.21794758739894,318.1024407696728 +321.7543033594488,479.807099478041,550.3699746275765,526.5629461790205 +395.99585351240137,55.92684892822362,88.96080367696457,187.5007687449539 +140.54556607485313,333.068691107106,7.828190400421921,205.40689256252998 +426.0768356195651,224.87568083161696,164.1720534874231,409.7229514139466 +252.7415268446436,186.96761521591344,15.503460762109562,332.86015339069485 +205.72025245194064,127.07429394760698,196.29617401813022,293.4151003329018 +311.349282523673,327.70978298485176,9.90684451950294,547.3102481354078 +337.91367312253954,199.50145310934292,549.6736050386617,137.90275163768916 +294.44462040437384,314.6695719011712,426.0592630436714,127.86736530350015 +254.9298906394224,506.96384414449756,350.047048111858,321.40322793628377 +191.5233823857713,510.89660830502044,79.10680276494605,140.54838710329295 +250.72696621725672,422.7550098447,197.87708813369372,483.9883548471132 +10.28733120174942,60.37147394684934,541.4920127358355,206.44550245188978 +262.9797530038602,380.1114103157363,117.83659547056746,595.2725794742072 +445.1630366581472,396.71534103639345,40.965705795473816,67.6322993502279 +376.3441095183851,557.1745625201798,391.99976690027324,220.86144991462243 +595.4753255164229,520.7609666272674,570.1429869812777,268.58343872228977 +408.8606661526875,50.25182546809212,208.768870436305,328.9671193287203 +63.02039872477998,455.09669490212013,455.1519849492842,210.7295377615182 +75.95295126535159,43.972301428045625,332.13826168212955,378.7578692649871 +445.36671802984455,527.3518266103257,276.9539414153711,282.903419835613 +36.38599097013204,430.6853302381208,421.3632395593584,230.34247861113917 +491.5137246307307,218.05379632265095,252.81377123850265,163.6796810099636 +599.9519646844869,521.0514138178954,155.78123498220913,469.1126670503997 +258.5576761869717,97.31485578372985,114.56199370330283,157.78683444771005 +406.1492052528445,152.12849392369318,250.95844568328312,306.3178949487802 +418.3802161314869,402.31157369864485,539.2436856840127,293.4068221980232 +144.37626695924695,302.86867527823205,463.9418016729922,508.2580194397914 +459.16041199515905,190.81744360482028,140.2586419350198,82.40105037243505 +123.59613631928765,281.59163123789284,593.0440377596508,85.07857954290498 +373.83631615841256,223.36143003094367,502.53080764824756,285.1371496325986 +79.01569506831486,210.44490603586942,161.1133359585553,185.26576903080283 +73.52304214336439,524.0408792630212,481.69760266607153,500.5343586389239 +199.50177728678156,24.02359553212434,76.25679718518971,399.73297028789193 +25.4741348921994,574.2028340689601,259.363252796725,231.94628106555137 +121.7176268232213,254.9237985828418,398.0700738399527,252.83088984357292 +438.1544771864929,446.722573492029,130.2794778945381,206.05188766883626 +381.92634086684916,153.63866912735435,332.2277885693891,97.7803234242921 +420.00088750630573,358.77899011515706,23.032060816610038,547.2877416529237 +233.1601467307858,586.3453820435028,162.3415003527969,570.825951914095 +388.4162521741469,170.10146888456268,52.65211140572376,378.7374286026266 +419.45159920949993,19.51771544759124,335.9283783959629,173.80764309190408 +583.8323289385891,309.6997388239192,502.4539199054203,248.5092856885845 +191.65527530223895,285.6010565964538,548.8605409277069,165.53583296148264 +594.3950114011972,51.4092663716439,112.52170087296335,454.4016519465051 +39.65161758168282,444.2112470739756,407.0825865382144,222.03750610141864 +292.1984494244568,341.5317693352042,565.8634686510904,288.4676969766699 +363.1587242393713,119.46295872685482,110.15261224848655,211.22513927618027 +262.5690584334812,47.974732147043824,108.40438704865896,141.56729928415206 +187.75390102855505,275.2220416356566,584.3210640317797,168.1810155613464 diff --git a/src/vai_lab/examples/xml_files/KNN-classification_demo.xml b/src/vai_lab/examples/xml_files/KNN-classification_demo.xml index e33eec3c..e6bc3fb5 100644 --- a/src/vai_lab/examples/xml_files/KNN-classification_demo.xml +++ b/src/vai_lab/examples/xml_files/KNN-classification_demo.xml @@ -4,7 +4,7 @@ - [(300.0,50),0,{}] + [(350.0,50),0,{}] @@ -19,24 +19,27 @@ - [(300.0,300.0),2,{0:'d0-u2'}] + [(350.0,350.0),2,{0:'d0-u2'}] - - - 50 - - - distance - - + + + + - - [(300.0,550),1,{2:'d2-u1'}] + [(350.0,650),1,{2:'d2-u1'}] + + + Modelling + + + .\examples\results\output.pkl + + diff --git a/src/vai_lab/examples/xml_files/SVR_demo.xml b/src/vai_lab/examples/xml_files/SVR_demo.xml index 1323ee67..f94fa31e 100644 --- a/src/vai_lab/examples/xml_files/SVR_demo.xml +++ b/src/vai_lab/examples/xml_files/SVR_demo.xml @@ -4,7 +4,7 @@ - [(300.0,50),0,{}] + [(350.0,50),0,{}] @@ -19,27 +19,34 @@ - [(300.0,300.0),2,{0:'d0-u2'}] + [(350.0,350.0),2,{0:'d0-u2'}] + + + - 0.01 + 0.1 - rbf + linear - - 10 - - - [(300.0,550),1,{2:'d2-u1'}] + [(350.0,650),1,{2:'d2-u1'}] + + + Modelling + + + .\examples\results\output.pkl + + diff --git a/src/vai_lab/examples/xml_files/canvas_demo.xml b/src/vai_lab/examples/xml_files/canvas_demo.xml index 5ed1f55d..d9d4859d 100644 --- a/src/vai_lab/examples/xml_files/canvas_demo.xml +++ b/src/vai_lab/examples/xml_files/canvas_demo.xml @@ -1,30 +1,44 @@ - + + + [(350.0,50),0,{}] + - - + + - + - + + + [(350.0,350.0),2,{0:'d0-u2'}] + + + + - - - all - - + + + My First UserFeedback Module + + + .\examples\results\output.pkl + + + [(350.0,650),1,{2:'d2-u1'}] + diff --git a/src/vai_lab/examples/xml_files/k-mean_clustering_demo.xml b/src/vai_lab/examples/xml_files/k-mean_clustering_demo.xml index 7c0a369f..658fc9db 100644 --- a/src/vai_lab/examples/xml_files/k-mean_clustering_demo.xml +++ b/src/vai_lab/examples/xml_files/k-mean_clustering_demo.xml @@ -4,7 +4,7 @@ - [(300.0,50),0,{}] + [(350.0,50),0,{}] @@ -17,11 +17,14 @@ - [(301,201),2,{0:'d0-u2'}] + [(350,200),2,{0:'d0-u2'}] - + + + + - X + X @@ -31,17 +34,27 @@ - [(300.0,300.0),3,{2:'d2-u3'}] + [(350.0,350.0),3,{2:'d2-u3'}] + + + - - [(300.0,550),1,{3:'d3-u1'}] + [(350.0,650),1,{3:'d3-u1'}] + + + Modelling + + + .\examples\results\output.pkl + + diff --git a/src/vai_lab/examples/xml_files/logistic_regression_demo.xml b/src/vai_lab/examples/xml_files/logistic_regression_demo.xml deleted file mode 100644 index 7606ece0..00000000 --- a/src/vai_lab/examples/xml_files/logistic_regression_demo.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - [(300.0,50),0,{}] - - - - - - - - - - - - - - - [(300.0,300.0),2,{0:'d0-u2'}] - - - - l2 - - - 0.01 - - - - - - - - - - [(300.0,550),1,{2:'d2-u1'}] - - - diff --git a/src/vai_lab/examples/xml_files/pybullet_env_example.xml b/src/vai_lab/examples/xml_files/pybullet_env_example.xml index 886051e0..53629908 100644 --- a/src/vai_lab/examples/xml_files/pybullet_env_example.xml +++ b/src/vai_lab/examples/xml_files/pybullet_env_example.xml @@ -4,7 +4,7 @@ - [(300.0,50),0,{}] + [(350.0,50),0,{}] @@ -13,7 +13,7 @@ - [(300.0,300.0),2,{0:'d0-u2'}] + [(350.0,350.0),2,{0:'d0-u2'}] @@ -35,14 +35,24 @@ 10 + + + - + + + MyEnv + + + .\examples\results\output.pkl + + - [(300.0,550),1,{2:'d2-u1'}] + [(350.0,650),1,{2:'d2-u1'}] \ No newline at end of file diff --git a/src/vai_lab/examples/xml_files/random_forest_class_demo.xml b/src/vai_lab/examples/xml_files/random_forest_class_demo.xml index e7c0d450..42d4e203 100644 --- a/src/vai_lab/examples/xml_files/random_forest_class_demo.xml +++ b/src/vai_lab/examples/xml_files/random_forest_class_demo.xml @@ -9,6 +9,9 @@ + + [(350.0,50),0,{}] + @@ -21,6 +24,9 @@ X + + + @@ -29,13 +35,28 @@ + + + + + [(350.0,350.0),2,{0:'d0-u2'}] + + + [(350.0,650),1,{2:'d2-u1'}] + - + + + My Modelling Module + + + .\examples\results\output.pkl + + - diff --git a/src/vai_lab/examples/xml_files/regression_demo.xml b/src/vai_lab/examples/xml_files/regression_demo.xml index a528722b..38faeca5 100644 --- a/src/vai_lab/examples/xml_files/regression_demo.xml +++ b/src/vai_lab/examples/xml_files/regression_demo.xml @@ -4,7 +4,7 @@ - [(300.0,50),0,{}] + [(350.0,50),0,{}] @@ -17,18 +17,28 @@ - [(300.0,300.0),2,{0:'d0-u2'}] + [(350.0,350.0),2,{0:'d0-u2'}] + + + - - + + + + Modelling + + + .\examples\results\output.pkl + + - [(300.0,550),1,{2:'d2-u1'}] + [(350.0,650),1,{2:'d2-u1'}] diff --git a/src/vai_lab/examples/xml_files/ridge-scalar-ridge_demo.xml b/src/vai_lab/examples/xml_files/ridge-scalar-ridge_demo.xml index 777ca31c..c98d1191 100644 --- a/src/vai_lab/examples/xml_files/ridge-scalar-ridge_demo.xml +++ b/src/vai_lab/examples/xml_files/ridge-scalar-ridge_demo.xml @@ -4,7 +4,7 @@ - [(300.0,50),0,{}] + [(350.0,50),0,{}] @@ -19,13 +19,16 @@ - [(300,180),2,{0:'d0-u2'}] + [(350,180),2,{0:'d0-u2'}] 0.01 + + + @@ -33,12 +36,15 @@ - [(300.0,300.0),3,{2:'d2-u3'}] + [(350.0,350.0),3,{2:'d2-u3'}] + + + - - True - + + X + @@ -47,8 +53,11 @@ - [(300,408),4,{3:'d3-u4'}] + [(350,408),4,{3:'d3-u4'}] + + + 0.01 @@ -56,12 +65,20 @@ - - [(300.0,550),1,{4:'d4-u1'}] + [(350.0,650),1,{4:'d4-u1'}] + + + Modelling + Modelling-1 + + + .\examples\results\output.pkl + + diff --git a/src/vai_lab/examples/xml_files/ridge_regression_demo.xml b/src/vai_lab/examples/xml_files/ridge_regression_demo.xml index 67b44bcd..58e182f7 100644 --- a/src/vai_lab/examples/xml_files/ridge_regression_demo.xml +++ b/src/vai_lab/examples/xml_files/ridge_regression_demo.xml @@ -4,7 +4,7 @@ - [(300.0,50),0,{}] + [(350.0,50),0,{}] @@ -19,21 +19,31 @@ - [(300.0,300.0),2,{0:'d0-u2'}] + [(350.0,350.0),2,{0:'d0-u2'}] - 0.02 + 0.01 + + + - - [(300.0,550),1,{2:'d2-u1'}] - + [(350.0,650),1,{2:'d2-u1'}] + + + + Modelling + + + .\examples\results\output.pkl + + diff --git a/src/vai_lab/examples/xml_files/scalar_demo.xml b/src/vai_lab/examples/xml_files/scalar_demo.xml index 10e3f914..5b2b1d9a 100644 --- a/src/vai_lab/examples/xml_files/scalar_demo.xml +++ b/src/vai_lab/examples/xml_files/scalar_demo.xml @@ -4,7 +4,7 @@ - [(300.0,50),0,{}] + [(350.0, 50), 0, {}] @@ -14,26 +14,39 @@ + + + - [(300.0,300.0),2,{0:'d0-u2'}] + [(350.0, 350.0), 2, {0: 'd0-u2'}] - - True - + + X + - + + + - [(300.0,550),1,{2:'d2-u1'}] + [(350.0, 650), 1, {2: 'd2-u1'}] + + + Data Processing + + + .\examples\results\output.pkl + + diff --git a/src/vai_lab/examples/xml_files/scaler-lasso_demo.xml b/src/vai_lab/examples/xml_files/scaler-lasso_demo.xml index 45a93a90..a05d1bfa 100644 --- a/src/vai_lab/examples/xml_files/scaler-lasso_demo.xml +++ b/src/vai_lab/examples/xml_files/scaler-lasso_demo.xml @@ -4,7 +4,7 @@ - [(300.0,50),0,{}] + [(350.0,50),0,{}] @@ -19,8 +19,11 @@ - [(296,183),2,{0:'d0-u2'}] + [(350,183),2,{0:'d0-u2'}] + + + X @@ -33,21 +36,32 @@ - [(300,328),3,{2:'d2-u3'}] + [(350,328),3,{2:'d2-u3'}] - + + + + - 0.0002 + 0.2 - - [(300.0,550),1,{3:'d3-u1'}] + [(350.0,650),1,{3:'d3-u1'}] + + + Data Processing + Modelling + + + ./examples/results/test.pkl + + diff --git a/src/vai_lab/examples/xml_files/user_feedback_demo.xml b/src/vai_lab/examples/xml_files/user_feedback_demo.xml deleted file mode 100644 index 6d1a21a6..00000000 --- a/src/vai_lab/examples/xml_files/user_feedback_demo.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - all - - - - - - - - diff --git a/src/vai_lab/examples/xml_files/user_feedback_demo2.xml b/src/vai_lab/examples/xml_files/user_feedback_demo2.xml new file mode 100644 index 00000000..bfe76cc7 --- /dev/null +++ b/src/vai_lab/examples/xml_files/user_feedback_demo2.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + [(350.0, 50), 0, {}] + + + + + + + + + + + + [(350.0, 350.0), 2, {0: 'd0-u2'}] + + + + + + + + + + + + [(350.0, 650), 1, {2: 'd2-u1'}] + + + + User Interaction + + + .\examples\results\output.pkl + + + + diff --git a/src/vai_lab/run_pipeline.py b/src/vai_lab/run_pipeline.py index 4aa9c9f8..a11c9620 100644 --- a/src/vai_lab/run_pipeline.py +++ b/src/vai_lab/run_pipeline.py @@ -58,7 +58,7 @@ def main(): args.file[i] = abspath(args.file[i]) core.load_config_file(args.file) - # Run pipeline + # Run pipeline core.run() if __name__=='__main__': diff --git a/src/vai_lab/utils/plugins/MainPage.py b/src/vai_lab/utils/plugins/MainPage.py index 92043453..e9b5dabe 100644 --- a/src/vai_lab/utils/plugins/MainPage.py +++ b/src/vai_lab/utils/plugins/MainPage.py @@ -320,7 +320,7 @@ def start_dataloader(self): # Infers by default, should it be None? data[variable] = pd.read_csv(filename) isVar[i] = 1 - self.controller.s.append_input_data(variable, rel_to_abs(filename)) + self.controller.xml_handler.append_input_data(variable, rel_to_abs(filename)) if i == 0: self.controller.Data.set(True) if any(isVar[1::2]) and ( @@ -343,7 +343,7 @@ def upload_data_path(self): title='Select a folder', mustexist=True) if folder is not None and len(folder) > 0: - self.controller.s.append_input_data('X', rel_to_abs(folder)) + self.controller.xml_handler.append_input_data('X', rel_to_abs(folder)) def upload_data_folder(self): """ Stores the directory containing the data that will be later loaded diff --git a/src/vai_lab/utils/plugins/aidCanvas.py b/src/vai_lab/utils/plugins/aidCanvas.py index ced0e04a..04171f0d 100644 --- a/src/vai_lab/utils/plugins/aidCanvas.py +++ b/src/vai_lab/utils/plugins/aidCanvas.py @@ -702,9 +702,9 @@ def save_file(self): # to avoid numpy bug during elementwise comparison of lists loop_modules.dtype = mn.dtype if len(loop_modules) == 0 else loop_modules.dtype - self.controller.s.update_module_coords(self.module_list[0],[self.canvas_startxy[0], 0, self.connections[0]]) - self.controller.s.append_module_relationships(self.module_list[0],list(mn[values[:,0]]),list(mn[values[0,:]])) - self.controller.s.filename = self.save_path.name + self.controller.xml_handler.update_module_coords(self.module_list[0],[self.canvas_startxy[0], 0, self.connections[0]]) + self.controller.xml_handler.append_module_relationships(self.module_list[0],list(mn[values[:,0]]),list(mn[values[0,:]])) + self.controller.xml_handler.filename = self.save_path.name for i, mnn in enumerate(mn_id): if (i > 1) and mnn: xml_parent = None @@ -713,7 +713,7 @@ def save_file(self): for x, loop in enumerate(self.loops): if mn[i] in loop['mod']: # Model in this loop if not out_loops[x]: # Loop already defined - self.controller.s.append_pipeline_loop(self.loops[x]['type'], + self.controller.xml_handler.append_pipeline_loop(self.loops[x]['type'], self.loops[x]['condition'], "loop" + str(x), @@ -728,7 +728,7 @@ def save_file(self): xml_parent = "loop"+str(x) parent_loops.append("loop"+str(x)) - self.controller.s.append_pipeline_module(self.module_list[i], + self.controller.xml_handler.append_pipeline_module(self.module_list[i], mn[i], "", {}, @@ -739,7 +739,7 @@ def save_file(self): xml_parent, [self.canvas_startxy[i], i, self.connections[i]]) - self.controller.s.append_pipeline_module(self.module_list[1], # Out + self.controller.xml_handler.append_pipeline_module(self.module_list[1], # Out mn[1], "", {}, @@ -747,7 +747,7 @@ def save_file(self): list(mn[values[1, :]]), None, [self.canvas_startxy[1], 1, self.connections[1]]) - self.controller.s.write_to_XML() + self.controller.xml_handler.write_to_XML() self.saved = True self.controller._append_to_output( "xml_filename", self.save_path.name) diff --git a/src/vai_lab/utils/plugins/dataLoader.py b/src/vai_lab/utils/plugins/dataLoader.py index bdff82a1..cd0559a4 100644 --- a/src/vai_lab/utils/plugins/dataLoader.py +++ b/src/vai_lab/utils/plugins/dataLoader.py @@ -6,6 +6,14 @@ from vai_lab._import_helper import get_lib_parent_dir # from ttkwidgets import CheckboxTreeview # from sys import platform +_PLUGIN_READABLE_NAMES = {"dataLoader": "default", + "data_Loader": "alias", + "data loader": "alias"} # type:ignore +_PLUGIN_MODULE_OPTIONS = {"layer_priority": 2, + "required_children": None} # type:ignore +_PLUGIN_REQUIRED_SETTINGS = {} # type:ignore +_PLUGIN_OPTIONAL_SETTINGS = {} # type:ignore + class dataLoader(): """ Creates a window diff --git a/src/vai_lab/utils/plugins/pluginCanvas.py b/src/vai_lab/utils/plugins/pluginCanvas.py index 5eb92fae..5c1e56c3 100644 --- a/src/vai_lab/utils/plugins/pluginCanvas.py +++ b/src/vai_lab/utils/plugins/pluginCanvas.py @@ -10,7 +10,7 @@ from PIL import Image, ImageTk import tkinter as tk from tkinter import messagebox, ttk - +from tkinter.filedialog import asksaveasfilename _PLUGIN_READABLE_NAMES = {"plugin_canvas": "default", "pluginCanvas": "alias", @@ -41,6 +41,8 @@ def __init__(self, parent, controller, config: dict): self.plugin: Dict[int, tk.StringVar] = {} self.dataType: Dict[int, tk.StringVar] = {} self.allWeHearIs: List[tk.Radiobutton] = [] + self.out_data_xml: List[int, tk.StringVar] = [] + self.out_data_list: List[int, tk.StringVar] = [] if not self.controller._debug: self._setup_frame() @@ -79,8 +81,8 @@ def _setup_frame(self): bg=self.bg, fg='white', anchor=tk.CENTER) - self.my_label.grid(column=5, - row=0, columnspan=2, padx=10) + self.my_label.grid(column=0, + row=0, columnspan=3, padx=10) self.back_img = ImageTk.PhotoImage(Image.open( os.path.join(script_dir, @@ -158,7 +160,7 @@ def select(self, x: float, y: float): self.check_updated() - if self.m in self.id_done and self.m > 1: + if self.m in self.id_done and self.m > 0: self.canvas.itemconfig('p'+str(self.m), fill='#46da63') else: self.canvas.itemconfig('p'+str(self.m), fill=self.bg) @@ -167,21 +169,32 @@ def select(self, x: float, y: float): if not (len(self.canvas.gettags(self.canvas_selected)[0].split('-')) > 1) and\ not (self.canvas.gettags(self.canvas_selected)[0].split('-')[0] == 'loop'): self.m = int(self.canvas.gettags(self.canvas_selected)[0][1:]) - if self.m > 1: - if self.m not in self.id_done and self.m > 1: + if self.m > 0: #> 1: + if self.m not in self.id_done: self.canvas.itemconfig('p'+str(self.m), fill='#dbaa21') for widget in self.allWeHearIs: widget.grid_remove() - - self.display_buttons() + if self.m > 1: + self.reset_sidecheck() + self.display_buttons() + else: + self.reset_sidepanel() + self.display_checklist() module_number = self.id_mod.index(self.m) if not hasattr(self, 'button_forw'): - if module_number == len(self.id_mod)-1: + if module_number == 1: self.button_forw = tk.Button( self.frame4, text='Finish', bg=self.bg, font=self.controller.pages_font, fg='white', height=3, width=15, command=self.finish, state=tk.NORMAL, image='') + elif module_number == len(self.id_mod)-1: + pCoord = self.canvas.coords( + 'p'+str(self.id_mod[1])) + self.button_forw = tk.Button( + self.frame4, image=self.forw_img, bg=self.bg, + command=lambda: self.select( + pCoord[0], pCoord[1]), state=tk.NORMAL) else: pCoord = self.canvas.coords( 'p'+str(self.id_mod[module_number+1])) @@ -191,10 +204,17 @@ def select(self, x: float, y: float): pCoord[0], pCoord[1]), state=tk.NORMAL) self.button_forw.grid( column=1, row=0, sticky="news", pady=(0, 10), padx=(0, 10)) - if module_number < 3: + if module_number == 1: + mCoord = self.canvas.coords( + 'p'+str(self.id_mod[-1])) self.button_back = tk.Button( self.frame4, image=self.back_img, bg=self.bg, - state=tk.DISABLED) + command=lambda: self.select( + mCoord[0], mCoord[1]), state=tk.NORMAL) + elif module_number < 3: + self.button_back = tk.Button( + self.frame4, image=self.back_img, bg=self.bg, + state=tk.DISABLED) else: mCoord = self.canvas.coords( 'p'+str(self.id_mod[module_number-1])) @@ -205,18 +225,30 @@ def select(self, x: float, y: float): self.button_back.grid( column=0, row=0, sticky="news", pady=(0, 10)) else: - if module_number == len(self.id_mod)-1: + if module_number == 1: self.button_forw.config(text='Finish', bg=self.bg, font=self.controller.pages_font, fg='white', height=3, width=15, command=self.finish, state=tk.NORMAL, image='') + elif module_number == len(self.id_mod)-1: + pCoord = self.canvas.coords( + 'p'+str(self.id_mod[1])) + self.button_forw.config(image=self.forw_img, bg=self.bg, + command=lambda: self.select( + pCoord[0], pCoord[1]), text='', state=tk.NORMAL) else: pCoord = self.canvas.coords( 'p'+str(self.id_mod[module_number+1])) self.button_forw.config(image=self.forw_img, bg=self.bg, command=lambda: self.select( pCoord[0], pCoord[1]), text='', state=tk.NORMAL) - if module_number < 3: + if module_number == 1: + mCoord = self.canvas.coords( + 'p'+str(self.id_mod[-1])) + self.button_back.config(image=self.back_img, bg=self.bg, + command=lambda: self.select( + mCoord[0], mCoord[1]), text='', state=tk.NORMAL) + elif module_number < 3: self.button_back.config(image=self.back_img, bg=self.bg, state=tk.DISABLED, text='') else: @@ -225,19 +257,30 @@ def select(self, x: float, y: float): self.button_back.config(image=self.back_img, bg=self.bg, command=lambda: self.select( mCoord[0], mCoord[1]), text='', state=tk.NORMAL) - else: # If user clicks on Initialiser or Output - self.my_label.config(text='') - for widget in self.allWeHearIs: - widget.grid_remove() - for widget in self.radio_label: - widget.grid_remove() + else: # If user clicks on Initialiser + self.reset_sidepanel() if hasattr(self, 'button_forw'): self.button_back.config(image=self.back_img, bg=self.bg, state=tk.DISABLED, text='') pCoord = self.canvas.coords('p'+str(self.id_mod[2])) self.button_forw.config(image=self.forw_img, bg=self.bg, command=lambda: self.select( - pCoord[0], pCoord[1]), text='', state=tk.NORMAL) + pCoord[0], pCoord[1]), text='', state=tk.NORMAL) + def reset_sidepanel(self): + """ Removes information from the panel to the side of the canvas. + """ + self.my_label.config(text='') + for widget in self.allWeHearIs: + widget.grid_remove() + for widget in self.radio_label: + widget.grid_remove() + self.reset_sidecheck() + + def reset_sidecheck(self): + if hasattr(self, 'frame_tree'): + self.frame_tree.grid_remove() + if hasattr(self, 'frame_path'): + self.frame_path.grid_remove() def finish(self): """ Calls function check_quit. @@ -248,17 +291,37 @@ def finish(self): self.check_quit() def check_updated(self): - """ Checks if the current plugin exists and - stores/updates the plugin options + """ Checks if the current plugin exists and stores/updates the plugin options. + It also cheks if the output data has been modfied and stores/updates the + information accordingly. """ if (self.m in self.plugin.keys()) and\ (self.plugin[self.m].get() != 'None'): # add self.id_done.append(self.m) - self.s.append_plugin_to_module(self.plugin[self.m].get(), - {**self.req_settings, ** - self.opt_settings}, - np.array(self.module_names)[ - self.m == np.array(self.id_mod)][0], + self.xml_handler.append_plugin_to_module( + self.plugin[self.m].get(), + {**self.req_settings, **self.opt_settings}, + self.plugin_inputData.get(), + np.array(self.module_names)[self.m == np.array(self.id_mod)][0], + True) + + elif len(set([elem.get() for elem in self.out_data_list if len(elem.get())>1]) + ^ set(self.out_data_xml)) > 0 : + self.out_data_xml = [elem.get() for elem in self.out_data_list if len(elem.get())>1] + self.id_done.append(self.m) + + if os.path.normpath(get_lib_parent_dir()) == os.path.normpath(os.path.commonpath([self.path_out, get_lib_parent_dir()])): + rel_path = os.path.join('.', os.path.relpath(self.path_out, + os.path.commonpath([self.path_out, get_lib_parent_dir()]))) + else: + rel_path = self.path_out + + self.xml_handler.append_plugin_to_module( + 'Output', + {'outdata': self.out_data_xml, + 'outpath': rel_path}, + None, + np.array(self.module_names)[self.m == np.array(self.id_mod)][0], True) def display_buttons(self): @@ -333,6 +396,81 @@ def display_buttons(self): self.CreateToolTip(rb, text=descriptions[p]) self.allWeHearIs.append(rb) + def display_checklist(self): + """ Updates the displayed tree to the left of canvas. + Used to specify the output data and files. """ + self.my_label.config( + text='Indicate which module\'s output data\nshould be saved:') + dataSources = [i for j, i in enumerate(self.module_names) if j != 1] + self.frame_tree = tk.Frame(self.frame_canvas, bg=self.bg) + self.frame_tree.grid(column=0, row=0, sticky="new", padx=(10, 0)) + for c, choice in enumerate(dataSources): + cb = tk.Checkbutton(self.frame_tree, var=self.out_data_list[c], text=choice, + onvalue=choice, offvalue="", + pady=10, + font=self.controller.pages_font, + bg=self.bg, + fg='white', + selectcolor=self.bg, + anchor='w', + width=20, + background=self.frame_canvas.cget("background") + ) + cb.grid(row=c, column=0) + if c == len(dataSources)-1: + cb.select() + self.frame_path = tk.Frame(self.frame_canvas, bg=self.bg) + self.frame_path.grid(column=0, row=1, sticky="new", padx=(10, 0)) + self.my_label = tk.Label(self.frame_path, + text='Indicate the output file name:', + pady=10, + font=self.controller.title_font, + bg=self.bg, + fg='white', + anchor=tk.CENTER) + self.my_label.grid(column=0, + row=0, columnspan=2, padx=10) + tk.Button(self.frame_path, + text="Browse", + command=self.upload_file + ).grid(column=0, row=1) + width = 63 + self.path_out = os.path.join(get_lib_parent_dir(),'examples','results','output.pkl') + filename = '...' + \ + self.path_out[-width + + 3:] if self.path_out and len(self.path_out) > width else self.path_out + self.label_list = tk.Label(self.frame_path, text=filename, + pady=10, + padx=10, + font=self.controller.pages_font, + fg='white', + bg=self.bg + ) + self.label_list.grid(column=1, row=1) + + def upload_file(self): + """ Asks for a file and stores the path and displays it. + """ + filename = asksaveasfilename(initialdir=os.path.join(get_lib_parent_dir(),'examples','results'), + title='Select an output file', + defaultextension='.pkl', + filetypes=[('Pickle file', '.pkl')]) + if filename is not None: + self.path_out = filename + width = 63 + filename = '...' + \ + filename[-width + + 3:] if filename and len(filename) > width else filename + self.label_list.config(text=filename) + + def getCheckedItems(self): + values = [] + for var in self.vars: + value = var.get() + if value: + values.append(value) + return values + def optionsWindow(self): """ Function to create a new window displaying the available options of the selected plugin.""" @@ -386,6 +524,21 @@ def optionsWindow(self): frame2.grid_rowconfigure(tuple(range(self.r)), weight=1) frame2.grid_columnconfigure(tuple(range(2)), weight=1) + frame5 = tk.Frame(self.newWindow) + tk.Label(frame5, + text="Indicate which plugin's output data should be used as input", anchor=tk.N, justify=tk.LEFT).pack(expand=True) + + frame6 = tk.Frame(self.newWindow, highlightbackground="black", highlightthickness=1) + + current = np.where(self.m == np.array(self.id_mod))[0][0] + dataSources = [i for j, i in enumerate(self.module_names) if j not in [1,current]] + + self.plugin_inputData = tk.StringVar(frame6) + dropDown = tk.ttk.OptionMenu(frame6, self.plugin_inputData, dataSources[current-2], *dataSources) + style.configure("TMenubutton", background="white") + dropDown["menu"].configure(bg="white") + dropDown.pack() + self.finishButton = tk.Button( frame4, text='Finish', command=self.removewindow) self.finishButton.grid( @@ -395,7 +548,10 @@ def optionsWindow(self): self.newWindow.protocol('WM_DELETE_WINDOW', self.removewindow) frame1.grid(column=0, row=0, sticky="ew") - frame4.grid(column=0, row=2, sticky="se") + frame4.grid(column=0, row=20, sticky="se") + frame5.grid(column=0, row=2, sticky="ew") + frame6.grid(column=0, row=3) + self.newWindow.grid_rowconfigure(1, weight=2) self.newWindow.grid_columnconfigure(0, weight=1) @@ -537,7 +693,7 @@ def removewindow(self): self.focus() def get_all_children(self, item=""): - """ Iterates over the treeview to get all childer """ + """ Iterates over the treeview to get all children """ children = self.tree.get_children(item) for child in children: children += self.get_all_children(child) @@ -630,10 +786,12 @@ def add_module(self,boxName: str,x: float,y:float,ini = False,out = False, iid = :param out: bool type of whether the module corresponds to output. """ iid = self.modules if iid is None else iid - if not ini and not out: - tag = ('o'+str(iid),) - else: #Make initialisation and output unmoveable + if ini: #Make initialisation and output unmoveable tag = ('n0',) + elif out: + tag = ('n1',) + else: + tag = ('o'+str(iid),) text_w = self.controller.pages_font.measure(boxName+'-00') + 10 self.canvas.create_rectangle( x - text_w/2 , @@ -707,10 +865,10 @@ def upload(self): self.reset() - self.s = XML_handler() - self.s.load_XML(filename) - # self.s._print_pretty(self.s.loaded_modules) - modules = self.s.loaded_modules + self.xml_handler = XML_handler() + self.xml_handler.load_XML(filename) + # self.xml_handler._print_pretty(self.xml_handler.loaded_modules) + modules = self.xml_handler.loaded_modules modout = modules['Output'] # They are generated when resetting del modules['Initialiser'], modules['Output'] @@ -759,6 +917,12 @@ def upload(self): rowspan=4, pady=(0, 10)) self.framex.grid_columnconfigure(tuple(range(2)), weight=1) self.frame_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + + # Define modules for output data selection + for choice in self.module_names: + var = tk.StringVar(value=choice) + var.set(0) + self.out_data_list.append(var) def set_mousewheel(self, widget, command): """Activate / deactivate mousewheel scrolling when @@ -867,7 +1031,7 @@ def reset(self): self.loops = [] self.drawLoop = False self.l = 0 - self.id_done = [0, 1] + self.id_done = [0] self.plugin = {} for widget in self.allWeHearIs: widget.grid_remove() @@ -885,18 +1049,18 @@ def check_quit(self): self.canvas.delete(tk.ALL) self.frame_canvas.delete(tk.ALL) self.saved = True - self.s.write_to_XML() + self.xml_handler.write_to_XML() self.controller.Plugin.set(True) self.controller._show_frame("MainPage") # TODO: Check if loaded - elif len(self.s.loaded_modules) == 0: + elif len(self.xml_handler.loaded_modules) == 0: self.controller._show_frame("MainPage") self.controller.Plugin.set(False) else: self.reset() self.canvas.delete(tk.ALL) self.frame_canvas.delete(tk.ALL) - self.s.write_to_XML() + self.xml_handler.write_to_XML() self.controller.Plugin.set(True) self.controller._show_frame("MainPage") diff --git a/tests/test_launch.py b/tests/test_launch.py index 07d70d5e..88866127 100644 --- a/tests/test_launch.py +++ b/tests/test_launch.py @@ -7,3 +7,4 @@ def test_launch(): core = ai.Core() core._debug = True core.run() + \ No newline at end of file