Esempio n. 1
0
class SmoothingLowess(Smoothing):
    smoothing_parameter = t.Range(low=0.,
                                  high=1.,
                                  value=0.5,
                                  )
    number_of_iterations = t.Range(low=1,
                                   value=1)

    def __init__(self, *args, **kwargs):
        super(SmoothingLowess, self).__init__(*args, **kwargs)

    def _smoothing_parameter_changed(self, old, new):
        if new == 0:
            self.smoothing_parameter = old
        else:
            self.update_lines()

    def _number_of_iterations_changed(self, old, new):
        self.update_lines()

    def model2plot(self, axes_manager=None):
        self.single_spectrum.data = self.signal().copy()
        self.single_spectrum.smooth_lowess(
            smoothing_parameter=self.smoothing_parameter,
            number_of_iterations=self.number_of_iterations,
            show_progressbar=False)

        return self.single_spectrum.data

    def apply(self):
        self.signal.smooth_lowess(
            smoothing_parameter=self.smoothing_parameter,
            number_of_iterations=self.number_of_iterations)
        self.signal._replot()
class PlotSettings(tr.HasStrictTraits):
    num_of_first_rows_to_take = tr.Range(low=0,
                                         high=10**9,
                                         value=6000,
                                         mode='spinner')
    num_of_rows_to_skip_after_each_section = tr.Range(low=0,
                                                      high=10**9,
                                                      value=20000,
                                                      mode='spinner')
    num_of_rows_in_each_section = tr.Range(low=0,
                                           high=10**9,
                                           value=200,
                                           mode='spinner')
class cash_flow_series(trapi.HasTraits):
    name = trapi.Str
    short_rate = trapi.Range(0.0, 0.5, 0.05)
    time_list = trapi.Array(dtype=np.float, shape=(1, 6))
    cash_flows = trapi.Array(dtype=np.float, shape=(1, 6))
    disc_values = trapi.Array(dtype=np.float, shape=(1, 6))
    present_values = trapi.Array(dtype=np.float, shape=(1, 6))
    net_present_value = trapi.Float
    update = trapi.Button

    def _update_fired(self):
        self.disc_values = np.exp(-self.short_rate * self.time_list)
        self.present_values = self.disc_values * self.cash_flows
        self.net_present_value = np.sum(self.present_values)

    v = trui.View(trui.Group(trui.Item(name='name'),
                             trui.Item(name='short_rate'),
                             trui.Item(name='time_list', label='Time List'),
                             trui.Item(name='cash_flows', label='Cash Flows'),
                             trui.Item('update', show_label=False),
                             trui.Item(name='disc_values',
                                       label='Discount Factors'),
                             trui.Item(name='present_values',
                                       label='Present Values'),
                             trui.Item(name='net_present_value',
                                       label='Net Present Value'),
                             show_border=True,
                             label='Calculate Present Values'),
                  buttons=[trui.OKButton, trui.CancelButton],
                  resizable=True)
Esempio n. 4
0
class EELSConfig(t.HasTraits):
    eels_gos_files_path = t.Directory(guess_gos_path(),
        label = 'GOS directory',
        desc = 'The GOS files are required to create the EELS edge components')
    fine_structure_width = t.CFloat(30,
        label = 'Fine structure lenght',
        desc = 'The default lenght of the fine structure from the edge onset')
    fine_structure_active = t.CBool(False,
        label = 'Enable fine structure',
        desc = "If enabled, the regions of the EELS spectrum defined as fine "
               "structure will be fitted with a spline. Please note that it "
               "enabling this feature only makes sense when the model is "
               "convolved to account for multiple scattering")
    fine_structure_smoothing = t.Range(0., 1., value = 0.3,
        label = 'Fine structure smoothing factor',
        desc = 'The lower the value the smoother the fine structure spline fit')
    synchronize_cl_with_ll = t.CBool(False)
    preedge_safe_window_width = t.CFloat(2,
        label = 'Pre-onset region (in eV)',
        desc = 'Some functions needs to define the regions between two '
               'ionisation edges. Due to limited energy resolution or chemical '
               'shift, the region is limited on its higher energy side by '
               'the next ionisation edge onset minus an offset defined by this '
               'parameters')
    min_distance_between_edges_for_fine_structure = t.CFloat(0,
        label = 'Minimum distance between edges',
        desc = 'When automatically setting the fine structure energy regions, '
               'the fine structure of an EELS edge component is automatically '
               'disable if the next ionisation edge onset distance to the '
               'higher energy side of the fine structure region is lower that '
               'the value of this parameter')
Esempio n. 5
0
class ButterworthFilter(Smoothing):
    cutoff_frequency_ratio = t.Range(0., 1., 0.05)
    type = t.Enum('low', 'high')
    order = t.Int(2)

    view = tu.View(
        tu.Group('cutoff_frequency_ratio', 'order', 'type'),
        kind='live',
        handler=SmoothingHandler,
        buttons=OKCancelButtons,
        title='Butterworth filter',
    )

    def _cutoff_frequency_ratio_changed(self, old, new):
        self.update_lines()

    def _type_changed(self, old, new):
        self.update_lines()

    def _order_changed(self, old, new):
        self.update_lines()

    def model2plot(self, axes_manager=None):
        b, a = sp.signal.butter(self.order, self.cutoff_frequency_ratio,
                                self.type)
        smoothed = sp.signal.filtfilt(b, a, self.signal())
        return smoothed
Esempio n. 6
0
class AutoRefreshDialog(traits.HasTraits):

    minutes = traits.Float(1.0)
    autoRefreshBool = traits.Bool()

    emailAlertBool = traits.Bool(False)
    soundAlertBool = traits.Bool(False)
    linesOfDataFrame = traits.Range(1, 10)
    alertCode = traits.Code(
        DEFAULT_ALERT_CODE,
        desc="python code for finding alert worthy elements")

    basicGroup = traitsui.Group("minutes", "autoRefreshBool")
    alertGroup = traitsui.VGroup(
        traitsui.HGroup(traitsui.Item("emailAlertBool"),
                        traitsui.Item("soundAlertBool")),
        traitsui.Item("linesOfDataFrame",
                      visible_when="emailAlertBool or soundAlertBool"),
        traitsui.Item("alertCode",
                      visible_when="emailAlertBool or soundAlertBool"))

    traits_view = traitsui.View(traitsui.VGroup(basicGroup, alertGroup),
                                title="auto refresh",
                                buttons=[OKButton],
                                kind='livemodal',
                                resizable=True)
Esempio n. 7
0
class ButterworthFilter(Smoothing):
    cutoff_frequency_ratio = t.Range(0.01, 1., 0.01)
    type = t.Enum('low', 'high')
    order = t.Int(2)

    def _cutoff_frequency_ratio_changed(self, old, new):
        self.update_lines()

    def _type_changed(self, old, new):
        self.update_lines()

    def _order_changed(self, old, new):
        self.update_lines()

    def model2plot(self, axes_manager=None):
        b, a = sp.signal.butter(self.order, self.cutoff_frequency_ratio,
                                self.type)
        smoothed = sp.signal.filtfilt(b, a, self.signal())
        return smoothed

    def apply(self):
        b, a = sp.signal.butter(self.order, self.cutoff_frequency_ratio,
                                self.type)
        f = functools.partial(sp.signal.filtfilt, b, a)
        self.signal.map(f)
class RGBA(traits.HasTraits):
    # r,g,b,a in the range 0-1 with default color 0,0,0,1 (black)
    r = traits.Range(0., 1., 0.)
    g = traits.Range(0., 1., 0.)
    b = traits.Range(0., 1., 0.)
    a = traits.Range(0., 1., 1.)

    def __init__(self, r=0., g=0., b=0., a=1.):
        self.r = r
        self.g = g
        self.b = b
        self.a = a

    def __repr__(self):
        return 'r,g,b,a = (%1.2f, %1.2f, %1.2f, %1.2f)'%\
               (self.r, self.g, self.b, self.a)
Esempio n. 9
0
class SmoothingLowess(Smoothing):
    smoothing_parameter = t.Range(low=0.,
                                  high=1.,
                                  value=0.5,
                                  )
    number_of_iterations = t.Range(low=1,
                                   value=1)
    view = tu.View(
        tu.Group(
            'smoothing_parameter',
            'number_of_iterations',
            'line_color'),
        kind='live',
        handler=SmoothingHandler,
        buttons=OKCancelButtons,
        title='Lowess Smoothing',)

    def __init__(self, *args, **kwargs):
        super(SmoothingLowess, self).__init__(*args, **kwargs)

    def _smoothing_parameter_changed(self, old, new):
        if new == 0:
            self.smoothing_parameter = old
        else:
            self.update_lines()

    def _number_of_iterations_changed(self, old, new):
        self.update_lines()

    def model2plot(self, axes_manager=None):
        self.single_spectrum.data = self.signal().copy()
        self.single_spectrum.smooth_lowess(
            smoothing_parameter=self.smoothing_parameter,
            number_of_iterations=self.number_of_iterations,
            show_progressbar=False)

        return self.single_spectrum.data

    def apply(self):
        self.signal.smooth_lowess(
            smoothing_parameter=self.smoothing_parameter,
            number_of_iterations=self.number_of_iterations)
        self.signal._replot()
Esempio n. 10
0
class MultiMeshMorpher(ta.HasTraits):
    visible = ta.Enum(values='_names')
    morph_target = ta.Enum(values='_names')
    morph_alpha = ta.Range(0.0, 1.0, 0.0)
    show_edges = ta.Bool(False)
    _names = ta.List()

    def __init__(self, list_verts, tris, names=None, fig=None, **kw):
        super(MultiMeshMorpher, self).__init__(**kw)
        self._list_verts = list_verts
        self._tris = tris

        if fig is None:
            self._fig = mlab.figure(bgcolor=(1, 1, 1))
        else:
            self._fig = fig

        if names is None:
            names = map(str, range(len(list_verts)))
        self._names = list(names)

        self._verts_by_name = dict(zip(self._names, list_verts))
        self._actor, self._pd = mesh_as_vtk_actor(list_verts[0], tris, return_polydata=True)
        self._actor.property.set(
            ambient=0.0,
            specular=0.15, 
            specular_power=128., 
            diffuse=0.8,
        )
        self._fig.scene.add_actor(self._actor)

        self.visible = self._names[0]
        if len(self._names) > 1:
            self.morph_target = self._names[1]

    @ta.on_trait_change('visible, show_edges, morph_target, morph_alpha')
    def _update(self):
        self._actor.property.edge_visibility = self.show_edges
        v1 = self._verts_by_name[self.visible]
        if self.morph_alpha > 0:
            v2 = self._verts_by_name[self.morph_target]
            self._pd.points = v1 * (1 - self.morph_alpha) + v2 * self.morph_alpha
        else:
            self._pd.points = v1
        self._fig.scene.render()

    view = tu.View(
        tu.Group(
            tu.Item('visible'),
            tu.Item('morph_target'),
            tu.Item('morph_alpha'),
            tu.Item('show_edges', name='Wireframe'),
            label="Viewer"),
        title="MultiMeshMorpher"
    )
Esempio n. 11
0
class GaussianFilter(Filter):
    width = tr.Range(1, 10)

    def _chan_changed(self):
        self.update()

    @tr.on_trait_change('width')
    def update(self):
        self.yf = nd.gaussian_filter1d(self.d[:, self.chan],
                                       self.width,
                                       mode='nearest')
        self.replot = True

    traits_view = ui.View(['width'])
Esempio n. 12
0
class SavGolFilter(Filter):
    order = tr.Range(1, 10)
    window_size = tr.Int(5)

    @tr.on_trait_change('order, window_size')
    def update(self):
        ws = (self.window_size / 2) * 2 + 1
        y = self.d[:, self.chan]
        self.yf = dv.savitzky_golay(y, ws, self.order)
        self.replot = True

    range_edit = ui.RangeEditor(low_name='order', high=51)
    view_window_size = ui.Item('window_size', editor=range_edit)
    traits_view = ui.View(['order', view_window_size])
Esempio n. 13
0
class Prop(tvtk_base.TVTKBase):
    def __init__(self, obj=None, update=1, **traits):
        tvtk_base.TVTKBase.__init__(
            self, vtk.vtkProperty, obj, update, **traits
        )

    edge_visibility = tvtk_base.false_bool_trait

    def _edge_visibility_changed(self, old_val, new_val):
        self._do_change(self._vtk_obj.SetEdgeVisibility, self.edge_visibility_)

    representation = tvtk_base.RevPrefixMap(
        {'points': 0, 'wireframe': 1, 'surface': 2},
        4, 5, default_value='surface')

    def _representation_changed(self, old_val, new_val):
        self._do_change(self._vtk_obj.SetRepresentation, self.representation_)

    opacity = traits.Trait(1.0, traits.Range(0.0, 1.0))

    def _opacity_changed(self, old_val, new_val):
        self._do_change(self._vtk_obj.SetOpacity,
                        self.opacity)

    specular_color = tvtk_base.vtk_color_trait((1.0, 1.0, 1.0))

    def _specular_color_changed(self, old_val, new_val):
        self._do_change(self._vtk_obj.SetSpecularColor,
                        self.specular_color, 1)

    diffuse_color = tvtk_base.vtk_color_trait((1.0, 1.0, 1.0))

    def _diffuse_color_changed(self, old_val, new_val):
        self._do_change(self._vtk_obj.SetDiffuseColor,
                        self.diffuse_color, 1)

    color = tvtk_base.vtk_color_trait((1.0, 1.0, 1.0))

    def _color_changed(self, old_val, new_val):
        self._do_change(self._vtk_obj.SetColor,
                        self.color)

    _updateable_traits_ = (('edge_visibility', 'GetEdgeVisibility'),
                           ('opacity', 'GetOpacity'),
                           ('specular_color', 'GetSpecularColor'),
                           ('color', 'GetColor'),
                           ('diffuse_color', 'GetDiffuseColor'),
                           ('representation', 'GetRepresentation'))
