-
Notifications
You must be signed in to change notification settings - Fork 7
Introduction for new developers
OpenMEE is written in python/Qt. The program can be seen to be based on the main_form window and the spreadsheet inside. This window contains the menus and toolbar actions that allow the user to perform analyses and operations on the data.
The spreadsheet is where the user interacts with the underlying data model. The spreadsheet is a QTableView that uses an instance of an EETableModel. The EETableModel is a QAbstractTableModel. The EETableModel contains an instance of an EEDataSet which contains all the data. The EETableModel serves as an intermediary between the GUI and the underlying dataset. The EEDataset is made up of 'studies' and 'variables' roughly corresponding to rows and columns of the spreadsheet. Each study has some value for each variable. Both studies and variables have labels. A variable can be of one of three types: categorical, continuous, and counts, corresponding to python str, float, and int types.
First, you write the routine (or wrapper for a third party R function) in the openmetar package of @bwallace 's OpenMeta[Analyst] since OpenMEE and OpenMetAnalyst both share openmetar as a backend. The convention that we generally follow for packaging the results for python at the end of the R function is that we have an R list called 'results' that contains the following members:
- "Summary" a string with results of the analysis.
- "images" a vector of paths to images that the routine generated
- "plot_params_paths" a vector of paths to parameter obejcts that the routine generated.
- and others...
If we follow this convention, the results_window knows how to parse out the various texts and images and make a pretty display that is shown to the user.
Next, you have to connect this routine to the GUI. Before we get started with that, I should mention another convention we follow. All calls to R from python are handled from the python_to_R.py module through rpy2 and shouldn't be done from elsewhere. Once you write and have tested the new routine in R, you should write a function for calling it in python_to_R. I like to structure new functions as follows:
def my_analysis_function(included_studies, other parameters, ...):
# package dataset as R data frame
....
r_str = "my_new_analysis_function_in_R(data={my_data}, first_arg={arg1} .... ).format(my_data=my_r_dataframe.r_repr(), arg1=first_argument_string, ....)
# run the analysis in R and get the result
result = exR.execute_in_R(r_str)
parsed_results = parse_out_results(result) # turn results in to a nice python dict
return(parsed_results)
Next, you need to write another function which displays a wizard to the user (Implemented with QWizard) that gets the parameters needed to run the function from the user and then calls the function you just wrote in python_to_R. This function should be in analyses.py:
def run_my_analysis(self):
wizard = my_analysis_wizard()
if wizard.exec_():
studies = wizard.get_included_studies()
param1 = wizard.get_param1()
param2 = wizard.get_param2()
.....
summary = wizard.get_summary()
results = python_to_R.my_analysis_function(studies, param1, param2, ...)
self._display_results(results, summary) # pass the results to the results_window for display
Finally, you just need to modify the main_window to add the action for the new method and maybe a toolbaar icon. If during this process, you modified a function in openmetar that OpenMetaAnalyst uses, make sure you didn't break compatibility with that program.
The convention with the wizards is that each page holds its own data choices. Then, one-line getter methods are written in the wizard class that get the data from the individual pages. This way, we can often re-use most of the wizard pages we already have when implementing a new feature. eg:
# data location page
def get_data_location(self):
return self.data_location_page.get_data_locations()