class HCFF2(tr.HasStrictTraits): '''High-Cycle Fatigue Filter ''' hcf = tr.Instance(HCFFRoot) def _hcf_default(self): return HCFFRoot(import_manager=FileImportManager()) figure = tr.Instance(Figure) def _figure_default(self): figure = Figure(facecolor='white') figure.set_tight_layout(True) return figure traits_view = ui.View( ui.HSplit( ui.Item(name='hcf', editor=tree_editor, show_label=False, width=0.3 ), ui.UItem('figure', editor=MPLFigureEditor(), resizable=True, springy=True, label='2d plots') ), title='HCF Filter', resizable=True, width=0.6, height=0.6 )
class NSolver(HasTraits): d_t = Float(0.01) t_max = Float(1.) k_max = Float(50) tolerance = Float(1e-5) disps = Str('0.0,10.0') d_array = Property(depends_on='disps') ''' convert the disps string to float array ''' @cached_property def _get_d_array(self): return np.array([float(x) for x in self.disps.split(',')]) time_func = Property(depends_on='disps, t_max') @cached_property def _get_time_func(self): dd_arr = np.abs(np.diff(self.d_array)) x = np.hstack((0, self.t_max * np.cumsum(dd_arr) / sum(dd_arr))) return interp1d(x, self.d_array) figure = Instance(Figure) def _figure_default(self): figure = Figure() return figure update = Button() def _update_fired(self): self.figure.clear() ax = self.figure.add_subplot(111) x = np.arange(0, self.t_max, self.d_t) ax.plot(x, self.time_func(x)) ax.set_xlabel('time') ax.set_ylabel('displacement') self.figure.canvas.draw() view = View(HSplit(Group(Item('d_t'), Item('k_max')), Group(Item('t_max'), Item('tolerance'))), Group(Item('disps'), Item('update', show_label=False)), Item('figure', editor=MPLFigureEditor(), dock='horizontal', show_label=False), kind='modal')
class MainWindow(HasTraits): """ The main window, here go the instructions to create and destroy the application. """ figure = Instance(Figure) panel = Instance(ControlPanel) def _figure_default(self): figure = Figure() figure.add_axes([0.05, 0.04, 0.9, 0.92]) return figure def _panel_default(self): return ControlPanel(figure=self.figure) view = View(HSplit(Item('figure', editor=MPLFigureEditor(), dock='vertical'), Item('panel', style="custom"), show_labels=False, ), resizable=True, height=0.75, width=0.75, handler=MainWindowHandler(), buttons=NoButtons)
class LoadingScenario(BMCSLeafNode): node_name = Str('Loading Scenario') number_of_cycles = Float(1.0) maximum_loading = Float(0.8) unloading_ratio = Range(0., 1., value=0.5) loading_type = Enum("Monotonic", "Cyclic") amplitude_type = Enum("Constant_Amplitude", "Variable_Amplitude") loading_levels = Enum("Increased_blocks(LS2)", "Flexible_loading_levels(LS3,LS4)") cycles_n_1 = Float(10.0) cycles_n_2 = Float(10.0) cycles_n_3 = Float(10.0) cycles_n_4 = Float(10.0) cycles_n_5 = Float(10.0) S_max_1 = Float(1.0) S_max_2 = Float(1.0) S_max_3 = Float(1.0) S_max_4 = Float(1.0) S_max_5 = Float(1.0) S_min_1 = Range(0., 1., value=0.1) S_min_2 = Range(0., 1., value=0.1) S_min_3 = Range(0., 1., value=0.1) S_min_4 = Range(0., 1., value=0.1) S_min_5 = Range(0., 1., value=0.1) max_monotonic = Float(10.0) number_of_levels = Int(10) number_of_cycles_each_level = Int(10) s_max_first = Float(0.1) s_min_all = Float(0.05) s_max_last = Float(0.7) number_of_repeted_blocks = Int(2) time = Range(0.00, 1.00, value=1.00) d_t = Float(0.005) t_max = Float(1.) d_array = Property( depends_on=' d_t, t_max, maximum_loading , number_of_cycles ,\ loading_type ,amplitude_type, loading_levels , unloading_ratio,\ cycles_n_1, cycles_n_2,cycles_n_3,cycles_n_4,cycles_n_5,\ S_max_1,S_max_2,S_max_3,S_max_4,S_max_5,\ S_min_1,S_min_2,S_min_3,S_min_4,S_min_5,\ max_monotonic, number_of_levels,s_max_first ,s_min_all ,s_max_last , number_of_cycles_each_level, number_of_repeted_blocks' ) @cached_property def _get_d_array(self): number_of_increments = self.t_max / self.d_t if self.loading_type == "Monotonic": self.number_of_cycles = 1 d_levels = np.linspace(0, self.maximum_loading, self.number_of_cycles * 2) d_levels[0] = 0 d_levels.reshape(-1, 2)[:, 0] *= 0 d_history = d_levels.flatten() d_arr = np.hstack([ np.linspace(d_history[i], d_history[i + 1], number_of_increments) for i in range(len(d_levels) - 1) ]) return d_arr if self.loading_type == "Cyclic" and self.amplitude_type == "Constant_Amplitude": d_1 = np.zeros(1) d_2 = np.linspace(0, self.maximum_loading, self.number_of_cycles * 2) d_2.reshape(-1, 2)[:, 0] = self.maximum_loading d_2.reshape(-1, 2)[:, 1] = self.maximum_loading * \ self.unloading_ratio d_history = d_2.flatten() d_arr = np.hstack((d_1, d_history)) d_arr = np.hstack([ np.linspace(d_arr[i], d_arr[i + 1], number_of_increments) for i in range(len(d_arr) - 1) ]) return d_arr if self.loading_type == "Cyclic" and self.amplitude_type == "Variable_Amplitude" and self.loading_levels == "Flexible_loading_levels(LS3,LS4)": d_0 = np.zeros(1) d_1 = np.linspace(0, self.max_monotonic * self.S_max_1, self.cycles_n_1 * 2) d_1.reshape(-1, 2)[:, 0] = self.max_monotonic * self.S_max_1 d_1.reshape(-1, 2)[:, 1] = self.max_monotonic * \ self.S_min_1 d_history_1 = d_1.flatten() d_2 = np.linspace(0, self.max_monotonic * self.S_max_2, self.cycles_n_2 * 2) d_2.reshape(-1, 2)[:, 0] = self.max_monotonic * self.S_max_2 d_2.reshape(-1, 2)[:, 1] = self.max_monotonic * \ self.S_min_2 d_history_2 = d_2.flatten() d_3 = np.linspace(0, self.max_monotonic * self.S_max_3, self.cycles_n_3 * 2) d_3.reshape(-1, 2)[:, 0] = self.max_monotonic * self.S_max_3 d_3.reshape(-1, 2)[:, 1] = self.max_monotonic * \ self.S_min_3 d_history_3 = d_3.flatten() d_4 = np.linspace(0, self.max_monotonic * self.S_max_4, self.cycles_n_4 * 2) d_4.reshape(-1, 2)[:, 0] = self.max_monotonic * self.S_max_4 d_4.reshape(-1, 2)[:, 1] = self.max_monotonic * \ self.S_min_4 d_history_4 = d_4.flatten() d_5 = np.linspace(0, self.max_monotonic * self.S_max_5, self.cycles_n_5 * 2) d_5.reshape(-1, 2)[:, 0] = self.max_monotonic * self.S_max_5 d_5.reshape(-1, 2)[:, 1] = self.max_monotonic * \ self.S_min_5 d_history_5 = d_5.flatten() d_arr_1 = np.hstack((d_0, d_history_1, d_history_2, d_history_3, d_history_4, d_history_5)) d_arr = d_arr_1 n = self.number_of_repeted_blocks if n > 1: for i in range(1, n): d_arr = np.hstack((d_arr, d_history_1, d_history_2, d_history_3, d_history_4, d_history_5)) d_arr = np.hstack([ np.linspace(d_arr[i], d_arr[i + 1], number_of_increments) for i in range(len(d_arr) - 1) ]) self.number_of_cycles = n * \ (self.cycles_n_1 + self.cycles_n_2 + self.cycles_n_3 + self.cycles_n_4 + self.cycles_n_5) return d_arr if self.loading_type == "Cyclic" and self.amplitude_type == "Variable_Amplitude" and self.loading_levels == "Increased_blocks(LS2)": d_arr_1 = np.zeros(1) for i in range(1, self.number_of_levels + 1, 1): d_i = np.linspace( 0, self.max_monotonic * (self.s_max_first + (i - 1.0) * (self.s_max_last - self.s_max_first) / (self.number_of_levels - 1.0)), self.number_of_cycles_each_level * 2) d_i.reshape(-1, 2)[:, 0] = self.max_monotonic * ( self.s_max_first + (i - 1.0) * (self.s_max_last - self.s_max_first) / (self.number_of_levels - 1.0)) d_i.reshape(-1, 2)[:, 1] = self.max_monotonic * self.s_min_all d_history_i = d_i.flatten() d_arr_1 = np.hstack((d_arr_1, d_history_i)) d_arr = d_arr_1 n = self.number_of_repeted_blocks for i in range(1, n): d_arr = np.hstack((d_arr, d_arr_1[1:])) d_arr = np.hstack([ np.linspace(d_arr[i], d_arr[i + 1], number_of_increments) for i in range(len(d_arr) - 1) ]) self.number_of_cycles = n * \ (self.number_of_levels * self.number_of_cycles_each_level) return d_arr time_func = Property( depends_on= 'loading_type ,amplitude_type, loading_levels ,maximum_loading,\ S_max_1, S_max_2, S_max_3, S_max_4,\ S_max_5, t_max ,d_t, d_array,max_monotonic, number_of_levels,\ s_max_first ,s_min_all ,s_max_last , number_of_cycles_each_level, number_of_repeted_blocks' ) @cached_property def _get_time_func(self): t_arr = np.linspace(0, self.t_max, len(self.d_array)) return interp1d(t_arr, self.d_array) figure = Instance(Figure) def _figure_default(self): figure = Figure() return figure update = Button() def _update_fired(self): self.figure.clear() ax = self.figure.add_subplot(111) x = np.arange(0, self.t_max, self.d_t) ax.plot(x, self.time_func(x), 'k') ax.set_xlabel('time') ax.set_ylabel('displacement') self.figure.canvas.draw() view = View( VGroup( Group(Item('loading_type'), Item('maximum_loading'), Item('number_of_cycles'), Item('amplitude_type'), Item('loading_levels'), Item('unloading_ratio'), show_border=True, label='Cyclic load inputs'), Group(Item('d_t'), Item('t_max'), show_border=True, label='Solver Settings'), Group(Item('max_monotonic'), HGroup(Item('number_of_levels'), Item('number_of_cycles_each_level')), HGroup(Item('s_max_first'), Item('s_max_last')), Item('s_min_all'), show_border=True, label='Increased Loading (LS2)'), Group(HGroup(Item('cycles_n_1'), Item('S_max_1')), Item('S_min_1'), HGroup(Item('cycles_n_2'), Item('S_max_2')), Item('S_min_2'), HGroup(Item('cycles_n_3'), Item('S_max_3')), Item('S_min_3'), HGroup(Item('cycles_n_4'), Item('S_max_4')), Item('S_min_4'), HGroup(Item('cycles_n_5'), Item('S_max_5')), Item('S_min_5'), Item('number_of_repeted_blocks'), show_border=True, label='flexible Loading Blocks (LS3,LS4)')), Group(Item('update', label='Plot Loading scenario')), Item('figure', editor=MPLFigureEditor(), dock='horizontal', show_label=False), Item('time', label='t/T_max'))
class BMCSVizSheet(ROutputSection): '''Vieualization sheet - controls the time displayed - contains several vizualization adapters. This class could be called BMCSTV - for watching the time dependent response. It can have several channels - in 2D and 3D ''' def __init__(self, *args, **kw): super(BMCSVizSheet, self).__init__(*args, **kw) self.on_trait_change(self.viz2d_list_items_changed, 'viz2d_list_items') name = Str hist = Instance(IHist) min = Float(0.0) '''Simulation start is always 0.0 ''' max = Float(1.0) '''Upper range limit of the current simulator. This range is determined by the the time-loop range of the model. ''' vot = Float def _vot_default(self): return self.min def _vot_changed(self): if self.hist: self.hist.vot = self.vot vot_slider = Range(low='min', high='max', step=0.01, enter_set=True, auto_set=False) '''Time line controlling the current state of the simulation. this value is synchronized with the control time of the time loop setting the tline. The vot_max = tline.max. The value of vot follows the value of tline.val in monitoring mode. By default, the monitoring mode is active with vot = tline.value. When sliding to a value vot < tline.value, the browser mode is activated. When sliding into the range vot > tline.value the monitoring mode is reactivated. ''' def _vot_slider_default(self): return 0.0 mode = Enum('monitor', 'browse') def _mode_changed(self): if self.mode == 'browse': self.offline = False time = Float(0.0) def time_range_changed(self, max_): self.max = max_ def time_changed(self, time): self.time = time if self.mode == 'monitor': self.vot = time self.vot_slider = time def _vot_slider_changed(self): if self.mode == 'browse': if self.vot_slider >= self.time: self.mode = 'monitor' self.vot_slider = self.time self.vot = self.time else: self.vot = self.vot_slider elif self.mode == 'monitor': if self.vot_slider < self.time: self.mode = 'browse' self.vot = self.vot_slider else: self.vot_slider = self.time self.vot = self.time offline = Bool(True) '''If the sheet is offline, the plot refresh is inactive. The sheet starts in offline mode and is activated once the signal run_started has been received. Upon run_finished the the sheet goes directly into the offline mode again. If the user switches to browser mode, the vizsheet gets online and reploting is activated. ''' running = Bool(False) def run_started(self): self.running = True self.offline = False for pp in self.pp_list: pp.clear() self.mode = 'monitor' if self.reference_viz2d: ax = self.reference_axes ax.clear() self.reference_viz2d.reset(ax) def run_finished(self): self.skipped_steps = self.monitor_chunk_size # self.update_pipeline(1.0) self.replot() self.running = False self.offline = True monitor_chunk_size = Int(10, label='Monitor each # steps') skipped_steps = Int(1) @on_trait_change('vot,n_cols') def replot(self): if self.offline: return if self.running and self.mode == 'monitor' and \ self.skipped_steps < (self.monitor_chunk_size - 1): self.skipped_steps += 1 return for pp in self.pp_list: pp.replot(self.vot) # for viz2d, ax in self.axes.items(): # ax.clear() # viz2d.clear() # viz2d.plot(ax, self.vot) # if self.selected_pp: # self.selected_pp.align_xaxis() if self.reference_viz2d: ax = self.reference_axes ax.clear() self.reference_viz2d.clear() self.reference_viz2d.plot(ax, self.vot) self.data_changed = True self.skipped_steps = 0 if self.mode == 'browse': self.update_pipeline(self.vot) else: up = RunThread(self, self.vot) up.start() viz2d_list = List(Viz2D) '''List of visualization adaptors for 2D. ''' viz2d_dict = Property def _get_viz2d_dict(self): return {viz2d.name: viz2d for viz2d in self.viz2d_list} viz2d_names = Property '''Names to be supplied to the selector of the reference graph. ''' def _get_viz2d_names(self): return list(self.viz2d_dict.keys()) viz2d_list_editor_clicked = Tuple viz2d_list_changed = Event def _viz2d_list_editor_clicked_changed(self, *args, **kw): _, column = self.viz2d_list_editor_clicked self.offline = False self.viz2d_list_changed = True if self.plot_mode == 'single': if column.name == 'visible': self.selected_viz2d.visible = True self.plot_mode = 'multiple' else: self.replot() elif self.plot_mode == 'multiple': if column.name != 'visible': self.plot_mode = 'single' else: self.replot() plot_mode = Enum('multiple', 'single') def _plot_mode_changed(self): if self.plot_mode == 'single': self.replot_selected_viz2d() elif self.plot_mode == 'multiple': self.replot() def replot_selected_viz2d(self): for viz2d in self.viz2d_list: viz2d.visible = False self.selected_viz2d.visible = True self.n_cols = 1 self.viz2d_list_changed = True self.replot() def viz2d_list_items_changed(self): self.replot() def get_subrecords(self): '''What is this good for? ''' return self.viz2d_list export_button = Button(label='Export selected diagram') def plot_in_window(self): fig = plt.figure(figsize=(self.fig_width, self.fig_height)) ax = fig.add_subplot(111) self.selected_viz2d.plot(ax, self.vot) fig.show() def _export_button_fired(self, vot=0): print('in export button fired') Thread(target=self.plot_in_window).start() print('thread started') fig_width = Float(8.0, auto_set=False, enter_set=True) fig_height = Float(5.0, auto_set=False, enter_set=True) save_button = Button(label='Save selected diagram') animate_button = Button(label='Animate selected diagram') def _animate_button_fired(self): ad = AnimationDialog(sheet=self) ad.edit_traits() return #========================================================================= # Reference figure serving for orientation. #========================================================================= reference_viz2d_name = Enum('', values="viz2d_names") '''Current name of the reference graphs. ''' def _reference_viz2d_name_changed(self): self.replot() reference_viz2d_cumulate = Bool(False, label='cumulate') reference_viz2d = Property(Instance(Viz2D), depends_on='reference_viz2d_name') '''Visualization of a graph showing the time context of the current visualization state. ''' def _get_reference_viz2d(self): if self.reference_viz2d_name == None: if len(self.viz2d_dict): return self.viz2d_list[0] else: return None return self.viz2d_dict[self.reference_viz2d_name] reference_figure = Instance(Figure) def _reference_figure_default(self): figure = Figure(facecolor='white') figure.set_tight_layout(True) return figure reference_axes = Property(List, depends_on='reference_viz2d_name') '''Derived axes objects reflecting the layout of plot pane and the individual. ''' @cached_property def _get_reference_axes(self): return self.reference_figure.add_subplot(1, 1, 1) selected_viz2d = Instance(Viz2D) def _selected_viz2d_changed(self): if self.plot_mode == 'single': self.replot_selected_viz2d() n_cols = Range(low=1, high=3, value=2, label='Number of columns', tooltip='Defines a number of columns within the plot pane', enter_set=True, auto_set=False) figure = Instance(Figure) tight_layout = Bool(True) def _figure_default(self): figure = Figure(facecolor='white') figure.set_tight_layout(self.tight_layout) return figure visible_viz2d_list = Property( List, depends_on='viz2d_list,viz2d_list_items,n_cols,viz2d_list_changed') '''Derived axes objects reflecting the layout of plot pane and the individual. ''' @cached_property def _get_visible_viz2d_list(self): viz_list = [] for viz2d in self.viz2d_list: if viz2d.visible: viz_list.append(viz2d) return viz_list pp_list = List(PlotPerspective) selected_pp = Instance(PlotPerspective) xaxes = Property(List, depends_on='selected_pp') '''Derived axes objects reflecting the layout of plot pane and the individual. ''' @cached_property def _get_xaxes(self): self.figure.clear() if self.selected_pp: self.selected_pp.figure = self.figure ad = self.selected_pp.axes else: n_fig = len(self.visible_viz2d_list) n_cols = self.n_cols n_rows = (n_fig + n_cols - 1) / self.n_cols ad = { viz2d: self.figure.add_subplot(n_rows, self.n_cols, i + 1) for i, viz2d in enumerate(self.visible_viz2d_list) } return ad data_changed = Event bgcolor = tr.Tuple(1.0, 1.0, 1.0) fgcolor = tr.Tuple(0.0, 0.0, 0.0) scene = Instance(MlabSceneModel) def _scene_default(self): return MlabSceneModel() mlab = Property(depends_on='input_change') '''Get the mlab handle''' def _get_mlab(self): return self.scene.mlab fig = Property() '''Figure for 3D visualization. ''' @cached_property def _get_fig(self): fig = self.mlab.gcf() bgcolor = tuple(self.bgcolor) fgcolor = tuple(self.fgcolor) self.mlab.figure(fig, fgcolor=fgcolor, bgcolor=bgcolor) return fig def show(self, *args, **kw): '''Render the visualization. ''' self.mlab.show(*args, **kw) def add_viz3d(self, viz3d, order=1): '''Add a new visualization objectk.''' viz3d.ftv = self vis3d = viz3d.vis3d name = viz3d.name label = '%s[%s:%s]-%s' % (name, str( vis3d.__class__), str(viz3d.__class__), vis3d) if label in self.viz3d_dict: raise KeyError('viz3d object named %s already registered' % label) viz3d.order = order self.viz3d_dict[label] = viz3d viz3d_dict = tr.Dict(tr.Str, tr.Instance(Viz3D)) '''Dictionary of visualization objects. ''' viz3d_list = tr.Property def _get_viz3d_list(self): map_order_viz3d = {} for idx, (viz3d) in enumerate(self.viz3d_dict.values()): order = viz3d.order map_order_viz3d['%5g%5g' % (order, idx)] = viz3d return [map_order_viz3d[key] for key in sorted(map_order_viz3d.keys())] pipeline_ready = Bool(False) def setup_pipeline(self): if self.pipeline_ready: return self.fig fig = self.mlab.gcf() fig.scene.disable_render = True for viz3d in self.viz3d_list: viz3d.setup() fig.scene.disable_render = False self.pipeline_ready = True def update_pipeline(self, vot): self.setup_pipeline() # get the current constrain information self.vot = vot fig = self.mlab.gcf() fig.scene.disable_render = True for viz3d in self.viz3d_list: viz3d.plot(vot) fig.scene.disable_render = False selected_viz3d = Instance(Viz3D) def _selected_viz3d_changed(self): print('selection done') # Traits view definition: traits_view = View( VSplit( HSplit( Tabbed( UItem( 'pp_list', id='notebook', style='custom', resizable=True, editor=ListEditor( use_notebook=True, deletable=False, # selected='selected_pp', export='DockWindowShell', page_name='.name')), UItem('scene', label='3d scene', editor=SceneEditor(scene_class=MayaviScene)), scrollable=True, label='Plot panel'), VGroup( Item('n_cols', width=250), Item('plot_mode@', width=250), VSplit( UItem('viz2d_list@', editor=viz2d_list_editor, width=100), UItem('selected_viz2d@', width=200), UItem('pp_list@', editor=pp_list_editor, width=100), # UItem('selected_pp@', # width=200), UItem('viz3d_list@', editor=viz3d_list_editor, width=100), UItem('selected_viz3d@', width=200), VGroup( # UItem('export_button', # springy=False, resizable=True), # VGroup( # HGroup( # UItem('fig_width', springy=True, # resizable=False), # UItem('fig_height', springy=True), # ), # label='Figure size' # ), UItem('animate_button', springy=False, resizable=True), ), VGroup( UItem('reference_viz2d_name', resizable=True), UItem( 'reference_figure', editor=MPLFigureEditor(), width=200, # springy=True ), label='Reference graph', )), label='Plot configure', scrollable=True), ), VGroup( HGroup( Item('mode', resizable=False, springy=False), Item('monitor_chunk_size', resizable=False, springy=False), ), Item('vot_slider', height=40), )), resizable=True, width=0.8, height=0.8, buttons=['OK', 'Cancel'])
class PlotPerspective(HasStrictTraits): name = Str('<unnamed>') viz2d_list = List(Viz2D, input=True) positions = List([], input=True) twinx = List([], input=True) twiny = List([], input=True) data_changed = Event figure = Instance(Figure) tight_layout = Bool(True) def _figure_default(self): figure = Figure(facecolor='white') figure.set_tight_layout(self.tight_layout) return figure viz2d_axes = Property @cached_property def _get_viz2d_axes(self): return { viz2d: self.figure.add_subplot(loc) for viz2d, loc in zip(self.viz2d_list, self.positions) } twinx_axes = Property @cached_property def _get_twinx_axes(self): return { viz_2: self.viz2d_axes[viz_1].twinx() for viz_1, viz_2, _ in self.twinx } twiny_axes = Property @cached_property def _get_twiny_axes(self): return { viz_2: self.viz2d_axes[viz_1].twiny() for viz_1, viz_2, _ in self.twiny } axes = Property @cached_property def _get_axes(self): ad = {} ad.update(self.viz2d_axes) ad.update(self.twinx_axes) ad.update(self.twiny_axes) return ad def clear(self): for viz2d, ax in self.viz2d_axes.items(): ax.clear() viz2d.reset(ax) for viz2d, ax in self.twinx_axes.items(): ax.clear() viz2d.reset(ax) for viz2d, ax in self.twiny_axes.items(): ax.clear() viz2d.reset(ax) def replot(self, vot): for viz2d, ax in self.axes.items(): ax.clear() viz2d.clear() viz2d.plot(ax, vot) self.data_changed = True def align_xaxis(self): for v1, v2, alignx in self.twiny: if alignx: ax1 = self.viz2d_axes[v1] ax2 = self.twiny_axes[v2] self._align_xaxis(ax1, ax2) def _align_xaxis(self, ax1, ax2): """Align zeros of the two axes, zooming them out by same ratio""" axes = (ax1, ax2) extrema = [ax.get_xlim() for ax in axes] tops = [extr[1] / (extr[1] - extr[0]) for extr in extrema] # Ensure that plots (intervals) are ordered bottom to top: if tops[0] > tops[1]: axes, extrema, tops = [ list(reversed(l)) for l in (axes, extrema, tops) ] # How much would the plot overflow if we kept current zoom levels? tot_span = tops[1] + 1 - tops[0] b_new_t = extrema[0][0] + tot_span * (extrema[0][1] - extrema[0][0]) t_new_b = extrema[1][1] - tot_span * (extrema[1][1] - extrema[1][0]) axes[0].set_xlim(extrema[0][0], b_new_t) axes[1].set_xlim(t_new_b, extrema[1][1]) trait_view = View( UItem( 'figure', editor=MPLFigureEditor(), resizable=True, springy=True, ), )
class MainWindow(HasTraits): mats_eval = Instance(MATSEval) fets_eval = Instance(FETS1D52ULRH) time_stepper = Instance(TStepper) time_loop = Instance(TLoop) tree = Instance(TreeStructure) t_record = Array U_record = Array F_record = Array sf_record = Array eps_record = List sig_record = List figure = Instance(Figure) def _figure_default(self): figure = Figure() return figure plot = Button() def _plot_fired(self): # assign the material parameters self.mats_eval.sigma_y = self.tree.material[0].sigma_y self.mats_eval.E_b = self.tree.material[0].E_b self.mats_eval.K_bar = self.tree.material[0].K_bar self.mats_eval.alpha = self.tree.material[0].alpha self.mats_eval.beta = self.tree.material[0].beta self.mats_eval.H_bar = self.tree.material[0].H_bar # assign the geometry parameters self.fets_eval.A_m = self.tree.geometry[0].A_m self.fets_eval.P_b = self.tree.geometry[0].P_b self.fets_eval.A_f = self.tree.geometry[0].A_f self.time_stepper.L_x = self.tree.geometry[0].L_x # assign the parameters for solver self.time_loop.t_max = self.tree.n_solver[0].t_max self.time_loop.d_t = self.tree.n_solver[0].d_t self.time_loop.k_max = self.tree.n_solver[0].k_max self.time_loop.tolerance = self.tree.n_solver[0].tolerance # assign the bc self.time_stepper.bc_list[1].value = 1.0 self.time_stepper.bc_list[ 1].time_function = self.tree.n_solver[0].time_func self.draw() self.time = 1.00 # self.figure.canvas.draw() ax1 = Property() @cached_property def _get_ax1(self): return self.figure.add_subplot(231) ax2 = Property() @cached_property def _get_ax2(self): return self.figure.add_subplot(232) ax3 = Property() @cached_property def _get_ax3(self): return self.figure.add_subplot(234) ax4 = Property() @cached_property def _get_ax4(self): return self.figure.add_subplot(235) ax5 = Property() @cached_property def _get_ax5(self): return self.figure.add_subplot(233) ax6 = Property() @cached_property def _get_ax6(self): return self.figure.add_subplot(236) def draw(self): self.U_record, self.F_record, self.sf_record, self.t_record, self.eps_record, self.sig_record = self.time_loop.eval() n_dof = 2 * self.time_stepper.domain.n_active_elems + 1 slip, sig_n_arr, sig_e_arr, w_arr = self.time_stepper.mats_eval.get_bond_slip() self.ax1.cla() l_bs, = self.ax1.plot(slip, sig_n_arr) self.ax1.plot(slip, sig_e_arr, '--') self.ax1.plot(slip, w_arr, '--') self.ax1.set_title('bond-slip law') self.ax2.cla() l_po, = self.ax2.plot(self.U_record[:, n_dof], self.F_record[:, n_dof]) marker_po, = self.ax2.plot( self.U_record[-1, n_dof], self.F_record[-1, n_dof], 'ro') self.ax2.set_title('pull-out force-displacement curve') self.ax3.cla() X = np.linspace( 0, self.time_stepper.L_x, self.time_stepper.n_e_x + 1) X_ip = np.repeat(X, 2)[1:-1] l_sf, = self.ax3.plot(X_ip, self.sf_record[-1, :]) self.ax3.set_title('shear flow in the bond interface') self.ax4.cla() U = np.reshape(self.U_record[-1, :], (-1, 2)).T l_u0, = self.ax4.plot(X, U[0]) l_u1, = self.ax4.plot(X, U[1]) l_us, = self.ax4.plot(X, U[1] - U[0]) self.ax4.set_title('displacement and slip') self.ax5.cla() l_eps0, = self.ax5.plot(X_ip, self.eps_record[-1][:, :, 0].flatten()) l_eps1, = self.ax5.plot(X_ip, self.eps_record[-1][:, :, 2].flatten()) self.ax5.set_title('strain') self.ax6.cla() l_sig0, = self.ax6.plot(X_ip, self.sig_record[-1][:, :, 0].flatten()) l_sig1, = self.ax6.plot(X_ip, self.sig_record[-1][:, :, 2].flatten()) self.ax6.set_title('stress') self.ax3.set_ylim(np.amin(self.sf_record), np.amax(self.sf_record)) self.ax4.set_ylim(np.amin(self.U_record), np.amax(self.U_record)) self.ax6.set_ylim(np.amin(self.sig_record), np.amax(self.sig_record)) self.figure.canvas.draw() time = Range(0.00, 1.00, value=1.00) @on_trait_change('time') def draw_t(self): idx = (np.abs(self.time * max(self.t_record) - self.t_record)).argmin() n_dof = 2 * self.time_stepper.domain.n_active_elems + 1 self.ax2.cla() l_po, = self.ax2.plot(self.U_record[:, n_dof], self.F_record[:, n_dof]) marker_po, = self.ax2.plot( self.U_record[idx, n_dof], self.F_record[idx, n_dof], 'ro') self.ax2.set_title('pull-out force-displacement curve') self.ax3.cla() X = np.linspace( 0, self.time_stepper.L_x, self.time_stepper.n_e_x + 1) X_ip = np.repeat(X, 2)[1:-1] l_sf, = self.ax3.plot(X_ip, self.sf_record[idx, :]) self.ax3.set_title('shear flow in the bond interface') self.ax4.cla() U = np.reshape(self.U_record[idx, :], (-1, 2)).T l_u0, = self.ax4.plot(X, U[0]) l_u1, = self.ax4.plot(X, U[1]) l_us, = self.ax4.plot(X, U[1] - U[0]) self.ax4.set_title('displacement and slip') self.ax5.cla() l_eps0, = self.ax5.plot(X_ip, self.eps_record[idx][:, :, 0].flatten()) l_eps1, = self.ax5.plot(X_ip, self.eps_record[idx][:, :, 2].flatten()) self.ax5.set_title('strain') self.ax6.cla() l_sig0, = self.ax6.plot(X_ip, self.sig_record[idx][:, :, 0].flatten()) l_sig1, = self.ax6.plot(X_ip, self.sig_record[idx][:, :, 2].flatten()) self.ax6.set_title('stress') self.ax3.set_ylim(np.amin(self.sf_record), np.amax(self.sf_record)) self.ax4.set_ylim(np.amin(self.U_record), np.amax(self.U_record)) self.ax6.set_ylim(np.amin(self.sig_record), np.amax(self.sig_record)) self.figure.canvas.draw() tree_editor = TreeEditor(nodes=[TreeNode(node_for=[TreeStructure], children='', label='name', view=View()), TreeNode(node_for=[TreeStructure], children='material', label='=Material', auto_open=True, view=View()), TreeNode(node_for=[TreeStructure], children='geometry', label='=Geometry', auto_open=True, view=View()), TreeNode(node_for=[TreeStructure], children='n_solver', label='=Nonlinear Solver', auto_open=True, view=View()), TreeNode(node_for=[Material], children='', label='=Material parameters'), TreeNode(node_for=[Geometry], children='', label='=Geometry parameters'), TreeNode(node_for=[NSolver], children='', label='=settings') ], orientation='vertical') view = View(HSplit(Group(VGroup(Item('tree', editor=tree_editor, show_label=False), Item('plot', show_label=False)), Item('time', label='t/T_max')), Item('figure', editor=MPLFigureEditor(), dock='vertical', width=0.7, height=0.9), show_labels=False), resizable=True, height=0.9, width=1.0 )
class LoadingScenario(BMCSLeafNode): node_name = Str('Loading Scenario') number_of_cycles = Float(1.0) maximum_loading = Float(0.5) unloading_ratio = Range(0., 1., value=0.5) number_of_increments = Float(10) loading_type = Enum("Monotonic", "Cyclic") amplitude_type = Enum("Increased_Amplitude", "Constant_Amplitude") loading_range = Enum("Non_symmetric", "Symmetric") time = Range(0.00, 1.00, value=1.00) d_t = Float(0.005) t_max = Float(1.) k_max = Float(200) tolerance = Float(1e-4) d_array = Property( depends_on= ' maximum_loading , number_of_cycles , loading_type , loading_range , amplitude_type, unloading_ratio' ) @cached_property def _get_d_array(self): if self.loading_type == "Monotonic": self.number_of_cycles = 1 d_levels = np.linspace(0, self.maximum_loading, self.number_of_cycles * 2) d_levels[0] = 0 d_levels.reshape(-1, 2)[:, 0] *= 0 d_history = d_levels.flatten() d_arr = np.hstack([ np.linspace(d_history[i], d_history[i + 1], self.number_of_increments) for i in range(len(d_levels) - 1) ]) return d_arr if self.amplitude_type == "Increased_Amplitude" and self.loading_range == "Symmetric": d_levels = np.linspace(0, self.maximum_loading, self.number_of_cycles * 2) d_levels.reshape(-1, 2)[:, 0] *= -1 d_history = d_levels.flatten() d_arr = np.hstack([ np.linspace(d_history[i], d_history[i + 1], self.number_of_increments) for i in range(len(d_levels) - 1) ]) return d_arr if self.amplitude_type == "Increased_Amplitude" and self.loading_range == "Non_symmetric": d_levels = np.linspace(0, self.maximum_loading, self.number_of_cycles * 2) d_levels.reshape(-1, 2)[:, 0] *= 0 d_history = d_levels.flatten() d_arr = np.hstack([ np.linspace(d_history[i], d_history[i + 1], self.number_of_increments) for i in range(len(d_levels) - 1) ]) return d_arr if self.amplitude_type == "Constant_Amplitude" and self.loading_range == "Symmetric": d_levels = np.linspace(0, self.maximum_loading, self.number_of_cycles * 2) d_levels.reshape(-1, 2)[:, 0] = -self.maximum_loading d_levels[0] = 0 d_levels.reshape(-1, 2)[:, 1] = self.maximum_loading d_history = d_levels.flatten() d_arr = np.hstack([ np.linspace(d_history[i], d_history[i + 1], self.number_of_increments) for i in range(len(d_levels) - 1) ]) return d_arr if self.amplitude_type == "Constant_Amplitude" and self.loading_range == "Non_symmetric": # d_1 = np.zeros(self.number_of_cycles*2 + 1) d_1 = np.zeros(1) d_2 = np.linspace(0, self.maximum_loading, self.number_of_cycles * 2) d_2.reshape(-1, 2)[:, 0] = self.maximum_loading d_2.reshape(-1, 2)[:, 1] = self.maximum_loading * \ self.unloading_ratio d_history = d_2.flatten() d_arr = np.hstack((d_1, d_history)) return d_arr time_func = Property(depends_on='maximum_loading, t_max , d_array') @cached_property def _get_time_func(self): t_arr = np.linspace(0, self.t_max, len(self.d_array)) return interp1d(t_arr, self.d_array) figure = Instance(Figure) def _figure_default(self): figure = Figure() return figure update = Button() def _update_fired(self): self.figure.clear() ax = self.figure.add_subplot(111) x = np.arange(0, self.t_max, self.d_t) ax.plot(x, self.time_func(x)) ax.set_xlabel('time') ax.set_ylabel('displacement') self.figure.canvas.draw() view = View( VGroup( Group(Item('loading_type')), Group(Item('maximum_loading')), Group(Item('number_of_cycles'), Item('amplitude_type'), Item('loading_range'), Item('unloading_ratio'), show_border=True, label='Cyclic load inputs'), Group(Item('d_t'), Item('t_max'), Item('k_max'), show_border=True, label='Solver Settings')), Group(Item('update', label='Plot Loading scenario')), Item('figure', editor=MPLFigureEditor(), dock='horizontal', show_label=False), Item('time', label='t/T_max'))
class HCFF(tr.HasStrictTraits): '''High-Cycle Fatigue Filter ''' #========================================================================= # Traits definitions #========================================================================= decimal = tr.Enum(',', '.') delimiter = tr.Str(';') file_csv = tr.File open_file_csv = tr.Button('Input file') skip_rows = tr.Int(4, auto_set=False, enter_set=True) columns_headers_list = tr.List([]) x_axis = tr.Enum(values='columns_headers_list') y_axis = tr.Enum(values='columns_headers_list') x_axis_multiplier = tr.Enum(1, -1) y_axis_multiplier = tr.Enum(-1, 1) npy_folder_path = tr.Str file_name = tr.Str apply_filters = tr.Bool force_name = tr.Str('Kraft') peak_force_before_cycles = tr.Float(30) plots_num = tr.Enum(1, 2, 3, 4, 6, 9) plot_list = tr.List() plot = tr.Button add_plot = tr.Button add_creep_plot = tr.Button parse_csv_to_npy = tr.Button generate_filtered_npy = tr.Button add_columns_average = tr.Button force_max = tr.Float(100) force_min = tr.Float(40) figure = tr.Instance(Figure) # plots_list = tr.List(editor=ui.SetEditor( # values=['kumquats', 'pomegranates', 'kiwi'], # can_move_all=False, # left_column_title='List')) #========================================================================= # File management #========================================================================= def _open_file_csv_fired(self): """ Handles the user clicking the 'Open...' button. """ extns = ['*.csv', ] # seems to handle only one extension... wildcard = '|'.join(extns) dialog = FileDialog(title='Select text file', action='open', wildcard=wildcard, default_path=self.file_csv) dialog.open() self.file_csv = dialog.path """ Filling x_axis and y_axis with values """ headers_array = np.array( pd.read_csv( self.file_csv, delimiter=self.delimiter, decimal=self.decimal, nrows=1, header=None ) )[0] for i in range(len(headers_array)): headers_array[i] = self.get_valid_file_name(headers_array[i]) self.columns_headers_list = list(headers_array) """ Saving file name and path and creating NPY folder """ dir_path = os.path.dirname(self.file_csv) self.npy_folder_path = os.path.join(dir_path, 'NPY') if os.path.exists(self.npy_folder_path) == False: os.makedirs(self.npy_folder_path) self.file_name = os.path.splitext(os.path.basename(self.file_csv))[0] #========================================================================= # Parameters of the filter algorithm #========================================================================= def _figure_default(self): figure = Figure(facecolor='white') figure.set_tight_layout(True) return figure def _parse_csv_to_npy_fired(self): print('Parsing csv into npy files...') for i in range(len(self.columns_headers_list)): column_array = np.array(pd.read_csv( self.file_csv, delimiter=self.delimiter, decimal=self.decimal, skiprows=self.skip_rows, usecols=[i])) np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '.npy'), column_array) print('Finsihed parsing csv into npy files.') def get_valid_file_name(self, original_file_name): valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) new_valid_file_name = ''.join( c for c in original_file_name if c in valid_chars) return new_valid_file_name # def _add_columns_average_fired(self): # columns_average = ColumnsAverage( # columns_names=self.columns_headers_list) # # columns_average.set_columns_headers_list(self.columns_headers_list) # columns_average.configure_traits() def _generate_filtered_npy_fired(self): # 1- Export filtered force force = np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.force_name + '.npy')).flatten() peak_force_before_cycles_index = np.where( abs((force)) > abs(self.peak_force_before_cycles))[0][0] force_ascending = force[0:peak_force_before_cycles_index] force_rest = force[peak_force_before_cycles_index:] force_max_indices, force_min_indices = self.get_array_max_and_min_indices( force_rest) force_max_min_indices = np.concatenate( (force_min_indices, force_max_indices)) force_max_min_indices.sort() force_rest_filtered = force_rest[force_max_min_indices] force_filtered = np.concatenate((force_ascending, force_rest_filtered)) np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + self.force_name + '_filtered.npy'), force_filtered) # 2- Export filtered displacements # TODO I skipped time with presuming it's the first column for i in range(1, len(self.columns_headers_list)): if self.columns_headers_list[i] != str(self.force_name): disp = np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '.npy')).flatten() disp_ascending = disp[0:peak_force_before_cycles_index] disp_rest = disp[peak_force_before_cycles_index:] disp_ascending = savgol_filter( disp_ascending, window_length=51, polyorder=2) disp_rest = disp_rest[force_max_min_indices] filtered_disp = np.concatenate((disp_ascending, disp_rest)) np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '_filtered.npy'), filtered_disp) # 3- Export creep for displacements # Cutting unwanted max min values to get correct full cycles and remove # false min/max values caused by noise force_max_indices_cutted, force_min_indices_cutted = self.cut_indices_in_range(force_rest, force_max_indices, force_min_indices, self.force_max, self.force_min) print("Cycles number= ", len(force_min_indices)) print("Cycles number after cutting unwanted max-min range= ", len(force_min_indices_cutted)) # TODO I skipped time with presuming it's the first column for i in range(1, len(self.columns_headers_list)): if self.columns_headers_list[i] != str(self.force_name): disp_rest_maxima = disp_rest[force_max_indices_cutted] disp_rest_minima = disp_rest[force_min_indices_cutted] np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '_max.npy'), disp_rest_maxima) np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '_min.npy'), disp_rest_minima) print('Filtered npy files are generated.') def cut_indices_in_range(self, array, max_indices, min_indices, range_upper_value, range_lower_value): cutted_max_indices = [] cutted_min_indices = [] for max_index in max_indices: if abs(array[max_index]) > abs(range_upper_value): cutted_max_indices.append(max_index) for min_index in min_indices: if abs(array[min_index]) < abs(range_lower_value): cutted_min_indices.append(min_index) return cutted_max_indices, cutted_min_indices def get_array_max_and_min_indices(self, input_array): # Checking dominant sign positive_values_count = np.sum(np.array(input_array) >= 0) negative_values_count = input_array.size - positive_values_count # Getting max and min indices if (positive_values_count > negative_values_count): force_max_indices = argrelextrema(input_array, np.greater_equal)[0] force_min_indices = argrelextrema(input_array, np.less_equal)[0] else: force_max_indices = argrelextrema(input_array, np.less_equal)[0] force_min_indices = argrelextrema(input_array, np.greater_equal)[0] # Remove subsequent max/min indices (np.greater_equal will give 1,2 for # [4, 8, 8, 1]) force_max_indices = self.remove_subsequent_max_values( force_max_indices) force_min_indices = self.remove_subsequent_min_values( force_min_indices) # If size is not equal remove the last element from the big one if force_max_indices.size > force_min_indices.size: force_max_indices = force_max_indices[:-1] elif force_max_indices.size < force_min_indices.size: force_min_indices = force_min_indices[:-1] return force_max_indices, force_min_indices def remove_subsequent_max_values(self, force_max_indices): to_delete_from_maxima = [] for i in range(force_max_indices.size - 1): if force_max_indices[i + 1] - force_max_indices[i] == 1: to_delete_from_maxima.append(i) force_max_indices = np.delete(force_max_indices, to_delete_from_maxima) return force_max_indices def remove_subsequent_min_values(self, force_min_indices): to_delete_from_minima = [] for i in range(force_min_indices.size - 1): if force_min_indices[i + 1] - force_min_indices[i] == 1: to_delete_from_minima.append(i) force_min_indices = np.delete(force_min_indices, to_delete_from_minima) return force_min_indices #========================================================================= # Plotting #========================================================================= plot_figure_num = tr.Int(0) def _plot_fired(self): ax = self.figure.add_subplot() def x_plot_fired(self): self.plot_figure_num += 1 plt.draw() plt.show() data_changed = tr.Event def _add_plot_fired(self): if False: # (len(self.plot_list) >= self.plots_num): dialog = MessageDialog( title='Attention!', message='Max plots number is {}'.format(self.plots_num)) dialog.open() return print('Loading npy files...') if self.apply_filters: x_axis_name = self.x_axis + '_filtered' y_axis_name = self.y_axis + '_filtered' x_axis_array = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_filtered.npy')) y_axis_array = self.y_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.y_axis + '_filtered.npy')) else: x_axis_name = self.x_axis y_axis_name = self.y_axis x_axis_array = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '.npy')) y_axis_array = self.y_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.y_axis + '.npy')) print('Adding Plot...') mpl.rcParams['agg.path.chunksize'] = 50000 # plt.figure(self.plot_figure_num) ax = self.figure.add_subplot(1, 1, 1) ax.set_xlabel('Displacement [mm]') ax.set_ylabel('kN') ax.set_title('Original data', fontsize=20) ax.plot(x_axis_array, y_axis_array, 'k', linewidth=0.8) self.plot_list.append('{}, {}'.format(x_axis_name, y_axis_name)) self.data_changed = True print('Finished adding plot!') def apply_new_subplot(self): plt = self.figure if (self.plots_num == 1): plt.add_subplot(1, 1, 1) elif (self.plots_num == 2): plot_location = int('12' + str(len(self.plot_list) + 1)) plt.add_subplot(plot_location) elif (self.plots_num == 3): plot_location = int('13' + str(len(self.plot_list) + 1)) plt.add_subplot(plot_location) elif (self.plots_num == 4): plot_location = int('22' + str(len(self.plot_list) + 1)) plt.add_subplot(plot_location) elif (self.plots_num == 6): plot_location = int('23' + str(len(self.plot_list) + 1)) plt.add_subplot(plot_location) elif (self.plots_num == 9): plot_location = int('33' + str(len(self.plot_list) + 1)) plt.add_subplot(plot_location) def _add_creep_plot_fired(self): plt = self.figure if (len(self.plot_list) >= self.plots_num): dialog = MessageDialog( title='Attention!', message='Max plots number is {}'.format(self.plots_num)) dialog.open() return disp_max = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_max.npy')) disp_min = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_min.npy')) print('Adding creep plot...') mpl.rcParams['agg.path.chunksize'] = 50000 self.apply_new_subplot() plt.xlabel('Cycles number') plt.ylabel('mm') plt.title('Fatigue creep curve', fontsize=20) plt.plot(np.arange(0, disp_max.size), disp_max, 'k', linewidth=0.8, color='red') plt.plot(np.arange(0, disp_min.size), disp_min, 'k', linewidth=0.8, color='green') self.plot_list.append('Plot {}'.format(len(self.plot_list) + 1)) print('Finished adding creep plot!') #========================================================================= # Configuration of the view #========================================================================= traits_view = ui.View( ui.HSplit( ui.VSplit( ui.HGroup( ui.UItem('open_file_csv'), ui.UItem('file_csv', style='readonly'), label='Input data' ), ui.Item('add_columns_average', show_label=False), ui.VGroup( ui.Item('skip_rows'), ui.Item('decimal'), ui.Item('delimiter'), ui.Item('parse_csv_to_npy', show_label=False), label='Filter parameters' ), ui.VGroup( ui.Item('plots_num'), ui.HGroup(ui.Item('x_axis'), ui.Item('x_axis_multiplier')), ui.HGroup(ui.Item('y_axis'), ui.Item('y_axis_multiplier')), ui.HGroup(ui.Item('add_plot', show_label=False), ui.Item('apply_filters')), ui.HGroup(ui.Item('add_creep_plot', show_label=False)), ui.Item('plot_list'), ui.Item('plot', show_label=False), show_border=True, label='Plotting settings'), ), ui.VGroup( ui.Item('force_name'), ui.HGroup(ui.Item('peak_force_before_cycles'), show_border=True, label='Skip noise of ascending branch:'), # ui.Item('plots_list'), ui.VGroup(ui.Item('force_max'), ui.Item('force_min'), show_border=True, label='Cut fake cycles for creep:'), ui.Item('generate_filtered_npy', show_label=False), show_border=True, label='Filters' ), ui.UItem('figure', editor=MPLFigureEditor(), resizable=True, springy=True, width=0.3, label='2d plots'), ), title='HCFF Filter', resizable=True, width=0.6, height=0.6 )
class HCFF(tr.HasStrictTraits): '''High-Cycle Fatigue Filter ''' #========================================================================= # Traits definitions #========================================================================= decimal = tr.Enum(',', '.') delimiter = tr.Str(';') records_per_second = tr.Float(100) take_time_from_first_column = tr.Bool file_csv = tr.File open_file_csv = tr.Button('Input file') skip_first_rows = tr.Int(3, auto_set=False, enter_set=True) columns_headers_list = tr.List([]) x_axis = tr.Enum(values='columns_headers_list') y_axis = tr.Enum(values='columns_headers_list') x_axis_multiplier = tr.Enum(1, -1) y_axis_multiplier = tr.Enum(-1, 1) npy_folder_path = tr.Str file_name = tr.Str apply_filters = tr.Bool normalize_cycles = tr.Bool smooth = tr.Bool plot_every_nth_point = tr.Range(low=1, high=1000000, mode='spinner') force_name = tr.Str('Kraft') old_peak_force_before_cycles = tr.Float peak_force_before_cycles = tr.Float window_length = tr.Int(31) polynomial_order = tr.Int(2) activate = tr.Bool(False) plots_num = tr.Enum(1, 2, 3, 4, 6, 9) plot_list = tr.List() add_plot = tr.Button add_creep_plot = tr.Button(desc='Creep plot of X axis array') clear_plot = tr.Button parse_csv_to_npy = tr.Button generate_filtered_and_creep_npy = tr.Button add_columns_average = tr.Button force_max = tr.Float(100) force_min = tr.Float(40) min_cycle_force_range = tr.Float(50) cutting_method = tr.Enum('Define min cycle range(force difference)', 'Define Max, Min') columns_to_be_averaged = tr.List figure = tr.Instance(Figure) def _figure_default(self): figure = Figure(facecolor='white') figure.set_tight_layout(True) return figure #========================================================================= # File management #========================================================================= def _open_file_csv_fired(self): self.reset() """ Handles the user clicking the 'Open...' button. """ extns = [ '*.csv', ] # seems to handle only one extension... wildcard = '|'.join(extns) dialog = FileDialog(title='Select text file', action='open', wildcard=wildcard, default_path=self.file_csv) result = dialog.open() """ Test if the user opened a file to avoid throwing an exception if he doesn't """ if result == OK: self.file_csv = dialog.path else: return """ Filling x_axis and y_axis with values """ headers_array = np.array( pd.read_csv(self.file_csv, delimiter=self.delimiter, decimal=self.decimal, nrows=1, header=None))[0] for i in range(len(headers_array)): headers_array[i] = self.get_valid_file_name(headers_array[i]) self.columns_headers_list = list(headers_array) """ Saving file name and path and creating NPY folder """ dir_path = os.path.dirname(self.file_csv) self.npy_folder_path = os.path.join(dir_path, 'NPY') if os.path.exists(self.npy_folder_path) == False: os.makedirs(self.npy_folder_path) self.file_name = os.path.splitext(os.path.basename(self.file_csv))[0] def _parse_csv_to_npy_fired(self): print('Parsing csv into npy files...') for i in range( len(self.columns_headers_list) - len(self.columns_to_be_averaged)): column_array = np.array( pd.read_csv(self.file_csv, delimiter=self.delimiter, decimal=self.decimal, skiprows=self.skip_first_rows, usecols=[i])) """ TODO! Create time array supposing it's column is the first one in the file and that we have 100 reads in 1 second """ if i == 0 and self.take_time_from_first_column == False: column_array = np.arange(start=0.0, stop=len(column_array) / self.records_per_second, step=1.0 / self.records_per_second) np.save( os.path.join( self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '.npy'), column_array) """ Exporting npy arrays of averaged columns """ for columns_names in self.columns_to_be_averaged: temp = np.zeros((1)) for column_name in columns_names: temp = temp + np.load( os.path.join(self.npy_folder_path, self.file_name + '_' + column_name + '.npy')).flatten() avg = temp / len(columns_names) avg_file_suffex = self.get_suffex_for_columns_to_be_averaged( columns_names) np.save( os.path.join(self.npy_folder_path, self.file_name + '_' + avg_file_suffex + '.npy'), avg) print('Finsihed parsing csv into npy files.') def get_suffex_for_columns_to_be_averaged(self, columns_names): suffex_for_saved_file_name = 'avg_' + '_'.join(columns_names) return suffex_for_saved_file_name def get_valid_file_name(self, original_file_name): valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) new_valid_file_name = ''.join(c for c in original_file_name if c in valid_chars) return new_valid_file_name def _clear_plot_fired(self): self.figure.clear() self.plot_list = [] self.data_changed = True def _add_columns_average_fired(self): columns_average = ColumnsAverage() for name in self.columns_headers_list: columns_average.columns.append(Column(column_name=name)) # kind='modal' pauses the implementation until the window is closed columns_average.configure_traits(kind='modal') columns_to_be_averaged_temp = [] for i in columns_average.columns: if i.selected: columns_to_be_averaged_temp.append(i.column_name) if columns_to_be_averaged_temp: # If it's not empty self.columns_to_be_averaged.append(columns_to_be_averaged_temp) avg_file_suffex = self.get_suffex_for_columns_to_be_averaged( columns_to_be_averaged_temp) self.columns_headers_list.append(avg_file_suffex) def _generate_filtered_and_creep_npy_fired(self): if self.npy_files_exist( os.path.join(self.npy_folder_path, self.file_name + '_' + self.force_name + '.npy')) == False: return # 1- Export filtered force force = np.load( os.path.join(self.npy_folder_path, self.file_name + '_' + self.force_name + '.npy')).flatten() peak_force_before_cycles_index = np.where( abs((force)) > abs(self.peak_force_before_cycles))[0][0] force_ascending = force[0:peak_force_before_cycles_index] force_rest = force[peak_force_before_cycles_index:] force_max_indices, force_min_indices = self.get_array_max_and_min_indices( force_rest) force_max_min_indices = np.concatenate( (force_min_indices, force_max_indices)) force_max_min_indices.sort() force_rest_filtered = force_rest[force_max_min_indices] force_filtered = np.concatenate((force_ascending, force_rest_filtered)) np.save( os.path.join( self.npy_folder_path, self.file_name + '_' + self.force_name + '_filtered.npy'), force_filtered) # 2- Export filtered displacements # TODO I skipped time presuming it's the first column for i in range(1, len(self.columns_headers_list)): if self.columns_headers_list[i] != str(self.force_name): disp = np.load( os.path.join( self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '.npy')).flatten() disp_ascending = disp[0:peak_force_before_cycles_index] disp_rest = disp[peak_force_before_cycles_index:] if self.activate == True: disp_ascending = savgol_filter( disp_ascending, window_length=self.window_length, polyorder=self.polynomial_order) disp_rest_filtered = disp_rest[force_max_min_indices] filtered_disp = np.concatenate( (disp_ascending, disp_rest_filtered)) np.save( os.path.join( self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '_filtered.npy'), filtered_disp) # 3- Export creep for displacements # Cutting unwanted max min values to get correct full cycles and remove # false min/max values caused by noise if self.cutting_method == "Define Max, Min": force_max_indices_cutted, force_min_indices_cutted = \ self.cut_indices_of_min_max_range(force_rest, force_max_indices, force_min_indices, self.force_max, self.force_min) elif self.cutting_method == "Define min cycle range(force difference)": force_max_indices_cutted, force_min_indices_cutted = \ self.cut_indices_of_defined_range(force_rest, force_max_indices, force_min_indices, self.min_cycle_force_range) print("Cycles number= ", len(force_min_indices)) print("Cycles number after cutting fake cycles because of noise= ", len(force_min_indices_cutted)) # TODO I skipped time with presuming it's the first column for i in range(1, len(self.columns_headers_list)): array = np.load( os.path.join( self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '.npy')).flatten() array_rest = array[peak_force_before_cycles_index:] array_rest_maxima = array_rest[force_max_indices_cutted] array_rest_minima = array_rest[force_min_indices_cutted] np.save( os.path.join( self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '_max.npy'), array_rest_maxima) np.save( os.path.join( self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '_min.npy'), array_rest_minima) print('Filtered and creep npy files are generated.') def cut_indices_of_min_max_range(self, array, max_indices, min_indices, range_upper_value, range_lower_value): cutted_max_indices = [] cutted_min_indices = [] for max_index in max_indices: if abs(array[max_index]) > abs(range_upper_value): cutted_max_indices.append(max_index) for min_index in min_indices: if abs(array[min_index]) < abs(range_lower_value): cutted_min_indices.append(min_index) return cutted_max_indices, cutted_min_indices def cut_indices_of_defined_range(self, array, max_indices, min_indices, range_): cutted_max_indices = [] cutted_min_indices = [] for max_index, min_index in zip(max_indices, min_indices): if abs(array[max_index] - array[min_index]) > range_: cutted_max_indices.append(max_index) cutted_min_indices.append(min_index) return cutted_max_indices, cutted_min_indices def get_array_max_and_min_indices(self, input_array): # Checking dominant sign positive_values_count = np.sum(np.array(input_array) >= 0) negative_values_count = input_array.size - positive_values_count # Getting max and min indices if (positive_values_count > negative_values_count): force_max_indices = argrelextrema(input_array, np.greater_equal)[0] force_min_indices = argrelextrema(input_array, np.less_equal)[0] else: force_max_indices = argrelextrema(input_array, np.less_equal)[0] force_min_indices = argrelextrema(input_array, np.greater_equal)[0] # Remove subsequent max/min indices (np.greater_equal will give 1,2 for # [4, 8, 8, 1]) force_max_indices = self.remove_subsequent_max_values( force_max_indices) force_min_indices = self.remove_subsequent_min_values( force_min_indices) # If size is not equal remove the last element from the big one if force_max_indices.size > force_min_indices.size: force_max_indices = force_max_indices[:-1] elif force_max_indices.size < force_min_indices.size: force_min_indices = force_min_indices[:-1] return force_max_indices, force_min_indices def remove_subsequent_max_values(self, force_max_indices): to_delete_from_maxima = [] for i in range(force_max_indices.size - 1): if force_max_indices[i + 1] - force_max_indices[i] == 1: to_delete_from_maxima.append(i) force_max_indices = np.delete(force_max_indices, to_delete_from_maxima) return force_max_indices def remove_subsequent_min_values(self, force_min_indices): to_delete_from_minima = [] for i in range(force_min_indices.size - 1): if force_min_indices[i + 1] - force_min_indices[i] == 1: to_delete_from_minima.append(i) force_min_indices = np.delete(force_min_indices, to_delete_from_minima) return force_min_indices def _activate_changed(self): if self.activate == False: self.old_peak_force_before_cycles = self.peak_force_before_cycles self.peak_force_before_cycles = 0 else: self.peak_force_before_cycles = self.old_peak_force_before_cycles def _window_length_changed(self, new): if new <= self.polynomial_order: dialog = MessageDialog( title='Attention!', message='Window length must be bigger than polynomial order.') dialog.open() if new % 2 == 0 or new <= 0: dialog = MessageDialog( title='Attention!', message='Window length must be odd positive integer.') dialog.open() def _polynomial_order_changed(self, new): if new >= self.window_length: dialog = MessageDialog( title='Attention!', message='Polynomial order must be less than window length.') dialog.open() #========================================================================= # Plotting #========================================================================= plot_list_current_elements_num = tr.Int(0) def npy_files_exist(self, path): if os.path.exists(path) == True: return True else: dialog = MessageDialog( title='Attention!', message='Please parse csv file to generate npy files first.'. format(self.plots_num)) dialog.open() return False def filtered_and_creep_npy_files_exist(self, path): if os.path.exists(path) == True: return True else: dialog = MessageDialog( title='Attention!', message='Please generate filtered and creep npy files first.'. format(self.plots_num)) dialog.open() return False def max_plots_number_is_reached(self): if len(self.plot_list) >= self.plots_num: dialog = MessageDialog(title='Attention!', message='Max plots number is {}'.format( self.plots_num)) dialog.open() return True else: return False def _plot_list_changed(self): if len(self.plot_list) > self.plot_list_current_elements_num: self.plot_list_current_elements_num = len(self.plot_list) data_changed = tr.Event def _add_plot_fired(self): if self.max_plots_number_is_reached() == True: return if self.apply_filters: if self.filtered_and_creep_npy_files_exist( os.path.join( self.npy_folder_path, self.file_name + '_' + self.x_axis + '_filtered.npy')) == False: return x_axis_name = self.x_axis + '_filtered' y_axis_name = self.y_axis + '_filtered' print('Loading npy files...') x_axis_array = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_filtered.npy')) y_axis_array = self.y_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.y_axis + '_filtered.npy')) else: if self.npy_files_exist( os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '.npy')) == False: return x_axis_name = self.x_axis y_axis_name = self.y_axis print('Loading npy files...') x_axis_array = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '.npy')) y_axis_array = self.y_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.y_axis + '.npy')) print('Adding Plot...') mpl.rcParams['agg.path.chunksize'] = 50000 ax = self.apply_new_subplot() ax.set_xlabel(x_axis_name) ax.set_ylabel(y_axis_name) ax.plot(x_axis_array, y_axis_array, 'k', linewidth=1.2, color=np.random.rand(3, ), label=self.file_name + ', ' + x_axis_name) ax.legend() self.plot_list.append('{}, {}'.format(x_axis_name, y_axis_name)) self.data_changed = True print('Finished adding plot!') def apply_new_subplot(self): plt = self.figure if (self.plots_num == 1): return plt.add_subplot(1, 1, 1) elif (self.plots_num == 2): plot_location = int('12' + str(len(self.plot_list) + 1)) return plt.add_subplot(plot_location) elif (self.plots_num == 3): plot_location = int('13' + str(len(self.plot_list) + 1)) return plt.add_subplot(plot_location) elif (self.plots_num == 4): plot_location = int('22' + str(len(self.plot_list) + 1)) return plt.add_subplot(plot_location) elif (self.plots_num == 6): plot_location = int('23' + str(len(self.plot_list) + 1)) return plt.add_subplot(plot_location) elif (self.plots_num == 9): plot_location = int('33' + str(len(self.plot_list) + 1)) return plt.add_subplot(plot_location) def _add_creep_plot_fired(self): if self.filtered_and_creep_npy_files_exist( os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_max.npy')) == False: return if self.max_plots_number_is_reached() == True: return disp_max = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_max.npy')) disp_min = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_min.npy')) complete_cycles_number = disp_max.size print('Adding creep-fatigue plot...') mpl.rcParams['agg.path.chunksize'] = 50000 ax = self.apply_new_subplot() ax.set_xlabel('Cycles number') ax.set_ylabel(self.x_axis) if self.plot_every_nth_point > 1: disp_max = disp_max[0::self.plot_every_nth_point] disp_min = disp_min[0::self.plot_every_nth_point] if self.smooth: # Keeping the first item of the array and filtering the rest disp_max = np.concatenate( (np.array([disp_max[0]]), savgol_filter(disp_max[1:], window_length=self.window_length, polyorder=self.polynomial_order))) disp_min = np.concatenate( (np.array([disp_min[0]]), savgol_filter(disp_min[1:], window_length=self.window_length, polyorder=self.polynomial_order))) if self.normalize_cycles: ax.plot(np.linspace(0, 1., disp_max.size), disp_max, 'k', linewidth=1.2, color='red', label='Max' + ', ' + self.file_name + ', ' + self.x_axis) ax.plot(np.linspace(0, 1., disp_max.size), disp_min, 'k', linewidth=1.2, color='green', label='Min' + ', ' + self.file_name + ', ' + self.x_axis) else: ax.plot(np.linspace(0, complete_cycles_number, disp_max.size), disp_max, 'k', linewidth=1.2, color='red', label='Max' + ', ' + self.file_name + ', ' + self.x_axis) ax.plot(np.linspace(0, complete_cycles_number, disp_max.size), disp_min, 'k', linewidth=1.2, color='green', label='Min' + ', ' + self.file_name + ', ' + self.x_axis) ax.legend() self.plot_list.append('Creep-fatigue: {}, {}'.format( self.x_axis, self.y_axis)) self.data_changed = True print('Finished adding creep-fatigue plot!') def reset(self): self.delimiter = ';' self.skip_first_rows = 3 self.columns_headers_list = [] self.npy_folder_path = '' self.file_name = '' self.apply_filters = False self.force_name = 'Kraft' self.plot_list = [] self.columns_to_be_averaged = [] #========================================================================= # Configuration of the view #========================================================================= traits_view = ui.View(ui.HSplit( ui.VSplit( ui.HGroup(ui.UItem('open_file_csv'), ui.UItem('file_csv', style='readonly', width=0.1), label='Input data'), ui.Item('add_columns_average', show_label=False), ui.VGroup( ui.VGroup(ui.Item( 'records_per_second', enabled_when='take_time_from_first_column == False'), ui.Item('take_time_from_first_column'), label='Time calculation', show_border=True), ui.VGroup(ui.Item('skip_first_rows'), ui.Item('decimal'), ui.Item('delimiter'), ui.Item('parse_csv_to_npy', show_label=False), label='Processing csv file', show_border=True), ui.VGroup(ui.HGroup(ui.Item('plots_num'), ui.Item('clear_plot')), ui.HGroup(ui.Item('x_axis'), ui.Item('x_axis_multiplier')), ui.HGroup(ui.Item('y_axis'), ui.Item('y_axis_multiplier')), ui.VGroup(ui.HGroup( ui.Item('add_plot', show_label=False), ui.Item('apply_filters')), show_border=True, label='Plotting X axis with Y axis'), ui.VGroup(ui.HGroup( ui.Item('add_creep_plot', show_label=False), ui.VGroup(ui.Item('normalize_cycles'), ui.Item('smooth'), ui.Item('plot_every_nth_point'))), show_border=True, label='Plotting Creep-fatigue of x-axis'), ui.Item('plot_list'), show_border=True, label='Plotting'))), ui.VGroup( ui.Item('force_name'), ui.VGroup(ui.VGroup( ui.Item('window_length'), ui.Item('polynomial_order'), enabled_when='activate == True or smooth == True'), show_border=True, label='Smoothing parameters (Savitzky-Golay filter):'), ui.VGroup(ui.VGroup( ui.Item('activate'), ui.Item('peak_force_before_cycles', enabled_when='activate == True')), show_border=True, label='Smooth ascending branch for all displacements:'), ui.VGroup( ui.Item('cutting_method'), ui.VGroup(ui.Item('force_max'), ui.Item('force_min'), label='Max, Min:', show_border=True, enabled_when='cutting_method == "Define Max, Min"'), ui.VGroup( ui.Item('min_cycle_force_range'), label='Min cycle force range:', show_border=True, enabled_when= 'cutting_method == "Define min cycle range(force difference)"' ), show_border=True, label='Cut fake cycles for creep:'), ui.Item('generate_filtered_and_creep_npy', show_label=False), show_border=True, label='Filters'), ui.UItem('figure', editor=MPLFigureEditor(), resizable=True, springy=True, width=0.8, label='2d plots')), title='HCFF Filter', resizable=True, width=0.85, height=0.7)
class TFunPWLInteractive(MFnLineArray, BMCSLeafNode, Vis2D): '''Interactive time function. ''' node_name = 'time function' t_values = List(Float, [0]) f_values = List(Float, [0]) def reset(self): self.f_values = [0] self.t_values = [0] self.f_value = self.f_min n_f_values = Int(10, input=True, auto_set=False, enter_set=True) f_min = Float(0.0, input=True, auto_set=False, enter_set=True, label='F minimum') f_max = Float(1.0, input=True, auto_set=False, enter_set=True, label='F maximum') t_ref = Float(1.0, auto_set=False, enter_set=True, label='Initial time range') f_value = Range(low='f_min', high='f_max', value=0, input=True, auto_set=False, enter_set=True) enable_slider = Bool(True, disable_on_run=True) run_eagerly = Bool(True, label='Run eagerly') t_snap = Float(0.1, label='Time step to snap to', auto_set=False, enter_set=True) def __init__(self, *arg, **kw): super(TFunPWLInteractive, self).__init__(*arg, **kw) self.xdata = np.array(self.t_values) self.ydata = np.array(self.f_values) d_t = Property(depends_on='t_ref,n_f_values') @cached_property def _get_d_t(self): return self.t_ref / self.n_f_values def _update_xy_arrays(self): delta_f = self.f_value - self.f_values[-1] self.f_values.append(self.f_value) rel_step = delta_f / (self.f_max - self.f_min) delta_t = rel_step * self.t_ref t_value = np.fabs(delta_t) + self.t_values[-1] n_steps = int(t_value / self.t_snap) + 1 t_value = n_steps * self.t_snap self.t_values.append(t_value) self.xdata = np.array(self.t_values) self.ydata = np.array(self.f_values) self.replot() def _f_value_changed(self): self._update_xy_arrays() t_value = self.t_values[-1] f_value = self.f_values[-1] if self.ui: self.ui.model.set_tmax(t_value) if self.run_eagerly: print('LS-run', t_value, f_value) self.ui.run() def get_ty_data(self, vot): return self.t_values, self.f_values viz2d_classes = { 'time_function': TFViz2D, } tree_view = View( VGroup( VSplit( VGroup( VGroup( Include('actions'), ), Tabbed( VGroup( VGroup( UItem('f_value', full_size=True, resizable=True, enabled_when='enable_slider' ), ), VGroup( Item('f_max', full_size=True, resizable=True), Item('f_min', full_size=True), Item('n_f_values', full_size=True), Item('t_snap', tooltip='Snap value to round off' 'the value to', full_size=True), ), spring, label='Steering', ), VGroup( Item('run_eagerly', full_size=True, resizable=True, tooltip='True - run calculation immediately' 'after moving the value slider; \nFalse - user must' 'start calculation by clicking Run button'), spring, label='Mode', ), ), ), UItem('figure', editor=MPLFigureEditor(), height=300, resizable=True, springy=True), ), ) ) traits_view = tree_view
class HCFT(tr.HasStrictTraits): '''High-Cycle Fatigue Tool ''' #========================================================================= # Traits definitions #========================================================================= decimal = tr.Enum(',', '.') delimiter = tr.Str(';') records_per_second = tr.Float(100) take_time_from_time_column = tr.Bool(True) file_csv = tr.File open_file_csv = tr.Button('Input file') skip_first_rows = tr.Range(low=1, high=10**9, mode='spinner') columns_headers_list = tr.List([]) x_axis = tr.Enum(values='columns_headers_list') y_axis = tr.Enum(values='columns_headers_list') force_column = tr.Enum(values='columns_headers_list') time_column = tr.Enum(values='columns_headers_list') x_axis_multiplier = tr.Enum(1, -1) y_axis_multiplier = tr.Enum(-1, 1) npy_folder_path = tr.Str file_name = tr.Str apply_filters = tr.Bool plot_settings_btn = tr.Button plot_settings = PlotSettings() plot_settings_active = tr.Bool normalize_cycles = tr.Bool smooth = tr.Bool plot_every_nth_point = tr.Range(low=1, high=1000000, mode='spinner') old_peak_force_before_cycles = tr.Float peak_force_before_cycles = tr.Float window_length = tr.Range(low=1, high=10**9 - 1, value=31, mode='spinner') polynomial_order = tr.Range(low=1, high=10**9, value=2, mode='spinner') activate = tr.Bool(False) add_plot = tr.Button add_creep_plot = tr.Button(desc='Creep plot of X axis array') clear_plot = tr.Button parse_csv_to_npy = tr.Button generate_filtered_and_creep_npy = tr.Button add_columns_average = tr.Button force_max = tr.Float(100) force_min = tr.Float(40) min_cycle_force_range = tr.Float(50) cutting_method = tr.Enum( 'Define min cycle range(force difference)', 'Define Max, Min') columns_to_be_averaged = tr.List figure = tr.Instance(mpl.figure.Figure) log = tr.Str('') clear_log = tr.Button def _figure_default(self): figure = mpl.figure.Figure(facecolor='white') figure.set_tight_layout(True) return figure #========================================================================= # File management #========================================================================= def _open_file_csv_fired(self): try: self.reset() """ Handles the user clicking the 'Open...' button. """ extns = ['*.csv', ] # seems to handle only one extension... wildcard = '|'.join(extns) dialog = FileDialog(title='Select text file', action='open', wildcard=wildcard, default_path=self.file_csv) result = dialog.open() """ Test if the user opened a file to avoid throwing an exception if he doesn't """ if result == OK: self.file_csv = dialog.path else: return """ Filling x_axis and y_axis with values """ headers_array = np.array( pd.read_csv( self.file_csv, delimiter=self.delimiter, decimal=self.decimal, nrows=1, header=None ) )[0] for i in range(len(headers_array)): headers_array[i] = self.get_valid_file_name(headers_array[i]) self.columns_headers_list = list(headers_array) """ Saving file name and path and creating NPY folder """ dir_path = os.path.dirname(self.file_csv) self.npy_folder_path = os.path.join(dir_path, 'NPY') if os.path.exists(self.npy_folder_path) == False: os.makedirs(self.npy_folder_path) self.file_name = os.path.splitext( os.path.basename(self.file_csv))[0] except Exception as e: self.deal_with_exception(e) def _parse_csv_to_npy_fired(self): # Run method on different thread so GUI doesn't freeze #thread = Thread(target = threaded_function, function_args = (10,)) thread = Thread(target=self.parse_csv_to_npy_fired) thread.start() def parse_csv_to_npy_fired(self): try: self.print_custom('Parsing csv into npy files...') for i in range(len(self.columns_headers_list) - len(self.columns_to_be_averaged)): current_column_name = self.columns_headers_list[i] column_array = np.array(pd.read_csv( self.file_csv, delimiter=self.delimiter, decimal=self.decimal, skiprows=self.skip_first_rows, usecols=[i])) if current_column_name == self.time_column and \ self.take_time_from_time_column == False: column_array = np.arange(start=0.0, stop=len(column_array) / self.records_per_second, step=1.0 / self.records_per_second) np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + current_column_name + '.npy'), column_array) """ Exporting npy arrays of averaged columns """ for columns_names in self.columns_to_be_averaged: temp = np.zeros((1)) for column_name in columns_names: temp = temp + np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + column_name + '.npy')).flatten() avg = temp / len(columns_names) avg_file_suffex = self.get_suffex_for_columns_to_be_averaged( columns_names) np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + avg_file_suffex + '.npy'), avg) self.print_custom('Finsihed parsing csv into npy files.') except Exception as e: self.deal_with_exception(e) def get_suffex_for_columns_to_be_averaged(self, columns_names): suffex_for_saved_file_name = 'avg_' + '_'.join(columns_names) return suffex_for_saved_file_name def get_valid_file_name(self, original_file_name): valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) new_valid_file_name = ''.join( c for c in original_file_name if c in valid_chars) return new_valid_file_name def _clear_plot_fired(self): self.figure.clear() self.data_changed = True def _add_columns_average_fired(self): try: columns_average = ColumnsAverage() for name in self.columns_headers_list: columns_average.columns.append(Column(column_name=name)) # kind='modal' pauses the implementation until the window is closed columns_average.configure_traits(kind='modal') columns_to_be_averaged_temp = [] for i in columns_average.columns: if i.selected: columns_to_be_averaged_temp.append(i.column_name) if columns_to_be_averaged_temp: # If it's not empty self.columns_to_be_averaged.append(columns_to_be_averaged_temp) avg_file_suffex = self.get_suffex_for_columns_to_be_averaged( columns_to_be_averaged_temp) self.columns_headers_list.append(avg_file_suffex) except Exception as e: self.deal_with_exception(e) def _generate_filtered_and_creep_npy_fired(self): # Run method on different thread so GUI doesn't freeze #thread = Thread(target = threaded_function, function_args = (10,)) thread = Thread(target=self.generate_filtered_and_creep_npy_fired) thread.start() def generate_filtered_and_creep_npy_fired(self): try: if self.npy_files_exist(os.path.join( self.npy_folder_path, self.file_name + '_' + self.force_column + '.npy')) == False: return self.print_custom('Generating filtered and creep files...') # 1- Export filtered force force = np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.force_column + '.npy')).flatten() peak_force_before_cycles_index = np.where( abs((force)) > abs(self.peak_force_before_cycles))[0][0] force_ascending = force[0:peak_force_before_cycles_index] force_rest = force[peak_force_before_cycles_index:] force_max_indices, force_min_indices = self.get_array_max_and_min_indices( force_rest) force_max_min_indices = np.concatenate( (force_min_indices, force_max_indices)) force_max_min_indices.sort() force_rest_filtered = force_rest[force_max_min_indices] force_filtered = np.concatenate( (force_ascending, force_rest_filtered)) np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + self.force_column + '_filtered.npy'), force_filtered) # 2- Export filtered displacements for i in range(0, len(self.columns_headers_list)): if self.columns_headers_list[i] != self.force_column and \ self.columns_headers_list[i] != self.time_column: disp = np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '.npy')).flatten() disp_ascending = disp[0:peak_force_before_cycles_index] disp_rest = disp[peak_force_before_cycles_index:] if self.activate == True: disp_ascending = savgol_filter( disp_ascending, window_length=self.window_length, polyorder=self.polynomial_order) disp_rest_filtered = disp_rest[force_max_min_indices] filtered_disp = np.concatenate( (disp_ascending, disp_rest_filtered)) np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '_filtered.npy'), filtered_disp) # 3- Export creep for displacements # Cutting unwanted max min values to get correct full cycles and remove # false min/max values caused by noise if self.cutting_method == "Define Max, Min": force_max_indices_cutted, force_min_indices_cutted = \ self.cut_indices_of_min_max_range(force_rest, force_max_indices, force_min_indices, self.force_max, self.force_min) elif self.cutting_method == "Define min cycle range(force difference)": force_max_indices_cutted, force_min_indices_cutted = \ self.cut_indices_of_defined_range(force_rest, force_max_indices, force_min_indices, self.min_cycle_force_range) self.print_custom("Cycles number= ", len(force_min_indices)) self.print_custom("Cycles number after cutting fake cycles = ", len(force_min_indices_cutted)) for i in range(0, len(self.columns_headers_list)): if self.columns_headers_list[i] != self.time_column: array = np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '.npy')).flatten() array_rest = array[peak_force_before_cycles_index:] array_rest_maxima = array_rest[force_max_indices_cutted] array_rest_minima = array_rest[force_min_indices_cutted] np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '_max.npy'), array_rest_maxima) np.save(os.path.join(self.npy_folder_path, self.file_name + '_' + self.columns_headers_list[i] + '_min.npy'), array_rest_minima) self.print_custom('Filtered and creep npy files are generated.') except Exception as e: self.deal_with_exception(e) def cut_indices_of_min_max_range(self, array, max_indices, min_indices, range_upper_value, range_lower_value): cutted_max_indices = [] cutted_min_indices = [] for max_index in max_indices: if abs(array[max_index]) > abs(range_upper_value): cutted_max_indices.append(max_index) for min_index in min_indices: if abs(array[min_index]) < abs(range_lower_value): cutted_min_indices.append(min_index) return cutted_max_indices, cutted_min_indices def cut_indices_of_defined_range(self, array, max_indices, min_indices, range_): cutted_max_indices = [] cutted_min_indices = [] for max_index, min_index in zip(max_indices, min_indices): if abs(array[max_index] - array[min_index]) > range_: cutted_max_indices.append(max_index) cutted_min_indices.append(min_index) if max_indices.size > min_indices.size: cutted_max_indices.append(max_indices[-1]) elif min_indices.size > max_indices.size: cutted_min_indices.append(min_indices[-1]) return cutted_max_indices, cutted_min_indices def get_array_max_and_min_indices(self, input_array): # Checking dominant sign positive_values_count = np.sum(np.array(input_array) >= 0) negative_values_count = input_array.size - positive_values_count # Getting max and min indices if (positive_values_count > negative_values_count): force_max_indices = self.get_max_indices(input_array) force_min_indices = self.get_min_indices(input_array) else: force_max_indices = self.get_min_indices(input_array) force_min_indices = self.get_max_indices(input_array) return force_max_indices, force_min_indices def get_max_indices(self, a): # This method doesn't qualify first and last elements as max max_indices = [] i = 1 while i < a.size - 1: previous_element = a[i - 1] # Skip repeated elements and record previous element value first_repeated_element = True while a[i] == a[i + 1] and i < a.size - 1: if first_repeated_element: previous_element = a[i - 1] first_repeated_element = False if i < a.size - 2: i += 1 else: break if a[i] > a[i + 1] and a[i] > previous_element: max_indices.append(i) i += 1 return np.array(max_indices) def get_min_indices(self, a): # This method doesn't qualify first and last elements as min min_indices = [] i = 1 while i < a.size - 1: previous_element = a[i - 1] # Skip repeated elements and record previous element value first_repeated_element = True while a[i] == a[i + 1]: if first_repeated_element: previous_element = a[i - 1] first_repeated_element = False if i < a.size - 2: i += 1 else: break if a[i] < a[i + 1] and a[i] < previous_element: min_indices.append(i) i += 1 return np.array(min_indices) def _activate_changed(self): if self.activate == False: self.old_peak_force_before_cycles = self.peak_force_before_cycles self.peak_force_before_cycles = 0 else: self.peak_force_before_cycles = self.old_peak_force_before_cycles def _window_length_changed(self, new): if new <= self.polynomial_order: dialog = MessageDialog( title='Attention!', message='Window length must be bigger than polynomial order.') dialog.open() if new % 2 == 0 or new <= 0: dialog = MessageDialog( title='Attention!', message='Window length must be odd positive integer.') dialog.open() def _polynomial_order_changed(self, new): if new >= self.window_length: dialog = MessageDialog( title='Attention!', message='Polynomial order must be smaller than window length.') dialog.open() #========================================================================= # Plotting #========================================================================= def _plot_settings_btn_fired(self): try: self.plot_settings.configure_traits(kind='modal') except Exception as e: self.deal_with_exception(e) def npy_files_exist(self, path): if os.path.exists(path) == True: return True else: # TODO fix this self.print_custom( 'Please parse csv file to generate npy files first.') # dialog = MessageDialog( # title='Attention!', # message='Please parse csv file to generate npy files first.') # dialog.open() return False def filtered_and_creep_npy_files_exist(self, path): if os.path.exists(path) == True: return True else: # TODO fix this self.print_custom( 'Please generate filtered and creep npy files first.') # dialog = MessageDialog( # title='Attention!', # message='Please generate filtered and creep npy files first.') # dialog.open() return False data_changed = tr.Event def _add_plot_fired(self): # Run method on different thread so GUI doesn't freeze #thread = Thread(target = threaded_function, function_args = (10,)) thread = Thread(target=self.add_plot_fired) thread.start() def add_plot_fired(self): try: if self.apply_filters: if self.filtered_and_creep_npy_files_exist(os.path.join( self.npy_folder_path, self.file_name + '_' + self.x_axis + '_filtered.npy')) == False: return x_axis_name = self.x_axis + '_filtered' y_axis_name = self.y_axis + '_filtered' self.print_custom('Loading npy files...') # when mmap_mode!=None, the array will be loaded as 'numpy.memmap' # object which doesn't load the array to memory until it's # indexed x_axis_array = np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_filtered.npy'), mmap_mode='r') y_axis_array = np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.y_axis + '_filtered.npy'), mmap_mode='r') else: if self.npy_files_exist(os.path.join( self.npy_folder_path, self.file_name + '_' + self.x_axis + '.npy')) == False: return x_axis_name = self.x_axis y_axis_name = self.y_axis self.print_custom('Loading npy files...') # when mmap_mode!=None, the array will be loaded as 'numpy.memmap' # object which doesn't load the array to memory until it's # indexed x_axis_array = np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '.npy'), mmap_mode='r') y_axis_array = np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.y_axis + '.npy'), mmap_mode='r') if self.plot_settings_active: print(self.plot_settings.first_rows) print(self.plot_settings.distance) print(self.plot_settings.num_of_rows_after_each_distance) print(np.size(x_axis_array)) indices = self.get_indices_array(np.size(x_axis_array), self.plot_settings.first_rows, self.plot_settings.distance, self.plot_settings.num_of_rows_after_each_distance) x_axis_array = self.x_axis_multiplier * x_axis_array[indices] y_axis_array = self.y_axis_multiplier * y_axis_array[indices] else: x_axis_array = self.x_axis_multiplier * x_axis_array y_axis_array = self.y_axis_multiplier * y_axis_array self.print_custom('Adding Plot...') mpl.rcParams['agg.path.chunksize'] = 10000 ax = self.figure.add_subplot(1, 1, 1) ax.set_xlabel(x_axis_name) ax.set_ylabel(y_axis_name) ax.plot(x_axis_array, y_axis_array, 'k', linewidth=1.2, color=np.random.rand(3), label=self.file_name + ', ' + x_axis_name) ax.legend() self.data_changed = True self.print_custom('Finished adding plot.') except Exception as e: self.deal_with_exception(e) def _add_creep_plot_fired(self): # Run method on different thread so GUI doesn't freeze #thread = Thread(target = threaded_function, function_args = (10,)) thread = Thread(target=self.add_creep_plot_fired) thread.start() def add_creep_plot_fired(self): try: if self.filtered_and_creep_npy_files_exist(os.path.join( self.npy_folder_path, self.file_name + '_' + self.x_axis + '_max.npy')) == False: return self.print_custom('Loading npy files...') disp_max = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_max.npy')) disp_min = self.x_axis_multiplier * \ np.load(os.path.join(self.npy_folder_path, self.file_name + '_' + self.x_axis + '_min.npy')) complete_cycles_number = disp_max.size self.print_custom('Adding creep-fatigue plot...') mpl.rcParams['agg.path.chunksize'] = 10000 ax = self.figure.add_subplot(1, 1, 1) ax.set_xlabel('Cycles number') ax.set_ylabel(self.x_axis) if self.plot_every_nth_point > 1: disp_max = disp_max[0::self.plot_every_nth_point] disp_min = disp_min[0::self.plot_every_nth_point] if self.smooth: # Keeping the first item of the array and filtering the rest disp_max = np.concatenate(( np.array([disp_max[0]]), savgol_filter(disp_max[1:], window_length=self.window_length, polyorder=self.polynomial_order) )) disp_min = np.concatenate(( np.array([disp_min[0]]), savgol_filter(disp_min[1:], window_length=self.window_length, polyorder=self.polynomial_order) )) if self.normalize_cycles: ax.plot(np.linspace(0, 1., disp_max.size), disp_max, 'k', linewidth=1.2, color=np.random.rand(3), label='Max' + ', ' + self.file_name + ', ' + self.x_axis) ax.plot(np.linspace(0, 1., disp_min.size), disp_min, 'k', linewidth=1.2, color=np.random.rand(3), label='Min' + ', ' + self.file_name + ', ' + self.x_axis) else: ax.plot(np.linspace(0, complete_cycles_number, disp_max.size), disp_max, 'k', linewidth=1.2, color=np.random.rand(3), label='Max' + ', ' + self.file_name + ', ' + self.x_axis) ax.plot(np.linspace(0, complete_cycles_number, disp_min.size), disp_min, 'k', linewidth=1.2, color=np.random.rand(3), label='Min' + ', ' + self.file_name + ', ' + self.x_axis) ax.legend() self.data_changed = True self.print_custom('Finished adding creep-fatigue plot.') except Exception as e: self.deal_with_exception(e) def get_indices_array(self, array_size, first_rows, distance, num_of_rows_after_each_distance): result_1 = np.arange(first_rows) result_2 = np.arange(start=first_rows, stop=array_size, step=distance + num_of_rows_after_each_distance) result_2_updated = np.array([], dtype=np.int_) for result_2_value in result_2: data_slice = np.arange(result_2_value, result_2_value + num_of_rows_after_each_distance) result_2_updated = np.concatenate((result_2_updated, data_slice)) result = np.concatenate((result_1, result_2_updated)) return result def reset(self): self.columns_to_be_averaged = [] self.log = '' def print_custom(self, *input_args): print(*input_args) if self.log == '': self.log = ''.join(str(e) for e in list(input_args)) else: self.log = self.log + '\n' + \ ''.join(str(e) for e in list(input_args)) def deal_with_exception(self, e): self.print_custom('SOMETHING WENT WRONG!') self.print_custom('--------- Error message: ---------') self.print_custom(traceback.format_exc()) self.print_custom('----------------------------------') def _clear_log_fired(self): self.log = '' #========================================================================= # Configuration of the view #========================================================================= traits_view = ui.View( ui.HSplit( ui.VSplit( ui.VGroup( ui.VGroup( ui.Item('decimal'), ui.Item('delimiter'), ui.HGroup( ui.UItem('open_file_csv', has_focus=True), ui.UItem('file_csv', style='readonly', width=0.1)), label='Importing csv file', show_border=True)), ui.VGroup( ui.VGroup( ui.VGroup( ui.Item('take_time_from_time_column'), ui.Item('time_column', enabled_when='take_time_from_time_column == True'), ui.Item('records_per_second', enabled_when='take_time_from_time_column == False'), label='Time calculation', show_border=True), ui.UItem('add_columns_average'), ui.Item('skip_first_rows'), ui.UItem('parse_csv_to_npy', resizable=True), label='Processing csv file', show_border=True)), ui.VGroup( ui.VGroup( ui.HGroup(ui.Item('x_axis'), ui.Item( 'x_axis_multiplier')), ui.HGroup(ui.Item('y_axis'), ui.Item( 'y_axis_multiplier')), ui.VGroup( ui.HGroup(ui.UItem('add_plot'), ui.Item('apply_filters'), ui.Item('plot_settings_btn', label='Settings', show_label=False, enabled_when='plot_settings_active == True'), ui.Item('plot_settings_active', show_label=False) ), show_border=True, label='Plotting X axis with Y axis' ), ui.VGroup( ui.HGroup(ui.UItem('add_creep_plot'), ui.VGroup( ui.Item('normalize_cycles'), ui.Item('smooth'), ui.Item('plot_every_nth_point')) ), show_border=True, label='Plotting Creep-fatigue of X axis variable' ), ui.UItem('clear_plot', resizable=True), show_border=True, label='Plotting')) ), ui.VGroup( ui.Item('force_column'), ui.VGroup(ui.VGroup( ui.Item('window_length'), ui.Item('polynomial_order'), enabled_when='activate == True or smooth == True'), show_border=True, label='Smoothing parameters (Savitzky-Golay filter):' ), ui.VGroup(ui.VGroup( ui.Item('activate'), ui.Item('peak_force_before_cycles', enabled_when='activate == True') ), show_border=True, label='Smooth ascending branch for all displacements:' ), ui.VGroup(ui.Item('cutting_method'), ui.VGroup(ui.Item('force_max'), ui.Item('force_min'), label='Max, Min:', show_border=True, enabled_when='cutting_method == "Define Max, Min"'), ui.VGroup(ui.Item('min_cycle_force_range'), label='Min cycle force range:', show_border=True, enabled_when='cutting_method == "Define min cycle range(force difference)"'), show_border=True, label='Cut fake cycles for creep:'), ui.VSplit( ui.UItem('generate_filtered_and_creep_npy'), ui.VGroup( ui.Item('log', width=0.1, style='custom'), ui.UItem('clear_log'))), show_border=True, label='Filters' ), ui.UItem('figure', editor=MPLFigureEditor(), resizable=True, springy=True, width=0.8, label='2d plots') ), title='High-cycle fatigue tool', resizable=True, width=0.85, height=0.7 )
class HCFF(tr.HasStrictTraits): '''High-Cycle Fatigue Filter ''' something = tr.Instance(Something) decimal = tr.Enum(',', '.') delimiter = tr.Str(';') path_hdf5 = tr.Str('') def _something_default(self): return Something() #========================================================================= # File management #========================================================================= file_csv = tr.File open_file_csv = tr.Button('Input file') def _open_file_csv_fired(self): """ Handles the user clicking the 'Open...' button. """ extns = [ '*.csv', ] # seems to handle only one extension... wildcard = '|'.join(extns) dialog = FileDialog(title='Select text file', action='open', wildcard=wildcard, default_path=self.file_csv) dialog.open() self.file_csv = dialog.path """ Filling x_axis and y_axis with values """ headers_array = np.array( pd.read_csv(self.file_csv, delimiter=self.delimiter, decimal=self.decimal, nrows=1, header=None))[0] for i in range(len(headers_array)): headers_array[i] = self.get_valid_file_name(headers_array[i]) self.columns_headers_list = list(headers_array) #========================================================================= # Parameters of the filter algorithm #========================================================================= chunk_size = tr.Int(10000, auto_set=False, enter_set=True) skip_rows = tr.Int(4, auto_set=False, enter_set=True) # 1) use the decorator @tr.on_trait_change('chunk_size, skip_rows') def whatever_name_size_changed(self): print('chunk-size changed') # 2) use the _changed or _fired extension def _chunk_size_changed(self): print('chunk_size changed - calling the named function') data = tr.Array(dtype=np.float_) read_loadtxt_button = tr.Button() def _read_loadtxt_button_fired(self): self.data = np.loadtxt(self.file_csv, skiprows=self.skip_rows, delimiter=self.delimiter) print(self.data.shape) read_csv_button = tr.Button read_hdf5_button = tr.Button def _read_csv_button_fired(self): self.read_csv() def _read_hdf5_button_fired(self): self.read_hdf5_no_filter() def read_csv(self): '''Read the csv file and transform it to the hdf5 format. The output file has the same name as the input csv file with an extension hdf5 ''' path_csv = self.file_csv # Following splitext splits the path into a pair (root, extension) self.path_hdf5 = os.path.splitext(path_csv)[0] + '.hdf5' for i, chunk in enumerate( pd.read_csv(path_csv, delimiter=self.delimiter, decimal=self.decimal, skiprows=self.skip_rows, chunksize=self.chunk_size)): chunk_array = np.array(chunk) chunk_data_frame = pd.DataFrame( chunk_array, columns=['a', 'b', 'c', 'd', 'e', 'f']) if i == 0: chunk_data_frame.to_hdf(self.path_hdf5, 'all_data', mode='w', format='table') else: chunk_data_frame.to_hdf(self.path_hdf5, 'all_data', append=True) def read_hdf5_no_filter(self): # reading hdf files is really memory-expensive! force = np.array(pd.read_hdf(self.path_hdf5, columns=['b'])) weg = np.array(pd.read_hdf(self.path_hdf5, columns=['c'])) disp1 = np.array(pd.read_hdf(self.path_hdf5, columns=['d'])) disp2 = np.array(pd.read_hdf(self.path_hdf5, columns=['e'])) disp3 = np.array(pd.read_hdf(self.path_hdf5, columns=['f'])) force = np.concatenate((np.zeros((1, 1)), force)) weg = np.concatenate((np.zeros((1, 1)), weg)) disp1 = np.concatenate((np.zeros((1, 1)), disp1)) disp2 = np.concatenate((np.zeros((1, 1)), disp2)) disp3 = np.concatenate((np.zeros((1, 1)), disp3)) dir_path = os.path.dirname(self.file_csv) npy_folder_path = os.path.join(dir_path, 'NPY') if os.path.exists(npy_folder_path) == False: os.makedirs(npy_folder_path) file_name = os.path.splitext(os.path.basename(self.file_csv))[0] np.save( os.path.join(npy_folder_path, file_name + '_Force_nofilter.npy'), force) np.save( os.path.join(npy_folder_path, file_name + '_Displacement_machine_nofilter.npy'), weg) np.save( os.path.join(npy_folder_path, file_name + '_Displacement_sliding1_nofilter.npy'), disp1) np.save( os.path.join(npy_folder_path, file_name + '_Displacement_sliding2_nofilter.npy'), disp2) np.save( os.path.join(npy_folder_path, file_name + '_Displacement_crack1_nofilter.npy'), disp3) # Defining chunk size for matplotlib points visualization mpl.rcParams['agg.path.chunksize'] = 50000 plt.subplot(111) plt.xlabel('Displacement [mm]') plt.ylabel('kN') plt.title('original data', fontsize=20) plt.plot(disp2, force, 'k') plt.show() figure = tr.Instance(Figure) def _figure_default(self): figure = Figure(facecolor='white') figure.set_tight_layout(True) return figure columns_headers_list = tr.List([]) x_axis = tr.Enum(values='columns_headers_list') y_axis = tr.Enum(values='columns_headers_list') npy_folder_path = tr.Str file_name = tr.Str plot = tr.Button def _plot_fired(self): ax = self.figure.add_subplot(111) print('plotting figure') print(type(self.x_axis), type(self.y_axis)) print(self.data[:, 1]) print(self.data[:, self.x_axis]) print(self.data[:, self.y_axis]) ax.plot(self.data[:, self.x_axis], self.data[:, self.y_axis]) traits_view = ui.View(ui.HSplit( ui.VSplit( ui.HGroup(ui.UItem('open_file_csv'), ui.UItem('file_csv', style='readonly'), label='Input data'), ui.VGroup(ui.Item('chunk_size'), ui.Item('skip_rows'), ui.Item('decimal'), ui.Item('delimiter'), label='Filter parameters'), ui.VGroup( ui.HGroup(ui.Item('read_loadtxt_button', show_label=False), ui.Item('plot', show_label=False), show_border=True), ui.HGroup(ui.Item('read_csv_button', show_label=False), ui.Item('read_hdf5_button', show_label=False), show_border=True))), ui.UItem('figure', editor=MPLFigureEditor(), resizable=True, springy=True, label='2d plots'), ), resizable=True, width=0.8, height=0.6)