Esempio n. 14
0
class Controller(traits.HasTraits):

    min_slab = traits.Int(0)
    max_slab = traits.Int(1E9)
    slab = traits.Range(low='min_slab',
                        high='max_slab',
                        value=0,
                        mode='spinner',
                        exclude_high=True)

    apply_registration = traits.Bool()

    pause = traits.Bool()

    view = View(
        Group(Item(name='slab'), Item(name='apply_registration'),
              Item(name='pause')))

    def __init__(self, view, job, *args, **kwargs):
        HasTraits.__init__(self, *args, **kwargs)
        self.view = view
        self.job = job
        self.max_slab = 0

    @traits.on_trait_change("pause")
    def job_pause(self, value):
        self.job.pause = value

    @traits.on_trait_change("slab,apply_registration")
    def update_slab(self):
        ## switch between the register of the previous and the current slab
        if self.apply_registration or self.slab > 0 and len(
                self.job.registered_slabs) > 0:
            sl = self.job.registered_slabs[self.slab]
            sl_reg = self.job.registered_slabs[self.slab +
                                               int(self.apply_registration) -
                                               1]
            self.view.update_slab(sl[0], sl[1], sl_reg[2], sl[3])

    def notify_changes(self):
        self.max_slab = len(self.job.registered_slabs)
        self.view.update_motion(np.c_[self.job.algo.filtered_state_means])
Esempio n. 15
0
 def __init__(self, robot):
     self.robot = robot
     for joint in robot.GetJoints():
         lower, upper = joint.GetLimits()
         lower = np.clip(lower, -np.pi, np.inf)
         upper = np.clip(upper, -np.inf, np.pi)
         self.add_trait(joint.GetName(), tr.Range(lower[0].item(), upper[0].item(), joint.GetValues()[0]))
     T = robot.GetTransform()
     rx,ry,rz = rave.axisAngleFromRotationMatrix(T[:3,:3])
     tx,ty,tz = T[:3,3]
     self.add_trait("tftx", tr.Range(-5.,5,tx.item()))
     self.add_trait("tfty", tr.Range(-5.,5,ty.item()))
     self.add_trait("tftz", tr.Range(-5.,5,tz.item()))
     self.add_trait("tfrx", tr.Range(-5.,5,rx.item()))
     self.add_trait("tfry", tr.Range(-5.,5,ry.item()))
     self.add_trait("tfrz", tr.Range(-5.,5,rz.item()))
     self.on_trait_change(self.update_robot, 'anytrait')
     tr.HasTraits.__init__(self)
Esempio n. 16
0
class SvdFilter(Filter):
    number_of_components = tr.Range(1, 20, 5)

    def _df_default(self):
        self.apply_filter()
        return self.df

    @tr.on_trait_change('number_of_components')
    def apply_filter(self):
        u, s, v = np.linalg.svd(self.d, full_matrices=False)
        s[self.number_of_components:] = 0
        s = np.diag(s)
        self.df = u.dot(np.dot(s, v))
        self.yf = self.df[:, self.chan]
        self.replot = True
        return self.df

    def _chan_changed(self, n):
        self.yf = self.df[:, n]
        self.replot = True

    traits_view = ui.View(['number_of_components'])
Esempio n. 17
0
class Morpher(ta.HasTraits):
    alpha = ta.Range(0.0, 1.0)

    def __init__(
            self,
            verts1,
            verts2,
            tris=None,
            lines=None,
            as_points=False,
            scalars=None,
            scalars2=None,
            vmin=None,
            vmax=None,
            actor_property=dict(specular=0.1, specular_power=128.,
                                diffuse=0.5),
    ):
        if tris is None:
            if lines is None:
                rep = 'points'
            else:
                rep = 'wireframe'
        else:
            rep = 'surface'
        super(Morpher, self).__init__()
        self._verts1, self._verts2 = verts1, verts2
        self._polydata = tvtk.PolyData(points=verts1)
        if rep == 'points':
            self._polydata.verts = np.r_[:len(verts1)].reshape(-1, 1)
        if tris is not None:
            self._polydata.polys = tris
        if lines is not None:
            self._polydata.lines = lines
        n = tvtk.PolyDataNormals(splitting=False)
        configure_input_data(n, self._polydata)
        self._actor = tvtk.Actor(mapper=tvtk.PolyDataMapper())
        configure_input(self._actor.mapper, n)
        self._actor.property.representation = rep
        if rep == 'points':
            self._actor.property.point_size = 5
        if as_points and scalars is None:
            self._polydata.point_data.scalars = \
                    np.random.uniform(0, 255, (len(verts1), 3)).astype(np.uint8)

        self._scalars12 = None
        if scalars is not None:
            self._polydata.point_data.scalars = scalars
            # automatically determine minimum/maximum from scalars if not given by user
            if vmin is None:
                vmin = scalars.min()
                if scalars2 is not None:
                    vmin = min(vmin, scalars2.min())
            if vmax is None:
                vmax = scalars.max()
                if scalars2 is not None:
                    vmax = max(vmax, scalars2.max())
            if scalars.ndim == 1:
                self._actor.mapper.use_lookup_table_scalar_range = False
                self._actor.mapper.scalar_range = (vmin, vmax)
                self._actor.mapper.lookup_table.hue_range = (0.33, 0)
            # when scalars of second mesh given we need to store both scalars in order
            # to interpolate between them during rendering
            if scalars2 is not None:
                self._scalars12 = (scalars, scalars2)
        else:
            self._actor.property.set(**actor_property)
        mlab.gcf().scene.add_actor(self._actor)

    def _alpha_changed(self):
        self._polydata.points = self._verts1 * (1 - self.alpha) \
                              + self._verts2 * self.alpha
        if self._scalars12 is not None:
            blended = self._scalars12[0] * (1 - self.alpha) \
                    + self._scalars12[1] * self.alpha
            # when scalars is a (n_verts, 3) color array (type uint8)
            # then above blending will cast to float, undo this here:
            if self._scalars12[0].dtype == np.uint8:
                blended = blended.astype(np.uint8)
            self._polydata.point_data.scalars = blended
        mlab.gcf().scene.render()

    traits_view = tu.View(tu.Item('alpha', show_label=False),
                          title='cgtools Morpher')
Esempio n. 18
0
    class Ctrl(ta.HasTraits):
        alpha = ta.Range(0., 1.)

        def _alpha_changed(self):
            pd.points = p + self.alpha * (p2 - p)
            mlab.gcf().scene.render()
Esempio n. 19
0
class BackgroundRemoval(SpanSelectorInSpectrum):
    background_type = t.Enum(
        'Power Law',
        'Gaussian',
        'Offset',
        'Polynomial',
        default='Power Law')
    polynomial_order = t.Range(1, 10)
    estimate_background = t.Enum(
        'Estimate',
        'Full fit',
        default='Estimate')
    background_estimator = t.Instance(Component)
    bg_line_range = t.Enum('from_left_range',
                           'full',
                           'ss_range',
                           default='full')
    hi = t.Int(0)
    view = tu.View(
        tu.Group(
            'background_type',
            tu.Group(
                'polynomial_order',
                visible_when='background_type == \'Polynomial\''),),
            'estimate_background',
            buttons=[OKButton, CancelButton],
            handler=SpanSelectorInSpectrumHandler,
            title='Background removal tool')

    def __init__(self, signal):
        super(BackgroundRemoval, self).__init__(signal)
        self.set_background_estimator()
        self.estimate_fit = True
        self.bg_line = None

    def on_disabling_span_selector(self):
        if self.bg_line is not None:
            self.bg_line.close()
            self.bg_line = None

    def set_background_estimator(self):

        if self.background_type == 'Power Law':
            self.background_estimator = components.PowerLaw()
            self.bg_line_range = 'from_left_range'
        elif self.background_type == 'Gaussian':
            self.background_estimator = components.Gaussian()
            self.bg_line_range = 'full'
        elif self.background_type == 'Offset':
            self.background_estimator = components.Offset()
            self.bg_line_range = 'full'
        elif self.background_type == 'Polynomial':
            self.background_estimator = \
                components.Polynomial(self.polynomial_order)
            self.bg_line_range = 'full'

    def _polynomial_order_changed(self, old, new):
        self.background_estimator = components.Polynomial(new)
        self.span_selector_changed()

    def _background_type_changed(self, old, new):
        self.set_background_estimator()
        self.span_selector_changed()

    def _estimate_background_changed(self, old, new):
        if self.estimate_background == 'Full fit':
            self.estimate_fit = False
        if self.estimate_background == 'Estimate':
            self.estimate_fit = True

    def _ss_left_value_changed(self, old, new):
        self.span_selector_changed()

    def _ss_right_value_changed(self, old, new):
        self.span_selector_changed()

    def create_background_line(self):
        self.bg_line = drawing.spectrum.SpectrumLine()
        self.bg_line.data_function = self.bg_to_plot
        self.bg_line.set_line_properties(
            color='blue',
            type='line',
            scaley=False)
        self.signal._plot.signal_plot.add_line(self.bg_line)
        self.bg_line.autoscale = False
        self.bg_line.plot()

    def bg_to_plot(self, axes_manager=None, fill_with=np.nan):
        # First try to update the estimation
        self.background_estimator.estimate_parameters(
            self.signal, self.ss_left_value, self.ss_right_value,
            only_current=True)

        if self.bg_line_range == 'from_left_range':
            bg_array = np.zeros(self.axis.axis.shape)
            bg_array[:] = fill_with
            from_index = self.axis.value2index(self.ss_left_value)
            bg_array[from_index:] = self.background_estimator.function(
                self.axis.axis[from_index:])
            to_return = bg_array
        elif self.bg_line_range == 'full':
            to_return = self.background_estimator.function(self.axis.axis)
        elif self.bg_line_range == 'ss_range':
            bg_array = np.zeros(self.axis.axis.shape)
            bg_array[:] = fill_with
            from_index = self.axis.value2index(self.ss_left_value)
            to_index = self.axis.value2index(self.ss_right_value)
            bg_array[from_index:] = self.background_estimator.function(
                self.axis.axis[from_index:to_index])
            to_return = bg_array

        if self.signal.metadata.Signal.binned is True:
            to_return *= self.axis.scale
        return to_return

    def span_selector_changed(self):
        if (self.ss_left_value is np.nan) or (self.ss_right_value is np.nan):
            return
        if self.background_estimator is None:
            print("No bg estimator")
            return
        if self.bg_line is None and \
            self.background_estimator.estimate_parameters(
                self.signal, self.ss_left_value, self.ss_right_value,
                only_current=True) is True:
            self.create_background_line()
        else:
            self.bg_line.update()

    def apply(self):
        self.signal._plot.auto_update_plot = False
        new_spectra = self.signal._remove_background_cli(
            (self.ss_left_value, self.ss_right_value),
            self.background_estimator, estimate_background=self.estimate_fit)
        self.signal.data = new_spectra.data
        self.signal._replot()
        self.signal._plot.auto_update_plot = True
