def loadSeries(self, directory): """Handles loading a given series in a directory. Also changes the current working directory self.Param_Dict["Directory"] Parameters: directory: path of the series returns: ts: yt DataSetSeries object """ GUILogger.info(f"{directory} is directory for series mode") self.Status_Dict["Dir"].setText(directory) self.Param_Dict["Directory"] = directory ok = self.askSeriesName() if ok: try: GUILogger.info(f"Loading series '{self.Param_Dict['Seriesname']}'...") ts = yt.load(directory + '/' + self.Param_Dict["Seriesname"]) self.Param_Dict["Filename"] = "" self.Status_Dict["File"].setText(self.Param_Dict["Filename"]) self.Param_Dict["isValidSeries"] = True self.Param_Dict["isValidFile"] = True return ts except YTOutputNotIdentified: sut.alertUser("Couldn't load this series. Please try again") # Ask the user to enter another series name. # If he cancels, pass. return self.loadSeries(directory) else: GUILogger.warning("Couldn't load series.") GUILogger.log(29, "Try replacing the last digits of your series with " "questionmarks or import all files of the directory " "by using *") return None
def setUpSeries(self): """When the series is given, make it ready for evaluation by updating fields for the axes""" if self.Param_Dict["isValidSeries"]: self.Param_Dict["SignalHandler"].changeEvalMode() self.Status_Dict["Status"].setText("Series ready to evaluate.") self.Button_Dict["MakeLinePlot"].hide() GUILogger.info("Scanning the first file for relevant fields...") # Update Geometry and hide the widgets that would cause errors self.Param_Dict["CurrentDataSet"] = self.Param_Dict["DataSeries"][0] sut.updateGeometry(self.Param_Dict, self.CheckBox_Dict, self.RadioDict_Dict, self.Edit_Dict, self.Label_Dict) # Update the comboBoxes according to entries in field lists try: sut.updateFields(self.Param_Dict, self.ComboBox_Dict) except Exception: return sut.resetExtrema(self.Param_Dict, self.Edit_Dict, self.Button_Dict, self.Label_Dict, self.ComboBox_Dict, self) self.Param_Dict["SignalHandler"].getOtherUnitInput("Grid") fillDataSetDict(self.Param_Dict, self.Status_Dict, self.Wid_Dict["TopLayout"], self._main) setUpWidgets(self.Param_Dict, self.CheckBox_Dict, self.Misc_Dict) updateLabels(self.Param_Dict, self.Label_Dict) self.Param_Dict["SignalHandler"].setPlotOptions() sut.refreshWidgets(self.Edit_Dict, self.ComboBox_Dict)
def setUpFile(self, testmode=""): """When the file is given, make it ready for evaluation by updating the fields for the axes and calculating their min and maxes. Parameters: testmode: argument given when called through the buttons to test """ if self.Param_Dict["isValidFile"]: self.Param_Dict["SignalHandler"].changeEvalMode() self.Button_Dict["MakeLinePlot"].hide() GUILogger.info("Scanning file for relevant fields...") # Update Geometry and hide the widgets that would cause errors sut.updateGeometry(self.Param_Dict, self.CheckBox_Dict, self.RadioDict_Dict, self.Edit_Dict, self.Label_Dict) # Update the comboBoxes according to entries in field lists try: sut.updateFields(self.Param_Dict, self.ComboBox_Dict) except Exception: return sut.resetExtrema(self.Param_Dict, self.Edit_Dict, self.Button_Dict, self.Label_Dict, self.ComboBox_Dict, self) self.Param_Dict["SignalHandler"].getOtherUnitInput("Grid") self.Param_Dict["SignalHandler"].setPlotOptions() updateLabels(self.Param_Dict, self.Label_Dict) GUILogger.log(29, f"Loaded '{self.Param_Dict['Filename'].split('/')[-1]}'.") GUILogger.info("It is now ready for plotting.") sut.refreshWidgets(self.Edit_Dict, self.ComboBox_Dict)
def testValidSeries(self): """Promts the user to enter a directory name. After one has been chosen, prompt for a series name. If yt can't load it, display an error message and try again. """ directory = QW.QFileDialog.getExistingDirectory(self, "Select a directory with your series in it", self.Param_Dict["Directory"]) if directory != '': # Information on DataSetSeries object: # http://yt-project.org/doc/reference/api/yt.data_objects.time_series.html#yt.data_objects.time_series.DataSetSeries ts = self.loadSeries(directory) if ts is None: return try: GUILogger.info(f"This series includes {len(ts)} files.") # ts = [yt.load(filename) for filename in ts._pre_outputs] self.Param_Dict["DataSeries"] = ts self.setUpSeries() except TypeError: self.RadioDict_Dict["EvalMode"]["Single file"].setChecked(True) self.Param_Dict["SingleDataSet"] = ts GUILogger.warning("Only a single file has been selected. Changing to single file mode.") self.Param_Dict["Filename"] = self.Param_Dict["Seriesname"] self.Param_Dict["Seriesname"] = "" self.Status_Dict["Series"].setText(self.Param_Dict["Seriesname"]) self.Status_Dict["File"].setText(self.Param_Dict["Seriesname"]) self.Param_Dict["isValidFile"] = True self.Param_Dict["isValidSeries"] = False self.setUpFile()
def evaluateSingle(self): """Passes the evaluation of data to a ProgressDialog""" if self.Param_Dict["EvalMode"] == "Single" and not self.Param_Dict["isValidFile"]: GUILogger.error("Evaluation stopped. Please open valid file first.") return if self.Param_Dict["EvalMode"] == "Series" and not self.Param_Dict["isValidSeries"]: GUILogger.error("Evaluation stopped. Please open valid directory " "first and enter valid series name.") return GUILogger.info("Evaluation started. Checking for missing extrema...") sut.checkExtremaForPlot(self.Param_Dict) self.progressDialog = ProgressDialog(self.Param_Dict, self, mode="PlotSingle") self.progressWorker.finished.connect(self.giveSingleFeedback)
def openFile(self): """Opens a file dialogue and promts the user to add a file or directory, depending on the mode selected in Param_Dict["EvalMode"]. Also tries to load the file using yt. """ if self.Param_Dict["EvalMode"] == "Single": # Create a window that contains dialogue for opening file GUILogger.info("Opening file in single file mode") self.testValidFile() else: # Create a window that contains dialogue for opening directory GUILogger.info("Opening file in time series mode") self.testValidSeries()
def evaluateMultiple(self, Request_Dict): """Passes the evaluation of multiple plots to a ProgressDialog.""" self.Param_Dict["OnlyEvery"] = Request_Dict["OnlyEvery"] if Request_Dict["MakeMovie"]: Request_Dict["Directory"] = sut.setUpMovieFolder(self.Param_Dict) if not Request_Dict["Directory"]: return GUILogger.info("Evaluation started. Checking for missing extrema...") sut.checkExtremaForPlot(self.Param_Dict) self.progressDialog = ProgressDialog(self.Param_Dict, self, mode="PlotAll", Request_Dict=Request_Dict, slider=self.Misc_Dict["SeriesSlider"]) self.progressWorker.finished.connect(self.giveMultipleFeedback)
def setUpWidgets(Param_Dict, CheckBox_Dict, Misc_Dict): """Formats the slider and spinner so it fits the time series given.""" slider = Misc_Dict["SeriesSlider"] length = len(Param_Dict["DataSeries"]) slider.setRange(0, length - 1) GUILogger.log( 29, f"Loaded all {length} datasets of '{str(Param_Dict['Seriesname'])}'.") GUILogger.info("They are now ready for plotting.") slider.valueChanged.emit(0) slider.show() spinner = Misc_Dict["ProfileSpinner"] spinner.setMaximum(length) spinner.setValue(1) spinner.setDisabled(False)
def startLine(self): """Initiates LineDrawing in Canvas""" # Enables the information receival from plot GUILogger.info("Ready to draw a line on the plot.") GUILogger.log(29, "Just <b>press and release left click</b> on top of the plot.") toolbar = self.Param_Dict["CurrentPlotWindow"].toolbar toolbar._active = "ZOOM" # This will set the cross toolbar._actions["pan"].setChecked(False) toolbar._actions["zoom"].setChecked(False) if toolbar._idPress is not None: toolbar._idPress = toolbar.canvas.mpl_disconnect(toolbar._idPress) if toolbar._idRelease is not None: toolbar._idRelease = toolbar.canvas.mpl_disconnect(toolbar._idRelease) toolbar.mode = '' self.Edit_Dict["LineUnit"].setText(self.Param_Dict["oldGridUnit"]) self.Starter = self.Param_Dict["CurrentPlotWindow"].canvas.mpl_connect('button_press_event', self.lStartInput) self.Ender = self.Param_Dict["CurrentPlotWindow"].canvas.mpl_connect('button_release_event', self.lEndInput)
def loadFile(self, filename): """Handles loading a given file filename. Also changes the current working directory self.Param_Dict["Directory"]. Parameters: filename: path of the file to load returns: ds: yt DataSet object """ # Perform a reverse split to receive the directory and name separately directory, name = filename.rsplit('/', 1) self.Status_Dict["Dir"].setText(directory) self.Status_Dict["File"].setText('File: ' + name) self.Param_Dict["Directory"] = directory ds = yt.load(filename) GUILogger.info(f"Loading file '{name}'...") return ds
def __init__(self, Param_Dict, axis, parent): super().__init__(parent=parent) GUILogger.info("Do you want to calculate the global extrema?") self.length = len(Param_Dict["DataSeries"]) self.axis = axis self.Param_Dict = Param_Dict self.setWindowFlags(QC.Qt.Window | QC.Qt.CustomizeWindowHint | QC.Qt.WindowTitleHint | QC.Qt.WindowMinimizeButtonHint | QC.Qt.WindowMaximizeButtonHint | QC.Qt.WindowCloseButtonHint) self.setModal(True) # This way, the user can't interact with the rest self.initUi() self.signalsConnection() self.resize(200, 100) self.setWindowIcon(QG.QIcon('simgui_registry/CoverIcon.png')) self.setWindowTitle("Options for extrema calculation") self.show()
def createProfWithTimeForX(Param_Dict, worker): """Make a profile plot having the time as the x-Axis. Parameters: Param_Dict: For the fields and DataSets to be plotted. Returns: arr: list containing two YTArrays having the time as the first and the y-field as second entry """ GUILogger.info("This may take some...time...") ts = Param_Dict["DataSeries"] timeMin = Param_Dict["XMin"] # they should already be converted to xunit. timeMax = Param_Dict["XMax"] times = [] datasets = [] emitStatus(worker, "Gathering time data") for ds in ts: # use the times we have already calculated for each dataset time = Param_Dict["DataSetDict"][str(ds) + "Time"].to_value(Param_Dict["XUnit"]) timecompare = float("{:.3g}".format(time)) if timeMin <= timecompare <= timeMax: times.append(time) datasets.append(str(ds)) GUILogger.log(29, "Iterating over the whole series from {:.3g} to {:.3g} {}..." .format(timeMin, timeMax, Param_Dict["XUnit"])) calcQuan = getCalcQuanName(Param_Dict) field = Param_Dict["YAxis"] calcQuanString = getCalcQuanString(Param_Dict) storage = {} i = 0 length = len(times) if Param_Dict["YAxis"] in Param_Dict["NewDerFieldDict"].keys(): for ds in ts: if str(ds) in datasets: try: yResult = Param_Dict["DataSetDict"][str(ds) + field + calcQuan] except KeyError: ad = ds.all_data() yResult = eval(calcQuanString) # save the plotpoints for later use value = yt.YTQuantity(yResult, Param_Dict["YUnit"]).to_value(Param_Dict["FieldUnits"][field]) Param_Dict["DataSetDict"][str(ds) + field + calcQuan] = value storage[str(i)] = yResult # this is kind of clunky, but this way we don't run into problems later i += 1 progString = f"{i}/{length} data points calculated" emitStatus(worker, progString) if i % ceil(length/10) == 0: # maximum of 10 updates GUILogger.info(f"Progress: {progString}.") else: # We want to use parallel iteration if possible yt.enable_parallelism(suppress_logging=True) newTS = yt.load(Param_Dict["Directory"] + "/" + Param_Dict["Seriesname"]) for store, ds in newTS.piter(storage=storage): try: yResult = Param_Dict["DataSetDict"][str(ds) + field + calcQuan] except KeyError: ad = ds.all_data() # This is needed for the following command yResult = eval(calcQuanString) # save the plotpoints for later use value = yt.YTQuantity(yResult, Param_Dict["YUnit"]).to_value(Param_Dict["FieldUnits"][field]) Param_Dict["DataSetDict"][str(ds) + field + calcQuan] = value store.result = yResult i += 1 progString = f"{i}/{length} data points calculated" emitStatus(worker, progString) if i % ceil(length/10) == 0: # maximum of 10 updates GUILogger.info(f"Progress: {progString}.") labels = [field] # Convert the storage dictionary values to an array, so they can be # easily plotted arr_x = yt.YTArray(times, Param_Dict["XUnit"]) arr_y = yt.YTArray(list(storage.values()), Param_Dict["YUnit"]) arr = [arr_x, arr_y] # print(arr) return arr, labels
def createMultipleProfiles(Param_Dict, worker): """Make a profile plot for each of the requested times and return them so they can be plotted. Parameters: Param_Dict: For the fields and DataSets to be plotted. Returns: arr: list containing YTArrays having the x-field as the first and the y-fields as second and following entries labels: the labels for the rows. """ GUILogger.info("This may take some time.") onlyEvery = Param_Dict["ProfOfEvery"] if onlyEvery == 1: numString = "" else: suf = lambda n: "%d%s "%(n,{1:"st",2:"nd",3:"rd"}.get(n if n<20 else n%10,"th")) numString = suf(onlyEvery) GUILogger.log(29, "Creating a profile for every {}dataset of the series...".format(numString)) # the user can input to only plot every nth file: yt.enable_parallelism(suppress_logging=True) storage = {} labels = [] i = 0 ts = Param_Dict["DataSeries"] length = ceil(len(ts)/onlyEvery) if Param_Dict["YAxis"] in Param_Dict["NewDerFieldDict"].keys(): for ds in ts: if i % onlyEvery == 0: # Create a data container to hold the whole dataset. ad = ds.all_data() # Create a 1d profile of xfield vs. yfield: prof = yt.create_profile(ad, Param_Dict["XAxis"], fields=[Param_Dict["YAxis"]], weight_field=Param_Dict["WeightField"]) # Add labels time = Param_Dict["DataSetDict"][str(ds) + "Time"] label = "{} at {:.3g} ".format(Param_Dict["YAxis"], time.value) label += str(time.units) labels.append(label) storage[str(i)] = prof[Param_Dict["YAxis"]] progString = f"{int(i/onlyEvery+1)}/{length} profiles done" emitStatus(worker, progString) if i % ceil(length/10) == 0: # maximum of 10 updates GUILogger.info(f"Progress: {progString}.") i += 1 else: # We want to use parallel iteration if possible ts = yt.load(Param_Dict["Directory"] + "/" + Param_Dict["Seriesname"]) for store, ds in ts.piter(storage=storage): if i % onlyEvery == 0: ad = ds.all_data() prof = yt.create_profile(ad, Param_Dict["XAxis"], fields=[Param_Dict["YAxis"]], weight_field=Param_Dict["WeightField"]) # Add labels time = Param_Dict["DataSetDict"][str(ds) + "Time"] label = "{} at {:.3g} ".format(Param_Dict["YAxis"], time.value) label += str(time.units) labels.append(label) store.result = prof[Param_Dict["YAxis"]] progString = f"{int(i/onlyEvery+1)}/{length} profiles done" emitStatus(worker, progString) GUILogger.info(f"Progress: {progString}.") i += 1 # Convert the storage dictionary values to an array with x-axis as first # row and then the results of y-field as following rows. arr_x = prof.x arr = [arr_x] for arr_y in storage.values(): if arr_y is not None: arr.append(arr_y) return arr, labels
def restoreFromParam_Dict(self): """Restores the settings used for the plot to the GUI""" self.readOutExtrema() self.Param_Dict["SignalHandler"].restoreFromParam_Dict(self.Param_Dict) GUILogger.info("The settings to recreate this plot have been " "transferred to the GUI.")