|
ENLIGHTEN
Cross-platform desktop GUI for Wasatch Photonics spectrometers
|
This class encapsulates all KnowItAll data, widgets and processing. More...
Public Member Functions | |
| __init__ (self, ctl) | |
| disconnect (self) | |
| enqueue_measurement (self, measurement) | |
| The user has clicked the "fingerprint" ID button on a saved Measurement thumbnail. | |
| process (self, pr, settings) | |
| Called by Controller.process_reading to apply any Raman ID for whatever we just read (or re-read) | |
| process_last (self) | |
| update (self) | |
| update_visibility (self) | |
Public Attributes | |
| bt_alias = cfu.pushButton_id_results_make_alias | |
| bt_benign = cfu.pushButton_id_results_flag_benign | |
| bt_clear = cfu.pushButton_id_results_clear | |
| bt_hazard = cfu.pushButton_id_results_flag_hazard | |
| bt_id = cfu.pushButton_scope_id | |
| bt_reset = cfu.pushButton_id_results_reset | |
| bt_suppress = cfu.pushButton_id_results_suppress | |
| cb_all = cfu.checkBox_kia_display_all_results | |
| cb_enabled = cfu.checkBox_kia_enabled | |
| cb_hazard = cfu.checkBox_kia_alarm_low_scoring_hazards | |
| bool | closing = False |
| config = Config() | |
| bool | connecting = True |
| ctl = ctl | |
| current_processed_reading = None | |
| display_all = self.cb_all.isChecked() | |
| bool | enabled = False |
| executable_pathname = None | |
| ext_wrapper = None | |
| frame_results = cfu.frame_id_results_white | |
| frame_side = cfu.frame_kia_outer | |
| bool | hidden = False |
| is_installed = self._check_installed() | |
| kia_pathname = None | |
| last_declared_match = None | |
| last_response = None | |
| last_tip = None | |
| lb_logo = cfu.label_kia_logo | |
| lb_name = cfu.label_kia_compound_name | |
| lb_path = cfu.label_kia_install_path | |
| lb_processing = cfu.label_kia_processing | |
| lb_score = cfu.label_kia_score | |
| max_results = self.sb_max_results.value() | |
| list | measurement_queue = [] |
| bool | processing = False |
| processing_start_time = None | |
| dict | recent_matches = {} |
| sb_max_results = cfu.spinBox_kia_max_results | |
| sb_score_min = cfu.spinBox_kia_score_min | |
| score_min = self.sb_score_min.value() | |
| bool | sent_install_tip = False |
| table_recent = cfu.tableWidget_id_match_recent | |
| table_results = cfu.tableWidget_id_match_results | |
| wrapper = None | |
Static Public Attributes | |
| str | BENIGN_COLOR_NAME = 'enlighten_benign' |
| str | BENIGN_PROPERTY = "wpBenign" |
| int | CLEAR_LAST_MATCH_SEC = 10 |
| str | HAZARD_COLOR_NAME = 'enlighten_hazard' |
| str | HAZARD_PROPERTY = "wpHazard" |
| str | KIA_CONSOLE_NAME = "KIAConsole.exe" |
| str | KIA_STYLED_NAME = '<html><head/><body><p>KnowItAll<sup>®</sup></p></body></html>' |
| str | KNOW_IT_ALL_DIRECTORY = "C:\\Program Files\\KnowItAll" |
| int | RECENT_COL_COMPOUND = 1 |
| int | RECENT_COL_TIME = 0 |
| int | RESULTS_COL_COMPOUND = 1 |
| int | RESULTS_COL_SCORE = 0 |
Protected Member Functions | |
| _alias_callback (self) | |
| The user has created an alias for a compound name. | |
| _all_callback (self) | |
| The user clicked the "show all results" checkbox, so display or hide the table. | |
| _benign_callback (self) | |
| The user has flagged a compound as benign. | |
| _check_installed (self) | |
| Test whether both the Know-It-All application, and our executable wrapper, are installed. | |
| _clear_callback (self) | |
| _clear_response (self, label="") | |
| _clear_suppressed (self, response) | |
| Remove any "suppressed" MatchResultEntries from the MatchResponse. | |
| _colorize_table_row (self, table, row, aliased_name) | |
| _connect (self) | |
| _declare_match (self, response) | |
| Using the Response object, return a DeclaredMatch with hazards, benigns, and aliases resolved. | |
| _enabled_callback (self, plugin_process=False) | |
| The user has clicked the "continuous" checkbox which enables or disables KIA processing of each acquired spectrum, so connect if necessary. | |
| _find_one_aliased (self, names, within) | |
| Given a list of names (presumably tied compounds), if EXACTLY ONE has an alias, return that name. | |
| _find_one_in_set (self, names, within) | |
| Given a list of names (presumably tied compounds), and a set 'within' (presumably hazards or benigns), if EXACTLY ONE of the list of names (including aliases of those names) falls within the set, return that name. | |
| _get_aliased_name (self, root) | |
| Given a compound name (possibly an alias), return an AliasedName containing the original (KnowItAll) name, the preferred alias (perhaps an alias-of-aliases, in case of manually-editted config files), and a non-empty set of all names (both the original and all known aliases). | |
| _get_elapsed_time_str (self) | |
| _get_selected_compound_name (self) | |
| _get_selected_item_recent (self) | |
| _get_selected_item_results (self) | |
| _hazard_callback (self) | |
| The user has flagged a compound as hazardous. | |
| _hide_callback (self) | |
| _id_callback (self) | |
| The user clicked on the fingerprint button atop the scope screen, indicating to identify the current processed reading (hopefully when paused). | |
| _init_table (self, table, cols) | |
| _init_tables (self) | |
| This method is provided to deal with an apparent bug in the pyside2-uic.exe tool that comes with PySide2 5.13.0. | |
| _is_benign (self, names) | |
| _is_hazard (self, names) | |
| _max_results_callback (self) | |
| _play_sound (self, category) | |
| For now, just play a standard Windows exclamation if matching a hazard. | |
| _process_response (self, response) | |
| _reset (self) | |
| _reset_callback (self) | |
| _score_callback (self) | |
| _send_cropped_request (self, pr, settings=None, measurement_id=None) | |
| _suppress_callback (self) | |
| The user has suppressed a compound. | |
| _table_recent_callback (self, row, column=0) | |
| The user clicked on a row, so enable buttons relevant to that compound. | |
| _table_results_callback (self, row, column=0) | |
| The user clicked on a row, so enable buttons relevant to that compound. | |
| _update_recent_table (self) | |
| _update_result_table (self) | |
| _update_table_buttons (self) | |
This class encapsulates all KnowItAll data, widgets and processing.
ENLIGHTEN primarily supports Raman compound ID using KnowItAll software, abbreviated in some code as KIA.
The KnowItAll API was documented here:
All communication between ENLIGHTEN and KnowItAll is encapsulated in this C++ wrapper program:
The wrapper is currently left as an out-of-process executable (KIAConsole.exe) as it crashes intermittently, and this way it doesn't bring down ENLIGHTEN.
Currently the KIAConsole.exe binary is stored in the ENLIGHTEN distribution under dist/, and is not dynamically built as part of the ENLIGHTEN build procedure.
It is rolled into the ENLIGHTEN installer by Application_InnoSetup.iss, which places KIAConsole.exe into \Program Files (x86)\Wasatch Photonics\Enlighten\ENLIGHTEN, alongside enlighten.exe.
Note that KIAConsole.exe requires the Visual C++ Redistributable Runtime be installed, which can be obtained from:
This runtime is now automatically installed by the InnoSetup installer.
The vendor provides a free 1-year trial license of KnowItAll Vibrational Spectroscopy Edition to all ENLIGHTEN users. Users are required to renew the license if they wish to continue using KnowItAll after the first year.
The KnowItAll software is installed as follows:
Note that significant functionality is further encapsulated into KnowItAll.Wrapper (a sibling to this class)..
That class is deliberately kept small and, significantly, devoid of callback functions to any class which "holds" Qt objects (like Controller, or Feature itself), as those were found to cause pickling exceptions in multiprocessing.Process.start.
The configuration needs of this feature exceed what Configuration's .ini format can easily provide, so KnowItAll.Config was provided to support configuration in JSON.
I'm treating the aliases as though the config file may be human-edited, and thus end up with cylic graphs like a -> b -> a, converging roots like a -> b and c -> b, and chains like a -> b -> c. One thing that CANNOT occur is diverging roots, i.e. a -> b and a -> c (such can appear in the file, but only one will win).
This is probably overcomplicating things, but down the rabbit-hole I went.
| enlighten.KnowItAll.Feature.Feature.__init__ | ( | self, | |
| ctl ) |
|
protected |
The user has created an alias for a compound name.
|
protected |
The user clicked the "show all results" checkbox, so display or hide the table.
|
protected |
The user has flagged a compound as benign.
|
protected |
Test whether both the Know-It-All application, and our executable wrapper, are installed.
|
protected |
|
protected |
|
protected |
Remove any "suppressed" MatchResultEntries from the MatchResponse.
|
protected |
|
protected |
|
protected |
Using the Response object, return a DeclaredMatch with hazards, benigns, and aliases resolved.
|
protected |
The user has clicked the "continuous" checkbox which enables or disables KIA processing of each acquired spectrum, so connect if necessary.
|
protected |
Given a list of names (presumably tied compounds), if EXACTLY ONE has an alias, return that name.
|
protected |
Given a list of names (presumably tied compounds), and a set 'within' (presumably hazards or benigns), if EXACTLY ONE of the list of names (including aliases of those names) falls within the set, return that name.
|
protected |
Given a compound name (possibly an alias), return an AliasedName containing the original (KnowItAll) name, the preferred alias (perhaps an alias-of-aliases, in case of manually-editted config files), and a non-empty set of all names (both the original and all known aliases).
In the case of converging roots (a -> b and c -> b), moving "back out to the root" could yield the wrong root, so hopefully this function won't need to be called from a non-root name. (Currently that is the case.)
This could be a static function in AliasedName ("create()"), but requires access to config, so we'd really need an AliasedNameFactory. Just leave it.
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
The user has flagged a compound as hazardous.
|
protected |
|
protected |
The user clicked on the fingerprint button atop the scope screen, indicating to identify the current processed reading (hopefully when paused).
|
protected |
|
protected |
This method is provided to deal with an apparent bug in the pyside2-uic.exe tool that comes with PySide2 5.13.0.
As far as I can tell, if enlighten_layout.ui contains two QTableWidgets within the same...something...that have NAMED COLUMN HEADERS, pyside2-uic gets internally confused and conflates the tables when converting the XML to Python.
In this case, the QTableWidgets table_results and table_recent both appear on the scope screen within frame_id_results. Each has two columns, which are (Score, Compound) and (Time, Compound) respectively. Each pair should be internally numbered (0, 1) within the table.
However, when pyside2-uic tries to assign the column names, it conflates the tables, thinking there actually 4 columns, and so treats the first column of the second table as column 2 rather than the second column 0:
I'd hoped that by wrapping each table inside its own QFrame and QWidget I might break this connection between them, but no dice.
Therefore, for now I'm creating and naming the columns programmatically. This will possibly be fixed in pyside2-uic by the time you read this, but who knows.
|
protected |
|
protected |
|
protected |
|
protected |
For now, just play a standard Windows exclamation if matching a hazard.
Later we can check self.config.sounds to see if it names a sound to use for "hazard", "benign" or "unknown"
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
The user has suppressed a compound.
|
protected |
The user clicked on a row, so enable buttons relevant to that compound.
|
protected |
The user clicked on a row, so enable buttons relevant to that compound.
|
protected |
|
protected |
|
protected |
| enlighten.KnowItAll.Feature.Feature.disconnect | ( | self | ) |
| enlighten.KnowItAll.Feature.Feature.enqueue_measurement | ( | self, | |
| measurement ) |
The user has clicked the "fingerprint" ID button on a saved Measurement thumbnail.
| enlighten.KnowItAll.Feature.Feature.process | ( | self, | |
| pr, | |||
| settings ) |
Called by Controller.process_reading to apply any Raman ID for whatever we just read (or re-read)
| enlighten.KnowItAll.Feature.Feature.process_last | ( | self | ) |
| enlighten.KnowItAll.Feature.Feature.update | ( | self | ) |
| enlighten.KnowItAll.Feature.Feature.update_visibility | ( | self | ) |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
protected |
|
static |
|
static |
| enlighten.KnowItAll.Feature.Feature.bt_alias = cfu.pushButton_id_results_make_alias |
| enlighten.KnowItAll.Feature.Feature.bt_benign = cfu.pushButton_id_results_flag_benign |
| enlighten.KnowItAll.Feature.Feature.bt_clear = cfu.pushButton_id_results_clear |
| enlighten.KnowItAll.Feature.Feature.bt_hazard = cfu.pushButton_id_results_flag_hazard |
| enlighten.KnowItAll.Feature.Feature.bt_id = cfu.pushButton_scope_id |
| enlighten.KnowItAll.Feature.Feature.bt_reset = cfu.pushButton_id_results_reset |
| enlighten.KnowItAll.Feature.Feature.bt_suppress = cfu.pushButton_id_results_suppress |
| enlighten.KnowItAll.Feature.Feature.cb_all = cfu.checkBox_kia_display_all_results |
| enlighten.KnowItAll.Feature.Feature.cb_enabled = cfu.checkBox_kia_enabled |
| enlighten.KnowItAll.Feature.Feature.cb_hazard = cfu.checkBox_kia_alarm_low_scoring_hazards |
|
static |
| bool enlighten.KnowItAll.Feature.Feature.closing = False |
| enlighten.KnowItAll.Feature.Feature.config = Config() |
| bool enlighten.KnowItAll.Feature.Feature.connecting = True |
| enlighten.KnowItAll.Feature.Feature.ctl = ctl |
| enlighten.KnowItAll.Feature.Feature.current_processed_reading = None |
| enlighten.KnowItAll.Feature.Feature.display_all = self.cb_all.isChecked() |
| bool enlighten.KnowItAll.Feature.Feature.enabled = False |
| enlighten.KnowItAll.Feature.Feature.executable_pathname = None |
| enlighten.KnowItAll.Feature.Feature.ext_wrapper = None |
| enlighten.KnowItAll.Feature.Feature.frame_results = cfu.frame_id_results_white |
| enlighten.KnowItAll.Feature.Feature.frame_side = cfu.frame_kia_outer |
|
static |
|
static |
| bool enlighten.KnowItAll.Feature.Feature.hidden = False |
| enlighten.KnowItAll.Feature.Feature.is_installed = self._check_installed() |
|
static |
| enlighten.KnowItAll.Feature.Feature.kia_pathname = None |
|
static |
|
static |
| enlighten.KnowItAll.Feature.Feature.last_declared_match = None |
| enlighten.KnowItAll.Feature.Feature.last_response = None |
| enlighten.KnowItAll.Feature.Feature.last_tip = None |
| enlighten.KnowItAll.Feature.Feature.lb_logo = cfu.label_kia_logo |
| enlighten.KnowItAll.Feature.Feature.lb_name = cfu.label_kia_compound_name |
| enlighten.KnowItAll.Feature.Feature.lb_path = cfu.label_kia_install_path |
| enlighten.KnowItAll.Feature.Feature.lb_processing = cfu.label_kia_processing |
| enlighten.KnowItAll.Feature.Feature.lb_score = cfu.label_kia_score |
| enlighten.KnowItAll.Feature.Feature.max_results = self.sb_max_results.value() |
| list enlighten.KnowItAll.Feature.Feature.measurement_queue = [] |
| bool enlighten.KnowItAll.Feature.Feature.processing = False |
| enlighten.KnowItAll.Feature.Feature.processing_start_time = None |
|
static |
|
static |
| enlighten.KnowItAll.Feature.Feature.recent_matches = {} |
|
static |
|
static |
| enlighten.KnowItAll.Feature.Feature.sb_max_results = cfu.spinBox_kia_max_results |
| enlighten.KnowItAll.Feature.Feature.sb_score_min = cfu.spinBox_kia_score_min |
| enlighten.KnowItAll.Feature.Feature.score_min = self.sb_score_min.value() |
| bool enlighten.KnowItAll.Feature.Feature.sent_install_tip = False |
| enlighten.KnowItAll.Feature.Feature.table_recent = cfu.tableWidget_id_match_recent |
| enlighten.KnowItAll.Feature.Feature.table_results = cfu.tableWidget_id_match_results |
| enlighten.KnowItAll.Feature.Feature.wrapper = None |