Esempio n. 20
0
class SpikesRemoval(SpanSelectorInSpectrum):
    interpolator_kind = t.Enum(
        'Linear',
        'Spline',
        default='Linear')
    threshold = t.Float()
    show_derivative_histogram = t.Button()
    spline_order = t.Range(1, 10, 3)
    interpolator = None
    default_spike_width = t.Int(5)
    index = t.Int(0)
    add_noise = t.Bool(True,
                       desc="Add noise to the healed portion of the "
                       "spectrum. Use the noise properties "
                       "defined in metadata if present, otherwise "
                       "it defaults to shot noise.")
    view = tu.View(tu.Group(
        tu.Group(
            tu.Item('show_derivative_histogram', show_label=False),
            'threshold',
            show_border=True,),
        tu.Group(
            'add_noise',
            'interpolator_kind',
            'default_spike_width',
            tu.Group(
                'spline_order',
                visible_when='interpolator_kind == \'Spline\''),
            show_border=True,
            label='Advanced settings'),
    ),
        buttons=[OKButton,
                 OurPreviousButton,
                 OurFindButton,
                 OurApplyButton, ],
        handler=SpikesRemovalHandler,
        title='Spikes removal tool')

    def __init__(self, signal, navigation_mask=None, signal_mask=None):
        super(SpikesRemoval, self).__init__(signal)
        self.interpolated_line = None
        self.coordinates = [coordinate for coordinate in
                            signal.axes_manager._am_indices_generator()
                            if (navigation_mask is None or not
                                navigation_mask[coordinate[::-1]])]
        self.signal = signal
        self.line = signal._plot.signal_plot.ax_lines[0]
        self.ax = signal._plot.signal_plot.ax
        signal._plot.auto_update_plot = False
        if len(self.coordinates) > 1:
            signal.axes_manager.indices = self.coordinates[0]
        self.threshold = 400
        self.index = 0
        self.argmax = None
        self.derivmax = None
        self.kind = "linear"
        self._temp_mask = np.zeros(self.signal().shape, dtype='bool')
        self.signal_mask = signal_mask
        self.navigation_mask = navigation_mask
        md = self.signal.metadata
        from hyperspy.signal import Signal
        if "Signal.Noise_properties" in md:
            if "Signal.Noise_properties.variance" in md:
                self.noise_variance = md.Signal.Noise_properties.variance
                if isinstance(md.Signal.Noise_properties.variance, Signal):
                    self.noise_type = "heteroscedastic"
                else:
                    self.noise_type = "white"
        else:
            self.noise_type = "shot noise"

    def _threshold_changed(self, old, new):
        self.index = 0
        self.update_plot()

    def _show_derivative_histogram_fired(self):
        self.signal._spikes_diagnosis(signal_mask=self.signal_mask,
                                      navigation_mask=self.navigation_mask)

    def detect_spike(self):
        derivative = np.diff(self.signal())
        if self.signal_mask is not None:
            derivative[self.signal_mask[:-1]] = 0
        if self.argmax is not None:
            left, right = self.get_interpolation_range()
            self._temp_mask[left:right] = True
            derivative[self._temp_mask[:-1]] = 0
        if abs(derivative.max()) >= self.threshold:
            self.argmax = derivative.argmax()
            self.derivmax = abs(derivative.max())
            return True
        else:
            return False

    def _reset_line(self):
        if self.interpolated_line is not None:
            self.interpolated_line.close()
            self.interpolated_line = None
            self.reset_span_selector()

    def find(self, back=False):
        self._reset_line()
        ncoordinates = len(self.coordinates)
        spike = self.detect_spike()
        while not spike and (
                (self.index < ncoordinates - 1 and back is False) or
                (self.index > 0 and back is True)):
            if back is False:
                self.index += 1
            else:
                self.index -= 1
            spike = self.detect_spike()

        if spike is False:
            messages.information('End of dataset reached')
            self.index = 0
            self._reset_line()
            return
        else:
            minimum = max(0, self.argmax - 50)
            maximum = min(len(self.signal()) - 1, self.argmax + 50)
            thresh_label = DerivativeTextParameters(
                text="$\mathsf{\delta}_\mathsf{max}=$",
                color="black")
            self.ax.legend([thresh_label], [repr(int(self.derivmax))], handler_map={
                           DerivativeTextParameters: DerivativeTextHandler()}, loc='best')
            self.ax.set_xlim(
                self.signal.axes_manager.signal_axes[0].index2value(
                    minimum),
                self.signal.axes_manager.signal_axes[0].index2value(
                    maximum))
            self.update_plot()
            self.create_interpolation_line()

    def update_plot(self):
        if self.interpolated_line is not None:
            self.interpolated_line.close()
            self.interpolated_line = None
        self.reset_span_selector()
        self.update_spectrum_line()
        if len(self.coordinates) > 1:
            self.signal._plot.pointer._update_patch_position()

    def update_spectrum_line(self):
        self.line.auto_update = True
        self.line.update()
        self.line.auto_update = False

    def _index_changed(self, old, new):
        self.signal.axes_manager.indices = self.coordinates[new]
        self.argmax = None
        self._temp_mask[:] = False

    def on_disabling_span_selector(self):
        if self.interpolated_line is not None:
            self.interpolated_line.close()
            self.interpolated_line = None

    def _spline_order_changed(self, old, new):
        self.kind = self.spline_order
        self.span_selector_changed()

    def _add_noise_changed(self, old, new):
        self.span_selector_changed()

    def _interpolator_kind_changed(self, old, new):
        if new == 'linear':
            self.kind = new
        else:
            self.kind = self.spline_order
        self.span_selector_changed()

    def _ss_left_value_changed(self, old, new):
        self.span_selector_changed()

    def _ss_right_value_changed(self, old, new):
        self.span_selector_changed()

    def create_interpolation_line(self):
        self.interpolated_line = drawing.spectrum.SpectrumLine()
        self.interpolated_line.data_function = \
            self.get_interpolated_spectrum
        self.interpolated_line.set_line_properties(
            color='blue',
            type='line')
        self.signal._plot.signal_plot.add_line(self.interpolated_line)
        self.interpolated_line.autoscale = False
        self.interpolated_line.plot()

    def get_interpolation_range(self):
        axis = self.signal.axes_manager.signal_axes[0]
        if self.ss_left_value == self.ss_right_value:
            left = self.argmax - self.default_spike_width
            right = self.argmax + self.default_spike_width
        else:
            left = axis.value2index(self.ss_left_value)
            right = axis.value2index(self.ss_right_value)

        # Clip to the axis dimensions
        nchannels = self.signal.axes_manager.signal_shape[0]
        left = left if left >= 0 else 0
        right = right if right < nchannels else nchannels - 1

        return left, right

    def get_interpolated_spectrum(self, axes_manager=None):
        data = self.signal().copy()
        axis = self.signal.axes_manager.signal_axes[0]
        left, right = self.get_interpolation_range()
        if self.kind == 'linear':
            pad = 1
        else:
            pad = 10
        ileft = left - pad
        iright = right + pad
        ileft = np.clip(ileft, 0, len(data))
        iright = np.clip(iright, 0, len(data))
        left = int(np.clip(left, 0, len(data)))
        right = int(np.clip(right, 0, len(data)))
        x = np.hstack((axis.axis[ileft:left], axis.axis[right:iright]))
        y = np.hstack((data[ileft:left], data[right:iright]))
        if ileft == 0:
            # Extrapolate to the left
            data[left:right] = data[right + 1]

        elif iright == (len(data) - 1):
            # Extrapolate to the right
            data[left:right] = data[left - 1]

        else:
            # Interpolate
            intp = sp.interpolate.interp1d(x, y, kind=self.kind)
            data[left:right] = intp(axis.axis[left:right])

        # Add noise
        if self.add_noise is True:
            if self.noise_type == "white":
                data[left:right] += np.random.normal(
                    scale=np.sqrt(self.noise_variance),
                    size=right - left)
            elif self.noise_type == "heteroscedastic":
                noise_variance = self.noise_variance(
                    axes_manager=self.signal.axes_manager)[left:right]
                noise = [np.random.normal(scale=np.sqrt(item))
                         for item in noise_variance]
                data[left:right] += noise
            else:
                data[left:right] = np.random.poisson(
                    np.clip(data[left:right], 0, np.inf))

        return data

    def span_selector_changed(self):
        if self.interpolated_line is None:
            return
        else:
            self.interpolated_line.update()

    def apply(self):
        self.signal()[:] = self.get_interpolated_spectrum()
        self.update_spectrum_line()
        self.interpolated_line.close()
        self.interpolated_line = None
        self.reset_span_selector()
        self.find()
Esempio n. 21
0
class CSVFile(tr.HasStrictTraits):
    path = tr.Str
    count_lines = tr.Button
    _lines_number = tr.Int  # _ is the private field convention
    show_lines_number = tr.Bool
    num_of_first_lines_to_show = tr.Int(10)
    num_of_last_lines_to_show = tr.Int(10)

    first_lines = tr.Property(
        depends_on='path, num_of_first_lines_to_show, first_lines_to_skip')
    last_lines = tr.Property(
        depends_on='path, num_of_last_lines_to_show, last_lines_to_skip')
    first_lines_to_skip = tr.Range(low=0, high=10**9, mode='spinner')
    last_lines_to_skip = tr.Range(low=0, high=10**9, mode='spinner')

    def _count_lines_fired(self):
        #         return sum(1 for line in open(self.path))
        self.show_lines_number = True
        self._lines_number = self._count_lines_in_file(self.path)

    def get_lines_number(self):
        # If it was not yet calculated, calc it first
        if self._lines_number == 0:
            self._lines_number = self._count_lines_in_file(self.path)
        return self._lines_number

    def _count_lines_in_file(self, file_name):
        ''' This method will count the number of lines in a huge file pretty
        quickly using custom buffering'''
        f = open(file_name, 'rb')
        bufgen = takewhile(lambda x: x,
                           (f.raw.read(1024 * 1024) for i in repeat(None)))
        return sum(buf.count(b'\n') for buf in bufgen) + 1

    @tr.cached_property
    def _get_first_lines(self):
        first_lines_list = []
        with open(self.path) as myfile:
            for i in range(self.num_of_first_lines_to_show):
                try:
                    # Get next line if it exists!
                    line = next(myfile)
                    # The following will not executed if an exception was thrown
                    first_lines_list.append(line)
                except StopIteration:
                    # If last line ends with \n then a new empty line is
                    # actually there
                    if len(first_lines_list) != 0:
                        if first_lines_list[-1].endswith('\n'):
                            first_lines_list.append('')
                    break
        first_lines_list = self.add_line_numbers(first_lines_list)
        first_lines_list = first_lines_list[self.first_lines_to_skip:]
        first_lines_str = ''.join(first_lines_list)
        return first_lines_str

    def add_line_numbers(self, lines_list):
        new_list = []
        for line_num, line in zip(range(1, len(lines_list) + 1), lines_list):
            new_list.append('(' + str(line_num) + ')--> ' + str(line))
        return new_list

    def add_reverse_line_numbers(self, lines_list):
        new_list = []
        for line_num, line in zip(range(len(lines_list), 0, -1), lines_list):
            new_list.append('(' + str(line_num) + ')--> ' + str(line))
        return new_list

    @tr.cached_property
    def _get_last_lines(self):
        last_lines_list = self.get_last_n_lines(self.path,
                                                self.num_of_last_lines_to_show,
                                                False)
        last_lines_list = self.add_reverse_line_numbers(last_lines_list)
        last_lines_list = last_lines_list[0:len(last_lines_list) -
                                          self.last_lines_to_skip]
        last_lines_str = ''.join(last_lines_list)
        return last_lines_str

    def get_last_n_lines(self, file_name, N, skip_empty_lines=False):
        # Create an empty list to keep the track of last N lines
        list_of_lines = []
        # Open file for reading in binary mode
        with open(file_name, 'rb') as read_obj:
            # Move the cursor to the end of the file
            read_obj.seek(0, os.SEEK_END)
            # Create a buffer to keep the last read line
            buffer = bytearray()
            # Get the current position of pointer i.e eof
            pointer_location = read_obj.tell()
            # Loop till pointer reaches the top of the file
            while pointer_location >= 0:
                # Move the file pointer to the location pointed by pointer_location
                read_obj.seek(pointer_location)
                # Shift pointer location by -1
                pointer_location = pointer_location - 1
                # read that byte / character
                new_byte = read_obj.read(1)
                # If the read byte is new line character then it means one line is read
                if new_byte == b'\n':
                    # Save the line in list of lines
                    line = buffer.decode()[::-1]
                    if (skip_empty_lines):
                        line_is_empty = line.isspace()
                        if (line_is_empty == False):
                            list_of_lines.append(line)
                    else:
                        list_of_lines.append(line)
                    # If the size of list reaches N, then return the reversed list
                    if len(list_of_lines) == N:
                        return list(reversed(list_of_lines))
                    # Reinitialize the byte array to save next line
                    buffer = bytearray()
                else:
                    # If last read character is not eol then add it in buffer
                    buffer.extend(new_byte)

            # As file is read completely, if there is still data in buffer, then its first line.
            if len(buffer) > 0:
                list_of_lines.append(buffer.decode()[::-1])
        # return the reversed list
        return list(reversed(list_of_lines))

    traits_view = ui.View(
        ui.Item('path', style='readonly', label='File'),
        ui.HGroup(
            ui.UItem('count_lines'),
            ui.Item('_lines_number',
                    style='readonly',
                    visible_when='show_lines_number == True')),
        ui.VSplit(
            ui.HGroup(ui.Item('first_lines', style='custom'),
                      'first_lines_to_skip',
                      label='First lines in the file'),
            ui.HGroup(ui.Item('last_lines', style='custom'),
                      'last_lines_to_skip',
                      label='Last lines in the file')))
