##############################################################################
# Braviz, Brain Data interactive visualization #
# Copyright (C) 2014 Diego Angulo #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU Lesser General Public License as #
# published by the Free Software Foundation, either version 3 of the #
# License, or (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU Lesser General Public License for more details. #
# #
# You should have received a copy of the GNU Lesser General Public License#
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
##############################################################################
from __future__ import division, print_function
import itertools
import cPickle
import logging
import PyQt4.QtGui as QtGui
import PyQt4.QtCore as QtCore
import numpy as np
import braviz
from braviz.interaction.qt_guis.outcome_select import Ui_SelectOutcomeDialog
from braviz.interaction.qt_guis.outcome_select_multi_plot import Ui_SelectOutcomeMPDialog
from braviz.interaction.qt_guis.regressors_select import Ui_AddRegressorDialog
from braviz.interaction.qt_guis.interactions_dialog import Ui_InteractionsDiealog
from braviz.interaction.qt_guis.context_variables_select import Ui_ContextVariablesDialog
from braviz.interaction.qt_guis.new_variable_dialog import Ui_NewVariableDialog
from braviz.interaction.qt_guis.load_bundles_dialog import Ui_LoadBundles
from braviz.interaction.qt_guis.save_fibers_bundle import Ui_SaveBundleDialog
from braviz.interaction.qt_guis.save_logic_fibers_bundle import Ui_SaveLogicBundleDialog
from braviz.interaction.qt_guis.save_scenario_dialog import Ui_SaveScenarioDialog
from braviz.interaction.qt_guis.load_scenario_dialog import Ui_LoadScenarioDialog
from braviz.interaction.qt_guis.load_logic_bundle import Ui_LoadLogicDialog
from braviz.interaction.logic_bundle_model import LogicBundleNode, LogicBundleQtTree
import braviz.interaction.qt_widgets
import braviz.interaction.qt_models as braviz_models
from braviz.readAndFilter.tabular_data import get_data_frame_by_name, get_var_idx, get_min_max_values_by_name, \
is_variable_name_real, get_var_description_by_name, save_is_real_by_name, \
save_real_meta_by_name, save_var_description_by_name, get_min_max_opt_values_by_name, register_new_variable, \
save_real_meta, save_var_description
import braviz.readAndFilter.tabular_data as braviz_tab_data
from braviz.readAndFilter import bundles_db
import braviz.readAndFilter.user_data as braviz_user_data
import os
from itertools import izip
import seaborn as sns
__author__ = 'Diego'
[docs]class VariableSelectDialog(QtGui.QDialog):
"""
**Abstract**, Implement common features for Outcome and Regressor Dialogs
This class is incomplete, in order to get a full dialog consider using one of the inherited
classes.
In particular there is no ui associated with this class, in subclasses you should add a UI
and then call ``finish_ui_setup``
Args:
sample (list) : Optional, list of subject indices to include in plot, if None, the whole sample is displayed
"""
def __init__(self, sample=None):
"""remember to call finish_ui_setup() after setting up ui"""
super(VariableSelectDialog, self).__init__()
self.var_name = None
self.rational = {}
self.matplot_widget = None
self.data = np.zeros(0)
self.nominal_model = None
if sample is None:
self.sample = braviz_tab_data.get_subjects()
else:
self.sample = sorted(map(int, sample))
log = logging.getLogger(__name__)
log.info("got custom sample")
log.info(self.sample)
def update_plot(self, data):
pass
def update_right_side(self, var_name):
try:
self.ui.var_name.setText(var_name)
except TypeError:
# if nothing is selected
return
self.ui.save_button.setEnabled(True)
self.ui.var_type_combo.setEnabled(True)
is_real = is_variable_name_real(var_name)
self.var_name = var_name
data = get_data_frame_by_name(self.var_name)
data.dropna(inplace=True)
try:
self.data = data.loc[self.sample]
except KeyError:
self.data = data.loc[[]]
# update scatter
self.update_plot(self.data)
var_description = get_var_description_by_name(var_name)
self.ui.var_description.setPlainText(var_description)
self.ui.var_description.setEnabled(True)
# update gui
if is_real:
self.ui.var_type_combo.setCurrentIndex(0)
self.update_details(0)
else:
self.ui.var_type_combo.setCurrentIndex(1)
self.update_details(1)
def update_details(self, index):
# is_real=self.ui.var_type_combo.currentIndex()
# print index
# print "===="
if index == 0:
self.ui.details_frame.setCurrentIndex(1)
self.update_real_details()
else:
self.ui.details_frame.setCurrentIndex(0)
self.update_nominal_details()
def guess_max_min(self):
data = self.data
mini = data.min()[0]
maxi = data.max(skipna=True)[0]
medi = data.median()[0]
self.rational["max"] = maxi
self.rational["min"] = mini
self.rational["opt"] = medi
def set_real_controls(self):
maxi = self.rational["max"]
mini = self.rational["min"]
medi = self.rational["opt"]
if maxi is None:
maxi = 10
if mini is None:
mini = 0
if medi is None:
medi = 0
self.ui.maximum_val.setValue(maxi)
self.ui.minimum_val.setValue(mini)
self.ui.minimum_val.setDecimals(3)
self.ui.maximum_val.setDecimals(3)
self.ui.minimum_val.setMinimum(min(mini * 100, -100))
self.ui.maximum_val.setMinimum(min(mini * 100, -100))
self.ui.minimum_val.setMaximum(max(maxi * 100, 1000))
self.ui.maximum_val.setMaximum(max(maxi * 100, 1000))
try:
self.ui.optimum_val.setValue(
int((medi - mini) / (maxi - mini) * 100))
except Exception:
self.ui.optimum_val.setValue(0)
self.update_optimum_real_value()
def update_optimum_real_value(self, perc_value=None):
if perc_value is None:
perc_value = self.ui.optimum_val.value()
try:
real_value = perc_value / 100 * \
(self.rational["max"] - self.rational["min"]) + \
self.rational["min"]
except TypeError:
real_value = 0
self.ui.optimum_real_value.setNum(real_value)
def update_real_details(self):
log = logging.getLogger(__name__)
log.info("creating real details")
# try to read values from DB
db_values = get_min_max_opt_values_by_name(self.var_name)
if db_values is None:
self.guess_max_min()
else:
self.rational["min"] = db_values[0]
self.rational["max"] = db_values[1]
self.rational["opt"] = db_values[2]
self.set_real_controls()
QtCore.QTimer.singleShot(0, self.update_limits_in_plot)
def reset_real_details(self):
self.guess_max_min()
self.set_real_controls()
self.update_plot(self.data)
QtCore.QTimer.singleShot(0, self.update_limits_in_plot)
def update_nominal_details(self):
var_name = self.var_name
log = logging.getLogger(__name__)
log.info("creating nominal details")
if self.nominal_model is None:
self.nominal_model = braviz_models.NominalVariablesMeta(var_name)
else:
self.nominal_model.update_model(var_name)
self.ui.labels_names_table.setModel(self.nominal_model)
QtCore.QTimer.singleShot(0, self.update_limits_in_plot)
def finish_ui_setup(self):
current_flags = self.windowFlags()
current_flags |= (QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowMaximizeButtonHint)
self.setWindowFlags(current_flags)
target = self.ui.plot_frame
layout = QtGui.QVBoxLayout()
self.matplot_widget = braviz.interaction.qt_widgets.MatplotWidget(
initial_message="Double click on variables\nto see plots")
layout.addWidget(self.matplot_widget)
target.setLayout(layout)
self.ui.save_button.clicked.connect(self.save_meta_data)
self.ui.var_type_combo.currentIndexChanged.connect(self.update_details)
self.matplot_widget.scatter_pick_signal.connect(self.show_plot_tooltip)
self.ui.tableView.customContextMenuRequested.connect(
self.show_delete_menu)
self.ui.details_frame.setCurrentIndex(1)
#Real details
self.ui.optimum_val.valueChanged.connect(
self.update_limits_in_plot)
self.ui.minimum_val.valueChanged.connect(
self.update_limits_in_plot)
self.ui.maximum_val.valueChanged.connect(
self.update_limits_in_plot)
self.ui.optimum_val.valueChanged.connect(
self.update_optimum_real_value)
self.ui.optimum_val.valueChanged.connect(self.ui.horizontalSlider.setValue)
self.ui.horizontalSlider.valueChanged.connect(self.ui.optimum_val.setValue)
self.ui.reset_real_meta.clicked.connect(self.reset_real_details)
def update_limits_in_plot(self, *args):
if self.ui.var_type_combo.currentIndex() != 0:
self.matplot_widget.add_max_min_opt_lines(None, None, None)
return
mini = self.ui.minimum_val.value()
maxi = self.ui.maximum_val.value()
opti = self.ui.optimum_val.value()
opti = mini + opti * (maxi - mini) / 100
self.rational["max"] = maxi
self.rational["min"] = mini
self.rational["opt"] = opti
self.matplot_widget.add_max_min_opt_lines(mini, opti, maxi)
def save_meta_data(self):
var_type = 0 # nominal should be 1
if self.ui.var_type_combo.currentIndex() == 0:
var_type = 1 # real should be 1
# save variable type
save_is_real_by_name(self.var_name, var_type)
# save description
desc_text = self.ui.var_description.toPlainText()
save_var_description_by_name(self.var_name, unicode(desc_text))
# save other values
if var_type == 1:
# real
save_real_meta_by_name(self.var_name, self.rational["min"],
self.rational["max"], self.rational["opt"])
elif var_type == 0:
self.nominal_model.save_into_db()
def show_plot_tooltip(self, subj, position):
message = "Subject: %s" % subj
QtGui.QToolTip.showText(self.matplot_widget.mapToGlobal(
QtCore.QPoint(*position)), message, self.matplot_widget)
def show_delete_menu(self, pos):
log = logging.getLogger(__name__)
log.info("showing menu")
menu = QtGui.QMenu()
mod = self.ui.tableView.model()
cur_idx = self.ui.tableView.currentIndex()
idx2 = mod.index(cur_idx.row(), 0)
var_name = mod.data(idx2, QtCore.Qt.DisplayRole)
def delete_var():
confirm = QtGui.QMessageBox.question(self,
"Confirm delete variable",
"Are you sure you want to delete \n%s ?\nThis is not reversible" % var_name,
QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel,
QtGui.QMessageBox.Cancel)
if confirm == QtGui.QMessageBox.Yes:
log.info("deleting")
var_idx = braviz_tab_data.get_var_idx(var_name)
if var_idx is not None:
braviz_tab_data.recursive_delete_variable(var_idx)
mod.update_list(None)
else:
log.info("cancelled")
action = QtGui.QAction("Delete %s" % var_name, menu)
menu.addAction(action)
action.triggered.connect(delete_var)
global_pos = self.ui.tableView.mapToGlobal(pos)
menu.exec_(global_pos)
[docs]class OutcomeSelectDialog(VariableSelectDialog):
"""
A dialog for selecting a single or multiple variable
The constructor takes a dictionary which will be used to save the selection in the dialog.
When the user clicks the *save and select* button, the dialog will close, and the current selection
will be available in the ``selected_outcome`` field of the dictionary.
If you need multiple variables consider using :class:`GenericVariableSelectDialog`.
If ``multiple = True`` is passed to the constructor the variable list will have check marks.
The output dictionary will still contain only one variable, but the list is available in
the ``vars_list_model`` field. You may get a set of selected variables by calling
``dialog.vars_list_model.checked_set``
The constructor also takes a ``sample`` parameter which can be used to set the sample used in the
right side plot.
Args:
params_dict (dict) : Output will be written in this object
multiple (bool) : If True, allows to select multiple variables by placing checkmarks
sample (list) : Optional, list of subject indices to include in plot, if None, the whole sample is displayed
"""
def __init__(self, params_dict, multiple=False, sample=None, highlight=None):
super(OutcomeSelectDialog, self).__init__(sample)
self.ui = Ui_SelectOutcomeDialog()
self.ui.setupUi(self)
self.finish_ui_setup()
self.params_dict = params_dict
self.highlight_subj = highlight
self.vars_list_model = braviz_models.VarListModel(checkeable=multiple)
self.ui.tableView.setModel(self.vars_list_model)
self.ui.tableView.clicked.connect(self.update_right_side)
self.ui.tableView.activated.connect(self.update_right_side)
self.ui.select_button.clicked.connect(self.select_and_return)
self.ui.search_box.returnPressed.connect(self.filter_list)
def update_right_side(self, var_name=None):
curr_idx = self.ui.tableView.currentIndex()
var_name = self.vars_list_model.data(curr_idx, QtCore.Qt.DisplayRole)
self.ui.select_button.setEnabled(True)
super(OutcomeSelectDialog, self).update_right_side(var_name)
def update_plot(self, data):
data2 = data.dropna()
data_values = data2.get_values()
jitter = np.random.rand(len(data_values))
self.matplot_widget.compute_scatter(data_values, jitter,
x_lab=self.var_name, y_lab="jitter", urls=data2.index.get_values())
if self.highlight_subj is not None:
try:
subj_index = data2.index.get_loc(int(self.highlight_subj))
self.matplot_widget.add_subject_points((data_values[subj_index]), (jitter[subj_index],),
urls=(self.highlight_subj,))
except KeyError:
pass
def select_and_return(self, *args):
if self.var_name is not None:
self.save_meta_data()
if self.params_dict is not None:
self.params_dict["selected_outcome"] = self.var_name
self.accept()
def filter_list(self):
mask = "%%%s%%" % self.ui.search_box.text()
self.vars_list_model.update_list(mask)
[docs]class GenericVariableSelectDialog(OutcomeSelectDialog):
"""
A dialog for selecting one or multiple variables with initial selection.
This dialog is optimized for multiple selections, and it improves :class:`~OutcomeSelectDialog` in that
- In the *multiple* mode, the output dictionary includes a ``checked`` field with the codes of the selected variables
- In the *multiple* mode, initial selections can be set using the ``initial_selection_names`` and
``initial_selection_idx`` parameters in the constructor.
Args:
params (dict) : Output will be written in this object
multiple (bool) : If True, allows to select multiple variables by placing checkmarks
initial_selection_names (list) : List of variable names which should be selected when the dialog opens
initial_selection_idx (list) : List of variable indeces which should be selected when the dialog opens
sample (list) : Optional, list of subject indices to include in plot, if None, the whole sample is displayed
"""
def __init__(self, params, multiple=False, initial_selection_names=None, initial_selection_idx=None, sample=None,
highlight=None):
OutcomeSelectDialog.__init__(
self, params, multiple=multiple, sample=sample, highlight=highlight)
self.multiple = multiple
self.setWindowTitle("Select Variables")
self.ui.select_button.setText("Accept Selection")
self.ui.select_button.setEnabled(True)
if multiple:
if initial_selection_idx is not None:
self.vars_list_model.select_items(initial_selection_idx)
elif initial_selection_names is not None:
self.vars_list_model.select_items_by_name(
initial_selection_names)
def select_and_return(self, *args):
if self.multiple is True:
selected_names = self.vars_list_model.checked_set
self.params_dict["checked"] = [
get_var_idx(name) for name in selected_names]
OutcomeSelectDialog.select_and_return(self, *args)
[docs]class MultiPlotOutcomeSelectDialog(OutcomeSelectDialog):
"""
A dialog for selecting one variable with multiple plot options
The selected variable will be available in the ``selected_outcome`` field of the
*params_dict* dictionary.
The constructor takes the ``available_plots`` argument, which contains a list of plots to make available
in the dialog. This list should contain tuples of the following types
- ``("scatter", None)`` : The default plot, *x* is the variable, and *y* is jitter
- ``("scatter", var)`` : An scatter plot in which *x* is variable *var* and *y*
is the current variable.
- ``("box",var)`` : A box plot using variable *var* for groups and the current variable for values
- ``("interaction", vars)`` : A two factor box plot where the groups are the interaction between the variables
in *vars* , which is a string with an ``*`` between the two names.
Args:
params_dict (dict) : Output will be written in this object
sample (list) : Optional, list of subject indices to include in plot, if None, the whole sample is displayed
available_plots (list) : List of plots which will be available for the user, syntax was explained above
"""
def __init__(self, params_dict, sample=None, available_plots=None):
VariableSelectDialog.__init__(self, sample=sample)
self.ui = Ui_SelectOutcomeMPDialog()
self.ui.setupUi(self)
if available_plots is not None:
for k in available_plots.iterkeys():
self.ui.plot_type.addItem(k)
self.available_plots = available_plots
self.data = np.zeros(0)
self.plot_data_frame = None
self.finish_ui_setup()
self.params_dict = params_dict
self.vars_list_model = braviz_models.VarListModel(checkeable=False)
self.ui.tableView.setModel(self.vars_list_model)
self.ui.tableView.clicked.connect(self.update_right_side)
self.ui.tableView.activated.connect(self.update_right_side)
self.ui.select_button.clicked.connect(self.select_and_return)
self.ui.search_box.returnPressed.connect(self.filter_list)
self.ui.plot_type.activated.connect(self.update_plot)
def update_plot(self, data=None):
if type(data) == int:
data = self.data
default_plot = ("scatter", None)
if self.available_plots is None:
plot_type = default_plot
else:
plot_str = unicode(self.ui.plot_type.currentText())
plot_type = self.available_plots.get(plot_str, default_plot)
log = logging.getLogger(__name__)
log.info(plot_type)
if plot_type[0] == "scatter":
if plot_type[1] is None:
data = data.dropna()
self.matplot_widget.compute_scatter(
data, x_lab=self.var_name, y_lab="jitter", urls=data.index)
self.matplot_widget.limits_vertical = True
else:
x = plot_type[1]
y = self.var_name
data = braviz_tab_data.get_data_frame_by_name([x, y])
data = data.loc[self.sample]
data.dropna(inplace=True)
self.matplot_widget.compute_scatter(
data[x], data[y], x_lab=x, y_lab=y, urls=data.index)
self.matplot_widget.limits_vertical = False
elif plot_type[0] == "box":
x = plot_type[1]
y = self.var_name
data = braviz_tab_data.get_data_frame_by_name([y, x])
data = data.loc[self.sample]
data.dropna(inplace=True)
label_nums = set(data[x])
labels_dict = braviz_tab_data.get_labels_dict_by_name(x)
self.matplot_widget.make_box_plot(data,x,y, x, y, labels_dict)
self.matplot_widget.limits_vertical = False
elif plot_type[0] == "interaction":
factors = plot_type[1].split("*")
self.matplot_widget.limits_vertical = False
self.two_factors_plot(factors)
QtCore.QTimer.singleShot(10, self.update_limits_in_plot)
def two_factors_plot(self, factors_list):
# copied from anova application... not a good practice
nominal_factors = []
real_factors = []
# classify factors
for f in factors_list:
is_real = braviz_tab_data.is_variable_name_real(f)
if is_real == 0:
nominal_factors.append(f)
else:
real_factors.append(f)
if len(real_factors) == 1:
top_labels_dict = braviz_tab_data.get_labels_dict_by_name(
nominal_factors[0])
colors = sns.color_palette("Dark2", len(top_labels_dict))
# print top_labels_strings
colors_dict = dict(izip(top_labels_dict.iterkeys(), colors))
plot_color = colors_dict
# Get Data
data = get_data_frame_by_name(
[real_factors[0], nominal_factors[0], self.var_name])
data = data.loc[self.sample]
data.dropna(inplace=True)
self.plot_data_frame = data
datax = []
datay = []
colors = []
labels = []
urls = []
for k, v in top_labels_dict.iteritems():
if k is None:
continue
if v is None:
v = "?"
labels.append(v)
colors.append(colors_dict[k])
datay.append(
data[self.var_name][data[nominal_factors[0]] == k].get_values())
datax.append(
data[real_factors[0]][data[nominal_factors[0]] == k].get_values())
urls.append(
data[self.var_name][data[nominal_factors[0]] == k].index.get_values())
# print datax
self.matplot_widget.compute_scatter(
datax, datay, real_factors[0], self.var_name, colors, labels, urls=urls)
elif len(real_factors) == 2:
log = logging.getLogger(__name__)
log.warning("Not yet implemented")
self.matplot_widget.initial_text("Not yet implemented")
else:
# get data
data = get_data_frame_by_name(nominal_factors + [self.var_name])
data = data.loc[self.sample]
data.dropna(inplace=True)
# find number of levels for nominal
nlevels = {}
for f in nominal_factors:
nlevels[f] = len(data[f].unique())
# print nlevels
nominal_factors.sort(key=nlevels.get, reverse=True)
# print nominal_factors
levels_second_factor = set(data[nominal_factors[1]].get_values())
levels_first_factor = set(data[nominal_factors[0]].get_values())
data_lists_top = []
for i in levels_second_factor:
data_list = []
for j in levels_first_factor:
data_col = data[self.var_name][(data[nominal_factors[1]] == i) &
(data[nominal_factors[0]] == j)].get_values()
data_list.append(data_col)
data_lists_top.append(data_list)
self.matplot_widget.make_linked_box_plot(
data, self.var_name, nominal_factors[0], nominal_factors[1])
[docs]class SelectOneVariableWithFilter(OutcomeSelectDialog):
"""
A dialog for selecting one variable of an specific kind.
This dialog behaves likes the :class:`OutcomeSelectDialog`, but you may choose to accept only
nominal or only real variables using the parameters ``accept_real`` and ``accept_nominal`` of the constructor.
Args:
params (dict) : Output will be written in this object
accept_nominal (bool) : If ``False`` the select button will be disabled for nominal variables
accept_real (bool) : If ``False`` the select button will be disabled for real variables
sample (list) : Optional, list of subject indices to include in plot, if None, the whole sample is displayed
"""
def __init__(self, params, accept_nominal=True, accept_real=True, sample=None):
OutcomeSelectDialog.__init__(
self, params, multiple=False, sample=sample)
self.setWindowTitle("Select Variable")
self.accept_real = accept_real
self.accept_nominal = accept_nominal
def check_selecion(self):
is_current_variable_real = (self.ui.var_type_combo.currentIndex() == 0)
if (is_current_variable_real and self.accept_real) or (not is_current_variable_real and self.accept_nominal):
self.ui.select_button.setEnabled(True)
else:
self.ui.select_button.setEnabled(False)
def update_details(self, index):
super(SelectOneVariableWithFilter, self).update_details(index)
self.check_selecion()
[docs]class RegressorSelectDialog(VariableSelectDialog):
"""
Dialog for selecting a secondary variable in the analysis.
The ``outcome_var`` parameter of the constructor may be used to specify a variable of reference.
The default plot would have current variable in the *x* axis and the *outcome_var* variable in the
*y* axis. If *outcome_var* is None, the *y* axis will be jitter.
The ``regressors_model`` parameter should be an instance of
:class:`~braviz.interaction.qt_models.AnovaRegressorsModel`. Variables will be added to and removed from
the model using the dialog.
This dialog also allows the user to sort the variables according to a ginni index over the
*outcome_var*
Args:
outcome_var (unicode) : Variable to use as reference. It will be the *y* axis of plots, look above
for more uses
regressors_model (braviz.interaction.qt_models.AnovaRegressorsModel): All operations will update this model
sample (list) : Optional, list of subject indices to include in plot, if None, the whole sample is displayed
"""
def __init__(self, outcome_var, regressors_model, sample=None):
super(RegressorSelectDialog, self).__init__(sample=sample)
self.outcome_var = outcome_var
self.ui = Ui_AddRegressorDialog()
self.ui.setupUi(self)
self.vars_model = braviz_models.VarAndGiniModel(outcome_var, sample=sample)
self.ui.tableView.setModel(self.vars_model)
self.ui.tableView.setColumnWidth(0,200)
self.finish_ui_setup()
self.ui.tableView.clicked.connect(self.update_right_side)
self.ui.tableView.activated.connect(self.update_right_side)
self.ui.add_button.clicked.connect(self.add_regressor)
self.regressors_table_model = regressors_model
self.ui.current_regressors_table.setModel(self.regressors_table_model)
self.ui.current_regressors_table.customContextMenuRequested.connect(
self.show_context_menu)
self.ui.done_button.clicked.connect(self.finish_close)
self.ui.search_box.returnPressed.connect(self.filter_list)
def update_right_side(self, name=None):
curr_idx = self.ui.tableView.currentIndex()
idx2 = self.vars_model.index(curr_idx.row(), 0)
var_name = self.vars_model.data(idx2, QtCore.Qt.DisplayRole)
self.ui.add_button.setEnabled(True)
super(RegressorSelectDialog, self).update_right_side(var_name)
def add_regressor(self):
self.regressors_table_model.add_regressor(self.var_name)
def show_context_menu(self, pos):
global_pos = self.ui.current_regressors_table.mapToGlobal(pos)
selection = self.ui.current_regressors_table.currentIndex()
remove_action = QtGui.QAction("Remove", None)
menu = QtGui.QMenu()
menu.addAction(remove_action)
def remove_item(*args):
self.regressors_table_model.removeRows(selection.row(), 1)
remove_action.triggered.connect(remove_item)
menu.addAction(remove_action)
selected_item = menu.exec_(global_pos)
# print selected_item
def update_plot(self, data):
regressor_data = data
if self.outcome_var is not None:
if self.outcome_var in regressor_data.columns:
both_data = regressor_data
else:
outcome_data = get_data_frame_by_name(self.outcome_var)
both_data = regressor_data.join(outcome_data)
both_data.dropna(inplace=True)
self.matplot_widget.compute_scatter(both_data[data.columns[0]].get_values(),
both_data[self.outcome_var].get_values(),
x_lab=self.var_name, y_lab=self.outcome_var,
urls=both_data.index.get_values())
else:
data2 = data.dropna()
self.matplot_widget.compute_scatter(
data2.get_values(), urls=data2.index.get_values())
def finish_close(self):
self.done(self.Accepted)
def filter_list(self):
mask = "%%%s%%" % self.ui.search_box.text()
self.vars_model.update_list(mask)
[docs]class InteractionSelectDialog(QtGui.QDialog):
"""
A dialog for specifying interactions between variables
The top panel contains a list of current variables, and the bottom panel contains a list of interaction terms
The user may select two or more variables and click *Add single term* to add the product of the selected variables
to the list of interactions. Clicking *Add all combinations* will add all possible combinations to the list.
All operations will update the specified *regressors_model*, which should be an instance of
:class:`~braviz.interaction.qt_models.AnovaRegressorsModel`
Args:
regressors_model (braviz.interaction.qt_models.AnovaRegressorsModel): All operations will update this model
"""
def __init__(self, regressors_model):
super(InteractionSelectDialog, self).__init__()
self.full_model = regressors_model
regressors = regressors_model.get_regressors()
self.only_regs_model = braviz_models.AnovaRegressorsModel(regressors)
self.ui = Ui_InteractionsDiealog()
self.ui.setupUi(self)
self.ui.reg_view.setModel(self.only_regs_model)
self.full_model.show_regressors(False)
self.ui.full_view.setModel(self.full_model)
self.ui.add_single_button.clicked.connect(self.add_single_term)
self.ui.add_all_button.clicked.connect(self.add_all_combinations)
def add_single_term(self):
selected_indexes = self.ui.reg_view.selectedIndexes()
selected_row_numbers = set(i.row() for i in selected_indexes)
log = logging.getLogger(__name__)
log.info(selected_row_numbers)
self.full_model.add_interactor(selected_row_numbers)
def add_all_combinations(self):
rows = range(self.only_regs_model.rowCount())
for r in xrange(2, len(rows) + 1):
for i in itertools.combinations(rows, r):
self.full_model.add_interactor(i)
[docs]class NewVariableDialog(QtGui.QDialog):
"""
A dialog for creating new variables
The dialog contains fields for entering a variable name and metadata, as well as a table view
where values can be entered.
The dialog attempts to save the variable into the database, and if it fails shows an error message and lets the user
change the variable name
"""
def __init__(self):
super(NewVariableDialog, self).__init__()
self.ui = Ui_NewVariableDialog()
self.ui.setupUi(self)
self.ui.var_type_combo.currentIndexChanged.connect(
self.create_meta_data_frame)
self.nominal_model = braviz_models.NominalVariablesMeta(None)
# self.clear_details_frame():
initial_nominal = 0
self.ui.var_type_combo.setCurrentIndex(initial_nominal)
if initial_nominal:
self.ui.details_frame.setCurrentIndex(0)
else:
self.ui.details_frame.setCurrentIndex(1)
# self.create_meta_data_frame(initial_nominal)
self.values_model = braviz_models.NewVariableValues()
self.ui.values_table.setModel(self.values_model)
self.ui.var_name_input.editingFinished.connect(
self.activate_save_button)
self.ui.save_button.clicked.connect(self.save_new_variable)
#real details
self.ui.optimum_val.valueChanged.connect(self.update_optimum_real_value)
#Nominal details
self.ui.labels_names_table.setModel(self.nominal_model)
add_label_button = QtGui.QPushButton("Add Label")
self.ui.verticalLayout.addWidget(add_label_button)
add_label_button.clicked.connect(self.nominal_model.add_label)
def create_meta_data_frame(self, is_nominal):
if is_nominal == 0:
self.ui.details_frame.setCurrentIndex(1)
self.setup_real_details()
else:
self.ui.details_frame.setCurrentIndex(0)
self.setup_nominal_details()
def setup_real_details(self):
# try to read values from DB
self.ui.maximum_val.setValue(100)
self.ui.minimum_val.setValue(0)
self.ui.optimum_val.setValue(50)
self.update_optimum_real_value()
def setup_nominal_details(self):
# print "creating details"
self.nominal_model.update_model(None)
def override_nominal_labels(self, labels_dict):
if self.nominal_model is None:
return
self.nominal_model.set_labels_dict(labels_dict)
def update_optimum_real_value(self, perc_value=None):
maxi = self.ui.maximum_val.value()
mini = self.ui.minimum_val.value()
if perc_value is None:
perc_value = self.ui.optimum_val.value()
real_value = perc_value / 100 * (maxi - mini) + mini
self.ui.optimum_real_value.setNum(real_value)
def activate_save_button(self):
if len(unicode(self.ui.var_name_input.text())) > 0:
self.ui.save_button.setEnabled(True)
def save_new_variable(self):
# create new variable
var_name = unicode(self.ui.var_name_input.text())
is_real = 1 - self.ui.var_type_combo.currentIndex()
var_idx = register_new_variable(var_name, is_real)
if var_idx is None:
m = """A variable with the same name already exists,\nplease choose a different name"""
QtGui.QMessageBox.critical(None, "Couldn't create variable", m,)
return
# add meta data
if is_real:
mini = self.ui.minimum_val.value()
maxi = self.ui.maximum_val.value()
opti = self.ui.optimum_val.value()
opti = mini + opti * (maxi - mini) / 100
save_real_meta(var_idx, mini, maxi, opti)
else:
self.nominal_model.save_into_db(var_idx)
# description
desc = unicode(self.ui.var_description.toPlainText())
save_var_description(var_idx, desc)
# values
self.values_model.save_into_db(var_idx)
self.accept()
[docs]class ContextVariablesSelectDialog(VariableSelectDialog):
"""
A dialog for selecting multiple variables, and make some of them editable
Args:
variables_list (list) : List of variables indices to include in the current selection
current_subject : This subject will be highlighted in plots
editables_dict (dict) : This dictionary will contain which variables were selected to be editable
keys are variable indices and values are booleans
sample (list) : Optional, list of subject indices to include in plot, if None, the whole sample is displayed
"""
def __init__(self, variables_list=None, current_subject=None, editables_dict=None, sample=None):
super(ContextVariablesSelectDialog, self).__init__(sample=sample)
if variables_list is None:
variables_list = []
self.__variable_lists_id = id(variables_list)
self.current_subject = current_subject
self.ui = Ui_ContextVariablesDialog()
self.ui.setupUi(self)
self.vars_model = braviz_models.VarListModel(checkeable=False)
self.ui.tableView.setModel(self.vars_model)
self.finish_ui_setup()
self.ui.tableView.clicked.connect(self.update_right_side)
self.ui.tableView.activated.connect(self.update_right_side)
self.ui.add_button.clicked.connect(self.add_variable)
self.current_variables_model = braviz_models.ContextVariablesModel(context_vars_list=variables_list,
editable_dict=editables_dict)
self.ui.current_variables.setModel(self.current_variables_model)
self.ui.current_variables.customContextMenuRequested.connect(
self.show_context_menu)
self.ui.done_button.clicked.connect(self.done)
self.finished.connect(self.finish_close)
self.ui.current_variables.clicked.connect(self.update_right_side2)
self.ui.create_varible_button.clicked.connect(
self.launch_new_variable_dialog)
self.ui.search_box.returnPressed.connect(self.filter_list)
self.jitter = None
self.variable_list = variables_list
def update_right_side(self, curr_idx=None):
idx2 = self.vars_model.index(curr_idx.row(), 0)
var_name = self.vars_model.data(idx2, QtCore.Qt.DisplayRole)
self.ui.add_button.setEnabled(True)
super(ContextVariablesSelectDialog, self).update_right_side(var_name)
def update_right_side2(self, idx):
var_name_idx = self.current_variables_model.index(idx.row(), 0)
var_name = self.current_variables_model.data(
var_name_idx, QtCore.Qt.DisplayRole)
super(ContextVariablesSelectDialog, self).update_right_side(var_name)
def add_variable(self):
var_idx = get_var_idx(self.var_name)
self.current_variables_model.add_variable(var_idx)
def show_context_menu(self, pos):
global_pos = self.ui.current_variables.mapToGlobal(pos)
selection = self.ui.current_variables.currentIndex()
remove_action = QtGui.QAction("Remove", None)
menu = QtGui.QMenu()
menu.addAction(remove_action)
def remove_item(*args):
self.current_variables_model.removeRows(selection.row(), 1)
remove_action.triggered.connect(remove_item)
menu.addAction(remove_action)
menu.exec_(global_pos)
def update_plot(self, data):
data = data.dropna()
self.jitter = np.random.random(len(data))
data_values = data.get_values()
xlimits = get_min_max_values_by_name(self.var_name)
self.matplot_widget.compute_scatter(data_values, self.jitter, x_lab=self.var_name, xlims=xlimits,
urls=data.index.get_values())
if self.current_subject is not None:
try:
subj_index = data.index.get_loc(int(self.current_subject))
self.matplot_widget.add_subject_points((data_values[subj_index]), (self.jitter[subj_index],),
urls=(self.current_subject,))
except KeyError:
pass
def finish_close(self, _):
new_list = self.current_variables_model.get_variables()
while len(self.variable_list) > 0:
self.variable_list.pop()
self.variable_list.extend(new_list)
assert id(self.variable_list) == self.__variable_lists_id
def launch_new_variable_dialog(self):
new_variable_dialog = NewVariableDialog()
r = new_variable_dialog.exec_()
if r == QtGui.QDialog.Accepted:
self.vars_model.update_list()
def filter_list(self):
mask = "%%%s%%" % self.ui.search_box.text()
self.vars_model.update_list(mask)
[docs]class BundleSelectionDialog(QtGui.QDialog):
"""
Selects a set of bundles
Args:
selected (list) : List of selected bundle ids. This object will be updated with the new selection.
names_dict (dict) : Dictionary mapping bundle ids to bundle names
"""
def __init__(self, selected, names_dict):
super(BundleSelectionDialog, self).__init__()
self.ui = None
self.bundles_list_model = braviz_models.BundlesSelectionList()
self.bundles_list_model.select_many_ids(selected)
self.load_ui()
self.selection = selected
self.names_dict = names_dict
def load_ui(self):
self.ui = Ui_LoadBundles()
self.ui.setupUi(self)
self.ui.all_bundles_list_view.setModel(self.bundles_list_model)
self.ui.buttonBox.accepted.connect(self.ok_handle)
def ok_handle(self):
new_select = set(self.bundles_list_model.get_selected())
self.selection.clear()
self.selection.update(new_select)
self.names_dict.update(self.bundles_list_model.names_dict)
[docs]class SaveFibersBundleDialog(QtGui.QDialog):
"""
Save a bundle defined from a list of models
The dialog asks for a name and a description, it also shows the list of structures and the operation.
Args:
checkpoints_list (list) : List of model names which define the bundle
operation_is_and (bool) : If ``True`` the bundle is composed of the fibers that pass through
*all* structures, otherwise it is composed of the fibers that pass throug *any* of the listed structures
"""
def __init__(self, checkpoints_list, operation_is_and):
super(SaveFibersBundleDialog, self).__init__()
self.ui = Ui_SaveBundleDialog()
self.ui.setupUi(self)
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Save).setEnabled(False)
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False)
self.ui.lineEdit.textChanged.connect(self.check_name)
self.ui.error_message.setText("")
self.ui.save_succesful.setText("")
operation = "And" if operation_is_and else "Or"
self.ui.operation_label.setText(operation)
self._checkpoints = tuple(checkpoints_list)
self.ui.structures_list.setPlainText(", ".join(self._checkpoints))
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Save).clicked.connect(self.accept_save)
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Ok).clicked.connect(self.accept)
self._and = operation_is_and
def check_name(self):
name = unicode(self.ui.lineEdit.text())
if len(name) < 2:
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Save).setEnabled(False)
return
if bundles_db.check_if_name_exists(name) is True:
self.ui.error_message.setText(
"A bundle with this name already exists")
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Save).setEnabled(False)
else:
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Save).setEnabled(True)
self.ui.error_message.setText("")
def accept_save(self):
log = logging.getLogger(__name__)
log.info("saving")
name = unicode(self.ui.lineEdit.text())
log.info(name)
op = "and" if self._and else "or"
log.info(op)
log.info(self._checkpoints)
try:
bundles_db.save_checkpoints_bundle(
name, self._and, self._checkpoints)
except:
log.error("problem saving into database")
raise
self.ui.save_succesful.setText("Save succesful")
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Save).setEnabled(False)
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Cancel).setEnabled(False)
self.ui.lineEdit.setEnabled(False)
[docs]class SaveLogicFibersBundleDialog(QtGui.QDialog):
"""
Saves a logic bundle
This dialog shows a tree summarizing the dialog
and it asks for a name and a description
Args:
tree_model (braviz.interaction.logic_bundle_model.LogicBundleNode) : Tree of the bundle
"""
def __init__(self, tree_model):
super(SaveLogicFibersBundleDialog, self).__init__()
self.__tree_model = tree_model
self.ui = Ui_SaveLogicBundleDialog()
self.ui.setupUi(self)
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Save).setEnabled(False)
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False)
self.ui.lineEdit.textChanged.connect(self.check_name)
self.ui.error_message.setText("")
self.ui.save_succesful.setText("")
self.ui.treeView.setModel(tree_model)
self.ui.treeView.expandAll()
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Save).clicked.connect(self.accept_save)
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Ok).clicked.connect(self.accept)
def check_name(self):
name = unicode(self.ui.lineEdit.text())
if len(name) < 2:
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Save).setEnabled(False)
return
if bundles_db.check_if_name_exists(name) is True:
self.ui.error_message.setText(
"A bundle with this name already exists")
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Save).setEnabled(False)
else:
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Save).setEnabled(True)
self.ui.error_message.setText("")
def accept_save(self):
log = logging.getLogger(__name__)
log.info("saving")
name = unicode(self.ui.lineEdit.text())
log.info(name)
tree_dict = self.__tree_model.root.to_dict()
log.info(tree_dict)
try:
bundles_db.save_logic_bundle(name, tree_dict)
except:
log.error("problem saving into database")
raise
self.ui.save_succesful.setText("Save succesful")
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Save).setEnabled(False)
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Cancel).setEnabled(False)
self.ui.lineEdit.setEnabled(False)
[docs]class SaveScenarioDialog(QtGui.QDialog):
"""
A dialog for saving scenarios, it doesn't save an screen-shot, this should be done afterwards by the application
Args:
app_name (unicode) : Name of application for which the scenario is created
state (dict) : Dictionary of application state
params (dict) : Optional, when the dialog closes, this object will contain
the key ``scn_id`` and its value will be the index of the newly created scenario.
Use this to save a corresponding screen-shot
"""
def __init__(self, app_name, state, params=None):
super(SaveScenarioDialog, self).__init__()
self.app_name = app_name
self.data = state
if params is None:
params = dict()
self.params = params
self.ui = None
self.init_gui()
def init_gui(self):
self.ui = Ui_SaveScenarioDialog()
self.ui.setupUi(self)
self.ui.app_name.setText(self.app_name)
self.ui.save_button = QtGui.QPushButton("Save")
self.ui.save_button.clicked.connect(self.save_into_db)
self.ui.buttonBox.addButton(
self.ui.save_button, QtGui.QDialogButtonBox.ActionRole)
self.ui.buttonBox.addButton(QtGui.QDialogButtonBox.Cancel)
self.ui.succesful_message.setText("")
def save_into_db(self):
scenario_name = unicode(self.ui.scenario_name.text())
if len(scenario_name) == 0:
scenario_name = "<Unnamed>"
description = unicode(self.ui.scn_description.toPlainText())
scn_id = braviz_user_data.save_scenario(
self.app_name, scenario_name, description, self.data)
self.params["scn_id"] = scn_id
self.params["scn_name"] = scenario_name
self.ui.succesful_message.setText("Save completed succesfully")
self.ui.buttonBox.clear()
self.ui.buttonBox.addButton(QtGui.QDialogButtonBox.Ok)
[docs]class LoadScenarioDialog(QtGui.QDialog):
"""
Dialog that shows the user a list of available scenarios, with screen-shots, and allows him to select one
Args:
app_name (unicode) : Restrict the list of scenarios to those created with an specific application
out_dict (dict) : When the dialog finishes this dictionary will contain the selected scenario data
"""
def __init__(self, app_name, out_dict=None):
super(LoadScenarioDialog, self).__init__()
if out_dict is None:
out_dict = {}
self.out_dict = out_dict
self.model = braviz_models.ScenariosTableModel(app_name)
self.current_row = None
self.ui = None
self.init_ui()
def init_ui(self):
self.ui = Ui_LoadScenarioDialog()
self.ui.setupUi(self)
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(0)
self.ui.scenarios_table.setModel(self.model)
self.ui.scenarios_table.clicked.connect(self.select_scenario)
self.ui.scenarios_table.activated.connect(self.select_scenario)
self.ui.scenarios_table.customContextMenuRequested.connect(
self.show_context_menu)
self.ui.buttonBox.button(
QtGui.QDialogButtonBox.Ok).clicked.connect(self.load_data)
def select_scenario(self, index):
row = index.row()
self.current_row = row
self.ui.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(1)
# load picture
index = self.model.data(index, QtCore.Qt.UserRole)
self.ui.screen_shot_label.setText("<No screenshot available>" % index)
self.ui.screen_shot_label.setScaledContents(False)
data_root = braviz.readAndFilter.braviz_auto_dynamic_data_root()
image_file = os.path.join(
data_root, "braviz_data", "scenarios", "scenario_%d.png" % index)
if os.path.isfile(image_file):
image = QtGui.QImage(image_file)
scaled_image = image.scaledToWidth(300, )
self.ui.screen_shot_label.setPixmap(
QtGui.QPixmap.fromImage(scaled_image))
def load_data(self):
scn_id = int(self.model.get_index(self.current_row))
parameters_dict = braviz_user_data.get_scenario_data_dict(scn_id)
parameters_dict["meta"]["scn_id"] = scn_id
self.out_dict.update(parameters_dict)
self.accept()
def show_context_menu(self, pos):
global_pos = self.ui.scenarios_table.mapToGlobal(pos)
selection = self.ui.scenarios_table.currentIndex()
if not selection.isValid():
return
selection_row = selection.row()
scn_idx = self.model.get_index(selection_row)
scn_name = self.model.get_name(selection_row)
remove_action = QtGui.QAction("Remove %s" % scn_name, None)
menu = QtGui.QMenu()
menu.addAction(remove_action)
def remove_item():
braviz_user_data.delete_scenario(int(scn_idx))
self.model.reload_data()
remove_action.triggered.connect(remove_item)
menu.addAction(remove_action)
selected_item = menu.exec_(global_pos)
# print selected_item
[docs]class LoadLogicBundle(QtGui.QDialog):
"""
Loading a logic bundle from the database
The dialog shows a preview of the tree associated with the bundle
This tree will be available in the *data* attribute after the selection is accepted
"""
def __init__(self):
super(LoadLogicBundle, self).__init__()
self.__tree_root = LogicBundleNode(
None, 0, LogicBundleNode.LOGIC, "AND")
self.__tree_model = LogicBundleQtTree(self.__tree_root)
self.__bundles = bundles_db.get_bundles_list(bundle_type=10)
self.__bundles_model = braviz_models.SimpleSetModel()
self.__bundles_model.set_elements(self.__bundles)
self.ui = Ui_LoadLogicDialog()
self.ui.setupUi(self)
self.ui.treeView.setModel(self.__tree_model)
self.ui.listView.setModel(self.__bundles_model)
self.ui.listView.clicked.connect(self.update_tree)
self.ui.listView.activated.connect(self.update_tree)
self.current_data = None
self.accepted.connect(self.before_accepting)
def update_tree(self, index):
name = unicode(self.__bundles_model.data(index, QtCore.Qt.DisplayRole))
data = bundles_db.get_logic_bundle_dict(bundle_name=name)
self.current_data = data
self.__tree_root = LogicBundleNode.from_dict(data)
self.__tree_model.set_root(self.__tree_root)
self.ui.treeView.expandAll()
def before_accepting(self):
index = self.ui.listView.currentIndex()
self.update_tree(index)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
out = {}
#vsd = GenericVariableSelectDialog(out, multiple=False,initial_selection_names=['ABCL_DSM_antisocial_T_padres'])
# vsd = MultiPlotOutcomeSelectDialog(out))
vsd = LoadLogicBundle()
vsd.exec_()