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 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 PhasePlot(Param_Dict, worker): """Takes a DataSet object loaded with yt and performs a phasePlot on it. Parameters: Param_Dict: to access the relevant parameters """ if Param_Dict["WeightField"] is None: GUILogger.warning('Having <font color="DarkViolet">None</font> as the ' "weight field just accumulates, " "so the extrema might be inaccurate.") ds = Param_Dict["CurrentDataSet"] XField, YField, ZField = Param_Dict["XAxis"], Param_Dict["YAxis"], \ Param_Dict["ZAxis"] ad = ds.all_data() if Param_Dict["ParticlePlot"]: plot = yt.ParticlePhasePlot(ad, XField, YField, ZField, weight_field=Param_Dict["WeightField"], fontsize=14) else: plot = yt.PhasePlot(ad, XField, YField, ZField, weight_field=Param_Dict["WeightField"], fontsize=14) emitStatus(worker, "Setting phase plot modifications") # Set min, max, unit log and color scheme: setAxisSettings(plot, Param_Dict, "X") setAxisSettings(plot, Param_Dict, "Y") setAxisSettings(plot, Param_Dict, "Z") emitStatus(worker, "Annotating the phase plot") plot.annotate_title(Param_Dict["PlotTitle"]) finallyDrawPlot(plot, Param_Dict, worker)
def testValidFile(self): """Promts the user to enter a file name. If yt can't load it, display an error message and try again. returns: True if load was successful False if user cancels before successful load """ filename = QW.QFileDialog.getOpenFileName(self, "Select a simulation file", self.Param_Dict["Directory"], "All files (*)")[0] if filename != '': try: # SingleDataSet is there so we can go back to a single dataset # if the user loaded one. self.Param_Dict["SingleDataSet"] = self.loadFile(filename) self.Param_Dict["CurrentDataSet"] = self.Param_Dict["SingleDataSet"] self.Param_Dict["Seriesname"] = "" self.Param_Dict["Filename"] = filename self.Status_Dict["Series"].setText(self.Param_Dict["Seriesname"]) self.Param_Dict["isValidFile"] = True self.Param_Dict["isValidSeries"] = False self.setUpFile() return except YTOutputNotIdentified: sut.alertUser("Couldn't load this file. Please try again") # Ask the user to enter another series name. # If he cancels, pass. self.testValidFile() else: GUILogger.warning("Couldn't load file. Click 'Open File' to start over.") return
def calcExtrema(Param_Dict, ds, field, projCond): """Tries to calculate the extrema.""" if projCond: # For a projection plot, we need to get the projected min and max # We also need to create new entries in the fieldMins minMaxArray = calcProjectionExtrema(Param_Dict, ds, field) else: try: minMaxArray = ds.all_data().quantities.extrema(field) except yt.utilities.exceptions.YTFieldNotFound: GUILogger.warning(f"Couldn't find {field} in the available fields") raise WorkingException return minMaxArray
def makeProfilePlot(self, Param_Dict, arr, labels, worker=None): """Plots the data of the array to the axes.""" self.arr = arr self.labels = labels emitStatus(worker, "Starting the plot") if Param_Dict["AddProfile"]: self.ax.tick_params(axis='y',) self.twinax = self.ax.twinx() x_values = arr[0].to_value(Param_Dict["XUnit"]) for i in range(len(arr)-1): y_values = arr[i+1].to_value(Param_Dict["YUnit"]) label = labels[i] self.twinax.plot(x_values, y_values, ":", linewidth=3, label=label) emitStatus(worker, "Setting plot modifications") setProfileAxisSettings(Param_Dict, "Y", self.twinax) self.twinax.tick_params(axis='y') # ask matplotlib for the plotted objects and their labels lines, labels = self.ax.get_legend_handles_labels() lines2, labels2 = self.twinax.get_legend_handles_labels() self.ax.legend(lines + lines2, labels + labels2) self.hasProfile = False # We only want the user to be able to add a plot if there is only one profile Param_Dict["SignalHandler"].changeToProfile() else: self.prepareFigure() # Clear everything before plotting # get x- and y-values and plot them: x_values = arr[0].to_value(Param_Dict["XUnit"]) for i in range(len(arr)-1): y_values = arr[i+1].to_value(Param_Dict["YUnit"]) label = labels[i] self.ax.plot(x_values, y_values, "-", linewidth=3, label=label) emitStatus(worker, "Setting plot modifications") setProfileAxisSettings(Param_Dict, "Y", self.ax) self.hasProfile = True Param_Dict["SignalHandler"].changeToProfile() if Param_Dict["Timestamp"] and Param_Dict["XAxis"] != "time": if len(arr) > 2: # This can probably be done more elegantly GUILogger.warning("Timestamp is not annotated for multiple" " profiles. Sorry for leaving the CheckBox there.") else: drawTimestampBox(Param_Dict, self.ax) self.ax.legend() self.ax.grid() setProfileAxisSettings(Param_Dict, "X", self.ax) self.ax.set_title(r"{}".format(Param_Dict["PlotTitle"])) emitStatus(worker, "Drawing plot onto the canvas") self.canvas.draw() # called twice because somehow it isn't fully sized self.canvas.draw() # at first... I don't know why. self.copyParamDict(Param_Dict)
def calcProjectionExtrema(Param_Dict, ds, field): """Creates dummy projection plots to then calculate the extrema in those. Returns a ytArray of these extrema""" try: if Param_Dict["ParticlePlot"]: projPlot = yt.ParticleProjectionPlot(ds, Param_Dict["NAxis"], field) else: projPlot = yt.ProjectionPlot(ds, Param_Dict["NAxis"], field) except yt.utilities.exceptions.YTFieldNotFound: GUILogger.warning(f"Couldn't find {field} in the available fields") return ZMin = projPlot.frb[field].min() ZMax = projPlot.frb[field].max() return yt.YTArray([ZMin, ZMax])
def setUpMovieFolder(Param_Dict): """Creates a folder for the movie pictures to be saved in.""" directory = QW.QFileDialog.getExistingDirectory( None, "Select a directory " "to save the pictures in", Param_Dict["Directory"]) if directory == "": GUILogger.warning( "Evaluation stopped. Please select a valid directory.") return False date = datetime.now().strftime("%d_%m_%Y_%H_%M_%S") plotMode = Param_Dict["PlotMode"] # for the fstring directory = f"{directory}/{plotMode}plots_{date}" mkdir(directory) GUILogger.log(29, f"The pictures are being saved to <b>{directory}</b>.") return directory
def annotatePlot(Param_Dict, plot): """Annotates the plot according to the selection of the user. Tutorial: https://yt-project.org/doc/visualizing/callbacks.html""" plot.annotate_title(Param_Dict["PlotTitle"]) if Param_Dict["Timestamp"]: plot.annotate_timestamp(corner='upper_left', draw_inset_box=True) if Param_Dict["Geometry"] == "cartesian": if Param_Dict["Scale"]: plot.annotate_scale(corner='upper_right') if Param_Dict["Contour"]: plot.annotate_contour(Param_Dict["ZAxis"]) if Param_Dict["VelVectors"]: plot.annotate_velocity(normalize=True) if Param_Dict["NormVecMode"] == "Axis-Aligned": if Param_Dict["Grid"]: plot.annotate_grids() issueAnnoWarning(plot, "Grids") if Param_Dict["VelStreamlines"]: issueAnnoWarning(plot, "Velocity streamlines") if Param_Dict["NAxis"] == "x": plot.annotate_streamlines("velocity_y", "velocity_z") elif Param_Dict["NAxis"] == "y": plot.annotate_streamlines("velocity_x", "velocity_z") elif Param_Dict["NAxis"] == "z": plot.annotate_streamlines("velocity_x", "velocity_y") if Param_Dict["MagVectors"]: plot.annotate_magnetic_field(normalize=True) if Param_Dict["MagStreamlines"]: issueAnnoWarning(plot, "Magnetic field streamlines") if Param_Dict["NAxis"] == "x": plot.annotate_streamlines("magy", "magz") elif Param_Dict["NAxis"] == "y": plot.annotate_streamlines("magx", "magz") elif Param_Dict["NAxis"] == "z": plot.annotate_streamlines("magx", "magy") if Param_Dict["ParticleAnno"] and not Param_Dict["ParticlePlot"]: if Param_Dict["PSlabWidth"] == "" or float(Param_Dict["PSlabWidth"]) == 0: Param_Dict["PSlabWidth"] = 1 height = abs(Param_Dict["FieldMins"]["DomainHeight"] - Param_Dict["FieldMaxs"]["DomainHeight"]) if Param_Dict["Zoom"] == 1: GUILogger.warning("When annotating particles, you may need a " "zoom above 1 for proper annotations") plot.annotate_particles(float(Param_Dict["PSlabWidth"])*height, p_size=3.0) elif Param_Dict["Geometry"] == "cylindrical": if Param_Dict["Grid"]: plot.annotate_grids()
def ProfilePlot(Param_Dict, worker): """Takes a DataSet object loaded with yt and performs a ProfilePlot with fields on it. Parameters: Param_Dict: Dict with Parameters """ if Param_Dict["XAxis"] == "time": arr, labels = createProfWithTimeForX(Param_Dict, worker) elif Param_Dict["TimeSeriesProf"]: arr, labels = createMultipleProfiles(Param_Dict, worker) else: arr, labels = createNormalProfile(Param_Dict) if Param_Dict["WeightField"] is None and Param_Dict["XAxis"] != "time": GUILogger.warning('Having <b><font color="DarkViolet">None</font></b> ' "as the weight field just accumulates, " "so the extrema might be inaccurate.") Canvas = Param_Dict["CurrentPlotWindow"] Canvas.makeProfilePlot(Param_Dict, arr, labels, worker)
def readOutExtrema(self): """Reads out the current constraints of x- and y-axis and stores them before restoring them to the gui""" mode = self.Param_Dict["PlotMode"] xmin, xmax = self.ax.get_xlim() ymin, ymax = self.ax.get_ylim() if mode in ["Profile", "Phase"]: self.Param_Dict["XMin"] = xmin self.Param_Dict["XMax"] = xmax if mode in ["Profile", "Phase", "Line"]: self.Param_Dict["YMin"] = ymin self.Param_Dict["YMax"] = ymax if mode in ["Slice", "Projection"]: self.Param_Dict["HorWidth"] = abs(xmin-xmax) self.Param_Dict["VerWidth"] = abs(ymin-ymax) self.Param_Dict["Zoom"] = 1.0 aligned = self.Param_Dict["NormVecMode"] == "Axis-Aligned" cart = self.Param_Dict["Geometry"] == "cartesian" if cart or self.Param_Dict["NAxis"] == "theta" and aligned: horCen = mean([xmin, xmax]) verCen = mean([ymin, ymax]) if self.Param_Dict["NAxis"] == "theta": n = 2 else: n = ["x", "y", "z"].index(self.Param_Dict["NAxis"]) horAxis = ["X", "Y", "Z"][convertToLessThanThree(n+1)] verAxis = ["X", "Y", "Z"][convertToLessThanThree(n+2)] self.Param_Dict[horAxis + "Center"] = horCen self.Param_Dict[verAxis + "Center"] = verCen elif not aligned: GUILogger.warning("For off-axis plots, setting the center " "coordinates is not supported.") else: GUILogger.warning("Reading out the center coordinates is not " "supported for having " f"{self.Param_Dict['NAxis']} as normal axis." "This may produce weird behaviour.")