Esempio n. 22
0
class HCFT(tr.HasStrictTraits):
    """High-Cycle Fatigue Tool"""
    # =========================================================================
    # Traits definitions
    # =========================================================================
    # Assigning the view
    traits_view = hcft_window

    # CSV import
    decimal = tr.Enum(',', '.')
    delimiter = tr.Str(';')
    file_path = tr.File
    open_file_button = tr.Button('Open file')
    columns_headers = tr.List
    npy_folder_path = tr.Str
    file_name = tr.Str

    # CSV processing
    take_time_from_time_column = tr.Bool(True)
    records_per_second = tr.Float(100)
    time_column = tr.Enum(values='columns_headers')
    skip_first_rows = tr.Range(low=1, high=10**9, value=3, mode='spinner')
    add_columns_average = tr.Button
    columns_to_be_averaged = tr.List
    parse_csv_to_npy = tr.Button

    # Plotting
    x_axis = tr.Enum(values='columns_headers')
    y_axis = tr.Enum(values='columns_headers')
    x_axis_multiplier = tr.Enum(1, -1)
    y_axis_multiplier = tr.Enum(-1, 1)
    add_plot = tr.Button
    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
    add_creep_plot = tr.Button(desc='Creep plot of X axis array')
    clear_plot = tr.Button

    force_column = tr.Enum(values='columns_headers')
    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_ascending_branch_smoothing = tr.Bool(False, label='Activate')

    generate_filtered_and_creep_npy = 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')

    log = tr.Str('')
    clear_log = tr.Button

    # =========================================================================
    # Assigning default values
    # =========================================================================
    ax = tr.Any
    figure = tr.Instance(mpl.figure.Figure)

    def _figure_default(self):
        figure = mpl.figure.Figure(facecolor='white')
        figure.set_tight_layout(True)
        self.create_axes(figure)
        return figure

    def create_axes(self, figure):
        self.ax = figure.add_subplot(1, 1, 1)

    # =========================================================================
    # File management
    # =========================================================================
    def _open_file_button_fired(self):
        try:
            self.reset()

            dialog = FileDialog(title='Select text file',
                                action='open',
                                default_path=self.file_path)
            result = dialog.open()

            # Test if the user opened a file to avoid throwing an exception if he doesn't
            if result == OK:
                self.file_path = dialog.path
            else:
                return

            # Populate headers list which fills the x-axis and y-axis with values automatically
            self.columns_headers = get_headers(self.file_path,
                                               decimal=self.decimal,
                                               delimiter=self.delimiter)

            # Saving file name and path and creating NPY folder
            dir_path = os.path.dirname(self.file_path)
            self.npy_folder_path = os.path.join(dir_path, 'NPY')
            if not os.path.exists(self.npy_folder_path):
                os.makedirs(self.npy_folder_path)

            self.file_name = os.path.splitext(os.path.basename(
                self.file_path))[0]

            self.import_data_json()

        except:
            self.log_exception()

    def _add_columns_average_fired(self):
        try:
            columns_average = ColumnsAverage()
            for name in self.columns_headers:
                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_suffix = self.get_suffix_for_columns_to_be_averaged(
                    columns_to_be_averaged_temp)
                self.columns_headers.append(avg_file_suffix)
        except:
            self.log_exception()

    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...')
            self.export_data_json()
            """ Exporting npy arrays of original columns """
            for i in range(
                    len(self.columns_headers) -
                    len(self.columns_to_be_averaged)):
                column_name = self.columns_headers[i]
                # One could provide the path directly to pd.read_csv but in this way we insure that this works also if the
                # path to the file include chars like ü,ä
                # (with) makes sure the file stream is closed after using it
                with open(self.file_path, encoding='utf-8') as file_stream:
                    column_array = np.array(
                        pd.read_csv(file_stream,
                                    delimiter=self.delimiter,
                                    decimal=self.decimal,
                                    skiprows=self.skip_first_rows,
                                    usecols=[i]))

                # TODO detect column name before loading completely to skip loading if the following condition applies
                if column_name == self.time_column and self.take_time_from_time_column is 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(self.get_npy_file_path(column_name), column_array)
            """ Exporting npy arrays of averaged columns """
            for columns_names in self.columns_to_be_averaged:
                temp_array = np.zeros((1))
                for column_name in columns_names:
                    temp_array = temp_array + np.load(
                        self.get_npy_file_path(column_name)).flatten()
                avg = temp_array / len(columns_names)

                np.save(self.get_average_npy_file_path(columns_names), avg)

            self.print_custom('Finished parsing csv into npy files.')
        except:
            self.log_exception()

    def get_npy_file_path(self, column_name):
        return os.path.join(self.npy_folder_path,
                            self.file_name + '_' + column_name + '.npy')

    def get_filtered_npy_file_path(self, column_name):
        return os.path.join(
            self.npy_folder_path,
            self.file_name + '_' + column_name + '_filtered.npy')

    def get_max_npy_file_path(self, column_name):
        return os.path.join(self.npy_folder_path,
                            self.file_name + '_' + column_name + '_max.npy')

    def get_min_npy_file_path(self, column_name):
        return os.path.join(self.npy_folder_path,
                            self.file_name + '_' + column_name + '_min.npy')

    def get_average_npy_file_path(self, columns_names):
        avg_file_suffix = self.get_suffix_for_columns_to_be_averaged(
            columns_names)
        return os.path.join(self.npy_folder_path,
                            self.file_name + '_' + avg_file_suffix + '.npy')

    def get_suffix_for_columns_to_be_averaged(self, columns_names):
        suffix_for_saved_file_name = 'avg_' + '_'.join(columns_names)
        return suffix_for_saved_file_name

    def export_data_json(self):
        # Output data MUST have exactly similar keys and variable names
        output_data = {
            'take_time_from_time_column': self.take_time_from_time_column,
            'time_column': self.time_column,
            'records_per_second': self.records_per_second,
            'skip_first_rows': self.skip_first_rows,
            'columns_headers': self.columns_headers,
            'columns_to_be_averaged': self.columns_to_be_averaged,
            'x_axis': self.x_axis,
            'y_axis': self.y_axis,
            'x_axis_multiplier': self.x_axis_multiplier,
            'y_axis_multiplier': self.y_axis_multiplier,
            'force_column': self.force_column,
            'window_length': self.window_length,
            'polynomial_order': self.polynomial_order,
            'peak_force_before_cycles': self.peak_force_before_cycles,
            'cutting_method': self.cutting_method,
            'force_max': self.force_max,
            'force_min': self.force_min,
            'min_cycle_force_range': self.min_cycle_force_range
        }
        with open(self.get_json_file_path(), 'w') as outfile:
            json.dump(output_data, outfile, sort_keys=True, indent=4)
        self.print_custom('.json data file exported successfully.')

    def import_data_json(self):
        json_path = self.get_json_file_path()
        if not os.path.isfile(json_path):
            return
        # class_vars is a list with class variables names
        # vars(self) & self.__dict__.items() didn't include some Trait variables like force_column = tr.Enum(values=..
        class_vars = [
            attr for attr in dir(self)
            if not attr.startswith("_") and not attr.startswith("__")
        ]
        with open(json_path) as infile:
            data_in = json.load(infile)
        for key_data, value_data in data_in.items():
            for key_class in class_vars:
                if key_data == key_class:
                    # Equivalent to: self.key_class = value_data
                    setattr(self, key_class, value_data)
                    break
        self.print_custom('.json data file imported successfully.')

    def get_json_file_path(self):
        return os.path.join(self.npy_folder_path, self.file_name + '.json')

    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:
            self.export_data_json()
            if not self.npy_files_exist(
                    self.get_npy_file_path(self.force_column)):
                return
            self.print_custom('Generating filtered and creep files...')

            # 1- Export filtered force
            force = np.load(self.get_npy_file_path(
                self.force_column)).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(self.get_filtered_npy_file_path(self.force_column),
                    force_filtered)

            # 2- Export filtered displacements
            # Export displacements combining processed ascending branch and unprocessed min/max values
            self.export_filtered_displacements(force_max_min_indices,
                                               peak_force_before_cycles_index)

            # 3- Export creep for displacements
            # Cut unwanted max min values to get correct full cycles and remove false min/max values caused by noise
            self.export_displacements_creep(force_rest, force_max_indices,
                                            force_min_indices,
                                            peak_force_before_cycles_index)

            self.print_custom('Filtered and creep npy files are generated.')
        except:
            self.log_exception()

    def export_filtered_displacements(self, force_max_min_indices,
                                      peak_force_before_cycles_index):
        for i in range(len(self.columns_headers)):
            if self.columns_headers[
                    i] != self.force_column and self.columns_headers[
                        i] != self.time_column:

                disp = np.load(self.get_npy_file_path(
                    self.columns_headers[i])).flatten()
                disp_ascending = disp[0:peak_force_before_cycles_index]
                disp_rest = disp[peak_force_before_cycles_index:]

                if self.activate_ascending_branch_smoothing:
                    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(
                    self.get_filtered_npy_file_path(self.columns_headers[i]),
                    filtered_disp)

    def export_displacements_creep(self, force_rest, force_max_indices,
                                   force_min_indices,
                                   peak_force_before_cycles_index):
        if self.cutting_method == "Define Max, Min":
            force_max_indices_cut, force_min_indices_cut = 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_cut, force_min_indices_cut = 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_cut))

        for i in range(len(self.columns_headers)):
            if self.columns_headers[i] != self.time_column:
                array = np.load(self.get_npy_file_path(
                    self.columns_headers[i])).flatten()
                array_rest = array[peak_force_before_cycles_index:]
                array_rest_maxima = array_rest[force_max_indices_cut]
                array_rest_minima = array_rest[force_min_indices_cut]
                np.save(self.get_max_npy_file_path(self.columns_headers[i]),
                        array_rest_maxima)
                np.save(self.get_min_npy_file_path(self.columns_headers[i]),
                        array_rest_minima)

    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):
        # TODO try to vectorize this
        # 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

            # Append value if it's a local max
            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):
        # TODO try to vectorize this
        # 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

            # Append value if it's a local min
            if a[i] < a[i + 1] and a[i] < previous_element:
                min_indices.append(i)
            i += 1
        return np.array(min_indices)

    def cut_indices_of_min_max_range(self, array, max_indices, min_indices,
                                     range_upper_value, range_lower_value):
        # TODO try to vectorize this
        cut_max_indices = []
        cut_min_indices = []

        for max_index in max_indices:
            if abs(array[max_index]) > abs(range_upper_value):
                cut_max_indices.append(max_index)
        for min_index in min_indices:
            if abs(array[min_index]) < abs(range_lower_value):
                cut_min_indices.append(min_index)
        return cut_max_indices, cut_min_indices

    def cut_indices_of_defined_range(self, array, max_indices, min_indices,
                                     range_):
        # TODO try to vectorize this
        cut_max_indices = []
        cut_min_indices = []

        for max_index, min_index in zip(max_indices, min_indices):
            if abs(array[max_index] - array[min_index]) > range_:
                cut_max_indices.append(max_index)
                cut_min_indices.append(min_index)

        if max_indices.size > min_indices.size:
            cut_max_indices.append(max_indices[-1])
        elif min_indices.size > max_indices.size:
            cut_min_indices.append(min_indices[-1])

        return cut_max_indices, cut_min_indices

    def _activate_changed(self):
        if not self.activate_ascending_branch_smoothing:
            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
    # =========================================================================
    data_changed = tr.Event

    def _plot_settings_btn_fired(self):
        try:
            self.plot_settings.configure_traits(kind='modal')
        except:
            self.log_exception()

    def npy_files_exist(self, path):
        if os.path.exists(path):
            return True
        else:
            self.print_custom(
                'Please parse csv file to generate npy files first!')
            return False

    def filtered_and_creep_npy_files_exist(self, path):
        if os.path.exists(path):
            return True
        else:
            self.print_custom(
                'Please generate filtered and creep npy files first!')
            return False

    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 not self.filtered_and_creep_npy_files_exist(
                        self.get_filtered_npy_file_path(self.x_axis)):
                    return
                # TODO link this _filtered to the path creation function
                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(self.get_filtered_npy_file_path(
                    self.x_axis),
                                       mmap_mode='r')
                y_axis_array = np.load(self.get_filtered_npy_file_path(
                    self.y_axis),
                                       mmap_mode='r')
            else:
                if not self.npy_files_exist(self.get_npy_file_path(
                        self.x_axis)):
                    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(self.get_npy_file_path(self.x_axis),
                                       mmap_mode='r')
                y_axis_array = np.load(self.get_npy_file_path(self.y_axis),
                                       mmap_mode='r')

            if self.plot_settings_active:
                print(self.plot_settings.num_of_first_rows_to_take)
                print(
                    self.plot_settings.num_of_rows_to_skip_after_each_section)
                print(self.plot_settings.num_of_rows_in_each_section)
                print(np.size(x_axis_array))
                indices = self.get_indices_array(
                    np.size(x_axis_array),
                    self.plot_settings.num_of_first_rows_to_take,
                    self.plot_settings.num_of_rows_to_skip_after_each_section,
                    self.plot_settings.num_of_rows_in_each_section)
                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.ax

            ax.set_xlabel(x_axis_name)
            ax.set_ylabel(y_axis_name)
            ax.plot(x_axis_array,
                    y_axis_array,
                    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:
            self.log_exception()

    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 not self.filtered_and_creep_npy_files_exist(
                    self.get_max_npy_file_path(self.x_axis)):
                return

            self.print_custom('Loading npy files...')
            disp_max = self.x_axis_multiplier * np.load(
                self.get_max_npy_file_path(self.x_axis))
            disp_min = self.x_axis_multiplier * np.load(
                self.get_min_npy_file_path(self.x_axis))
            complete_cycles_number = disp_max.size

            self.print_custom('Adding creep-fatigue plot...')
            mpl.rcParams['agg.path.chunksize'] = 10000

            ax = self.ax

            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:
            self.log_exception()

    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 _clear_plot_fired(self):
        self.figure.clear()
        self.create_axes(self.figure)
        self.data_changed = True

    # =========================================================================
    # Logging
    # =========================================================================
    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 log_exception(self):
        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 = ''

    # =========================================================================
    # Other functions
    # =========================================================================
    def reset(self):
        self.columns_to_be_averaged = []
        self.log = ''
Esempio n. 23
0
class CSVJoiner(tr.HasStrictTraits):
    open_csv_files = tr.Button
    csv_files = tr.List(CSVFile)
    num_of_first_lines_to_show = tr.Range(low=0,
                                          high=10**9,
                                          value=10,
                                          mode='spinner')
    num_of_last_lines_to_show = tr.Range(low=0,
                                         high=10**9,
                                         value=10,
                                         mode='spinner')
    selected = tr.Instance(CSVFile)
    join_csv_files = tr.Button
    accumulate_time = tr.Bool
    files_end_with_empty_line = tr.Bool(True)
    columns_headers = tr.List
    time_column = tr.Enum(values='columns_headers')
    progress = tr.Int

    def _join_csv_files_fired(self):
        output_file_path = self.get_output_file_path()
        with open(output_file_path, 'w') as outfile:
            for csv_file, i in zip(self.csv_files, range(len(self.csv_files))):
                current_line = 1
                num_of_first_lines_to_skip = csv_file.first_lines_to_skip
                num_of_last_lines_to_skip = csv_file.last_lines_to_skip
                last_line_to_write = csv_file.get_lines_number(
                ) - num_of_last_lines_to_skip
                progress_of_a_file = 1.0 / len(self.csv_files)
                initial_progress = i / len(self.csv_files)
                with open(csv_file.path) as opened_csv_file:
                    for line in opened_csv_file:
                        if current_line > num_of_first_lines_to_skip and current_line <= last_line_to_write:
                            outfile.write(line)
                            self.progress = int(
                                (initial_progress + progress_of_a_file *
                                 (current_line / last_line_to_write)) * 100)
                        current_line += 1
                if not self.files_end_with_empty_line:
                    outfile.write('\n')
        self.progress = 100
        dialog = MessageDialog(title='Finished!',
                               message='Files joined successfully, see "' +
                               output_file_path + '"')
        dialog.open()

    def get_output_file_path(self):
        file_path = self.csv_files[0].path
        file_path_without_ext = os.path.splitext(file_path)[0]
        file_ext = os.path.splitext(file_path)[1]
        return file_path_without_ext + '_joined' + file_ext

    def _accumulate_time_changed(self):
        pass

    #         if self.csv_files == []:
    #             return
    #         np.array(pd.read_csv(
    #                     self.file_csv, delimiter=self.delimiter, decimal=self.decimal,
    #                     nrows=1, header=None
    #                 )
    #             )[0]
    #         if self.accumulate_time:
    #             class TimeColumnChooser(tr.HasTraits):
    #                 time_column = tr.Enum(values = 'columns_headers')
    #             chooser = TimeColumnChooser()
    #             chooser.configure_traits(kind='modal')

    def _num_of_first_lines_to_show_changed(self):
        for file in self.csv_files:
            file.num_of_first_lines_to_show = self.num_of_first_lines_to_show

    def _num_of_last_lines_to_show_changed(self):
        for file in self.csv_files:
            file.num_of_last_lines_to_show = self.num_of_last_lines_to_show

    def _open_csv_files_fired(self):
        extensions = ['*.csv', '*.txt']  # handle only one extension...
        wildcard = ';'.join(extensions)
        dialog = pf.FileDialog(title='Select csv files',
                               action='open files',
                               wildcard=wildcard,
                               default_path=os.path.expanduser("~"))
        result = dialog.open()

        csv_files_paths = []
        # Test if the user opened a file to avoid throwing an exception
        # if he doesn't
        if result == pf.OK:
            csv_files_paths = dialog.paths
        else:
            return

        self.csv_files = []
        for file_path in csv_files_paths:
            csv_file = CSVFile(
                path=file_path,
                num_of_first_lines_to_show=self.num_of_first_lines_to_show,
                num_of_last_lines_to_show=self.num_of_last_lines_to_show,
            )
            self.csv_files.append(csv_file)

    # =========================================================================
    # Configuration of the view
    # =========================================================================
    traits_view = ui.View(
        ui.VGroup(
            ui.UItem('open_csv_files', width=150),
            ui.HGroup(ui.Item('num_of_first_lines_to_show'), ui.spring),
            ui.HGroup(ui.Item('num_of_last_lines_to_show'), ui.spring),
            ui.HGroup(
                ui.Item('files_end_with_empty_line'),
                # ui.Item('accumulate_time', enabled_when='False'),
                ui.spring),
            ui.VGroup(
                ui.Item('csv_files',
                        show_label=False,
                        style='custom',
                        editor=ui.ListEditor(use_notebook=True,
                                             deletable=False,
                                             selected='selected',
                                             export='DockWindowShell',
                                             page_name='.name'))),
            ui.HGroup(
                ui.UItem('join_csv_files', width=150),
                ui.UItem('progress', editor=ProgressEditor(min=0, max=100))),
            show_border=True),
        title='CSV files joiner',
        resizable=True,
        width=0.6,
        height=0.7)
Esempio n. 24
0
class SpikesRemoval(SpanSelectorInSpectrum):
    interpolator_kind = t.Enum(
        'Linear',
        'Spline',
        default = 'Linear')
    threshold = t.Float()
    show_derivative_histogram = t.Button()
    spline_order = t.Range(1,10, 3)
    interpolator = None
    default_spike_width = t.Int(5)
    index = t.Int(0)
    view = tu.View(tu.Group(
        tu.Group(
                 tu.Item('show_derivative_histogram', show_label=False),
                 'threshold',
                 show_border=True,),
        tu.Group(
            'interpolator_kind',
            'default_spike_width',
            tu.Group(
                'spline_order', 
                visible_when = 'interpolator_kind == \'Spline\''),
            show_border=True,
            label='Advanced settings'),
            ),
            buttons= [OKButton,
                      OurPreviousButton,
                      OurFindButton,
                      OurApplyButton,],
            handler = SpikesRemovalHandler,
            title = 'Spikes removal tool')
                 
    def __init__(self, signal,navigation_mask=None, signal_mask=None):
        super(SpikesRemoval, self).__init__(signal)
        self.interpolated_line = None
        self.coordinates = [coordinate for coordinate in 
                            signal.axes_manager._am_indices_generator()
                            if (navigation_mask is None or not 
                                navigation_mask[coordinate[::-1]])]
        self.signal = signal
        sys.setrecursionlimit(np.cumprod(self.signal.data.shape)[-1])
        self.line = signal._plot.signal_plot.ax_lines[0]
        self.ax = signal._plot.signal_plot.ax
        signal._plot.auto_update_plot = False
        signal.axes_manager.indices = self.coordinates[0]
        self.threshold = 400
        self.index = 0
        self.argmax = None
        self.kind = "linear"
        self._temp_mask = np.zeros(self.signal().shape, dtype='bool')
        self.signal_mask = signal_mask
        self.navigation_mask = navigation_mask
        
    def _threshold_changed(self, old, new):
        self.index = 0
        self.update_plot()
        
    def _show_derivative_histogram_fired(self):
        self.signal._spikes_diagnosis(signal_mask=self.signal_mask,
                                navigation_mask=self.navigation_mask)
        
    def detect_spike(self):
        derivative = np.diff(self.signal())
        if self.signal_mask is not None:
            derivative[self.signal_mask[:-1]] = 0
        if self.argmax is not None:
            left, right = self.get_interpolation_range()
            self._temp_mask[left:right] = True
            derivative[self._temp_mask[:-1]] = 0
        if abs(derivative.max()) >= self.threshold:
            self.argmax = derivative.argmax()
            return True
        else:
            return False

    def find(self, back=False):
        if ((self.index == len(self.coordinates) - 1 and back is False)
        or (back is True and self.index == 0)):
            messages.information('End of dataset reached')
            return
        if self.interpolated_line is not None:
            self.interpolated_line.close()
            self.interpolated_line = None
            self.reset_span_selector()
        
        if self.detect_spike() is False:
            if back is False:
                self.index += 1
            else:
                self.index -= 1
            self.find(back=back)
        else:
            minimum = max(0,self.argmax - 50)
            maximum = min(len(self.signal()) - 1, self.argmax + 50)
            self.ax.set_xlim(
                self.signal.axes_manager.signal_axes[0].index2value(
                    minimum),
                self.signal.axes_manager.signal_axes[0].index2value(
                    maximum))
            self.update_plot()
            self.create_interpolation_line()

    def update_plot(self):
        if self.interpolated_line is not None:
            self.interpolated_line.close()
            self.interpolated_line = None
        self.reset_span_selector()
        self.update_spectrum_line()
        self.signal._plot.pointer.update_patch_position()
        
    def update_spectrum_line(self):
        self.line.auto_update = True
        self.line.update()
        self.line.auto_update = False
        
    def _index_changed(self, old, new):
        self.signal.axes_manager.indices = self.coordinates[new]
        self.argmax = None
        self._temp_mask[:] = False
        
    def on_disabling_span_selector(self):
        if self.interpolated_line is not None:
            self.interpolated_line.close()
            self.interpolated_line = None
           
    def _spline_order_changed(self, old, new):
        self.kind = self.spline_order
        self.span_selector_changed()
            
    def _interpolator_kind_changed(self, old, new):
        if new == 'linear':
            self.kind = new
        else:
            self.kind = self.spline_order
        self.span_selector_changed()
        
    def _ss_left_value_changed(self, old, new):
        self.span_selector_changed()
        
    def _ss_right_value_changed(self, old, new):
        self.span_selector_changed()
        
    def create_interpolation_line(self):
        self.interpolated_line = drawing.spectrum.SpectrumLine()
        self.interpolated_line.data_function = \
            self.get_interpolated_spectrum
        self.interpolated_line.set_line_properties(
            color='blue',
            type='line')
        self.signal._plot.signal_plot.add_line(self.interpolated_line)
        self.interpolated_line.autoscale = False
        self.interpolated_line.plot()
        
    def get_interpolation_range(self):
        axis = self.signal.axes_manager.signal_axes[0]
        if self.ss_left_value == self.ss_right_value:
            left = self.argmax - self.default_spike_width
            right = self.argmax + self.default_spike_width
        else:
            left = axis.value2index(self.ss_left_value)
            right = axis.value2index(self.ss_right_value)
        
        # Clip to the axis dimensions
        nchannels = self.signal.axes_manager.signal_shape[0]
        left = left if left >= 0 else 0
        right = right if right < nchannels else nchannels - 1
            
        return left,right
        
        
    def get_interpolated_spectrum(self, axes_manager=None):
        data = self.signal().copy()
        axis = self.signal.axes_manager.signal_axes[0]
        left, right = self.get_interpolation_range()
        if self.kind == 'linear':
            pad = 1
        else:
            pad = 10
        ileft = left - pad
        iright = right + pad
        ileft = np.clip(ileft, 0, len(data))
        iright = np.clip(iright, 0, len(data))
        left = np.clip(left, 0, len(data))
        right = np.clip(right, 0, len(data))
        x = np.hstack((axis.axis[ileft:left], axis.axis[right:iright]))
        y = np.hstack((data[ileft:left], data[right:iright]))
        if ileft == 0:
            # Extrapolate to the left
            data[left:right] = data[right + 1]
            
        elif iright == (len(data) - 1):
            # Extrapolate to the right
            data[left:right] = data[left - 1]
            
        else:
            # Interpolate
            intp = sp.interpolate.interp1d(x, y, kind=self.kind)
            data[left:right] = intp(axis.axis[left:right])
        
        # Add noise
        data = np.random.poisson(np.clip(data, 0, np.inf))
        return data

                      
    def span_selector_changed(self):
        if self.interpolated_line is None:
            return
        else:
            self.interpolated_line.update()
            
    def apply(self):
        self.signal()[:] = self.get_interpolated_spectrum()
        self.update_spectrum_line()
        self.interpolated_line.close()
        self.interpolated_line = None
        self.reset_span_selector()
        self.find()
Esempio n. 25
0
class DataAxis(t.HasTraits):
    name = t.Str()
    units = t.Str()
    scale = t.Float()
    offset = t.Float()
    size = t.CInt()
    low_value = t.Float()
    high_value = t.Float()
    value = t.Range('low_value', 'high_value')
    low_index = t.Int(0)
    high_index = t.Int()
    slice = t.Instance(slice)
    navigate = t.Bool(t.Undefined)
    index = t.Range('low_index', 'high_index')
    axis = t.Array()
    continuous_value = t.Bool(False)

    def __init__(self,
                 size,
                 index_in_array=None,
                 name=t.Undefined,
                 scale=1.,
                 offset=0.,
                 units=t.Undefined,
                 navigate=t.Undefined):
        super(DataAxis, self).__init__()
        self.name = name
        self.units = units
        self.scale = scale
        self.offset = offset
        self.size = size
        self.high_index = self.size - 1
        self.low_index = 0
        self.index = 0
        self.update_axis()
        self.navigate = navigate
        self.axes_manager = None
        self.on_trait_change(self.update_axis,
                             ['scale', 'offset', 'size'])
        self.on_trait_change(self.update_value, 'index')
        self.on_trait_change(self.set_index_from_value, 'value')
        self.on_trait_change(self._update_slice, 'navigate')
        self.on_trait_change(self.update_index_bounds, 'size')
        # The slice must be updated even if the default value did not
        # change to correctly set its value.
        self._update_slice(self.navigate)

    @property
    def index_in_array(self):
        if self.axes_manager is not None:
            return self.axes_manager._axes.index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    @property
    def index_in_axes_manager(self):
        if self.axes_manager is not None:
            return self.axes_manager._get_axes_in_natural_order().\
                index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    def _get_positive_index(self, index):
        if index < 0:
            index = self.size + index
            if index < 0:
                raise IndexError("index out of bounds")
        return index

    def _get_index(self, value):
        if isfloat(value):
            return self.value2index(value)
        else:
            return value

    def _get_array_slices(self, slice_):
        """Returns a slice to slice the corresponding data axis without
        changing the offset and scale of the DataAxis.

        Parameters
        ----------
        slice_ : {float, int, slice}

        Returns
        -------
        my_slice : slice

        """
        v2i = self.value2index

        if isinstance(slice_, slice):
            start = slice_.start
            stop = slice_.stop
            step = slice_.step
        else:
            if isfloat(slice_):
                start = v2i(slice_)
            else:
                start = self._get_positive_index(slice_)
            stop = start + 1
            step = None

        if isfloat(step):
            step = int(round(step / self.scale))
        if isfloat(start):
            try:
                start = v2i(start)
            except ValueError:
                # The value is below the axis limits
                # we slice from the start.
                start = None
        if isfloat(stop):
            try:
                stop = v2i(stop)
            except ValueError:
                # The value is above the axes limits
                # we slice up to the end.
                stop = None

        if step == 0:
            raise ValueError("slice step cannot be zero")

        return slice(start, stop, step)

    def _slice_me(self, slice_):
        """Returns a slice to slice the corresponding data axis and
        change the offset and scale of the DataAxis acordingly.

        Parameters
        ----------
        slice_ : {float, int, slice}

        Returns
        -------
        my_slice : slice

        """
        i2v = self.index2value

        my_slice = self._get_array_slices(slice_)

        start, stop, step = my_slice.start, my_slice.stop, my_slice.step

        if start is None:
            if step > 0 or step is None:
                start = 0
            else:
                start = self.size - 1
        self.offset = i2v(start)
        if step is not None:
            self.scale *= step

        return my_slice

    def _get_name(self):
        if self.name is t.Undefined:
            if self.axes_manager is None:
                name = "Unnamed"
            else:
                name = "Unnamed " + ordinal(self.index_in_axes_manager)
        else:
            name = self.name
        return name

    def __repr__(self):
        text = '<%s axis, size: %i' % (self._get_name(),
                                       self.size,)
        if self.navigate is True:
            text += ", index: %i" % self.index
        text += ">"
        return text.encode('utf8')

    def __str__(self):
        return self._get_name() + " axis"

    def connect(self, f, trait='value'):
        self.on_trait_change(f, trait)

    def disconnect(self, f, trait='value'):
        self.on_trait_change(f, trait, remove=True)

    def update_index_bounds(self):
        self.high_index = self.size - 1

    def update_axis(self):
        self.axis = generate_axis(self.offset, self.scale, self.size)
        if len(self.axis) != 0:
            self.low_value, self.high_value = (
                self.axis.min(), self.axis.max())

    def _update_slice(self, value):
        if value is False:
            self.slice = slice(None)
        else:
            self.slice = None

    def get_axis_dictionary(self):
        adict = {
            'name': self.name,
            'scale': self.scale,
            'offset': self.offset,
            'size': self.size,
            'units': self.units,
            'navigate': self.navigate
        }
        return adict

    def copy(self):
        return DataAxis(**self.get_axis_dictionary())

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo):
        cp = self.copy()
        return cp

    def update_value(self):
        self.value = self.axis[self.index]

    def value2index(self, value, rounding=round):
        """Return the closest index to the given value if between the limit.

        Parameters
        ----------
        value : number or numpy array

        Returns
        -------
        index : integer or numpy array

        Raises
        ------
        ValueError if any value is out of the axis limits.

        """
        if value is None:
            return None

        if isinstance(value, np.ndarray):
            if rounding is round:
                rounding = np.round
            elif rounding is math.ceil:
                rounding = np.ceil
            elif rounding is math.floor:
                rounding = np.floor

        index = rounding((value - self.offset) / self.scale)

        if isinstance(value, np.ndarray):
            index = index.astype(int)
            if np.all(self.size > index) and np.all(index >= 0):
                return index
            else:
                raise ValueError("A value is out of the axis limits")
        else:
            index = int(index)
            if self.size > index >= 0:
                return index
            else:
                raise ValueError("The value is out of the axis limits")

    def index2value(self, index):
        if isinstance(index, np.ndarray):
            return self.axis[index.ravel()].reshape(index.shape)
        else:
            return self.axis[index]

    def set_index_from_value(self, value):
        self.index = self.value2index(value)
        # If the value is above the limits we must correct the value
        if self.continuous_value is False:
            self.value = self.index2value(self.index)

    def calibrate(self, value_tuple, index_tuple, modify_calibration=True):
        scale = (value_tuple[1] - value_tuple[0]) /\
            (index_tuple[1] - index_tuple[0])
        offset = value_tuple[0] - scale * index_tuple[0]
        if modify_calibration is True:
            self.offset = offset
            self.scale = scale
        else:
            return offset, scale

    def value_range_to_indices(self, v1, v2):
        """Convert the given range to index range.

        When an out of the axis limits, the endpoint is used instead.

        Parameters
        ----------
        v1, v2 : float
            The end points of the interval in the axis units. v2 must be
            greater than v1.

        """
        if v1 > v2:
            raise ValueError("v2 must be greater than v1.")

        if v1 is not None and v1 > self.low_value and v1 <= self.high_value:
            i1 = self.value2index(v1)
        else:
            i1 = 0
        if v2 is not None and v2 < self.high_value and v2 >= self.low_value:
            i2 = self.value2index(v2)
        else:
            i2 = self.size - 1
        return i1, i2
