Skip to content
This repository was archived by the owner on Aug 13, 2025. It is now read-only.
This repository was archived by the owner on Aug 13, 2025. It is now read-only.

line segments #63

@jmjech

Description

@jmjech

Hi Rick,
I am mapping trawl profiles on acoustic data and am grabbing the bins along the trawl path. The trawl paths are line segments, as opposed to your "lines", which need to span the entire echogram. So, I modified your apply_lines (and other associated functions) and wrote some apply_line_segments functions. This bit of code goes into the mask.py script - I put it just below the apply_line sections. You may have had this capability already, but I couldn't find it, so you can incorporate, or leave it out. I'll leave it up to you.
mike

def apply_between_line_segments(self, upper_line_segment, lower_line_segment, value=True):
    """Sets mask elements between the provided line segment to the specified
    value. This does not require the line to span the entire echogram. See
    apply_line to do that.

    This is a convenience function. See apply_line_segment for details.

    Args:
        upper_line_segment (line): The line object used to define the upper boundary
                           on the mask where the provided value will be
                           applied.
        lower_line_segment (line): The line object used to define the lower boundary
                           on the mask where the provided value will be
                           applied.
        value (bool): Set this keyword to True to set the mask elements to
                      True, False to False. Default: True

    Raises:
        TypeError: When the mask is a ping mask (1-d mask). You cannot apply
                   a line to a ping mask.
    """

    self.apply_line_segment(upper_line_segment, value=value, other_line_segment=lower_line_segment)


def apply_below_line_segment(self, line_obj, value=True):
    """Sets mask elements below the line segment to the specified value. This does not
    require the line to span the entire echogram. See apply_below_line to do that.

    This is a convenience function. See apply_line_segment for details.

    Args:
        line_obj (line): The line object used to define the upper boundary
                         on the mask where the provided value will be
                         applied. All mask elements at or below the line segment
                         will be set.
        value (bool): Set this keyword to True to set the mask elements to
                      True, False to False. Default: True

    Raises:
        TypeError: When the mask is a ping mask (1-d mask). You cannot apply
                   a line to a ping mask.
    """

    self.apply_line_segment(line_obj, value=value, apply_above=False)

def apply_above_line_segment(self, line_obj, value=True):
    """Sets mask elements above the line segment to the specified value. This does not
    require the line to span the entire echogram. See apply_line_above to do that.

    This is a convenience function. See apply_line_segment for details.

    Args:
        line_obj (line): The line object used to define the lower boundary
                         on the mask where the provided value will be
                         applied. All mask elements at or above the line
                         will be set.
        value (bool): Set this keyword to True to set the mask elements to
                      True, False to False. Default: True

    Raises:
        TypeError: When the mask is a ping mask (1-d mask). You cannot apply
                   a line to a ping mask.
        ValueError: Line line ping times do not match mask times. The line(s)
                    and mask axes must match.
    """

    self.apply_line_segment(line_obj, value=value, apply_above=True)

def apply_line_segment(self, line_obj, apply_above=False, value=True,
        other_line_segment=None):
    """Sets mask elements above, below, and between line segments. This does not
    require the line segment to span the entire echogram. See apply_line to 
    do that.

    This method sets this mask's elements above, below, or between the
    provided echolab2.processing.line object(s) to the specified boolean
    value.

    Set apply_above to True to apply the provided value to samples with
    range/depth values LESS THAN OR EQUAL TO the provided line segment.

    Set apply_above to False to apply the provided value to samples with
    range/depth values GREATER THAN OR EQUAL TO the provided line segment.

    If you set other_line to a line object, the apply_above argument will
    be ignored and samples greater than or equal to line_obj and samples
    less than or equal to other_line_segment will be set to the provided value.
    In other words, setting other_line_segment will set samples between the two
    line segments.


    Args:
        line_obj (line): The line object used to define the vertical
                         boundary for each
        apply_above (bool): Set apply_above to True to apply the provided
                            value to all samples equal to or less than the
                            line segment range/depth. Set to False to apply to
                            samples greater than or equal to the line  segment range/
                            depth. Default: False
        other_line (line): Set other_line_segment to a line object to set all samples
                           between line_obj and other_line_segment to the provided
                           value. Default: None
        value (bool): Set this keyword to True to set the mask elements to
                      True, False to False. Default: True

    Raises:
        TypeError: When the mask is a ping mask (1-d mask). You cannot apply
                   a line to a ping mask.
    """
    # Make sure this is a sample mask.
    if self.type == 'ping':
        raise TypeError('You cannot apply a line to a ping mask.  You '
                        'must convert it to a sample mask first.')
    # Ensure value is a bool.
    value = bool(value)

    # get our vertical axis
    if hasattr(self, 'range'):
        v_axis = self.range
    else:
        v_axis = self.depth

    # get the ping indices of the data object that match the line segments
    didx = list(self.ping_time)
    idx = [didx.index(min(didx, key=lambda t0: abs(t0-t1))) for t1 in line_obj.ping_time]

    #  first check if we're setting between two lines
    if other_line_segment is not None:
        # apply value to mask elements between the two provided line segments
        for i in range(len(idx)):
            samps_to_mask = v_axis >= line_obj.data[i]
            samps_to_mask &= v_axis <= other_line_segment.data[i]
            self.mask[idx[i]][samps_to_mask] = value

    else:
        #  only one line passed so we'll apply above or below that line segment
        if apply_above:
            # apply value to mask elements less than or equal to the line segment
            for i in range(len(idx)):
                samps_to_mask = v_axis <= line_obj.data[i]
                self.mask[idx[i]][samps_to_mask] = value
        else:
            # apply value to mask elements greater than or equal to the line
            for i in range(len(idx)):
                samps_to_mask = v_axis >= line_obj.data[i]
                self.mask[idx[i]][samps_to_mask] = value

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions