Skip to content

Commit

Permalink
UI updates, xlsx sheet export updates, adds dump and load json featur…
Browse files Browse the repository at this point in the history
…es, adds comments
  • Loading branch information
peytoncchen committed Sep 4, 2020
1 parent f554313 commit 9890e7c
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 72 deletions.
177 changes: 149 additions & 28 deletions datamodeler.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# Data Modeler for Power Calculations Python Edition
# Dedicated to the Appel Lab at Stanford University Department of Bioengineering
# Developed by Peyton Chen, Summer 2020

import sys
import pandas as pd
import numpy as np
import webbrowser
import json
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
Expand Down Expand Up @@ -108,6 +110,11 @@ def __init__(self, *args, **kwargs):
self.actionDocumentation.triggered.connect(self.opendocs)
self.actionDocumentation.setShortcut("Ctrl+D")

self.actionSave_2.triggered.connect(self.savejson)
self.actionSave_2.setShortcut("Ctrl+J")
self.actionLoad.triggered.connect(self.loadjson)
self.actionLoad.setShortcut("Ctrl+L")

#Timer used in a few places for statusBar background
self.timer = QTimer(self)
self.timer.timeout.connect(self.resetSBbkgrd)
Expand All @@ -132,6 +139,114 @@ def __init__(self, *args, **kwargs):
self.completer3.setCaseSensitivity(0)


def savejson(self):
#Saves to json so that user can load in data from a session later
if self.results.multiRun: #Can't be empty to save
dlg = QFileDialog()
dlg.setFileMode(QFileDialog.Directory)
if dlg.exec_():
directory, _filter = dlg.getSaveFileName()
outdic = {}
outdic['s1Inputs'] = self.inputs.s1Inputs
outdic['s2Inputs'] = self.inputs.s2Inputs
outdic['s3Inputs'] = self.inputs.s3Inputs
outdic['s4Inputs'] = self.inputs.s4Inputs
outdic['s4labels'] = self.inputs.s4labels
outdic['s5Inputs'] = self.inputs.s5Inputs
outdic['errorResults'] = self.results.errorResults
outdic['multiRun'] = self.results.multiRun
outdic['finalexpand'] = self.finalexpand
with open(str(directory) + '.json', 'w') as write_file:
json.dump(outdic,write_file)
else:
self.statusBar.setStyleSheet("background-color: #FFFF99")
self.statusBar.showMessage('Generate some values before you export to json!', 7000)
self.timer.start(7000)


def loadjson(self):
self.reset() #Resets to prepare for loading in
dlg = QFileDialog()
dlg.setFileMode(QFileDialog.ExistingFile)
filename, _filter = dlg.getOpenFileName(None, "Load in json", ".", "(*.json)")

if filename:
self.reset()
with open(filename, 'r') as read_file:
indic = json.load(read_file)

#Set text for S1
self.numMeasure.setText(indic['s1Inputs'][0])
self.numMeasure.setModified(True)
self.numMeasure.repaint()
self.numTreat.setText(indic['s1Inputs'][1])
self.numTreat.setModified(True)
self.numTreat.repaint()
self.numBf.setText(indic['s1Inputs'][2])
self.numBf.setModified(True)
self.numBf.repaint()
self.nameMeas.setText(indic['s1Inputs'][3])
self.nameMeas.setModified(True)
self.nameMeas.repaint()
self.namedVar.setText(indic['s1Inputs'][4])
self.namedVar.setModified(True)
self.namedVar.repaint()
self.s1process()

#Set text for S2
for i, obj in enumerate(self.inputs.s2Obj[0]): #labels
obj.setText(indic['s2Inputs'][0][i])
obj.repaint()
for i, obj in enumerate(self.inputs.s2Obj[1]): #values
obj.setText(indic['s2Inputs'][1][i])
obj.repaint()
self.s2process()

#Set text for S3
for i, obj in enumerate(self.inputs.s3Obj):
obj.setText(indic['s3Inputs'][i])
obj.repaint()

#Set text for S4
for i, obj in enumerate(self.inputs.s4Obj):
obj.setText(indic['s4Inputs'][i])
obj.repaint()
for i, obj in enumerate(self.inputs.s4labelobj):
obj.setText(indic['s4labels'][i])
obj.repaint()
self.s3and4process()

#Set text for S5 and storage
self.results.multiRun = indic['multiRun']
self.results.dVResults = self.results.multiRun[-1]
self.initdVValView()
self.results.errorResults = indic['errorResults']
self.initcurrInpView()
self.inputs.s5Inputs = indic['s5Inputs']
for i, obj in enumerate(self.inputs.s5Obj[0]): #Treatment col
obj.setText(indic['s5Inputs'][0][i])
obj.repaint()
for i,lst in enumerate(self.inputs.s5Obj[1]): #Blocking fac cols
for j,obj in enumerate(lst):
obj.setText(indic['s5Inputs'][1][i][j])
obj.repaint()
self.lockgrid()
self.lockinputs()
self.editInputs.show()
self.editInputs.repaint()
self.runcounter = len(self.results.multiRun)
self.runCount.setText('Current run count: ' + str(self.runcounter))
self.runCount.repaint()
self.s5but.setText('Reset runs')
self.s5but.repaint()
self.updates4.show()
self.updates4.repaint()
self.shows6fields()