Esempio n. 26
0
class BackgroundRemoval(SpanSelectorInSpectrum):
    background_type = t.Enum('Power Law',
                             'Gaussian',
                             'Offset',
                             'Polynomial',
                             default='Power Law')
    polynomial_order = t.Range(1, 10)
    background_estimator = t.Instance(Component)
    bg_line_range = t.Enum('from_left_range',
                           'full',
                           'ss_range',
                           default='full')
    hi = t.Int(0)
    view = tu.View(tu.Group(
        'background_type',
        tu.Group('polynomial_order',
                 visible_when='background_type == \'Polynomial\''),
    ),
                   buttons=[OKButton, CancelButton],
                   handler=SpanSelectorInSpectrumHandler,
                   title='Background removal tool')

    def __init__(self, signal):
        super(BackgroundRemoval, self).__init__(signal)
        self.set_background_estimator()
        self.bg_line = None

    def on_disabling_span_selector(self):
        if self.bg_line is not None:
            self.bg_line.close()
            self.bg_line = None

    def set_background_estimator(self):

        if self.background_type == 'Power Law':
            self.background_estimator = components.PowerLaw()
            self.bg_line_range = 'from_left_range'
        elif self.background_type == 'Gaussian':
            self.background_estimator = components.Gaussian()
            self.bg_line_range = 'full'
        elif self.background_type == 'Offset':
            self.background_estimator = components.Offset()
            self.bg_line_range = 'full'
        elif self.background_type == 'Polynomial':
            self.background_estimator = \
                components.Polynomial(self.polynomial_order)
            self.bg_line_range = 'full'

    def _polynomial_order_changed(self, old, new):
        self.background_estimator = components.Polynomial(new)
        self.span_selector_changed()

    def _background_type_changed(self, old, new):
        self.set_background_estimator()
        self.span_selector_changed()

    def _ss_left_value_changed(self, old, new):
        self.span_selector_changed()

    def _ss_right_value_changed(self, old, new):
        self.span_selector_changed()

    def create_background_line(self):
        self.bg_line = drawing.spectrum.SpectrumLine()
        self.bg_line.data_function = self.bg_to_plot
        self.bg_line.set_line_properties(color='blue', type='line')
        self.signal._plot.signal_plot.add_line(self.bg_line)
        self.bg_line.autoscale = False
        self.bg_line.plot()

    def bg_to_plot(self, axes_manager=None, fill_with=np.nan):
        # First try to update the estimation
        self.background_estimator.estimate_parameters(self.signal,
                                                      self.ss_left_value,
                                                      self.ss_right_value,
                                                      only_current=True)

        if self.bg_line_range == 'from_left_range':
            bg_array = np.zeros(self.axis.axis.shape)
            bg_array[:] = fill_with
            from_index = self.axis.value2index(self.ss_left_value)
            bg_array[from_index:] = self.background_estimator.function(
                self.axis.axis[from_index:])
            return bg_array
        elif self.bg_line_range == 'full':
            return self.background_estimator.function(self.axis.axis)
        elif self.bg_line_range == 'ss_range':
            bg_array = np.zeros(self.axis.axis.shape)
            bg_array[:] = fill_with
            from_index = self.axis.value2index(self.ss_left_value)
            to_index = self.axis.value2index(self.ss_right_value)
            bg_array[from_index:] = self.background_estimator.function(
                self.axis.axis[from_index:to_index])

    def span_selector_changed(self):
        if self.background_estimator is None:
            print("No bg estimator")
            return
        if self.bg_line is None and \
            self.background_estimator.estimate_parameters(
                self.signal, self.ss_left_value, self.ss_right_value,
                only_current = True) is True:
            self.create_background_line()
        else:
            self.bg_line.update()

    def apply(self):
        self.signal._plot.auto_update_plot = False
        maxval = self.signal.axes_manager.navigation_size
        if maxval > 0:
            pbar = progressbar(maxval=maxval)
        i = 0
        self.bg_line_range = 'full'
        for s in self.signal:
            s.data[:] -= \
            np.nan_to_num(self.bg_to_plot(self.signal.axes_manager,
                                          0))
            if self.background_type == 'Power Law':
                s.data[:self.axis.value2index(self.ss_right_value)] = 0

            i += 1
            if maxval > 0:
                pbar.update(i)
        if maxval > 0:
            pbar.finish()

        self.signal._replot()
        self.signal._plot.auto_update_plot = True
