class AnimationWindow(wx.Frame): def __init__(self, parent, data_list, config=None, yvals=None, mode="1D", pks=None, pksmode="mz", *args, **kwargs): """ A simple window for animating mulitple 1D or 2D plots in a sequence. :param parent: Parent window. Passed to wx.Frame. :param data_list: List of data to be plotted :param config: UniDecConfig object :param yvals: Titles for the plots. :param mode: 1 = 1D plots, 2 = 2D plots :param args: :param kwargs: :return: None """ wx.Frame.__init__(self, parent, title="Plot Animations", size=(-1, -1)) # Initialize parameters if mode == "2D": self.mode = 2 else: self.mode = 1 if config is None: self.config = unidecstructure.UniDecConfig() self.config.initialize() else: self.config = config self.datalist = data_list self.pks = pks self.pksmode = pksmode if self.pksmode == "mz": self.xlabel = "m/z (Th)" self.testkda = False elif self.pksmode == "CCS": self.xlabel = "CCS" self.testkda = False else: self.xlabel = "Mass (Da)" self.testkda = True self.yvals = yvals if self.yvals is None: self.yvals = list(range(0, len(data_list))) self.dim = 1 self.pos = -1 self.play = False self.animation = None # Create GUI # Make the menu filemenu = wx.Menu() menu_save_fig = filemenu.Append(wx.ID_ANY, "Save Figures", "Save all figures at selected path") self.Bind(wx.EVT_MENU, self.on_save_fig, menu_save_fig) menu_bar = wx.MenuBar() menu_bar.Append(filemenu, "&File") self.SetMenuBar(menu_bar) self.CreateStatusBar(2) panel = wx.Panel(self) sizer = wx.BoxSizer(wx.VERTICAL) if self.mode == 1: self.plot = plot1d.Plot1d(panel) else: self.plot = plot2d.Plot2d(panel) sizer.Add(self.plot, 0, wx.EXPAND) controlsizer = wx.BoxSizer(wx.HORIZONTAL) sb = wx.StaticBox(panel, label='Frame Rate (ms/frame)') sbs = wx.StaticBoxSizer(sb, orient=wx.VERTICAL) frmax = 2000 frmin = 1 self.frslider = wx.Slider( panel, wx.ID_ANY, 500, frmin, frmax, (30, 60), (250, -1), wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS) self.frslider.SetTickFreq(100) sbs.Add(self.frslider, 0, wx.EXPAND) self.Bind(wx.EVT_COMMAND_SCROLL_THUMBRELEASE, self.update_framerate, self.frslider) controlsizer.Add(sbs, 0, wx.EXPAND) self.playbutton = wx.ToggleButton(panel, label="Play") self.nextbutton = wx.Button(panel, label="Next") self.backbutton = wx.Button(panel, label="Back") controlsizer.Add(self.backbutton, 0, wx.EXPAND) controlsizer.Add(self.playbutton, 0, wx.EXPAND) controlsizer.Add(self.nextbutton, 0, wx.EXPAND) self.Bind(wx.EVT_TOGGLEBUTTON, self.on_play, self.playbutton) self.Bind(wx.EVT_BUTTON, self.on_next, self.nextbutton) self.Bind(wx.EVT_BUTTON, self.on_back, self.backbutton) self.ctlautoscale = wx.CheckBox(panel, label="Autoscale") controlsizer.Add(self.ctlautoscale, 0, wx.EXPAND) if self.mode == 2: self.ctlautoscale.SetValue(True) sizer.Add(controlsizer, 0, wx.EXPAND) panel.SetSizer(sizer) sizer.Fit(self) self.Bind(wx.EVT_CLOSE, self.on_close, self) self.init() self.Centre() self.Show(True) def on_close(self, e): """ Stop the animation and close the window. :param e: Unused event :return: None """ print("Closing") try: self.animation._stop() except: pass self.Destroy() def update(self, frame_number): """ Continues to increment the plot to the next value in the data_list. Will stop if self.play is False. :param frame_number: Required but unused. Filled by FuncAnimation. :return: 0 """ if self.play: self.pos += 1 self.update_plot() return 0 else: return 0 def update_plot(self): """ Increment to the next data set and update the plot with the new data. Tries to keep some of the old plotting parameters like the zoom the same. Stops the animation if an error occurs. :return: None """ try: if self.pks is not None: self.refresh_plot() self.add_peaks() return self.pos %= len(self.datalist) newdata = self.datalist[self.pos] title = str(self.yvals[self.pos]) if self.mode == 1: # 1D Plot line = self.plot.subplot1.lines[0] xlim = self.plot.subplot1.get_xlim() ylim = self.plot.subplot1.get_ylim() line.set_data(newdata[:, 0], newdata[:, 1]) self.plot.subplot1.set_title(title) autoflag = self.ctlautoscale.GetValue() if autoflag: self.plot.subplot1.set_autoscale_on(True) self.plot.subplot1.relim() self.plot.subplot1.autoscale_view(True, True, True) else: self.plot.subplot1.set_xlim(xlim) self.plot.subplot1.set_ylim(ylim) self.plot.repaint() else: # 2D plot xlim = self.plot.subplot1.get_xlim() ylim = self.plot.subplot1.get_ylim() self.plot.contourplot(newdata, self.config, xlab=self.xlabel, title=title, repaint=False) autoflag = self.ctlautoscale.GetValue() if not autoflag: self.plot.subplot1.set_xlim(xlim) self.plot.subplot1.set_ylim(ylim) self.plot.add_title(title) self.plot.repaint() except Exception as e: self.animation._stop() print(e) def init(self): """ Create a fresh plot and start the animation. :return: None """ self.pos = 0 self.refresh_plot() self.animation = FuncAnimation(self.plot.figure, self.update, interval=500) self.animation._start() def on_play(self, e): """ Toggles self.play on or off. Will break the while loop in self.update if self.play = False. :param e: Unused event :return: None """ tog = self.playbutton.GetValue() if tog: self.play = True else: self.play = False pass def refresh_plot(self): """ Create a fresh plot from the top. :return: None """ self.pos %= len(self.datalist) newdata = self.datalist[self.pos] title = str(self.yvals[self.pos]) if self.mode == 1: self.plot.plotrefreshtop(newdata[:, 0], newdata[:, 1], title, self.xlabel, "Intensity", "", self.config, test_kda=self.testkda) self.plot.add_title(title) if self.pks is not None: self.add_peaks() else: self.plot.contourplot(newdata, self.config, xlab=self.xlabel, title=title) self.plot.add_title(title) def on_next(self, e): """ Plot the next data set in data_list. :param e: Unused event :return: None """ self.pos += 1 self.update_plot() pass def on_back(self, e): """ Plot the previous data set in data_list. :param e: Unused event :return: None """ self.pos -= 1 self.update_plot() pass def update_framerate(self, e): """ Change the frame rate. Restart the animation with fresh frame rate. :param e: Unused event :return: None """ framerate = self.frslider.GetValue() # print "Updated framerate to:", framerate # self.animation._interval=framerate # self.animation.new_frame_seq() self.animation._stop() self.animation = FuncAnimation(self.plot.figure, self.update, interval=framerate) self.animation._start() def add_peaks(self, e=None): if self.pksmode == "mz": self.add_peaks_mz() else: self.add_peaks_mass() def add_peaks_mz(self, e=None): for p in self.pks.peaks: if p.ignore == 0: list1 = [] list2 = [] mztab = p.mztab[self.pos] mztab2 = p.mztab2[self.pos] if (not ud.isempty(mztab)) and (not ud.isempty(mztab2)): mztab = np.array(mztab) mztab2 = np.array(mztab2) maxval = np.amax(p.mztab[:, :, 1]) for k in range(0, len(mztab)): if mztab[k, 1] > self.config.peakplotthresh * maxval: list1.append(mztab2[k, 0]) list2.append(mztab2[k, 1]) # print mztab[k] self.plot.plotadddot(np.array(list1), np.array(list2), p.color, p.marker) self.plot.repaint() def add_peaks_mass(self, e=None): for p in self.pks.peaks: if p.ignore == 0: pos = ud.nearest(self.datalist[self.pos][:, 0], p.mass) data = self.datalist[self.pos][pos] if data[1] > self.config.peakplotthresh * np.amax( self.datalist[self.pos][:, 1]): self.plot.plotadddot(data[0], data[1], p.color, p.marker) self.plot.repaint() def on_save_fig(self, e=None): path = FileDialogs.save_file_dialog() base, ext = os.path.splitext(path) #self.init() #self.save_fig(base,ext) for i in range(0, len(self.datalist)): self.on_next(None) self.save_fig(base, ext) def save_fig(self, base, ext): path = base + str(self.pos) + ext print(self.pos, path) self.plot.save_figure(path)
class SpatialVariance(PlotsInterval): name = 'Spatial Variance' plot = Button('Plot variogram') normalize = Bool(True) robust = Bool(True) cloud = Bool(False) se = Bool(False) n_samps = Int(100) dist_bin = Float(0.5) estimator = Enum('ergodic', ('ergodic', 'spot')) # animated variogram anim_time_scale = Enum(50, [0.5, 1, 5, 10, 20, 50, 100]) plot_anim = Button('Animate variogram') # Array map tool button vis_tool = Button('Covar map') # Correlation graph button plot_graph = Button('Plot graph') graph_stagger_x = Bool(False) graph_stagger_y = Bool(False) def _plot_graph_fired(self): t, y = self.curve_manager.interactive_curve.current_data() y = y[np.newaxis, :, :] label = '{0: .2f} sec'.format(t.mean()) fig, axs = self._get_fig(ncols=2, figsize=(12, 5)) fig = plot_site_corr(y, self.chan_map, label, normed=self.normalize, stagger_x=self.graph_stagger_x, stagger_y=self.graph_stagger_y, axs=axs) try: fig.canvas.draw_idle() except BaseException: pass return fig def _vis_tool_fired(self): _, y = self.curve_manager.interactive_curve.current_data() y *= 1e6 if self.normalize: cov = np.corrcoef(y) else: cov = np.cov(y) chan_map = self.chan_map tool = ArrayVarianceTool(cov, chan_map) view = tool.default_traits_view() view.kind = 'live' tool.edit_traits(view=view) return tool def compute_variogram(self, array, chan_map, **kwargs): """ Returns variogram points from the field defined by an array and channel map. The number of parameters returned depends on whether a variogram cloud is requested. If the cloud is not requested, then binned aggregates (x, y, se, Nd) are returned (that is: distance bins, mean semivariance at each distance, standard error of mean, and number of points in the original sample). Else, those binned aggregates are returned pre-pended by the non-aggregated (xcloud, ycloud) points. :param array: :param chan_map: :param kwargs: :return: """ robust = kwargs.pop('robust', self.robust) n_samps = kwargs.pop('n_samps', self.n_samps) normed = kwargs.pop('normalize', self.normalize) cloud = kwargs.pop('cloud', self.cloud) if normed: array = array / np.std(array, axis=1, keepdims=1) pts = np.linspace(0, array.shape[1] - 1, n_samps).astype('i') if isinstance(chan_map, ChannelMap): combs = chan_map.site_combinations else: combs = chan_map # I think turn off binning if a cloud is requested bin_size = None if (self.dist_bin < 0 or cloud) else self.dist_bin # Turn off se if cloud is True se = not cloud counts = not cloud if self.estimator == 'ergodic': vg_method = partial(fast_semivariogram, xbin=bin_size, trimmed=True, se=se, cloud=cloud, counts=counts) else: vg_method = partial(semivariogram, robust=robust, xbin=bin_size, trimmed=True, se=se, cloud=cloud, counts=counts) if cloud: bin_size = None if self.dist_bin < 0 else self.dist_bin xc, yc = vg_method(array[:, pts], combs) xb, yb = binned_variance(xc, yc, binsize=bin_size) # this will bring back mean and sem by default xb, yb, se, Nd = binned_variance_aggregate(xb, yb) return xc, yc, xb, yb, se, Nd x, y, Nd, se = vg_method(array[:, pts], combs) return x, y, se, Nd def _plot_anim_fired(self): if not hasattr(self, '_animating'): self._animating = False if self._animating: self._f_anim._stop() self._animating = False return t, y = self.curve_manager.interactive_curve.current_data() y *= 1e6 if self.normalize: y = y / np.std(y, axis=1, keepdims=1) #y = y / np.std(y, axis=0, keepdims=1) cm = self.chan_map t0 = time.time() r = self.compute_variogram(y[:, 0][:, None], cm, n_samps=1, normalize=False, cloud=False) t_call = time.time() - t0 scaled_dt = self.anim_time_scale * (t[1] - t[0]) f_skip = 1 t_pause = scaled_dt - t_call / float(f_skip) while t_pause < 0: f_skip += 1 t_pause = scaled_dt - t_call / float(f_skip) print('skipping', f_skip, 'samples and pausing', t_pause, 'sec') # this figure lives outside of figure "management" fig, axes = subplots() c = FigureCanvas(fig) x, svg, svg_se, Nd = r # also compute how long it takes to draw the errorbars line = axes.plot(x, svg, marker='s', ms=6, ls='--')[0] t0 = time.time() #ec = axes.errorbar(x, svg, yerr=svg_se, fmt='none', ecolor='gray') t_call = t_call + (time.time() - t0) t_pause = scaled_dt - t_call / float(f_skip) while t_pause < 0: f_skip += 1 t_pause = scaled_dt - t_call / float(f_skip) print('skipping', f_skip, 'samples and pausing', t_pause, 'sec') # average together frames at the skip rate? N = y.shape[1] blks = N // f_skip y = y[:, :blks * f_skip].reshape(-1, blks, f_skip).mean(-1) # print y.mean() def _step(n): c.draw() print('frame', n) x, svg, svg_se, Nd = self.compute_variogram(y[:, n:n + 1], cm, n_samps=1, normalize=False) # ec.remove() line.set_data(x, svg) #ec = axes.errorbar(x, svg, yerr=svg_se, fmt='none', ecolor='gray') self.parent._qtwindow.vline.setPos(t[n * f_skip]) if n == blks - 1: self._animating = False return (line, ) c.show() max_var = 5.0 if self.normalize else y.var(0).max() axes.set_ylim(0, 1.05 * max_var) if not self.normalize: axes.axhline(max_var, color='k', ls='--', lw=2) #axes.autoscale(axis='both', enable=True) plotters.sns.despine(ax=axes) self._f_anim = FuncAnimation(fig, _step, blks, interval=scaled_dt * 1e3, blit=True) self._f_anim.repeat = False self._animating = True self._f_anim._start() def _plot_fired(self): t, y = self.curve_manager.interactive_curve.current_data() y *= 1e6 r = self.compute_variogram(y, self.chan_map) if self.cloud: xc, yc, x, svg, svg_se, Nd = r else: x, svg, svg_se, Nd = r fig, ax = self._get_fig() label = 't ~ {0:.1f}'.format(t.mean()) clr = self._colors[self._axplots[ax]] if self.cloud: ax.scatter(xc, yc, s=4, alpha=0.25, c=clr) ax.plot(x, svg, marker='s', ms=6, ls='--', color=clr, label=label) ax.errorbar(x, svg, svg_se, fmt='none', ecolor=clr) # if self.normalize: # sill = 1.0 # ax.axhline(1.0, color=clr, ls='--') # else: # sill = np.median(y.var(1)) # ax.axhline(sill, color=clr, ls='--') #ax.set_ylim(0, 1.05 * sill) ax.set_xlim(xmin=0) ax.autoscale(axis='y', enable=True) ax.set_ylim(ymin=0) ax.legend() ax.set_xlabel('Distance (mm)') ax.set_ylabel('Semivariance') plotters.sns.despine(ax=ax) fig.tight_layout() try: fig.canvas.draw_idle() except BaseException: pass def default_traits_view(self): v = View( HGroup( VGroup( Label('Plot in new figure'), UItem('new_figure'), UItem('plot'), UItem('vis_tool'), HGroup(VGroup( Item('graph_stagger_x', label='Stagger horizontal'), Item('graph_stagger_y', label='Stagger vertical')), UItem('plot_graph'), label='Corr. graph')), VGroup(Item('estimator', label='Estimator'), Item('cloud', label='Cloud'), Item('se', label='Std Err'), Item('n_samps', label='# of samples'), Item('dist_bin', label='Distance bin (mm)'), Item('normalize', label='Normalized'), Item('robust', label='Robust'), columns=2, label='Estimation params'), VGroup(Item('anim_time_scale', label='Time stretch'), UItem('plot_anim'), label='Animate variogram'))) return v
class RunAnalysisInput(QDialog): def __init__(self, project, analysis_ID, analysis_type_label, *args, **kwargs): super().__init__(*args, **kwargs) uic.loadUi('data/user_input/ui/Analysis/runAnalysisInput.ui', self) icons_path = 'data\\icons\\' self.icon = QIcon(icons_path + 'pulse.png') self.setWindowIcon(self.icon) self.setWindowFlags(Qt.WindowStaysOnTopHint) # self.setWindowModality(Qt.WindowModal) self.label_title = self.findChild(QLabel, 'label_title') self.label_message = self.findChild(QLabel, 'label_message') self.label_message.setWordWrap(True) self.config_title_font() self.config_message_font() self.project = project self.solve = None self.analysis_ID = analysis_ID self.analysis_type_label = analysis_type_label self.frequencies = self.project.frequencies self.damping = self.project.global_damping self.modes = self.project.modes self.solution_acoustic = None self.solution_structural = None self.convergence_dataLog = None self.natural_frequencies_acoustic = [] self.natural_frequencies_structural = [] self.complete = False LoadingScreen('SOLUTION IN PROGRESS', 'Processing the cross-sections', target=self.process_cross_sections, project=project) if self.project.preprocessor.stop_processing: self.project.preprocessor.stop_processing = False return LoadingScreen('SOLUTION IN PROGRESS', 'Preparing the model to solve', target=self.preparing_mathematical_model_to_solve) self.pre_non_linear_convergence_plot() LoadingScreen('SOLUTION IN PROGRESS', 'Solving the analysis', target=self.process_analysis, project=project) self.post_non_linear_convergence_plot() if self.project.preprocessor.stop_processing: self.reset_all_results() self.project.preprocessor.stop_processing = False else: LoadingScreen('SOLUTION IN PROGRESS', 'Post-processing the obtained results', target=self.post_process_results) self.exec() self.check_warnings() def pre_non_linear_convergence_plot(self): if isinstance(self.solve, SolutionAcoustic): if self.analysis_ID in [3,5,6]: if self.solve.non_linear: fig = plt.figure(figsize=[8,6]) ax = fig.add_subplot(1,1,1) self.anime = FuncAnimation(fig, self.solve.graph_callback, fargs=(fig,ax), interval=2000) self.anime._start() plt.ion() plt.show() def post_non_linear_convergence_plot(self): if isinstance(self.solve, SolutionAcoustic): if self.analysis_ID in [3,5,6]: if self.solve.non_linear: self.anime._stop() def process_cross_sections(self): t0i = time() self.complete = False self.project.process_cross_sections_mapping() self.project.time_to_process_cross_sections = time() - t0i def preparing_mathematical_model_to_solve(self): t0 = time() if self.analysis_ID in [0,1,3,5,6]: if self.frequencies is None: return if len(self.frequencies) == 0: return if self.project.preprocessor._process_beam_nodes_and_indexes(): if self.analysis_ID not in [0,1,2]: title = "INCORRECT ANALYSIS TYPE" message = "There are only BEAM_1 elements in the model, therefore, \nonly structural analysis are allowable." info_text = [title, message, window_title_2] PrintMessageInput(info_text) return if self.analysis_ID == 2: self.project.preprocessor.enable_fluid_mass_adding_effect(reset=True) self.solve = self.project.get_structural_solve() elif self.analysis_ID == 4: self.solve = self.project.get_acoustic_solve() elif self.analysis_ID == 3: self.solve = self.project.get_acoustic_solve() elif self.analysis_ID in [5,6]: self.project.preprocessor.enable_fluid_mass_adding_effect() self.solve = self.project.get_acoustic_solve() else: self.project.preprocessor.enable_fluid_mass_adding_effect(reset=True) self.solve = self.project.get_structural_solve() self.project.time_to_preprocess_model = time() - t0 def process_analysis(self): t0 = time() if self.analysis_ID == 0: self.solution_structural = self.solve.direct_method(self.damping) # Structural Harmonic Analysis - Direct Method elif self.analysis_ID == 1: # Structural Harmonic Analysis - Mode Superposition Method self.solution_structural = self.solve.mode_superposition(self.modes, self.damping) elif self.analysis_ID == 3: # Acoustic Harmonic Analysis - Direct Method self.solution_acoustic, self.convergence_dataLog = self.solve.direct_method() elif self.analysis_ID == 5: # Coupled Harmonic Analysis - Direct Method t0_acoustic = time() self.solution_acoustic, self.convergence_dataLog = self.solve.direct_method() #Acoustic Harmonic Analysis - Direct Method self.project.time_to_solve_acoustic_model = time() - t0_acoustic self.project.set_acoustic_solution(self.solution_acoustic) self.solve = self.project.get_structural_solve() t0_structural = time() self.solution_structural = self.solve.direct_method(self.damping) #Coupled Harmonic Analysis - Direct Method self.project.time_to_solve_structural_model = time() - t0_structural elif self.analysis_ID == 6: # Coupled Harmonic Analysis - Mode Superposition Method t0_acoustic = time() self.solution_acoustic, self.convergence_dataLog = self.solve.direct_method() #Acoustic Harmonic Analysis - Direct Method self.project.time_to_solve_acoustic_model = time() - t0_acoustic self.project.set_acoustic_solution(self.solution_acoustic) self.solve = self.project.get_structural_solve() t0_structural = time() self.solution_structural = self.solve.mode_superposition(self.modes, self.damping) self.project.time_to_solve_structural_model = time() - t0_structural elif self.analysis_ID == 2: # Structural Modal Analysis self.natural_frequencies_structural, self.solution_structural = self.solve.modal_analysis(modes = self.modes, sigma=self.project.sigma) elif self.analysis_ID == 4: # Acoustic Modal Analysis self.natural_frequencies_acoustic, self.solution_acoustic = self.solve.modal_analysis(modes = self.modes, sigma=self.project.sigma) self.project.time_to_solve_model = time() - t0 if isinstance(self.solve, SolutionAcoustic): if self.analysis_ID in [3,5,6]: if self.solve.non_linear: sleep(2) def post_process_results(self): t0 = time() self.project.set_perforated_plate_convergence_dataLog(self.convergence_dataLog) if self.analysis_ID == 2: if self.solution_structural is None: return self.project.set_structural_solution(self.solution_structural) self.project.set_structural_natural_frequencies(self.natural_frequencies_structural.tolist()) elif self.analysis_ID == 4: if self.solution_acoustic is None: return self.project.set_acoustic_solution(self.solution_acoustic) self.project.set_acoustic_natural_frequencies(self.natural_frequencies_acoustic.tolist()) elif self.analysis_ID == 3: if self.solution_acoustic is None: return self.project.set_acoustic_solution(self.solution_acoustic) elif self.analysis_ID in [0,1,5,6]: if self.solution_structural is None: return self.project.set_structural_solve(self.solve) self.project.set_structural_solution(self.solution_structural) self.dict_reactions_at_constrained_dofs = self.solve.get_reactions_at_fixed_nodes(self.damping) self.dict_reactions_at_springs, self.dict_reactions_at_dampers = self.solve.get_reactions_at_springs_and_dampers() self.project.set_structural_reactions([ self.dict_reactions_at_constrained_dofs, self.dict_reactions_at_springs, self.dict_reactions_at_dampers ]) self.project.time_to_postprocess = time() - t0 _times = [self.project.time_to_process_cross_sections, self.project.time_to_preprocess_model, self.project.time_to_solve_model, self.project.time_to_postprocess] self.project.total_time = sum(_times) self.print_final_log() self.complete = True def check_warnings(self): # WARNINGS REACHED DURING SOLUTION title = self.analysis_type_label message = "" if self.analysis_type_label == "Harmonic Analysis - Structural": if self.solve.flag_ModeSup_prescribed_NonNull_DOFs: message = self.solve.warning_ModeSup_prescribedDOFs if self.solve.flag_Clump and self.analysis_ID==1: message = self.solve.warning_Clump[0] if self.analysis_type_label == "Modal Analysis - Structural": if self.solve.flag_Modal_prescribed_NonNull_DOFs: message = self.solve.warning_Modal_prescribedDOFs[0] if message != "": PrintMessageInput([title, message, window_title_2]) def reset_all_results(self): self.solution_structural = None self.solution_acoustic = None if self.analysis_ID == 2: self.project.set_structural_solution(None) self.project.set_structural_natural_frequencies(None) elif self.analysis_ID == 4: self.project.set_acoustic_solution(None) self.project.set_acoustic_natural_frequencies(None) elif self.analysis_ID == 3: self.project.set_acoustic_solution(None) elif self.analysis_ID in [0,1,5,6]: self.project.set_acoustic_solution(None) self.project.set_structural_solution(None) self.project.set_structural_reactions([ {}, {}, {} ]) def config_title_font(self): font = QFont() font.setPointSize(19) font.setBold(True) font.setItalic(True) font.setFamily("Arial") # font.setWeight(60) self.label_title.setFont(font) self.label_title.setStyleSheet("color:black") def config_message_font(self): font = QFont() font.setPointSize(17) font.setBold(True) # font.setItalic(True) font.setFamily("Arial") # font.setWeight(60) self.label_message.setFont(font) self.label_message.setStyleSheet("color:blue") def print_final_log(self): text = "Solution finished!\n\n" # text += "Time to check all entries: {} [s]\n".format(round(self.project.time_to_checking_entries, 6)) text += "Time to load/create the project: {} [s]\n".format(round(self.project.time_to_load_or_create_project, 4)) text += "Time to process cross-sections: {} [s]\n".format(round(self.project.time_to_process_cross_sections, 4)) text += "Time elapsed in pre-processing: {} [s]\n".format(round(self.project.time_to_preprocess_model, 4)) if self.analysis_ID in [5,6]: text += "Time to solve the acoustic model: {} [s]\n".format(round(self.project.time_to_solve_acoustic_model, 4)) text += "Time to solve the structural model: {} [s]\n".format(round(self.project.time_to_solve_structural_model, 4)) else: text += "Time to solve the model: {} [s]\n".format(round(self.project.time_to_solve_model, 4)) text += "Time elapsed in post-processing: {} [s]\n\n".format(round(self.project.time_to_postprocess, 4)) text += "Total time elapsed: {} [s]\n\n\n".format(round(self.project.total_time, 4)) text += "Press ESC to continue..." self.label_message.setText(text)
class UI: def __init__(self, visual_que, event_que, audio_sampler, audio_detector, args): # user interface setting self.window_height = 1000 self.window_width = int((1 / 2) * self.window_height) # H:W = 2:1 self.bgColor = "#009ADC" self.eventColor = "red" self.visual_que = visual_que self.event_que = event_que self.sampler = audio_sampler self.detector = audio_detector self.args = args self.threadLock = threading.RLock() self.is_recording = False self.buffer_size = int( (args.sr // args.ws) * args.ws * args.msc * args.frame) self.num_windows = self.buffer_size // (args.ws) self.num_frames = self.buffer_size // (args.sr * args.msc) self.audio_buffer = deque(np.zeros(self.buffer_size), maxlen=self.buffer_size) self.colored_buffer = [] self.backColor_buffer = deque(np.zeros(5), maxlen=5) self.count = 0 self.fig = Figure(facecolor=self.bgColor) self.ax = self.fig.add_subplot(111) self.ax_position = self.ax.get_position() self.ax.set_ylim(-1.0, 1.0) self.ax.axis('off') self.TIME = np.linspace(0, self.buffer_size // args.sr, num=self.buffer_size) self.line, = self.ax.plot(self.TIME, np.array(self.audio_buffer), color='white') # wsData_pos and wsData_in_buffer_pos_map are for tracking group of same window size data in audio buffer self.wsData_pos = deque(np.zeros(self.num_windows), maxlen=self.num_windows) self.wsData_pos_map = np.linspace(0, self.ax_position.x1, num=self.num_windows, endpoint=False) ## User Interface widgets self.root = tk.Tk() self.root.title("Sound Event {}".format(args.pmp)) self.root.geometry("{}x{}".format(self.window_width, self.window_height)) def on_closing_window(): self.sampler.stop() self.detector.stop() self.root.destroy() self.root.protocol("WM_DELETE_WINDOW", on_closing_window) self.animate = None self.bgFrame = tk.Frame(self.root, background=self.bgColor) self.audio_graph = FigureCanvasTkAgg(self.fig, master=self.bgFrame) self.img = ImageTk.PhotoImage( Image.open("./img/baby_cry.png").convert("RGBA")) self.baby_cry_img = tk.Label(self.bgFrame, image=self.img, background=self.eventColor) # place the widgets on the window self.bgFrame.place(relwidth=1.0, relheight=1.0) self.audio_graph.get_tk_widget().place(relwidth=1.0, relheight=0.4) self.baby_cry_img.place(relx=0.25, rely=0.5) self.start() self.root.mainloop() def fill_audio_buffer_with_que(self): while self.is_recording: while not self.visual_que.empty(): data, timeStamp = self.visual_que.get() self.audio_buffer.extendleft(data) with self.threadLock: # wsData_pos self.wsData_pos.appendleft(timeStamp) if len(self.colored_buffer) > 0: for rect in self.colored_buffer: pos = rect.get_x() if pos <= self.ax_position.x1: rect.set_x(pos + self.ax_position.x1 / self.num_windows) else: rect.remove() self.colored_buffer.remove(rect) def mark_audio_frame_by_audio_event(self): while self.is_recording: while not self.event_que.empty(): event, frame_start_time = self.event_que.get() self.backColor_buffer.appendleft(event) ii = 0 for i in self.backColor_buffer: if (i == 1): ii += 1 self.count = ii print(self.count) def plot_audio_in_buffer(self, frame): plot_data = np.array(self.audio_buffer) self.line.set_data(self.TIME, plot_data) # change UI color based on event if self.count >= 3: self.bgFrame.after( 50, self.bgFrame.configure(background=self.eventColor)) self.fig.set_facecolor(self.eventColor) self.baby_cry_img.place(relx=0.25, rely=0.5) else: self.bgFrame.after(50, self.bgFrame.configure(background=self.bgColor)) self.fig.set_facecolor(self.bgColor) self.baby_cry_img.place_forget() return [self.line, self.fig] + self.colored_buffer def pause_animation(self): while not self.visual_que.empty(): pass self.animate.event_source.stop() def start(self): if self.is_recording == False: self.is_recording = True self.sampler.start() self.detector.start() threading.Thread(target=self.fill_audio_buffer_with_que, daemon=True).start() threading.Thread(target=self.mark_audio_frame_by_audio_event, daemon=True).start() if self.animate is None: self.animate = FuncAnimation(self.fig, self.plot_audio_in_buffer, frames=self.buffer_size, interval=50, blit=False, repeat=False) self.animate._start() else: self.animate.event_source.start() def stop(self): if self.is_recording == True: threading.Thread(target=self.pause_animation).start() self.sampler.stop() self.detector.stop() self.is_recording = False