if indic['finalexpand']:
self.runglm()
self.pwr()


def s1process(self):
#Continue/Update for initial parameters
Expand Down Expand Up @@ -188,8 +303,6 @@ def s1process(self):
self.dViewlabelchanged = False
if self.firstexpand:
self.unlockgrid()
self.results.genEVals(self.inputs.s2Inputs, self.inputs.s3Inputs)
self.initcurrInpView() #Reinitializes current input box: if blank, updated needed S3 or S4


def s2process(self):
Expand Down Expand Up @@ -218,7 +331,7 @@ def s2process(self):
self.unlockgrid()
self.results.genEVals(self.inputs.s2Inputs, self.inputs.s3Inputs)
self.initcurrInpView() #Reinitializes current input box: if blank, updated needed S3 or S4
self.minimize() #Minimizes 3rd pane if it exists



def s3and4process(self):
Expand All @@ -245,7 +358,6 @@ def s3and4process(self):
self.results.genEVals(self.inputs.s2Inputs, self.inputs.s3Inputs)
self.initcurrInpView()
self.unlockgrid()
self.minimize() #Minimizes 3rd pane if it exists


def s3and4update(self):
Expand All @@ -267,7 +379,6 @@ def s3and4update(self):
self.initcurrInpView()
self.updatebool = True #To update not reinitialize and overwrite current dVVal view
self.unlockgrid()
self.minimize() #Minimizes 3rd pane if it exists


def s5process(self):
Expand Down Expand Up @@ -302,7 +413,6 @@ def s5process(self):
self.updates4.show()
self.updates4.repaint()
self.shows6fields()
self.updatebool = True
else:
self.shows6fields()
self.updatedVVal()
Expand Down Expand Up @@ -398,7 +508,7 @@ def genGrid(self):

if not verify[0]:
self.statusBar.showMessage(verify[1])
self.statusBar.setStyleSheet("background-color: #FFFF99") #Light yellow warning
self.statusBar.setStyleSheet("background-color: pink;") #Light yellow warning
return #will not fit to grid unless #of measurements is multiple of combos
else:
dic = combotofitgrid(combos, self.inputs.s2Inputs, self.inputs.s1Inputs)
Expand Down Expand Up @@ -460,7 +570,6 @@ def runglm(self):
self.statusBar.showMessage('Warning - this experiment is designed without enough separation in treatment and blocking factor assignments, unable to complete f-test', 10000)
self.timer.start(10000)


#Initializing tableviews for pairwise t-test
self.dfBox.addWidget(QLabel('Pairwise t-test results:'))
for frame in self.results.resultframes:
Expand Down Expand Up @@ -526,9 +635,7 @@ def exportframes(self):


def exporttxt(self):
#Exports a read-out of current session into text file
#Includes all inputs, generated error, treatment means, all runs and dVVal generation, power estimation results
#if they exist. CSV dataframes must be separately exported
#Exports a read-out of all runs and only runs into text file
dlg = QFileDialog()
dlg.setFileMode(QFileDialog.Directory)
outstring = preparemultitxt(self.inputs.s5Inputs, self.results.multiRun, self.inputs.s1Inputs, self.inputs.s2Inputs)
Expand Down Expand Up @@ -557,6 +664,9 @@ def exportsas(self):


def exportxlsx(self):
#Exports a read-out of current session into excel file
#Includes all inputs, generated error, treatment means, all runs and dVVal generation, power estimation results
#if they exist. CSV dataframes must be separately exported
if self.updatebool:
dlg = QFileDialog()
dlg.setFileMode(QFileDialog.Directory)
Expand Down Expand Up @@ -639,6 +749,7 @@ def initdVValView(self):
labellst.append(label)
self.dGrid.addWidget(label,i+1,colCount)
self.results.dVObjects = labellst
self.updatebool = True


def updateDviewlabels(self):
Expand Down Expand Up @@ -799,6 +910,7 @@ def initBfView(self):


def lockinputs(self):
#Locks input QLineEdits and QPushButtons for pane 1
self.editInputs.setEnabled(True)
self.editInputs.repaint()

Expand Down Expand Up @@ -835,8 +947,10 @@ def lockinputs(self):


def unlockinputs(self):
#Unlocks QLineEdits and QPushButtons to update inputs for pane 1
self.editInputs.setEnabled(False)
self.editInputs.repaint()
self.minimize()

if self.firstexpand:
self.unlockgrid()
Expand All @@ -851,30 +965,34 @@ def unlockinputs(self):
self.s1but.repaint()