Esempio n. 27
0
class SpikesRemoval(SpanSelectorInSignal1D):
    interpolator_kind = t.Enum(
        'Linear',
        'Spline',
        default='Linear',
        desc="the type of interpolation to use when\n"
        "replacing the signal where a spike has been replaced")
    threshold = t.Float(desc="the derivative magnitude threshold above\n"
                        "which to find spikes")
    click_to_show_instructions = t.Button()
    show_derivative_histogram = t.Button()
    spline_order = t.Range(1,
                           10,
                           3,
                           desc="the order of the spline used to\n"
                           "connect the reconstructed data")
    interpolator = None
    default_spike_width = t.Int(
        5,
        desc="the width over which to do the interpolation\n"
        "when removing a spike (this can be "
        "adjusted for each\nspike by clicking "
        "and dragging on the display during\n"
        "spike replacement)")
    index = t.Int(0)
    add_noise = t.Bool(True,
                       desc="whether to add noise to the interpolated\nportion"
                       "of the spectrum. The noise properties defined\n"
                       "in the Signal metadata are used if present,"
                       "otherwise\nshot noise is used as a default")

    thisOKButton = tu.Action(name="OK",
                             action="OK",
                             tooltip="Close the spikes removal tool")

    thisApplyButton = tu.Action(name="Remove spike",
                                action="apply",
                                tooltip="Remove the current spike by "
                                "interpolating\n"
                                "with the specified settings (and find\n"
                                "the next spike automatically)")
    thisFindButton = tu.Action(
        name="Find next",
        action="find",
        tooltip="Find the next (in terms of navigation\n"
        "dimensions) spike in the data.")

    thisPreviousButton = tu.Action(name="Find previous",
                                   action="back",
                                   tooltip="Find the previous (in terms of "
                                   "navigation\n"
                                   "dimensions) spike in the data.")
    view = tu.View(
        tu.Group(
            tu.Group(
                tu.Item(
                    'click_to_show_instructions',
                    show_label=False,
                ),
                tu.Item('show_derivative_histogram',
                        show_label=False,
                        tooltip="To determine the appropriate threshold,\n"
                        "plot the derivative magnitude histogram, \n"
                        "and look for outliers at high magnitudes \n"
                        "(which represent sudden spikes in the data)"),
                'threshold',
                show_border=True,
            ),
            tu.Group('add_noise',
                     'interpolator_kind',
                     'default_spike_width',
                     tu.Group('spline_order',
                              enabled_when='interpolator_kind == \'Spline\''),
                     show_border=True,
                     label='Advanced settings'),
        ),
        buttons=[
            thisOKButton,
            thisPreviousButton,
            thisFindButton,
            thisApplyButton,
        ],
        handler=SpikesRemovalHandler,
        title='Spikes removal tool',
        resizable=False,
    )

    def __init__(self, signal, navigation_mask=None, signal_mask=None):
        super(SpikesRemoval, self).__init__(signal)
        self.interpolated_line = None
        self.coordinates = [
            coordinate
            for coordinate in signal.axes_manager._am_indices_generator() if
            (navigation_mask is None or not navigation_mask[coordinate[::-1]])
        ]
        self.signal = signal
        self.line = signal._plot.signal_plot.ax_lines[0]
        self.ax = signal._plot.signal_plot.ax
        signal._plot.auto_update_plot = False
        if len(self.coordinates) > 1:
            signal.axes_manager.indices = self.coordinates[0]
        self.threshold = 400
        self.index = 0
        self.argmax = None
        self.derivmax = None
        self.kind = "linear"
        self._temp_mask = np.zeros(self.signal().shape, dtype='bool')
        self.signal_mask = signal_mask
        self.navigation_mask = navigation_mask
        md = self.signal.metadata
        from hyperspy.signal import BaseSignal

        if "Signal.Noise_properties" in md:
            if "Signal.Noise_properties.variance" in md:
                self.noise_variance = md.Signal.Noise_properties.variance
                if isinstance(md.Signal.Noise_properties.variance, BaseSignal):
                    self.noise_type = "heteroscedastic"
                else:
                    self.noise_type = "white"
            else:
                self.noise_type = "shot noise"
        else:
            self.noise_type = "shot noise"

    def _threshold_changed(self, old, new):
        self.index = 0
        self.update_plot()

    def _click_to_show_instructions_fired(self):
        m = information(None, "\nTo remove spikes from the data:\n\n"
                        "   1. Click \"Show derivative histogram\" to "
                        "determine at what magnitude the spikes are present.\n"
                        "   2. Enter a suitable threshold (lower than the "
                        "lowest magnitude outlier in the histogram) in the "
                        "\"Threshold\" box, which will be the magnitude "
                        "from which to search. \n"
                        "   3. Click \"Find next\" to find the first spike.\n"
                        "   4. If desired, the width and position of the "
                        "boundaries used to replace the spike can be "
                        "adjusted by clicking and dragging on the displayed "
                        "plot.\n "
                        "   5. View the spike (and the replacement data that "
                        "will be added) and click \"Remove spike\" in order "
                        "to alter the data as shown. The tool will "
                        "automatically find the next spike to replace.\n"
                        "   6. Repeat this process for each spike throughout "
                        "the dataset, until the end of the dataset is "
                        "reached.\n"
                        "   7. Click \"OK\" when finished to close the spikes "
                        "removal tool.\n\n"
                        "Note: Various settings can be configured in "
                        "the \"Advanced settings\" section. Hover the "
                        "mouse over each parameter for a description of what "
                        "it does."
                        "\n",
                        title="Instructions"),

    def _show_derivative_histogram_fired(self):
        self.signal._spikes_diagnosis(signal_mask=self.signal_mask,
                                      navigation_mask=self.navigation_mask)

    def detect_spike(self):
        derivative = np.diff(self.signal())
        if self.signal_mask is not None:
            derivative[self.signal_mask[:-1]] = 0
        if self.argmax is not None:
            left, right = self.get_interpolation_range()
            self._temp_mask[left:right] = True
            derivative[self._temp_mask[:-1]] = 0
        if abs(derivative.max()) >= self.threshold:
            self.argmax = derivative.argmax()
            self.derivmax = abs(derivative.max())
            return True
        else:
            return False

    def _reset_line(self):
        if self.interpolated_line is not None:
            self.interpolated_line.close()
            self.interpolated_line = None
            self.reset_span_selector()

    def find(self, back=False):
        self._reset_line()
        ncoordinates = len(self.coordinates)
        spike = self.detect_spike()
        while not spike and ((self.index < ncoordinates - 1 and back is False)
                             or (self.index > 0 and back is True)):
            if back is False:
                self.index += 1
            else:
                self.index -= 1
            spike = self.detect_spike()

        if spike is False:
            messages.information('End of dataset reached')
            self.index = 0
            self._reset_line()
            return
        else:
            minimum = max(0, self.argmax - 50)
            maximum = min(len(self.signal()) - 1, self.argmax + 50)
            thresh_label = DerivativeTextParameters(
                text="$\mathsf{\delta}_\mathsf{max}=$", color="black")
            self.ax.legend([thresh_label], [repr(int(self.derivmax))],
                           handler_map={
                               DerivativeTextParameters:
                               DerivativeTextHandler()
                           },
                           loc='best')
            self.ax.set_xlim(
                self.signal.axes_manager.signal_axes[0].index2value(minimum),
                self.signal.axes_manager.signal_axes[0].index2value(maximum))
            self.update_plot()
            self.create_interpolation_line()

    def update_plot(self):
        if self.interpolated_line is not None:
            self.interpolated_line.close()
            self.interpolated_line = None
        self.reset_span_selector()
        self.update_spectrum_line()
        if len(self.coordinates) > 1:
            self.signal._plot.pointer._update_patch_position()

    def update_spectrum_line(self):
        self.line.auto_update = True
        self.line.update()
        self.line.auto_update = False

    def _index_changed(self, old, new):
        self.signal.axes_manager.indices = self.coordinates[new]
        self.argmax = None
        self._temp_mask[:] = False

    def on_disabling_span_selector(self):
        if self.interpolated_line is not None:
            self.interpolated_line.close()
            self.interpolated_line = None

    def _spline_order_changed(self, old, new):
        self.kind = self.spline_order
        self.span_selector_changed()

    def _add_noise_changed(self, old, new):
        self.span_selector_changed()

    def _interpolator_kind_changed(self, old, new):
        if new == 'linear':
            self.kind = new
        else:
            self.kind = self.spline_order
        self.span_selector_changed()

    def _ss_left_value_changed(self, old, new):
        if not (np.isnan(self.ss_right_value) or np.isnan(self.ss_left_value)):
            self.span_selector_changed()

    def _ss_right_value_changed(self, old, new):
        if not (np.isnan(self.ss_right_value) or np.isnan(self.ss_left_value)):
            self.span_selector_changed()

    def create_interpolation_line(self):
        self.interpolated_line = drawing.signal1d.Signal1DLine()
        self.interpolated_line.data_function = self.get_interpolated_spectrum
        self.interpolated_line.set_line_properties(color='blue', type='line')
        self.signal._plot.signal_plot.add_line(self.interpolated_line)
        self.interpolated_line.autoscale = False
        self.interpolated_line.plot()

    def get_interpolation_range(self):
        axis = self.signal.axes_manager.signal_axes[0]
        if np.isnan(self.ss_left_value) or np.isnan(self.ss_right_value):
            left = self.argmax - self.default_spike_width
            right = self.argmax + self.default_spike_width
        else:
            left = axis.value2index(self.ss_left_value)
            right = axis.value2index(self.ss_right_value)

        # Clip to the axis dimensions
        nchannels = self.signal.axes_manager.signal_shape[0]
        left = left if left >= 0 else 0
        right = right if right < nchannels else nchannels - 1

        return left, right

    def get_interpolated_spectrum(self, axes_manager=None):
        data = self.signal().copy()
        axis = self.signal.axes_manager.signal_axes[0]
        left, right = self.get_interpolation_range()
        if self.kind == 'linear':
            pad = 1
        else:
            pad = 10
        ileft = left - pad
        iright = right + pad
        ileft = np.clip(ileft, 0, len(data))
        iright = np.clip(iright, 0, len(data))
        left = int(np.clip(left, 0, len(data)))
        right = int(np.clip(right, 0, len(data)))
        x = np.hstack((axis.axis[ileft:left], axis.axis[right:iright]))
        y = np.hstack((data[ileft:left], data[right:iright]))
        if ileft == 0:
            # Extrapolate to the left
            data[left:right] = data[right + 1]

        elif iright == (len(data) - 1):
            # Extrapolate to the right
            data[left:right] = data[left - 1]

        else:
            # Interpolate
            intp = sp.interpolate.interp1d(x, y, kind=self.kind)
            data[left:right] = intp(axis.axis[left:right])

        # Add noise
        if self.add_noise is True:
            if self.noise_type == "white":
                data[left:right] += np.random.normal(scale=np.sqrt(
                    self.noise_variance),
                                                     size=right - left)
            elif self.noise_type == "heteroscedastic":
                noise_variance = self.noise_variance(
                    axes_manager=self.signal.axes_manager)[left:right]
                noise = [
                    np.random.normal(scale=np.sqrt(item))
                    for item in noise_variance
                ]
                data[left:right] += noise
            else:
                data[left:right] = np.random.poisson(
                    np.clip(data[left:right], 0, np.inf))

        return data

    def span_selector_changed(self):
        if self.interpolated_line is None:
            return
        else:
            self.interpolated_line.update()

    def apply(self):
        self.signal()[:] = self.get_interpolated_spectrum()
        self.signal.events.data_changed.trigger(obj=self.signal)
        self.update_spectrum_line()
        self.interpolated_line.close()
        self.interpolated_line = None
        self.reset_span_selector()
        self.find()
Esempio n. 28
0
class Oscilloscope(traits.HasTraits):
    """Oscilloscope style plot of the selected channels. Rolling mode/ auto trigger """
    masterContainer = traits.Instance(chaco.Plot)
    arrayPlotData = traits.Instance(chaco.ArrayPlotData)
    visibleChannels = traits.List([0])
    connection = None
    numberOfPoints = traits.Int(
        10000,
        desc=
        "number of points displayed on plot. number of Points*resolution = timespan of plot"
    )
    verticalLimit = traits.Range(low=0.0, high=5.0, value=3.3)
    resolution = traits.Float(
        0.1,
        desc=
        "number of points displayed on plot. number of Points*resolution = timespan of plot"
    )

    settingsGroup = traitsui.Group(
        traitsui.Item("numberOfPoints"),
        traitsui.Item("verticalLimit", label="Vertical Scale"))

    traits_view = traitsui.View(
        traitsui.VGroup(
            settingsGroup,
            traitsui.Group(
                traitsui.Item('masterContainer',
                              editor=ComponentEditor(),
                              show_label=False))))

    def __init__(self, **traitsDict):
        """initialise the plot"""
        super(Oscilloscope, self).__init__(**traitsDict)
        self.colors = ["black", "red", "blue"]
        self.initialiseData()
        self.initialisePlots()
        self._visibleChannels_changed()

    def _visibleChannels_changed(self):
        """make channels visible or not depending on list """
        for i in range(0, 8):
            if i in self.visibleChannels:
                self.masterContainer.plots["channel" +
                                           str(i)][0].visible = True
            else:
                print i
                self.masterContainer.plots["channel" +
                                           str(i)][0].visible = False

    def _numberOfPoints_changed(self):
        """when number of points changes re-initialise the data """
        self.reinitialiseData()

    def _resolution_changed(self):
        """when resolution of points changes re-initialise the data """
        self.reinitialiseData()

    def _verticalLimit_changed(self):
        """"changes y scale of vertical axis """
        self.masterContainer.range2d.y_range.high = self.verticalLimit

    def initialisePlots(self):
        """draw plots """
        self.masterContainer = chaco.Plot(self.arrayPlotData,
                                          padding=100,
                                          bgcolor="white",
                                          use_backbuffer=True,
                                          border_visible=False,
                                          fill_padding=True)
        self.masterContainer.plot(("xs", "channel0"),
                                  type="line",
                                  name="channel0",
                                  color=self.colors[0 % len(self.colors)])

        self.masterContainer.plot(("xs", "channel1"),
                                  type="line",
                                  name="channel1",
                                  color=self.colors[1 % len(self.colors)])

        self.masterContainer.plot(("xs", "channel2"),
                                  type="line",
                                  name="channel2",
                                  color=self.colors[2 % len(self.colors)])
        self.masterContainer.plot(("xs", "channel3"),
                                  type="line",
                                  name="channel3",
                                  color=self.colors[3 % len(self.colors)])

        self.masterContainer.plot(("xs", "channel4"),
                                  type="line",
                                  name="channel4",
                                  color=self.colors[4 % len(self.colors)])
        self.masterContainer.plot(("xs", "channel5"),
                                  type="line",
                                  name="channel5",
                                  color=self.colors[5 % len(self.colors)])

        self.masterContainer.plot(("xs", "channel6"),
                                  type="line",
                                  name="channel6",
                                  color=self.colors[6 % len(self.colors)])
        self.masterContainer.plot(("xs", "channel7"),
                                  type="line",
                                  name="channel7",
                                  color=self.colors[7 % len(self.colors)])
        self.masterContainer.plot(("cursorXS", "cursorVertical"),
                                  type="line",
                                  line_style="dash",
                                  name="cursor",
                                  color="green")

    def getCurrentPositionAsFloat(self):
        return self.currentPosition * self.resolution

    def getCurrentPositionArray(self):
        return scipy.array([self.currentPosition * self.resolution] * 2)

    def initialiseData(self):
        """sets up data arrays and fills arrayPlotData """
        self.currentPosition = 0
        self.xs = scipy.linspace(0.0, self.numberOfPoints * self.resolution,
                                 self.numberOfPoints)
        self.cursorXS = self.getCurrentPositionArray()
        self.cursorVertical = scipy.array([self.verticalLimit, 0.0])
        self.array0 = scipy.zeros(self.numberOfPoints)
        self.array1 = scipy.zeros(self.numberOfPoints)
        self.array2 = scipy.zeros(self.numberOfPoints)
        self.array3 = scipy.zeros(self.numberOfPoints)
        self.array4 = scipy.zeros(self.numberOfPoints)
        self.array5 = scipy.zeros(self.numberOfPoints)
        self.array6 = scipy.zeros(self.numberOfPoints)
        self.array7 = scipy.zeros(self.numberOfPoints)
        self.channels = [
            self.array0, self.array1, self.array2, self.array3, self.array4,
            self.array5, self.array6, self.array7
        ]
        self.arrayPlotData = chaco.ArrayPlotData(
            xs=self.xs,
            channel0=self.array0,
            channel1=self.array1,
            channel2=self.array2,
            channel3=self.array3,
            channel4=self.array4,
            channel5=self.array5,
            channel6=self.array6,
            channel7=self.array7,
            cursorXS=self.cursorXS,
            cursorVertical=self.cursorVertical
        )  #will be the ArrayPlotData We need

    def reinitialiseData(self):
        """sets up data arrays and fills arrayPlotData """
        if self.arrayPlotData is not None:
            self.currentPosition = 0
            self.xs = scipy.linspace(0.0,
                                     self.numberOfPoints * self.resolution,
                                     self.numberOfPoints)
            self.cursorXS = self.getCurrentPositionArray()
            self.cursorVertical = scipy.array([self.verticalLimit, 0.0])
            self.arrayPlotData.set_data("xs", self.xs)
            self.array0 = scipy.zeros(self.numberOfPoints)
            self.array1 = scipy.zeros(self.numberOfPoints)
            self.array2 = scipy.zeros(self.numberOfPoints)
            self.array3 = scipy.zeros(self.numberOfPoints)
            self.array4 = scipy.zeros(self.numberOfPoints)
            self.array5 = scipy.zeros(self.numberOfPoints)
            self.array6 = scipy.zeros(self.numberOfPoints)
            self.array7 = scipy.zeros(self.numberOfPoints)
            self.channels = [
                self.array0, self.array1, self.array2, self.array3,
                self.array4, self.array5, self.array6, self.array7
            ]
            self.updateArrayPlotData()

    def _voltage_get(self, channelNumber):
        """Uses PyHWI connection to ADC server to return voltage """
        #print "latest=%s" %  self.connection.latestResults
        if channelNumber in self.connection.latestResults:
            return self.connection.latestResults[channelNumber]
        else:
            return scipy.NaN

    def updateArrays(self):
        """update all arrays with the latest value """
        for channelNumber in range(0, 8):
            self.channels[channelNumber][
                self.currentPosition] = self._voltage_get(
                    channelNumber)  #update next element in each array
        self.currentPosition += 1
        if self.currentPosition >= self.numberOfPoints:  #reset position to beginning when we hit max number of points (like rolling oscilloscope)
            self.currentPosition = 0
        self.cursorXS = self.getCurrentPositionArray()
        #could also set the next points to NaN's to make a gap!

    def updateArrayPlotData(self):
        """push changes of arrays to the plot """
        self.arrayPlotData.set_data("channel0", self.array0)
        self.arrayPlotData.set_data("channel1", self.array1)
        self.arrayPlotData.set_data("channel2", self.array2)
        self.arrayPlotData.set_data("channel3", self.array3)
        self.arrayPlotData.set_data("channel4", self.array4)
        self.arrayPlotData.set_data("channel5", self.array5)
        self.arrayPlotData.set_data("channel6", self.array6)
        self.arrayPlotData.set_data("channel7", self.array7)
        self.arrayPlotData.set_data("cursorXS", self.cursorXS)