#Unlocking S2
for obj in self.inputs.s2Obj[0]:
obj.setReadOnly(False)
for obj in self.inputs.s2Obj[1]:
obj.setReadOnly(False)
if int(self.inputs.s1Inputs[2]) != 0:
self.s2but.setEnabled(True)
self.s2but.repaint()
if self.inputs.s2Obj:
for obj in self.inputs.s2Obj[0]:
obj.setReadOnly(False)
for obj in self.inputs.s2Obj[1]:
obj.setReadOnly(False)
if int(self.inputs.s1Inputs[2]) != 0:
self.s2but.setEnabled(True)
self.s2but.repaint()

#Unlocking S3
for obj in self.inputs.s3Obj:
obj.setReadOnly(False)
if self.inputs.s3Obj:
for obj in self.inputs.s3Obj:
obj.setReadOnly(False)

#Unlocking S4
for obj in self.inputs.s4Obj:
obj.setReadOnly(False)
for obj in self.inputs.s4labelobj:
obj.setReadOnly(False)
self.s4but.setEnabled(True)
self.s4but.repaint()
self.updates4.setEnabled(True)
self.updates4.repaint()
if self.inputs.s4Obj:
for obj in self.inputs.s4Obj:
obj.setReadOnly(False)
for obj in self.inputs.s4labelobj:
obj.setReadOnly(False)
self.s4but.setEnabled(True)
self.s4but.repaint()
self.updates4.setEnabled(True)
self.updates4.repaint()


def unlockgrid(self):
#Unlocks distribution grid on pane 2
self.hides6fields()
self.results.multiRun.clear()
self.runcounter = 0
Expand All @@ -895,6 +1013,7 @@ def unlockgrid(self):


def lockgrid(self):
#Locks distribution grid on pane 2
for obj in self.inputs.s5Obj[0]: #Treatment col
obj.setReadOnly(True)
for lst in self.inputs.s5Obj[1]: #Blocking fac cols
Expand All @@ -903,10 +1022,12 @@ def lockgrid(self):


def changedViewlabelsbool(self):
#Changes bool dViewlabelchanged to True
self.dViewlabelchanged = True


def resetSBbkgrd(self):
#Changes status bar background back to none
self.statusBar.setStyleSheet("background-color: none;")


Expand Down
14 changes: 13 additions & 1 deletion mainwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,8 @@
</property>
<addaction name="actionSave"/>
<addaction name="actionReset"/>
<addaction name="actionSave_2"/>
<addaction name="actionLoad"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
Expand All @@ -1124,7 +1126,7 @@
</widget>
<action name="actionSave">
<property name="text">
<string>Save</string>
<string>Save to Excel</string>
</property>
</action>
<action name="actionReset">
Expand All @@ -1137,6 +1139,16 @@
<string>Documentation</string>
</property>
</action>
<action name="actionSave_2">
<property name="text">
<string>Dump to JSON</string>
</property>
</action>
<action name="actionLoad">
<property name="text">
<string>Load from JSON</string>
</property>
</action>
</widget>
<resources/>
<connections/>
Expand Down
10 changes: 9 additions & 1 deletion modules/Mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,14 @@ def setupUi(self, MainWindow):
self.actionReset.setObjectName("actionReset")
self.actionDocumentation = QtWidgets.QAction(MainWindow)
self.actionDocumentation.setObjectName("actionDocumentation")
self.actionSave_2 = QtWidgets.QAction(MainWindow)
self.actionSave_2.setObjectName("actionSave_2")
self.actionLoad = QtWidgets.QAction(MainWindow)
self.actionLoad.setObjectName("actionLoad")
self.menuSession.addAction(self.actionSave)
self.menuSession.addAction(self.actionReset)
self.menuSession.addAction(self.actionSave_2)
self.menuSession.addAction(self.actionLoad)
self.menuHelp.addAction(self.actionDocumentation)
self.menuBar.addAction(self.menuSession.menuAction())
self.menuBar.addAction(self.menuHelp.menuAction())
Expand Down Expand Up @@ -486,9 +492,11 @@ def retranslateUi(self, MainWindow):
self.PCGroupBox.setTitle(_translate("MainWindow", "Power estimation calculation and results:"))
self.menuSession.setTitle(_translate("MainWindow", "Session"))
self.menuHelp.setTitle(_translate("MainWindow", "Help"))
self.actionSave.setText(_translate("MainWindow", "Save"))
self.actionSave.setText(_translate("MainWindow", "Save to Excel"))
self.actionReset.setText(_translate("MainWindow", "Reset"))
self.actionDocumentation.setText(_translate("MainWindow", "Documentation"))
self.actionSave_2.setText(_translate("MainWindow", "Dump to JSON"))
self.actionLoad.setText(_translate("MainWindow", "Load from JSON"))


if __name__ == "__main__":
Expand Down

0 comments on commit 9890e7c

Please sign in to comment.