Esempio n. 29
0
class BackgroundRemoval(SpanSelectorInSignal1D):
    background_type = t.Enum('Power Law',
                             'Gaussian',
                             'Offset',
                             'Polynomial',
                             default='Power Law')
    polynomial_order = t.Range(1, 10)
    fast = t.Bool(True,
                  desc=("Perform a fast (analytic, but possibly less accurate)"
                        " estimation of the background. Otherwise use "
                        "non-linear least squares."))
    background_estimator = t.Instance(Component)
    bg_line_range = t.Enum('from_left_range',
                           'full',
                           'ss_range',
                           default='full')
    hi = t.Int(0)
    view = tu.View(
        tu.Group(
            'background_type',
            'fast',
            tu.Group('polynomial_order',
                     visible_when='background_type == \'Polynomial\''),
        ),
        buttons=[OKButton, CancelButton],
        handler=SpanSelectorInSignal1DHandler,
        title='Background removal tool',
        resizable=True,
        width=300,
    )

    def __init__(self, signal):
        super(BackgroundRemoval, self).__init__(signal)
        self.set_background_estimator()
        self.bg_line = None

    def on_disabling_span_selector(self):
        if self.bg_line is not None:
            self.bg_line.close()
            self.bg_line = None

    def set_background_estimator(self):

        if self.background_type == 'Power Law':
            self.background_estimator = components1d.PowerLaw()
            self.bg_line_range = 'from_left_range'
        elif self.background_type == 'Gaussian':
            self.background_estimator = components1d.Gaussian()
            self.bg_line_range = 'full'
        elif self.background_type == 'Offset':
            self.background_estimator = components1d.Offset()
            self.bg_line_range = 'full'
        elif self.background_type == 'Polynomial':
            self.background_estimator = components1d.Polynomial(
                self.polynomial_order)
            self.bg_line_range = 'full'

    def _polynomial_order_changed(self, old, new):
        self.background_estimator = components1d.Polynomial(new)
        self.span_selector_changed()

    def _background_type_changed(self, old, new):
        self.set_background_estimator()
        self.span_selector_changed()

    def _ss_left_value_changed(self, old, new):
        if not (np.isnan(self.ss_right_value) or np.isnan(self.ss_left_value)):
            self.span_selector_changed()

    def _ss_right_value_changed(self, old, new):
        if not (np.isnan(self.ss_right_value) or np.isnan(self.ss_left_value)):
            self.span_selector_changed()

    def create_background_line(self):
        self.bg_line = drawing.signal1d.Signal1DLine()
        self.bg_line.data_function = self.bg_to_plot
        self.bg_line.set_line_properties(color='blue',
                                         type='line',
                                         scaley=False)
        self.signal._plot.signal_plot.add_line(self.bg_line)
        self.bg_line.autoscale = False
        self.bg_line.plot()

    def bg_to_plot(self, axes_manager=None, fill_with=np.nan):
        # First try to update the estimation
        self.background_estimator.estimate_parameters(self.signal,
                                                      self.ss_left_value,
                                                      self.ss_right_value,
                                                      only_current=True)

        if self.bg_line_range == 'from_left_range':
            bg_array = np.zeros(self.axis.axis.shape)
            bg_array[:] = fill_with
            from_index = self.axis.value2index(self.ss_left_value)
            bg_array[from_index:] = self.background_estimator.function(
                self.axis.axis[from_index:])
            to_return = bg_array
        elif self.bg_line_range == 'full':
            to_return = self.background_estimator.function(self.axis.axis)
        elif self.bg_line_range == 'ss_range':
            bg_array = np.zeros(self.axis.axis.shape)
            bg_array[:] = fill_with
            from_index = self.axis.value2index(self.ss_left_value)
            to_index = self.axis.value2index(self.ss_right_value)
            bg_array[from_index:] = self.background_estimator.function(
                self.axis.axis[from_index:to_index])
            to_return = bg_array

        if self.signal.metadata.Signal.binned is True:
            to_return *= self.axis.scale
        return to_return

    def span_selector_changed(self):
        if self.ss_left_value is np.nan or self.ss_right_value is np.nan or\
                self.ss_right_value <= self.ss_left_value:
            return
        if self.background_estimator is None:
            return
        if self.bg_line is None and \
            self.background_estimator.estimate_parameters(
                self.signal, self.ss_left_value,
                self.ss_right_value,
                only_current=True) is True:
            self.create_background_line()
        else:
            self.bg_line.update()

    def apply(self):
        self.signal._plot.auto_update_plot = False
        new_spectra = self.signal._remove_background_cli(
            (self.ss_left_value, self.ss_right_value),
            self.background_estimator,
            fast=self.fast)
        self.signal.data = new_spectra.data
        self.signal._replot()
        self.signal._plot.auto_update_plot = True
Esempio n. 30
0
class DataAxis(t.HasTraits):
    name = t.Str()
    units = t.Str()
    scale = t.Float()
    offset = t.Float()
    size = t.CInt()
    low_value = t.Float()
    high_value = t.Float()
    value = t.Range('low_value', 'high_value')
    low_index = t.Int(0)
    high_index = t.Int()
    slice = t.Instance(slice)
    navigate = t.Bool(t.Undefined)
    index = t.Range('low_index', 'high_index')
    axis = t.Array()
    continuous_value = t.Bool(False)

    def __init__(self,
                 size,
                 index_in_array=None,
                 name=t.Undefined,
                 scale=1.,
                 offset=0.,
                 units=t.Undefined,
                 navigate=t.Undefined):
        super(DataAxis, self).__init__()
        self.events = Events()
        self.events.index_changed = Event("""
            Event that triggers when the index of the `DataAxis` changes

            Triggers after the internal state of the `DataAxis` has been
            updated.

            Arguments:
            ---------
            obj : The DataAxis that the event belongs to.
            index : The new index
            """,
                                          arguments=["obj", 'index'])
        self.events.value_changed = Event("""
            Event that triggers when the value of the `DataAxis` changes

            Triggers after the internal state of the `DataAxis` has been
            updated.

            Arguments:
            ---------
            obj : The DataAxis that the event belongs to.
            value : The new value
            """,
                                          arguments=["obj", 'value'])
        self._suppress_value_changed_trigger = False
        self._suppress_update_value = False
        self.name = name
        self.units = units
        self.scale = scale
        self.offset = offset
        self.size = size
        self.high_index = self.size - 1
        self.low_index = 0
        self.index = 0
        self.update_axis()
        self.navigate = navigate
        self.axes_manager = None
        self.on_trait_change(self.update_axis, ['scale', 'offset', 'size'])
        self.on_trait_change(self._update_slice, 'navigate')
        self.on_trait_change(self.update_index_bounds, 'size')
        # The slice must be updated even if the default value did not
        # change to correctly set its value.
        self._update_slice(self.navigate)

    def _index_changed(self, name, old, new):
        self.events.index_changed.trigger(obj=self, index=self.index)
        if not self._suppress_update_value:
            new_value = self.axis[self.index]
            if new_value != self.value:
                self.value = new_value

    def _value_changed(self, name, old, new):
        old_index = self.index
        new_index = self.value2index(new)
        if self.continuous_value is False:  # Only values in the grid alowed
            if old_index != new_index:
                self.index = new_index
                if new == self.axis[self.index]:
                    self.events.value_changed.trigger(obj=self, value=new)
            elif old_index == new_index:
                new_value = self.index2value(new_index)
                if new_value == old:
                    self._suppress_value_changed_trigger = True
                    try:
                        self.value = new_value
                    finally:
                        self._suppress_value_changed_trigger = False

                elif new_value == new and not\
                        self._suppress_value_changed_trigger:
                    self.events.value_changed.trigger(obj=self, value=new)
        else:  # Intergrid values are alowed. This feature is deprecated
            self.events.value_changed.trigger(obj=self, value=new)
            if old_index != new_index:
                self._suppress_update_value = True
                self.index = new_index
                self._suppress_update_value = False

    @property
    def index_in_array(self):
        if self.axes_manager is not None:
            return self.axes_manager._axes.index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    @property
    def index_in_axes_manager(self):
        if self.axes_manager is not None:
            return self.axes_manager._get_axes_in_natural_order().\
                index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    def _get_positive_index(self, index):
        if index < 0:
            index = self.size + index
            if index < 0:
                raise IndexError("index out of bounds")
        return index

    def _get_index(self, value):
        if isfloat(value):
            return self.value2index(value)
        else:
            return value

    def _get_array_slices(self, slice_):
        """Returns a slice to slice the corresponding data axis without
        changing the offset and scale of the DataAxis.

        Parameters
        ----------
        slice_ : {float, int, slice}

        Returns
        -------
        my_slice : slice

        """
        v2i = self.value2index

        if isinstance(slice_, slice):
            start = slice_.start
            stop = slice_.stop
            step = slice_.step
        else:
            if isfloat(slice_):
                start = v2i(slice_)
            else:
                start = self._get_positive_index(slice_)
            stop = start + 1
            step = None

        if isfloat(step):
            step = int(round(step / self.scale))
        if isfloat(start):
            try:
                start = v2i(start)
            except ValueError:
                if start > self.high_value:
                    # The start value is above the axis limit
                    raise IndexError(
                        "Start value above axis high bound for  axis %s."
                        "value: %f high_bound: %f" %
                        (repr(self), start, self.high_value))
                else:
                    # The start value is below the axis limit,
                    # we slice from the start.
                    start = None
        if isfloat(stop):
            try:
                stop = v2i(stop)
            except ValueError:
                if stop < self.low_value:
                    # The stop value is below the axis limits
                    raise IndexError(
                        "Stop value below axis low bound for  axis %s."
                        "value: %f low_bound: %f" %
                        (repr(self), stop, self.low_value))
                else:
                    # The stop value is below the axis limit,
                    # we slice until the end.
                    stop = None

        if step == 0:
            raise ValueError("slice step cannot be zero")

        return slice(start, stop, step)

    def _slice_me(self, slice_):
        """Returns a slice to slice the corresponding data axis and
        change the offset and scale of the DataAxis acordingly.

        Parameters
        ----------
        slice_ : {float, int, slice}

        Returns
        -------
        my_slice : slice

        """
        i2v = self.index2value

        my_slice = self._get_array_slices(slice_)

        start, stop, step = my_slice.start, my_slice.stop, my_slice.step

        if start is None:
            if step is None or step > 0:
                start = 0
            else:
                start = self.size - 1
        self.offset = i2v(start)
        if step is not None:
            self.scale *= step

        return my_slice

    def _get_name(self):
        if self.name is t.Undefined:
            if self.axes_manager is None:
                name = "Unnamed"
            else:
                name = "Unnamed " + ordinal(self.index_in_axes_manager)
        else:
            name = self.name
        return name

    def __repr__(self):
        text = '<%s axis, size: %i' % (
            self._get_name(),
            self.size,
        )
        if self.navigate is True:
            text += ", index: %i" % self.index
        text += ">"
        return text

    def __str__(self):
        return self._get_name() + " axis"

    def update_index_bounds(self):
        self.high_index = self.size - 1

    def update_axis(self):
        self.axis = generate_axis(self.offset, self.scale, self.size)
        if len(self.axis) != 0:
            self.low_value, self.high_value = (self.axis.min(),
                                               self.axis.max())

    def _update_slice(self, value):
        if value is False:
            self.slice = slice(None)
        else:
            self.slice = None

    def get_axis_dictionary(self):
        adict = {
            'name': self.name,
            'scale': self.scale,
            'offset': self.offset,
            'size': self.size,
            'units': self.units,
            'navigate': self.navigate
        }
        return adict

    def copy(self):
        return DataAxis(**self.get_axis_dictionary())

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo):
        cp = self.copy()
        return cp

    def value2index(self, value, rounding=round):
        """Return the closest index to the given value if between the limit.

        Parameters
        ----------
        value : number or numpy array

        Returns
        -------
        index : integer or numpy array

        Raises
        ------
        ValueError if any value is out of the axis limits.

        """
        if value is None:
            return None

        if isinstance(value, np.ndarray):
            if rounding is round:
                rounding = np.round
            elif rounding is math.ceil:
                rounding = np.ceil
            elif rounding is math.floor:
                rounding = np.floor

        index = rounding((value - self.offset) / self.scale)

        if isinstance(value, np.ndarray):
            index = index.astype(int)
            if np.all(self.size > index) and np.all(index >= 0):
                return index
            else:
                raise ValueError("A value is out of the axis limits")
        else:
            index = int(index)
            if self.size > index >= 0:
                return index
            else:
                raise ValueError("The value is out of the axis limits")

    def index2value(self, index):
        if isinstance(index, np.ndarray):
            return self.axis[index.ravel()].reshape(index.shape)
        else:
            return self.axis[index]

    def calibrate(self, value_tuple, index_tuple, modify_calibration=True):
        scale = (value_tuple[1] - value_tuple[0]) /\
            (index_tuple[1] - index_tuple[0])
        offset = value_tuple[0] - scale * index_tuple[0]
        if modify_calibration is True:
            self.offset = offset
            self.scale = scale
        else:
            return offset, scale

    def value_range_to_indices(self, v1, v2):
        """Convert the given range to index range.

        When an out of the axis limits, the endpoint is used instead.

        Parameters
        ----------
        v1, v2 : float
            The end points of the interval in the axis units. v2 must be
            greater than v1.

        """
        if v1 is not None and v2 is not None and v1 > v2:
            raise ValueError("v2 must be greater than v1.")

        if v1 is not None and self.low_value < v1 <= self.high_value:
            i1 = self.value2index(v1)
        else:
            i1 = 0
        if v2 is not None and self.high_value > v2 >= self.low_value:
            i2 = self.value2index(v2)
        else:
            i2 = self.size - 1
        return i1, i2

    def update_from(self, axis, attributes=["scale", "offset", "units"]):
        """Copy values of specified axes fields from the passed AxesManager.

        Parameters
        ----------
        axis : DataAxis
            The DataAxis instance to use as a source for values.
        attributes : iterable container of strings.
            The name of the attribute to update. If the attribute does not
            exist in either of the AxesManagers, an AttributeError will be
            raised.
        Returns
        -------
        A boolean indicating whether any changes were made.

        """
        any_changes = False
        changed = {}
        for f in attributes:
            if getattr(self, f) != getattr(axis, f):
                changed[f] = getattr(axis, f)
        if len(changed) > 0:
            self.trait_set(**changed)
            any_changes = True
        return any_changes