if copy:<EOL><INDENT>d = self.__dict__.copy()<EOL>del(d['<STR_LIT>'])<EOL>del(d['<STR_LIT>'])<EOL>self.base.invert()<EOL>self.top.invert()<EOL>return Interval(top=self.base, base=self.top, **d)<EOL><DEDENT>else:<EOL><INDENT>self.base.invert()<EOL>self.top.invert()<EOL>old_base = self.base<EOL>self.base = self.top<EOL>self.top = old_base<EOL>return<EOL><DEDENT>

Inverts the interval. If it was depth-ordered (positive numbers
increasing downwards.), it will now be elevation-ordered, and
vice versa.

Args:
    copy (bool): Whether to make a copy or not. Default: False.


return Interval(**self.__dict__.copy())<EOL>


o = {'<STR_LIT>': operator.lt, '<STR_LIT>': operator.gt}[self.order]<EOL>top_inside = o(self.top.z, other.top.z) and o(other.top.z, self.base.z)<EOL>base_inside = o(self.top.z, other.base.z) and o(other.base.z, self.base.z)<EOL>above_below = o(other.top.z, self.top.z) and o(self.base.z, other.base.z)<EOL>if top_inside and base_inside:<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>elif above_below:<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>elif top_inside or base_inside:<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>elif (self.top.z == other.base.z) or (self.base.z == other.top.z):<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>return None<EOL><DEDENT>

Returns the relationship style. Completely deterministic.


def _overlaps(self, other, rel='<STR_LIT>'):

overlaps = ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>']<EOL>acceptable = overlaps + ['<STR_LIT>', '<STR_LIT>']<EOL>if rel not in acceptable:<EOL><INDENT>m = '<STR_LIT>'.format('<STR_LIT:U+002CU+0020>'.join(acceptable))<EOL>raise IntervalError(m)<EOL><DEDENT>r = self.relationship(other)<EOL>if r:<EOL><INDENT>if (r == rel) or ((rel == '<STR_LIT>') and (r in overlaps)):<EOL><INDENT>return True<EOL><DEDENT><DEDENT>return False<EOL>

Checks to see if and how two intervals overlap.


o = {'<STR_LIT>': operator.le, '<STR_LIT>': operator.ge}[self.order]<EOL>return (o(d, self.base.z) and o(self.top.z, d))<EOL>

Determines if depth d is within this interval.

Args:
    d (float): Level or 'depth' to evaluate.

Returns:
    bool. Whether the depth is in the interval.


if not self.spans(d):<EOL><INDENT>m = '<STR_LIT>'.format(d, self)<EOL>raise IntervalError(m)<EOL><DEDENT>int1, int2 = self.copy(), self.copy()<EOL>int1.base = d<EOL>int2.top = d<EOL>return int1, int2<EOL>

Splits an interval.

Args:
    d (float): Level or 'depth' to split at.

Returns:
    tuple. The two intervals that result from the split.


if not self.order == other.order:<EOL><INDENT>m = '<STR_LIT>'<EOL>raise IntervalError(m)<EOL><DEDENT>uppermost = max(self, other).copy()<EOL>lowermost = min(self, other).copy()  <EOL>if self.partially_overlaps(other):<EOL><INDENT>upper, _ = uppermost.split_at(lowermost.top.z)<EOL>middle, lower = lowermost.split_at(uppermost.base.z)<EOL><DEDENT>else:<EOL><INDENT>upper_temp, lower = uppermost.split_at(lowermost.base.z)<EOL>upper, _ = upper_temp.split_at(lowermost.top.z)<EOL>middle = lowermost<EOL><DEDENT>return upper, middle, lower<EOL>

Private function. 'Explodes' an interval with another interval.
Note that `self` must at least partially overlap `other`.

Args:
    other (Interval): The other Interval.

Returns:
    tuple. Three Intervals: upper, middle, lower; `middle` has the
        properties of the lowermost Interval.


self_data = getattr(self, '<STR_LIT:data>', None)<EOL>other_data = getattr(other, '<STR_LIT:data>', None)<EOL>if (self_data is None) and (other_data is None):<EOL><INDENT>return {}<EOL><DEDENT>elif (self_data is not None) and (other_data is None):<EOL><INDENT>return self_data<EOL><DEDENT>elif (self_data is None) and (other_data is not None):<EOL><INDENT>return other_data<EOL><DEDENT>else:<EOL><INDENT>data = {}<EOL>for k, v in other_data.items():<EOL><INDENT>if k in self_data:<EOL><INDENT>v = utils.list_and_add(self_data[k], v)<EOL><DEDENT>data[k] = v<EOL><DEDENT>return data<EOL><DEDENT>

Combines data only.

Args:
    other (Interval): The other Interval.

Returns:
    dict. The blended data.


thin, thick = sorted([self, other], key=lambda k: k.thickness)<EOL>total = thin.thickness + thick.thickness<EOL>prop = <NUM_LIT:100> * thick.thickness / total<EOL>if self.components == other.components:<EOL><INDENT>return self.description.strip('<STR_LIT>')<EOL><DEDENT>d1 = thick.description.strip('<STR_LIT>') or thick.summary()<EOL>d2 = thin.description.strip('<STR_LIT>') or thin.summary()<EOL>if d1:<EOL><INDENT>d = '<STR_LIT>'.format(prop, d1, <NUM_LIT:100>-prop, d2)<EOL><DEDENT>else:<EOL><INDENT>d = '<STR_LIT>'<EOL><DEDENT>return d<EOL>

Private method. Computes the description for combining two intervals.
Make sure that the intervals are already adjusted to the correct
thicknesses.

Args:
    other (Interval): The other Interval.

Returns:
    str. The blended description.


def _combine(self, old_self, other, blend=True):

if blend:<EOL><INDENT>self.components = old_self.components.copy()<EOL>for c in other.components:<EOL><INDENT>if c not in self.components:<EOL><INDENT>self.components.append(c)<EOL><DEDENT><DEDENT>self.description = old_self._blend_descriptions(other)<EOL>self.data = old_self._combine_data(other)<EOL><DEDENT>else:<EOL><INDENT>self.components = other.components<EOL>self.description = other.description<EOL>self.data = other.data<EOL><DEDENT>return self<EOL>

Private method. Combines data, components, and descriptions but
nothing else.

Args:
    old_self (Interval): You have to pass the instance explicitly.
    other (Interval): The other Interval.
    blend (bool): Whether to blend or not.

Returns:
    Interval. The combined description.


if not self.any_overlaps(other):<EOL><INDENT>m = '<STR_LIT>'<EOL>raise IntervalError(m)<EOL><DEDENT>_, intersection, _ = self._explode(other)<EOL>return intersection._combine(self, other, blend=blend)<EOL>

Perform the intersection binary operation. self must at least
partially overlap with other or an IntervalError is raised.

If blend is False, you are essentially replacing self with other.

Args:
    other (Interval): The other Interval.
    blend (bool): Whether to blend or not.

Returns:
    Interval. The intersection of the Interval with the one provided.


if not self.any_overlaps(other):<EOL><INDENT>m = '<STR_LIT>'<EOL>raise IntervalError(m)<EOL><DEDENT>upper, middle, lower = self._explode(other)<EOL>if self.top.z == upper.top.z:<EOL><INDENT>self_is_uppermost = True<EOL><DEDENT>else:<EOL><INDENT>self_is_uppermost = False<EOL><DEDENT>middle = middle._combine(self, other, blend=blend)<EOL>if self.partially_overlaps(other) and (not blend):<EOL><INDENT>if self_is_uppermost:<EOL><INDENT>result = [upper, other]<EOL><DEDENT>else:<EOL><INDENT>result = [other, lower]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>result = [lower, middle, upper]<EOL><DEDENT>from .striplog import Striplog  <EOL>if self.order == '<STR_LIT>':<EOL><INDENT>return Striplog(result[::-<NUM_LIT:1>])<EOL><DEDENT>else:<EOL><INDENT>return Striplog(result)<EOL><DEDENT>

Perform the merge binary operation. self must at least
partially overlap with other or an IntervalError is raised.

If blend is False, you are essentially replacing self with other.

Args:
    other (Interval): The other Interval.
    blend (bool): Whether to blend or not.

Returns:
    Striplog. The merge of the Interval with the one provided.


if not (self.touches(other) or self.any_overlaps(other)):<EOL><INDENT>return self, other<EOL><DEDENT>if self.order == '<STR_LIT>':<EOL><INDENT>top = max(self.top.z, other.top.z)<EOL>bot = min(self.base.z, other.base.z)<EOL><DEDENT>else:<EOL><INDENT>top = min(self.top.z, other.top.z)<EOL>bot = max(self.base.z, other.base.z)<EOL><DEDENT>result = self.copy()<EOL>result.top = top<EOL>result.base = bot<EOL>return result._combine(self, other, blend=blend)<EOL>

Perform the union binary operation. self must at least touch other or
an IntervalError is raised.

If blend is False, you are essentially replacing self with other.

Args:
    other (Interval): The other Interval.
    blend (bool): Whether to blend or not.

Returns:
    Interval. The union of the Interval with the one provided.


if self.touches(other) or (not self.any_overlaps(other)):<EOL><INDENT>return self<EOL><DEDENT>elif self.completely_contains(other):<EOL><INDENT>upper, _, lower = self._explode(other)<EOL>return upper, lower<EOL><DEDENT>else:<EOL><INDENT>if self > other:<EOL><INDENT>return self.split_at(other.top.z)[<NUM_LIT:0>]<EOL><DEDENT>elif self < other:<EOL><INDENT>return self.split_at(other.base.z)[<NUM_LIT:1>]<EOL><DEDENT>else:  <EOL><INDENT>return None<EOL><DEDENT><DEDENT>

Perform the difference binary operation.

Args:
    other (Interval): The other Interval.

Returns:
    Interval. One or two Intervals.


if abbreviations:<EOL><INDENT>text = lexicon.expand_abbreviations(self.description)<EOL><DEDENT>else:<EOL><INDENT>text = self.description<EOL><DEDENT>components = []<EOL>for p, part in enumerate(lexicon.split_description(text)):<EOL><INDENT>if p == max_component:<EOL><INDENT>break<EOL><DEDENT>components.append(Component.from_text(part, lexicon))<EOL><DEDENT>return components<EOL>

Turns a description into a lists of components. The items in the
list are in the order they were found in the description, which is
usually order of importance.

Args:
    lexicon (Lexicon): The translation between words and their meaning.
    max_component (int): The most components to return. Default 1.
    abbreviations (bool): Whether to expand abreviations or not.
        Default False.

Returns:
    List. A list of Components extracted from the description text.


rows = '<STR_LIT>'<EOL>s = '<STR_LIT>'<EOL>for k, v in dictionary.items():<EOL><INDENT>rows += s.format(k=k, v=v)<EOL><DEDENT>html = '<STR_LIT>'.format(rows)<EOL>return html<EOL>


return x<EOL>

Null function. Used for default in functions that can apply a user-
supplied function to data before returning.


def null(y):<EOL><INDENT>return x<EOL><DEDENT>return null<EOL>


return<EOL>


for n, h in defaults.COLOURS.items():<EOL><INDENT>if (len(n) > <NUM_LIT:1>) and (h == hexx.upper()):<EOL><INDENT>return n.lower()<EOL><DEDENT><DEDENT>return None<EOL>

Convert hex to a color name, using matplotlib's colour names.

Args:
    hexx (str): A hexadecimal colour, starting with '#'.

Returns:
    str: The name of the colour, or None if not found.


return defaults.COLOURS[name.lower()].lower()<EOL>

Convert a color name to hex, using matplotlib's colour names.

Args:
    name (str): The name of a colour, e.g. 'red'.

Returns:
    str: The hex code for the colour.


r, g, b = rgb[:<NUM_LIT:3>]<EOL>if (r < <NUM_LIT:0>) or (g < <NUM_LIT:0>) or (b < <NUM_LIT:0>):<EOL><INDENT>raise Exception("<STR_LIT>")<EOL><DEDENT>if (r > <NUM_LIT:255>) or (g > <NUM_LIT:255>) or (b > <NUM_LIT:255>):<EOL><INDENT>raise Exception("<STR_LIT>")<EOL><DEDENT>if (<NUM_LIT:0> < r < <NUM_LIT:1>) or (<NUM_LIT:0> < g < <NUM_LIT:1>) or (<NUM_LIT:0> < b < <NUM_LIT:1>):<EOL><INDENT>if (r > <NUM_LIT:1>) or (g > <NUM_LIT:1>) or (b > <NUM_LIT:1>):<EOL><INDENT>raise Exception("<STR_LIT>")<EOL><DEDENT><DEDENT>if (<NUM_LIT:0> <= r <= <NUM_LIT:1>) and (<NUM_LIT:0> <= g <= <NUM_LIT:1>) and (<NUM_LIT:0> <= b <= <NUM_LIT:1>):<EOL><INDENT>rgb = tuple([int(round(val * <NUM_LIT:255>)) for val in [r, g, b]])<EOL><DEDENT>else:<EOL><INDENT>rgb = (int(r), int(g), int(b))<EOL><DEDENT>result = '<STR_LIT>' % rgb<EOL>return result.lower()<EOL>

Utility function to convert (r,g,b) triples to hex.
http://ageo.co/1CFxXpO
Args:
  rgb (tuple): A sequence of RGB values in the
    range 0-255 or 0-1.
Returns:
  str: The hex code for the colour.


h = hexx.strip('<STR_LIT:#>')<EOL>l = len(h)<EOL>return tuple(int(h[i:i+l//<NUM_LIT:3>], <NUM_LIT:16>) for i in range(<NUM_LIT:0>, l, l//<NUM_LIT:3>))<EOL>

Utility function to convert hex to (r,g,b) triples.
http://ageo.co/1CFxXpO

Args:
    hexx (str): A hexadecimal colour, starting with '#'.

Returns:
    tuple: The equivalent RGB triple, in the range 0 to 255.


r, g, b = hex_to_rgb(hexx)<EOL>luma = (<NUM_LIT> * r + <NUM_LIT> * g + <NUM_LIT> * b) / <NUM_LIT>  <EOL>return (luma < percent)<EOL>

Function to decide if a hex colour is dark.

Args:
    hexx (str): A hexadecimal colour, starting with '#'.

Returns:
    bool: The colour's brightness is less than the given percent.


def text_colour_for_hex(hexx, percent=<NUM_LIT:50>, dark='<STR_LIT>', light='<STR_LIT>'):

return light if hex_is_dark(hexx, percent=percent) else dark<EOL>

Function to decide what colour to use for a given hex colour.

Args:
    hexx (str): A hexadecimal colour, starting with '#'.

Returns:
    bool: The colour's brightness is less than the given percent.


im = plt.imread(filename)<EOL>if offset < <NUM_LIT:1>:<EOL><INDENT>col = int(im.shape[<NUM_LIT:1>] * offset)<EOL><DEDENT>else:<EOL><INDENT>col = offset<EOL><DEDENT>return im[:, col, :<NUM_LIT:3>]<EOL>

Get a log-like stream of RGB values from an image.

Args:
    filename (str): The filename of a PNG image.
    offset (Number): If < 1, interpreted as proportion of way across
        the image. If > 1, interpreted as pixels from left.

Returns:
    ndarray: A 2d array (a column of RGB triples) at the specified
    offset.

TODO:
    Generalize this to extract 'logs' from images in other ways, such
    as giving the mean of a range of pixel columns, or an array of
    columns. See also a similar routine in pythonanywhere/freqbot.


def tops_from_loglike(a, offset=<NUM_LIT:0>, null=None):

a = np.copy(a)<EOL>try:<EOL><INDENT>contains_nans = np.isnan(a).any()<EOL><DEDENT>except:<EOL><INDENT>contains_nans = False<EOL><DEDENT>if contains_nans:<EOL><INDENT>_null = null or -<NUM_LIT:1><EOL>while _null in a:<EOL><INDENT>_null -= <NUM_LIT:1><EOL><DEDENT>try:<EOL><INDENT>a[np.isnan(a)] = _null<EOL>transformed = True<EOL><DEDENT>except:<EOL><INDENT>transformed = False<EOL><DEDENT><DEDENT>edges = a[<NUM_LIT:1>:] == a[:-<NUM_LIT:1>]<EOL>edges = np.append(True, edges)<EOL>tops = np.where(~edges)[<NUM_LIT:0>]<EOL>tops = np.append(<NUM_LIT:0>, tops)<EOL>values = a[tops + offset]<EOL>if contains_nans and transformed:<EOL><INDENT>values[values == _null] = np.nan<EOL><DEDENT>return tops, values<EOL>

Take a log-like stream of numbers or strings, and return two arrays:
one of the tops (changes), and one of the values from the stream.

Args:
    loglike (array-like): The input stream of loglike data.
    offset (int): Offset (down) from top at which to get lithology,
        to be sure of getting 'clean' pixels.

Returns:
    ndarray: Two arrays, tops and values.


if not isinstance(b, list):<EOL><INDENT>b = [b]<EOL><DEDENT>if not isinstance(a, list):<EOL><INDENT>a = [a]<EOL><DEDENT>return a + b<EOL>

Coerce to lists and concatenate.

Args:
    a: A thing.
    b: A thing.

Returns:
    List. All the things.


if (l == []) or (l is None):<EOL><INDENT>return l<EOL><DEDENT>if isinstance(l[<NUM_LIT:0>], list):<EOL><INDENT>return flatten_list(l[<NUM_LIT:0>]) + flatten_list(l[<NUM_LIT:1>:])<EOL><DEDENT>return l[:<NUM_LIT:1>] + flatten_list(l[<NUM_LIT:1>:])<EOL>


def axis_transform(ax, x, y, xlim=None, ylim=None, inverse=False):

xlim = xlim or ax.get_xlim()<EOL>ylim = ylim or ax.get_ylim()<EOL>xdelta = xlim[<NUM_LIT:1>] - xlim[<NUM_LIT:0>]<EOL>ydelta = ylim[<NUM_LIT:1>] - ylim[<NUM_LIT:0>]<EOL>if not inverse:<EOL><INDENT>xout = xlim[<NUM_LIT:0>] + x * xdelta<EOL>yout = ylim[<NUM_LIT:0>] + y * ydelta<EOL><DEDENT>else:<EOL><INDENT>xdelta2 = x - xlim[<NUM_LIT:0>]<EOL>ydelta2 = y - ylim[<NUM_LIT:0>]<EOL>xout = xdelta2 / xdelta<EOL>yout = ydelta2 / ydelta<EOL><DEDENT>return xout, yout<EOL>

http://stackoverflow.com/questions/29107800

inverse = False : Axis => Data
        = True  : Data => Axis


def get_field(self, field_name, args, kwargs):

try:<EOL><INDENT>s = super(CustomFormatter, self)<EOL>return s.get_field(field_name, args, kwargs)<EOL><DEDENT>except KeyError:    <EOL><INDENT>return ("<STR_LIT:_>", field_name)<EOL><DEDENT>except IndexError:  <EOL><INDENT>return ("<STR_LIT:_>", field_name)<EOL><DEDENT>

Return an underscore if the attribute is absent.
Not all components have the same attributes.


def convert_field(self, value, conversion):

try:  <EOL><INDENT>s = super(CustomFormatter, self)<EOL>return s.convert_field(value, conversion)<EOL><DEDENT>except ValueError:<EOL><INDENT>funcs = {'<STR_LIT:s>': str,    <EOL>'<STR_LIT:r>': repr,   <EOL>'<STR_LIT:a>': ascii,  <EOL>'<STR_LIT:u>': str.upper,<EOL>'<STR_LIT:l>': str.lower,<EOL>'<STR_LIT:c>': str.capitalize,<EOL>'<STR_LIT:t>': str.title,<EOL>'<STR_LIT:m>': np.mean,<EOL>'<STR_LIT>': np.mean,<EOL>'<STR_LIT:v>': np.var,<EOL>'<STR_LIT:d>': np.std,<EOL>'<STR_LIT:+>': np.sum,<EOL>'<STR_LIT>': np.sum,<EOL>'<STR_LIT:x>': np.product,<EOL>}<EOL>return funcs.get(conversion)(value)<EOL><DEDENT>

Define some extra field conversion functions.


return cls(defaults.LEXICON)<EOL>

Makes the default lexicon, as provided in ``defaults.py``.

Returns:
    Lexicon: The default lexicon.


with open(filename, '<STR_LIT:r>') as fp:<EOL><INDENT>return cls(json.load(fp))<EOL><DEDENT>

Load a lexicon from a JSON file.

Args:
    filename (str): The path to a JSON dump.


def find_word_groups(self, text, category, proximity=<NUM_LIT:2>):

f = re.IGNORECASE<EOL>words = getattr(self, category)<EOL>regex = re.compile(r'<STR_LIT>' + r'<STR_LIT>'.join(words) + r'<STR_LIT>', flags=f)<EOL>candidates = regex.finditer(text)<EOL>starts, ends = [], []<EOL>groups = []<EOL>for item in candidates:<EOL><INDENT>starts.append(item.span()[<NUM_LIT:0>])<EOL>ends.append(item.span()[<NUM_LIT:1>])<EOL>groups.append(item.group().lower())<EOL><DEDENT>new_starts = []  <EOL>new_groups = []  <EOL>skip = False<EOL>for i, g in enumerate(groups):<EOL><INDENT>if skip:<EOL><INDENT>skip = False<EOL>continue<EOL><DEDENT>if (i < len(groups)-<NUM_LIT:1>) and (starts[i+<NUM_LIT:1>]-ends[i] <= proximity):<EOL><INDENT>if g[-<NUM_LIT:1>] == '<STR_LIT:->':<EOL><INDENT>sep = '<STR_LIT>'  <EOL><DEDENT>else:<EOL><INDENT>sep = '<STR_LIT:U+0020>'<EOL><DEDENT>new_groups.append(g + sep + groups[i+<NUM_LIT:1>])<EOL>new_starts.append(starts[i])<EOL>skip = True<EOL><DEDENT>else:<EOL><INDENT>if g not in new_groups:<EOL><INDENT>new_groups.append(g)<EOL>new_starts.append(starts[i])<EOL><DEDENT>skip = False<EOL><DEDENT><DEDENT>return new_groups<EOL>

Given a string and a category, finds and combines words into
groups based on their proximity.

Args:
    text (str): Some text.
    tokens (list): A list of regex strings.

Returns:
    list. The combined strings it found.

Example:
    COLOURS = [r"red(?:dish)?", r"grey(?:ish)?", r"green(?:ish)?"]
    s = 'GREYISH-GREEN limestone with RED or GREY sandstone.'
    find_word_groups(s, COLOURS) --> ['greyish green', 'red', 'grey']


if word and self.synonyms:<EOL><INDENT>reverse_lookup = {}<EOL>for k, v in self.synonyms.items():<EOL><INDENT>for i in v:<EOL><INDENT>reverse_lookup[i.lower()] = k.lower()<EOL><DEDENT><DEDENT>if word.lower() in reverse_lookup:<EOL><INDENT>return reverse_lookup[word.lower()]<EOL><DEDENT><DEDENT>return word<EOL>

Given a string and a dict of synonyms, returns the 'preferred'
word. Case insensitive.

Args:
    word (str): A word.

Returns:
    str: The preferred word, or the input word if not found.

Example:
    >>> syn = {'snake': ['python', 'adder']}
    >>> find_synonym('adder', syn)
    'snake'
    >>> find_synonym('rattler', syn)
    'rattler'

TODO:
    Make it handle case, returning the same case it received.


if not self.abbreviations:<EOL><INDENT>raise LexiconError("<STR_LIT>")<EOL><DEDENT>def chunks(data, SIZE=<NUM_LIT>):<EOL><INDENT>"""<STR_LIT>"""<EOL>it = iter(data)<EOL>for i in range(<NUM_LIT:0>, len(data), SIZE):<EOL><INDENT>yield {k: data[k] for k in islice(it, SIZE)}<EOL><DEDENT><DEDENT>def cb(g):<EOL><INDENT>"""<STR_LIT>"""<EOL>return self.abbreviations.get(g.group(<NUM_LIT:0>)) or g.group(<NUM_LIT:0>)<EOL><DEDENT>text = re.sub(r'<STR_LIT>', r'<STR_LIT>', text)<EOL>for subdict in chunks(self.abbreviations):<EOL><INDENT>regex = r'<STR_LIT>' + r'<STR_LIT>'.join(subdict.keys()) + r'<STR_LIT>'<EOL>text = re.sub(regex, cb, text)<EOL><DEDENT>return text<EOL>

Parse a piece of text and replace any abbreviations with their full
word equivalents. Uses the lexicon.abbreviations dictionary to find
abbreviations.

Args:
    text (str): The text to parse.

Returns:
    str: The text with abbreviations replaced.


def get_component(self, text, required=False, first_only=True):

component = {}<EOL>for i, (category, words) in enumerate(self.__dict__.items()):<EOL><INDENT>if category in SPECIAL:<EOL><INDENT>continue<EOL><DEDENT>groups = self.find_word_groups(text, category)<EOL>if groups and first_only:<EOL><INDENT>groups = groups[:<NUM_LIT:1>]<EOL><DEDENT>elif groups:<EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>groups = [None]<EOL>if required:<EOL><INDENT>with warnings.catch_warnings():<EOL><INDENT>warnings.simplefilter("<STR_LIT>")<EOL>w = "<STR_LIT>"<EOL>warnings.warn(w.format(text))<EOL><DEDENT><DEDENT><DEDENT>filtered = [self.find_synonym(i) for i in groups]<EOL>if first_only:<EOL><INDENT>component[category] = filtered[<NUM_LIT:0>]<EOL><DEDENT>else:<EOL><INDENT>component[category] = filtered<EOL><DEDENT><DEDENT>return component<EOL>

Takes a piece of text representing a lithologic description for one
component, e.g. "Red vf-f sandstone" and turns it into a dictionary
of attributes.

TODO:
    Generalize this so that we can use any types of word, as specified
    in the lexicon.


<EOL>t = re.sub(r'<STR_LIT>', r'<STR_LIT>', text)  <EOL>t = re.sub(r'<STR_LIT>', r'<STR_LIT>', t)  <EOL>words = getattr(self, '<STR_LIT>')<EOL>try:<EOL><INDENT>splitter = words[<NUM_LIT:0>].strip()<EOL><DEDENT>except:<EOL><INDENT>splitter = '<STR_LIT>'<EOL><DEDENT>t = re.sub(r'<STR_LIT>', r'<STR_LIT:U+0020>'+splitter+'<STR_LIT>', t)<EOL>f = re.IGNORECASE<EOL>pattern = re.compile(r'<STR_LIT>' + r'<STR_LIT:|>'.join(words) + r'<STR_LIT:)>', flags=f)<EOL>parts = filter(None, pattern.split(t))<EOL>return [i.strip() for i in parts]<EOL>

Split a description into parts, each of which can be turned into
a single component.


keys = [k for k in self.__dict__.keys() if k not in SPECIAL]<EOL>return keys<EOL>

Lists the categories in the lexicon, except the
optional categories.

Returns:
    list: A list of strings of category names.


try:<EOL><INDENT>result = self.__list[self.__index]<EOL><DEDENT>except IndexError:<EOL><INDENT>self.__index = <NUM_LIT:0><EOL>raise StopIteration<EOL><DEDENT>self.__index += <NUM_LIT:1><EOL>return result<EOL>


return self.__next__()<EOL>


if self.order == '<STR_LIT>':<EOL><INDENT>return self[<NUM_LIT:0>].top<EOL><DEDENT>else:<EOL><INDENT>return self[-<NUM_LIT:1>].base<EOL><DEDENT>

Property. The closest Position to the datum.

Returns:
    Position.


if self.order == '<STR_LIT>':<EOL><INDENT>return self[-<NUM_LIT:1>].base<EOL><DEDENT>else:<EOL><INDENT>return self[<NUM_LIT:0>].top<EOL><DEDENT>

Property. The furthest Position from the datum.

Returns:
    Position.


self.__list.sort(key=operator.attrgetter('<STR_LIT>'))<EOL>return<EOL>

Private method. Sorts into 'natural' order: top-down for depth-ordered
striplogs; bottom-up for elevation-ordered.

Sorts in place.

Returns:
    None.


def conc(a, b):<EOL><INDENT>return a + b<EOL><DEDENT>b = np.array(reduce(conc, [[i.top.z, i.base.z] for i in self]))<EOL>return all(np.diff(b) >= <NUM_LIT:0>)<EOL>

Private method. Checks if striplog is monotonically increasing in
depth.

Returns:
    Bool.


total = <NUM_LIT:0.0><EOL>for i in self:<EOL><INDENT>total += i.thickness<EOL><DEDENT>return total<EOL>

Property. Gives the cumulative thickness of all filled intervals.

It would be nice to use sum() for this (by defining __radd__),
but I quite like the ability to add striplogs and get a striplog
and I don't think we can have both, it's too confusing.

Not calling it sum, because that's a keyword.

Returns:
    Float. The cumulative thickness.


return self.cum / len(self)<EOL>

Property. Returns the mean thickness of all filled intervals.

Returns:
    Float. The mean average of interval thickness.


return [i[<NUM_LIT:0>] for i in self.unique if i[<NUM_LIT:0>]]<EOL>

Property. Returns the list of compenents in the striplog.

Returns:
    List. A list of the unique components.


all_rx = set([iv.primary for iv in self])<EOL>table = {r: <NUM_LIT:0> for r in all_rx}<EOL>for iv in self:<EOL><INDENT>table[iv.primary] += iv.thickness<EOL><DEDENT>return sorted(table.items(), key=operator.itemgetter(<NUM_LIT:1>), reverse=True)<EOL>

Property. Summarize a Striplog with some statistics.

Returns:
    List. A list of (Component, total thickness thickness) tuples.


<EOL>with warnings.catch_warnings():<EOL><INDENT>warnings.simplefilter("<STR_LIT>")<EOL>w = "<STR_LIT>"<EOL>warnings.warn(w, DeprecationWarning, stacklevel=<NUM_LIT:2>)<EOL><DEDENT>return self.unique<EOL>


<EOL>length = float(basis.size)<EOL>start, stop = basis[<NUM_LIT:0>], basis[-<NUM_LIT:1>]<EOL>tops = [start + (p/(length-<NUM_LIT:1>)) * (stop-start) for p in tops]<EOL>bases = tops[<NUM_LIT:1>:] + [stop]<EOL>list_of_Intervals = []<EOL>for i, t in enumerate(tops):<EOL><INDENT>v, c, d = values[i], [], {}<EOL>if ignore_nan and np.isnan(v):<EOL><INDENT>continue<EOL><DEDENT>if (field is not None):<EOL><INDENT>d = {field: v}<EOL><DEDENT>if components is not None:<EOL><INDENT>try:<EOL><INDENT>c = [deepcopy(components[int(v)])]<EOL><DEDENT>except IndexError:<EOL><INDENT>c = []<EOL><DEDENT>if c and (c[<NUM_LIT:0>] is None):<EOL><INDENT>c = []<EOL><DEDENT><DEDENT>interval = Interval(t, bases[i], data=d, components=c)<EOL>list_of_Intervals.append(interval)<EOL><DEDENT>return list_of_Intervals<EOL>

Private method. Take a sequence of tops in an arbitrary dimension,
and provide a list of intervals from which a striplog can be made.

This is only intended to be used by ``from_image()``.

Args:
    tops (iterable). A list of floats.
    values (iterable). A list of values to look up.
    basis (iterable). A list of components.
    components (iterable). A list of Components.

Returns:
    List. A list of Intervals.


@classmethod<EOL><INDENT>def _clean_longitudinal_data(cls, data, null=None):<DEDENT>

<EOL>if ('<STR_LIT>' not in data.keys()):<EOL><INDENT>data['<STR_LIT>'] = data.pop('<STR_LIT>', data.pop('<STR_LIT>', None))<EOL><DEDENT>idx = list(data.keys()).index('<STR_LIT>')<EOL>values = sorted(zip(*data.values()), key=lambda x: x[idx])<EOL>data = {k: list(v) for k, v in zip(data.keys(), zip(*values))}<EOL>if data['<STR_LIT>'] is None:<EOL><INDENT>raise StriplogError('<STR_LIT>')<EOL><DEDENT>if null is not None:<EOL><INDENT>for k, v in data.items():<EOL><INDENT>data[k] = [i if i != null else None for i in v]<EOL><DEDENT><DEDENT>return data<EOL>

Private function. Make sure we have what we need to make a striplog.


result = utils.read_petrel(filename,<EOL>function=function,<EOL>remap=remap,<EOL>)<EOL>data = cls._clean_longitudinal_data(result,<EOL>null=null<EOL>)<EOL>list_of_Intervals = cls._build_list_of_Intervals(data,<EOL>stop=stop,<EOL>points=points,<EOL>include=include,<EOL>exclude=exclude,<EOL>ignore=ignore<EOL>)<EOL>if list_of_Intervals:<EOL><INDENT>return cls(list_of_Intervals)<EOL><DEDENT>return None<EOL>

Makes a striplog from a Petrel text file.

Returns:
    striplog.


include = include or {}<EOL>exclude = exclude or {}<EOL>ignore = ignore or []<EOL>all_data = []<EOL>for data in zip(*data_dict.values()):<EOL><INDENT>all_data.append({k: v for k, v in zip(data_dict.keys(), data)})<EOL><DEDENT>all_data = sorted(all_data, key=lambda x: x['<STR_LIT>'])<EOL>wanted_data = []<EOL>for dictionary in all_data:<EOL><INDENT>keep = True<EOL>delete = []<EOL>for k, v in dictionary.items():<EOL><INDENT>incl = include.get(k, utils.null_default(True))<EOL>excl = exclude.get(k, utils.null_default(False))<EOL>if k in ignore:<EOL><INDENT>delete.append(k)<EOL><DEDENT>if not incl(v):<EOL><INDENT>keep = False<EOL><DEDENT>if excl(v):<EOL><INDENT>keep = False<EOL><DEDENT><DEDENT>if delete:<EOL><INDENT>for key in delete:<EOL><INDENT>_ = dictionary.pop(key, None)<EOL><DEDENT><DEDENT>if keep:<EOL><INDENT>wanted_data.append(dictionary)<EOL><DEDENT><DEDENT>if not points:<EOL><INDENT>for i, iv in enumerate(wanted_data):<EOL><INDENT>if iv.get('<STR_LIT>', None) is None:<EOL><INDENT>try:  <EOL><INDENT>iv['<STR_LIT>'] = wanted_data[i+<NUM_LIT:1>]['<STR_LIT>']<EOL><DEDENT>except (IndexError, KeyError):<EOL><INDENT>if stop is not None:<EOL><INDENT>thick = stop - iv['<STR_LIT>']<EOL><DEDENT>else:<EOL><INDENT>thick = <NUM_LIT:1><EOL><DEDENT>iv['<STR_LIT>'] = iv['<STR_LIT>'] + thick<EOL><DEDENT><DEDENT><DEDENT><DEDENT>list_of_Intervals = []<EOL>for iv in wanted_data:<EOL><INDENT>top = iv.pop('<STR_LIT>')<EOL>base = iv.pop('<STR_LIT>', None)<EOL>descr = iv.pop('<STR_LIT:description>', '<STR_LIT>')<EOL>if iv:<EOL><INDENT>c, d = {}, {}<EOL>for k, v in iv.items():<EOL><INDENT>if (k[:<NUM_LIT:5>].lower() == '<STR_LIT>') or (k[:<NUM_LIT:9>].lower() == '<STR_LIT>'):<EOL><INDENT>k = re.sub(r'<STR_LIT>', '<STR_LIT>', k, flags=re.I)<EOL>c[k] = v  <EOL><DEDENT>else:<EOL><INDENT>if v is not None:<EOL><INDENT>d[k] = v  <EOL><DEDENT><DEDENT><DEDENT>comp = [Component(c)] if c else None<EOL>this = Interval(**{'<STR_LIT>': top,<EOL>'<STR_LIT>': base,<EOL>'<STR_LIT:description>': descr,<EOL>'<STR_LIT:data>': d,<EOL>'<STR_LIT>': comp})<EOL><DEDENT>else:<EOL><INDENT>this = Interval(**{'<STR_LIT>': top,<EOL>'<STR_LIT>': base,<EOL>'<STR_LIT:description>': descr,<EOL>'<STR_LIT>': lexicon})<EOL><DEDENT>list_of_Intervals.append(this)<EOL><DEDENT>return list_of_Intervals<EOL>

Private function. Takes a data dictionary and reconstructs a list
of Intervals from it.

Args:
    data_dict (dict)
    stop (float): Where to end the last interval.
    points (bool)
    include (dict)
    exclude (dict)
    ignore (list)
    lexicon (Lexicon)

Returns:
    list.


if (filename is None) and (text is None):<EOL><INDENT>raise StriplogError("<STR_LIT>")<EOL><DEDENT>if (filename is not None):<EOL><INDENT>if source is None:<EOL><INDENT>source = filename<EOL><DEDENT>with open(filename, '<STR_LIT:r>') as f:<EOL><INDENT>text = f.read()<EOL><DEDENT><DEDENT>source = source or '<STR_LIT>'<EOL>if dlm == '<STR_LIT:U+0020>':<EOL><INDENT>text = re.sub(r'<STR_LIT>', '<STR_LIT:U+0020>', text)<EOL><DEDENT>if fieldnames is not None:<EOL><INDENT>text = dlm.join(fieldnames) + '<STR_LIT:\n>' + text<EOL><DEDENT>try:<EOL><INDENT>f = StringIO(text)  <EOL><DEDENT>except TypeError:<EOL><INDENT>f = StringIO(unicode(text))  <EOL><DEDENT>reader = csv.DictReader(f, delimiter=dlm)<EOL>reorg = {k.strip().lower(): [] for k in reader.fieldnames if k is not None}<EOL>t = f.tell()<EOL>for key in reorg:<EOL><INDENT>f.seek(t)<EOL>for r in reader:<EOL><INDENT>s = {k.strip().lower(): v.strip() for k, v in r.items()}<EOL>try:<EOL><INDENT>reorg[key].append(float(s[key]))<EOL><DEDENT>except ValueError:<EOL><INDENT>reorg[key].append(s[key])<EOL><DEDENT><DEDENT><DEDENT>f.close()<EOL>remap = remap or {}<EOL>for k, v in remap.items():<EOL><INDENT>reorg[v] = reorg.pop(k)<EOL><DEDENT>data = cls._clean_longitudinal_data(reorg, null=null)<EOL>list_of_Intervals = cls._build_list_of_Intervals(data,<EOL>points=points,<EOL>lexicon=lexicon,<EOL>include=include,<EOL>exclude=exclude,<EOL>ignore=ignore,<EOL>stop=stop)<EOL>return cls(list_of_Intervals, source=source)<EOL>


text = re.sub(r'<STR_LIT>', '<STR_LIT:\n>', text.strip())<EOL>as_strings = []<EOL>try:<EOL><INDENT>f = StringIO(text)  <EOL><DEDENT>except TypeError:<EOL><INDENT>f = StringIO(unicode(text))  <EOL><DEDENT>reader = csv.reader(f, delimiter=dlm, skipinitialspace=True)<EOL>for row in reader:<EOL><INDENT>as_strings.append(row)<EOL><DEDENT>f.close()<EOL>if not columns:<EOL><INDENT>if order[<NUM_LIT:0>].lower() == '<STR_LIT:e>':<EOL><INDENT>columns = ('<STR_LIT>', '<STR_LIT>', '<STR_LIT:description>')<EOL><DEDENT>else:<EOL><INDENT>columns = ('<STR_LIT>', '<STR_LIT>', '<STR_LIT:description>')<EOL><DEDENT><DEDENT>result = {k: [] for k in columns}<EOL>tix = columns.index('<STR_LIT>')<EOL>bix = columns.index('<STR_LIT>')<EOL>dix = columns.index('<STR_LIT:description>')<EOL>for i, row in enumerate(as_strings):<EOL><INDENT>if len(row) == <NUM_LIT:2>:<EOL><INDENT>row = [row[<NUM_LIT:0>], None, row[<NUM_LIT:1>]]<EOL><DEDENT>this_top = float(row[tix])<EOL>if row[<NUM_LIT:1>] is None:<EOL><INDENT>if i < len(as_strings)-<NUM_LIT:1>:<EOL><INDENT>this_base = float(as_strings[i+<NUM_LIT:1>][<NUM_LIT:0>])  <EOL><DEDENT>else:<EOL><INDENT>this_base = this_top + <NUM_LIT:1>  <EOL><DEDENT><DEDENT>else:<EOL><INDENT>this_base = float(row[bix])<EOL><DEDENT>this_descr = row[dix].strip()<EOL>if not points:<EOL><INDENT>if complete and (i > <NUM_LIT:0>) and (this_top != result['<STR_LIT>'][-<NUM_LIT:1>]):<EOL><INDENT>result['<STR_LIT>'].append(result['<STR_LIT>'][-<NUM_LIT:1>])<EOL>result['<STR_LIT>'].append(this_top)<EOL>result['<STR_LIT:description>'].append('<STR_LIT>')<EOL><DEDENT><DEDENT>else:<EOL><INDENT>this_base = None  <EOL><DEDENT>result['<STR_LIT>'].append(this_top)<EOL>result['<STR_LIT>'].append(this_base)<EOL>result['<STR_LIT:description>'].append(this_descr)<EOL><DEDENT>list_of_Intervals = []<EOL>for i, t in enumerate(result['<STR_LIT>']):<EOL><INDENT>b = result['<STR_LIT>'][i]<EOL>d = result['<STR_LIT:description>'][i]<EOL>interval = Interval(t, b, description=d,<EOL>lexicon=lexicon,<EOL>abbreviations=abbreviations)<EOL>list_of_Intervals.append(interval)<EOL><DEDENT>return cls(list_of_Intervals, source=source)<EOL>

Convert a CSV string into a striplog. Expects 2 or 3 fields:
    top, description
    OR
    top, base, description

Args:
    text (str): The input text, given by ``well.other``.
    lexicon (Lexicon): A lexicon, required to extract components.
    source (str): A source. Default: 'CSV'.
    dlm (str): The delimiter, given by ``well.dlm``. Default: ','
    points (bool): Whether to treat as points or as intervals.
    abbreviations (bool): Whether to expand abbreviations in the
        description. Default: False.
    complete (bool): Whether to make 'blank' intervals, or just leave
        gaps. Default: False.
    order (str): The order, 'depth' or 'elevation'. Default: 'depth'.
    columns (tuple or list): The names of the columns.

Returns:
    Striplog: A ``striplog`` object.

Example:
    # TOP       BOT        LITH
    312.34,   459.61,    Sandstone
    459.71,   589.61,    Limestone
    589.71,   827.50,    Green shale
    827.60,   1010.84,   Fine sandstone


@classmethod<EOL><INDENT>def from_image(cls, filename, start, stop, legend,<EOL>source="<STR_LIT>",<EOL>col_offset=<NUM_LIT:0.1>,<EOL>row_offset=<NUM_LIT:2>,<EOL>tolerance=<NUM_LIT:0>):<DEDENT>

rgb = utils.loglike_from_image(filename, col_offset)<EOL>loglike = np.array([utils.rgb_to_hex(t) for t in rgb])<EOL>tops, hexes = utils.tops_from_loglike(loglike, offset=row_offset)<EOL>nonconsecutive = np.append(np.diff(tops), <NUM_LIT:2>)<EOL>tops = tops[nonconsecutive > <NUM_LIT:1>]<EOL>hexes = hexes[nonconsecutive > <NUM_LIT:1>]<EOL>hexes_reduced = list(set(hexes))<EOL>components = [legend.get_component(h, tolerance=tolerance)<EOL>for h in hexes_reduced]<EOL>values = [hexes_reduced.index(i) for i in hexes]<EOL>basis = np.linspace(start, stop, loglike.size)<EOL>list_of_Intervals = cls.__intervals_from_tops(tops,<EOL>values,<EOL>basis,<EOL>components)<EOL>return cls(list_of_Intervals, source="<STR_LIT>")<EOL>

Read an image and generate Striplog.

Args:
    filename (str): An image file, preferably high-res PNG.
    start (float or int): The depth at the top of the image.
    stop (float or int): The depth at the bottom of the image.
    legend (Legend): A legend to look up the components in.
    source (str): A source for the data. Default: 'Image'.
    col_offset (Number): The proportion of the way across the image
        from which to extract the pixel column. Default: 0.1 (ie 10%).
    row_offset (int): The number of pixels to skip at the top of
        each change in colour. Default: 2.
    tolerance (float): The Euclidean distance between hex colours,
        which has a maximum (black to white) of 441.67 in base 10.
        Default: 0.

Returns:
    Striplog: The ``striplog`` object.


@classmethod<EOL><INDENT>def from_img(cls, *args, **kwargs):<DEDENT>

with warnings.catch_warnings():<EOL><INDENT>warnings.simplefilter("<STR_LIT>")<EOL>w = "<STR_LIT>"<EOL>warnings.warn(w)<EOL><DEDENT>return cls.from_image(*args, **kwargs)<EOL>


with warnings.catch_warnings():<EOL><INDENT>warnings.simplefilter("<STR_LIT>")<EOL>w = "<STR_LIT>"<EOL>warnings.warn(w, DeprecationWarning, stacklevel=<NUM_LIT:2>)<EOL><DEDENT>csv_text = '<STR_LIT>'<EOL>for interval in a:<EOL><INDENT>interval = [str(i) for i in interval]<EOL>if (len(interval) < <NUM_LIT:2>) or (len(interval) > <NUM_LIT:3>):<EOL><INDENT>raise StriplogError('<STR_LIT>')<EOL><DEDENT>descr = interval[-<NUM_LIT:1>].strip('<STR_LIT>')<EOL>interval[-<NUM_LIT:1>] = '<STR_LIT:">' + descr + '<STR_LIT:">'<EOL>csv_text += '<STR_LIT:U+002CU+0020>'.join(interval) + '<STR_LIT:\n>'<EOL><DEDENT>return cls.from_descriptions(csv_text,<EOL>lexicon,<EOL>source=source,<EOL>points=points,<EOL>abbreviations=abbreviations)<EOL>

DEPRECATING.

Turn an array-like into a Striplog. It should have the following
format (where ``base`` is optional):

    [(top, base, description),
     (top, base, description),
     ...
     ]

Args:
    a (array-like): A list of lists or of tuples, or an array.
    lexicon (Lexicon): A language dictionary to extract structured
        objects from the descriptions.
    source (str): The source of the data. Default: ''.
    points (bool): Whether to treat as point data. Default: False.

Returns:
    Striplog: The ``striplog`` object.


if (components is None) and (legend is None) and (field is None):<EOL><INDENT>m = '<STR_LIT>'<EOL>raise StriplogError(m)<EOL><DEDENT>if (legend is not None) and (legend_field is None):<EOL><INDENT>try:  <EOL><INDENT>components = [deepcopy(decor.component) for decor in legend]<EOL><DEDENT>except AttributeError:  <EOL><INDENT>pass<EOL><DEDENT><DEDENT>if legend_field is not None:<EOL><INDENT>field_values = [getattr(d, legend_field, <NUM_LIT:0>) for d in legend]<EOL>components = [Component() for i in range(int(max(field_values)+<NUM_LIT:1>))]<EOL>for i, decor in enumerate(legend):<EOL><INDENT>components[i] = deepcopy(decor.component)<EOL><DEDENT><DEDENT>if cutoff is not None:<EOL><INDENT>try:<EOL><INDENT>n = len(cutoff)<EOL><DEDENT>except TypeError:<EOL><INDENT>n = <NUM_LIT:1><EOL><DEDENT>if len(components) < n+<NUM_LIT:1>:<EOL><INDENT>m = '<STR_LIT>'<EOL>m += '<STR_LIT>'<EOL>raise StriplogError(m)<EOL><DEDENT>try:  <EOL><INDENT>a = np.digitize(log, cutoff, right)<EOL><DEDENT>except ValueError:  <EOL><INDENT>a = np.digitize(log, [cutoff], right)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>a = np.copy(log)<EOL><DEDENT>tops, values = utils.tops_from_loglike(a)<EOL>if basis is None:<EOL><INDENT>m = '<STR_LIT>'<EOL>raise StriplogError(m)<EOL><DEDENT>list_of_Intervals = cls.__intervals_from_tops(tops,<EOL>values,<EOL>basis,<EOL>components,<EOL>field=field<EOL>)<EOL>return cls(list_of_Intervals, source=source)<EOL>

Turn a 1D array into a striplog, given a cutoff.

Args:
    log (array-like): A 1D array or a list of integers.
    cutoff (number or array-like): The log value(s) at which to bin
        the log. Optional.
    components (array-like): A list of components. Use this or
        ``legend``.
    legend (``Legend``): A legend object. Use this or ``components``.
    legend_field ('str'): If you're not trying to match against
        components, then you can match the log values to this field in
        the Decors.
    field (str): The field in the Interval's ``data`` to store the log
        values as.
    right (bool): Which side of the cutoff to send things that are
        equal to, i.e. right on, the cutoff.
    basis (array-like): A depth basis for the log, so striplog knows
        where to put the boundaries.
    source (str): The source of the data. Default 'Log'.

Returns:
    Striplog: The ``striplog`` object.


f = re.DOTALL | re.IGNORECASE<EOL>regex = r'<STR_LIT>'<EOL>pattern = re.compile(regex, flags=f)<EOL>text = pattern.search(string).group(<NUM_LIT:1>)<EOL>s = re.search(r'<STR_LIT>', string)<EOL>if s:<EOL><INDENT>source = s.group(<NUM_LIT:1>).strip()<EOL><DEDENT>return cls.from_descriptions(text, lexicon,<EOL>source=source,<EOL>dlm=dlm,<EOL>abbreviations=abbreviations)<EOL>

Turn LAS3 'lithology' section into a Striplog.

Args:
    string (str): A section from an LAS3 file.
    lexicon (Lexicon): The language for conversion to components.
    source (str): A source for the data.
    dlm (str): The delimiter.
    abbreviations (bool): Whether to expand abbreviations.

Returns:
    Striplog: The ``striplog`` object.

Note:
    Handles multiple 'Data' sections. It would be smarter for it
    to handle one at a time, and to deal with parsing the multiple
    sections in the Well object.

    Does not read an actual LAS file. Use the Well object for that.


@classmethod<EOL><INDENT>def from_canstrat(cls, filename, source='<STR_LIT>'):<DEDENT>

with open(filename) as f:<EOL><INDENT>dat = f.read()<EOL><DEDENT>data = parse_canstrat(dat)<EOL>list_of_Intervals = []<EOL>for d in data[<NUM_LIT:7>]:  <EOL><INDENT>if d.pop('<STR_LIT>'):<EOL><INDENT>continue<EOL><DEDENT>top = d.pop('<STR_LIT>')<EOL>base = d.pop('<STR_LIT>')<EOL>comps = [Component({'<STR_LIT>': d['<STR_LIT>'],<EOL>'<STR_LIT>': d['<STR_LIT>']<EOL>})]<EOL>iv = Interval(top=top, base=base, components=comps, data=d)<EOL>list_of_Intervals.append(iv)<EOL><DEDENT>return cls(list_of_Intervals, source=source)<EOL>

Eat a Canstrat DAT file and make a striplog.


return Striplog([i.copy() for i in self],<EOL>order=self.order,<EOL>source=self.source)<EOL>


def to_canstrat(self, filename, params):

return None<EOL>

Write a Canstrat ASCII file.

Args:
    filename (str)
    params (dict): The well details. You can use a ``welly`` header
        object.

Returns:


if (filename is None):<EOL><INDENT>if (not as_text):<EOL><INDENT>raise StriplogError("<STR_LIT>")<EOL><DEDENT><DEDENT>else:<EOL><INDENT>as_text = False<EOL><DEDENT>if as_text:<EOL><INDENT>output = StringIO()<EOL><DEDENT>else:<EOL><INDENT>output = open(filename, '<STR_LIT:w>')<EOL><DEDENT>fieldnames = ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>']<EOL>writer = csv.DictWriter(output,<EOL>delimiter=dlm,<EOL>fieldnames=fieldnames,<EOL>quoting=csv.QUOTE_MINIMAL)<EOL>if header:<EOL><INDENT>writer.writeheader()<EOL><DEDENT>for i in self.__list:<EOL><INDENT>if use_descriptions and i.description:<EOL><INDENT>text = i.description<EOL><DEDENT>elif i.primary:<EOL><INDENT>text = i.primary.summary()<EOL><DEDENT>else:<EOL><INDENT>text = '<STR_LIT>'<EOL><DEDENT>data = {j: k for j, k in zip(fieldnames, [i.top.z, i.base.z, text])}<EOL>writer.writerow(data)<EOL><DEDENT>if as_text:<EOL><INDENT>return output.getvalue()<EOL><DEDENT>else:<EOL><INDENT>output.close<EOL>return None<EOL><DEDENT>

Returns a CSV string built from the summaries of the Intervals.

Args:
    use_descriptions (bool): Whether to use descriptions instead
        of summaries, if available.
    dlm (str): The delimiter.
    header (bool): Whether to form a header row.

Returns:
    str: A string of comma-separated values.


def to_las3(self, use_descriptions=False, dlm="<STR_LIT:U+002C>", source="<STR_LIT>"):

Returns an LAS 3.0 section string.

Args:
    use_descriptions (bool): Whether to use descriptions instead
        of summaries, if available.
    dlm (str): The delimiter.
    source (str): The sourse of the data.

Returns:
    str: A string forming Lithology section of an LAS3 file.


<EOL>if basis is not None:<EOL><INDENT>start, stop = basis[<NUM_LIT:0>], basis[-<NUM_LIT:1>]<EOL>step = basis[<NUM_LIT:1>] - start<EOL><DEDENT>else:<EOL><INDENT>start = start or self.start.z<EOL>stop = stop or self.stop.z<EOL>pts = np.ceil((stop - start)/step) + <NUM_LIT:1><EOL>basis = np.linspace(start, stop, int(pts))<EOL><DEDENT>if (field is not None) or (legend_field is not None):<EOL><INDENT>result = np.zeros_like(basis, dtype=dtype)<EOL><DEDENT>else:<EOL><INDENT>result = np.zeros_like(basis, dtype=np.int)<EOL><DEDENT>if np.isnan(undefined):<EOL><INDENT>try:<EOL><INDENT>result[:] = np.nan<EOL><DEDENT>except:<EOL><INDENT>pass  <EOL><DEDENT><DEDENT>if table is None:<EOL><INDENT>table = [Component({})]<EOL>if legend:<EOL><INDENT>table += [j.component for j in legend]<EOL><DEDENT>elif field:<EOL><INDENT>s = set([iv.data.get(field) for iv in self])<EOL>table = [None] + list(filter(None, s))<EOL><DEDENT>else:<EOL><INDENT>table += [j[<NUM_LIT:0>] for j in self.unique]<EOL><DEDENT><DEDENT>if match_only is not None:<EOL><INDENT>if not isinstance(match_only, (list, tuple, set,)):<EOL><INDENT>raise StriplogError("<STR_LIT>")<EOL><DEDENT>table_new = []<EOL>for c in table:<EOL><INDENT>if c == '<STR_LIT>':<EOL><INDENT>continue  <EOL><DEDENT>c_new = Component({k: v for k, v in c.__dict__.items()<EOL>if k in match_only})<EOL>if c_new not in table_new:<EOL><INDENT>table_new.append(c_new)<EOL><DEDENT><DEDENT>table = table_new<EOL><DEDENT>else:<EOL><INDENT>match_only = []<EOL><DEDENT>start_ix = self.read_at(start, index=True)<EOL>stop_ix = self.read_at(stop, index=True)<EOL>if stop_ix is not None:<EOL><INDENT>stop_ix += <NUM_LIT:1><EOL><DEDENT>for i in self[start_ix:stop_ix]:<EOL><INDENT>c = i.primary<EOL>if match_only:<EOL><INDENT>c = Component({k: getattr(c, k, None)<EOL>for k in match_only})<EOL><DEDENT>if legend and legend_field:  <EOL><INDENT>try:<EOL><INDENT>key = legend.getattr(c, legend_field, undefined)<EOL>key = key or undefined<EOL><DEDENT>except ValueError:<EOL><INDENT>key = undefined<EOL><DEDENT><DEDENT>elif field:  <EOL><INDENT>f = field_function or utils.null<EOL>try:<EOL><INDENT>v = f(i.data.get(field, undefined)) or undefined<EOL>key = table.index(v)<EOL><DEDENT>except ValueError:<EOL><INDENT>key = undefined<EOL><DEDENT><DEDENT>else:  <EOL><INDENT>try:<EOL><INDENT>key = table.index(c) or undefined<EOL><DEDENT>except ValueError:<EOL><INDENT>key = undefined<EOL><DEDENT><DEDENT>top_index = int(np.ceil((max(start, i.top.z)-start)/step))<EOL>base_index = int(np.ceil((min(stop, i.base.z)-start)/step))<EOL>try:<EOL><INDENT>result[top_index:base_index+<NUM_LIT:1>] = key<EOL><DEDENT>except:  <EOL><INDENT>result[top_index:base_index+<NUM_LIT:1>] = key[<NUM_LIT:0>]<EOL><DEDENT><DEDENT>if return_meta:<EOL><INDENT>return result, basis, table<EOL><DEDENT>else:<EOL><INDENT>return result<EOL><DEDENT>

Return a fully sampled log from a striplog. Useful for crossplotting
with log data, for example.

Args:
    step (float): The step size. Default: 1.0.
    start (float): The start depth of the new log. You will want to
        match the logs, so use the start depth from the LAS file.
        Default: The basis if provided, else the start of the striplog.
    stop (float): The stop depth of the new log. Use the stop depth
        of the LAS file. Default: The basis if provided, else the stop
        depth of the striplog.
    field (str): If you want the data to come from one of the
        attributes of the components in the striplog, provide it.
    field_function (function): Provide a function to apply to the field
        you are asking for. It's up to you to make sure the function
        does what you want.
    legend (Legend): If you want the codes to come from a legend,
        provide one. Otherwise the codes come from the log, using
        integers in the order of prevalence. If you use a legend,
        they are assigned in the order of the legend.
    legend_field (str): If you want to get a log representing one of
        the fields in the legend, such as 'width' or 'grainsize'.
    match_only (list): If you only want to match some attributes of
        the Components (e.g. lithology), provide a list of those
        you want to match.
    undefined (number): What to fill in where no value can be
        determined, e.g. ``-999.25`` or ``np.null``. Default 0.
    return_meta (bool): If ``True``, also return the depth basis
        (np.linspace), and the component table.

Returns:
    ndarray: If ``return_meta`` was ``True``, you get:

          * The log data as an array of ints.
          * The depth basis as an array of floats.
          * A list of the components in the order matching the ints.

        If ``return_meta`` was ``False`` (the default), you only get
        the log data.


return self.to_log(**kwargs).astype(bool)<EOL>

A wrapper for ``to_log()`` that returns a boolean array.
Useful for masking. Has the same interface as ``to_log()``.


ys = [iv.top.z for iv in self]<EOL>if field is not None:<EOL><INDENT>f = field_function or utils.null<EOL>xs = [f(iv.data.get(field, undefined)) for iv in self]<EOL><DEDENT>else:<EOL><INDENT>xs = [<NUM_LIT:1> for iv in self]<EOL><DEDENT>ax.set_xlim((min(xs), max(xs)))<EOL>for x, y in zip(xs, ys):<EOL><INDENT>ax.axhline(y, color='<STR_LIT>', zorder=<NUM_LIT:0>)<EOL><DEDENT>ax.scatter(xs, ys, clip_on=False, **kwargs)<EOL>return ax<EOL>

Plotting, but only for points (as opposed to intervals).


def plot_tops(self, ax, legend=None, field=None, **kwargs):

if field is None:<EOL><INDENT>raise StriplogError('<STR_LIT>')<EOL><DEDENT>ys = [iv.top.z for iv in self]<EOL>try:<EOL><INDENT>try:<EOL><INDENT>ts = [getattr(iv.primary, field) for iv in self]<EOL><DEDENT>except:<EOL><INDENT>ts = [iv.data.get(field) for iv in self]<EOL><DEDENT><DEDENT>except:<EOL><INDENT>raise StriplogError('<STR_LIT>')<EOL><DEDENT>for y, t in zip(ys, ts):<EOL><INDENT>ax.axhline(y, color='<STR_LIT>', lw=<NUM_LIT:3>, zorder=<NUM_LIT:0>)<EOL>ax.text(<NUM_LIT:0.1>, y-max(ys)/<NUM_LIT:200>, t, ha='<STR_LIT:left>')<EOL><DEDENT>return ax<EOL>

Plotting, but only for tops (as opposed to intervals).


def plot_field(self, ax, legend=None, field=None, **kwargs):

if field is None:<EOL><INDENT>raise StriplogError('<STR_LIT>')<EOL><DEDENT>try:<EOL><INDENT>try:<EOL><INDENT>xs = [getattr(iv.primary, field) for iv in self]<EOL><DEDENT>except:<EOL><INDENT>xs = [iv.data.get(field) for iv in self]<EOL><DEDENT><DEDENT>except:<EOL><INDENT>raise StriplogError('<STR_LIT>')<EOL><DEDENT>for iv, x in zip(self.__list, xs):<EOL><INDENT>_, ymin = utils.axis_transform(ax, <NUM_LIT:0>, iv.base.z, ylim=(self.start.z, self.stop.z), inverse=True)<EOL>_, ymax = utils.axis_transform(ax, <NUM_LIT:0>, iv.top.z, ylim=(self.start.z, self.stop.z), inverse=True)<EOL>ax.axvline(x, ymin=ymin, ymax=ymax)<EOL><DEDENT>return ax<EOL>


default_c = None<EOL>patches = []<EOL>for iv in self.__list:<EOL><INDENT>origin = (<NUM_LIT:0>, iv.top.z)<EOL>d = legend.get_decor(iv.primary, match_only=match_only)<EOL>thick = iv.base.z - iv.top.z<EOL>if ladder:<EOL><INDENT>if width_field is not None:<EOL><INDENT>w = iv.data.get(width_field, <NUM_LIT:1>)<EOL>w = default_width * w/self.max_field(width_field)<EOL>default_c = '<STR_LIT>'<EOL><DEDENT>elif legend is not None:<EOL><INDENT>w = d.width or default_width<EOL>try:<EOL><INDENT>w = default_width * w/legend.max_width<EOL><DEDENT>except:<EOL><INDENT>w = default_width<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>w = default_width<EOL><DEDENT>this_patch_kwargs = kwargs.copy()<EOL>lw = this_patch_kwargs.pop('<STR_LIT>', <NUM_LIT:0>)<EOL>ec = this_patch_kwargs.pop('<STR_LIT>', '<STR_LIT:k>')<EOL>fc = this_patch_kwargs.pop('<STR_LIT>', None) or default_c or d.colour<EOL>if colour is None:<EOL><INDENT>rect = mpl.patches.Rectangle(origin,<EOL>w,<EOL>thick,<EOL>fc=fc,<EOL>lw=lw,<EOL>hatch=d.hatch,<EOL>ec=ec,  <EOL>**this_patch_kwargs)<EOL>ax.add_patch(rect)<EOL><DEDENT>else:<EOL><INDENT>rect = mpl.patches.Rectangle(origin,<EOL>w,<EOL>thick,<EOL>lw=lw,<EOL>ec=ec,  <EOL>**this_patch_kwargs)<EOL>patches.append(rect)<EOL><DEDENT><DEDENT>if colour is not None:<EOL><INDENT>cmap = cmap or '<STR_LIT>'<EOL>p = mpl.collections.PatchCollection(patches, cmap=cmap, lw=lw)<EOL>p.set_array(self.get_data(colour, colour_function, default=default))<EOL>ax.add_collection(p)<EOL>cb = plt.colorbar(p)  <EOL>cb.outline.set_linewidth(<NUM_LIT:0>)<EOL><DEDENT>return ax<EOL>

Plotting, but only the Rectangles. You have to set up the figure.
Returns a matplotlib axis object.

Args:
    ax (axis): The matplotlib axis to plot into.
    legend (Legend): The Legend to use for colours, etc.
    ladder (bool): Whether to use widths or not. Default False.
    default_width (int): A width for the plot if not using widths.
        Default 1.
    match_only (list): A list of strings matching the attributes you
        want to compare when plotting.
    colour (str): Which data field to use for colours.
    cmap (cmap): Matplotlib colourmap. Default ``viridis``.
    default (float): The default (null) value.
    width_field (str): The field to use for the width of the patches.
    **kwargs are passed through to matplotlib's ``patches.Rectangle``.

Returns:
    axis: The matplotlib.pyplot axis.


def get_data(self, field, function=None, default=None):

f = function or utils.null<EOL>data = []<EOL>for iv in self:<EOL><INDENT>d = iv.data.get(field)<EOL>if d is None:<EOL><INDENT>if default is not None:<EOL><INDENT>d = default<EOL><DEDENT>else:<EOL><INDENT>d = np.nan<EOL><DEDENT><DEDENT>data.append(f(d))<EOL><DEDENT>return np.array(data)<EOL>


if legend is None:<EOL><INDENT>legend = Legend.random(self.components)<EOL><DEDENT>if style.lower() == '<STR_LIT>':<EOL><INDENT>width = max([<NUM_LIT:3>, width])<EOL><DEDENT>if ax is None:<EOL><INDENT>return_ax = False<EOL>fig = plt.figure(figsize=(width, aspect*width))<EOL>ax = fig.add_axes([<NUM_LIT>, <NUM_LIT>, <NUM_LIT>, <NUM_LIT>])<EOL><DEDENT>else:<EOL><INDENT>return_ax = True<EOL><DEDENT>if (self.order == '<STR_LIT:none>') or (style.lower() == '<STR_LIT>'):<EOL><INDENT>ax = self.plot_points(ax=ax, legend=legend, field=field, **kwargs)<EOL><DEDENT>elif style.lower() == '<STR_LIT>':<EOL><INDENT>if field is None:<EOL><INDENT>raise StriplogError('<STR_LIT>')<EOL><DEDENT>ax = self.plot_field(ax=ax, legend=legend, field=field)<EOL><DEDENT>elif style.lower() == '<STR_LIT>':<EOL><INDENT>ax = self.plot_tops(ax=ax, legend=legend, field=field)<EOL>ax.set_xticks([])<EOL><DEDENT>else:<EOL><INDENT>ax = self.plot_axis(ax=ax,<EOL>legend=legend,<EOL>ladder=ladder,<EOL>default_width=width,<EOL>match_only=kwargs.get('<STR_LIT>', match_only),<EOL>colour=colour,<EOL>cmap=cmap,<EOL>default=default,<EOL>width_field=field,<EOL>**kwargs<EOL>)<EOL>ax.set_xlim([<NUM_LIT:0>, width])<EOL>ax.set_xticks([])<EOL><DEDENT>lower, upper = self[-<NUM_LIT:1>].base.z, self[<NUM_LIT:0>].top.z<EOL>rng = abs(upper - lower)<EOL>ax.set_ylim([lower, upper])<EOL>try:<EOL><INDENT>ticks = tuple(ticks)<EOL><DEDENT>except TypeError:<EOL><INDENT>ticks = (<NUM_LIT:1>, ticks)<EOL><DEDENT>while rng/ticks[<NUM_LIT:0>] > <NUM_LIT>:<EOL><INDENT>mi, ma = <NUM_LIT:10>*ticks[<NUM_LIT:0>], ticks[<NUM_LIT:1>]<EOL>if ma <= mi:<EOL><INDENT>ma = <NUM_LIT:10> * mi<EOL><DEDENT>ticks = (mi, ma)<EOL><DEDENT>minorLocator = mpl.ticker.MultipleLocator(ticks[<NUM_LIT:0>])<EOL>ax.yaxis.set_minor_locator(minorLocator)<EOL>majorLocator = mpl.ticker.MultipleLocator(ticks[<NUM_LIT:1>])<EOL>majorFormatter = mpl.ticker.FormatStrFormatter('<STR_LIT>')<EOL>ax.yaxis.set_major_locator(majorLocator)<EOL>ax.yaxis.set_major_formatter(majorFormatter)<EOL>ax.spines['<STR_LIT>'].set_visible(False)<EOL>ax.spines['<STR_LIT:right>'].set_visible(False)<EOL>ax.spines['<STR_LIT>'].set_visible(False)<EOL>ax.yaxis.set_ticks_position('<STR_LIT:left>')<EOL>ax.get_yaxis().set_tick_params(which='<STR_LIT>', direction='<STR_LIT>')<EOL>title = getattr(self, '<STR_LIT:title>', None)<EOL>if title is not None:<EOL><INDENT>ax.set_title(title)<EOL><DEDENT>ax.patch.set_alpha(<NUM_LIT:0>)<EOL>if return_ax:<EOL><INDENT>return ax<EOL><DEDENT>elif return_fig:<EOL><INDENT>return fig<EOL><DEDENT>else:<EOL><INDENT>return<EOL><DEDENT>

Hands-free plotting.

Args:
    legend (Legend): The Legend to use for colours, etc.
    width (int): The width of the plot, in inches. Default 1.
    ladder (bool): Whether to use widths or not. Default False.
    aspect (int): The aspect ratio of the plot. Default 10.
    ticks (int or tuple): The (minor,major) tick interval for depth.
        Only the major interval is labeled. Default (1,10).
    match_only (list): A list of strings matching the attributes you
        want to compare when plotting.
    ax (ax): A maplotlib axis to plot onto. If you pass this, it will
        be returned. Optional.
    return_fig (bool): Whether or not to return the maplotlib ``fig``
        object. Default False.
    colour (str): Which data field to use for colours.
    cmap (cmap): Matplotlib colourmap. Default ``viridis``.
    **kwargs are passed through to matplotlib's ``patches.Rectangle``.

Returns:
    None. Unless you specify ``return_fig=True`` or pass in an ``ax``.


for i, iv in enumerate(self):<EOL><INDENT>if iv.spans(d):<EOL><INDENT>return i if index else iv<EOL><DEDENT><DEDENT>return None<EOL>

Get the index of the interval at a particular 'depth' (though this
    might be an elevation or age or anything).

Args:
    d (Number): The 'depth' to query.
    index (bool): Whether to return the index instead of the interval.

Returns:
    Interval: The interval, or if ``index==True`` the index of the
        interval, at the specified 'depth', or ``None`` if the depth is
        outside the striplog's range.


with warnings.catch_warnings():<EOL><INDENT>warnings.simplefilter("<STR_LIT>")<EOL>w = "<STR_LIT>"<EOL>warnings.warn(w)<EOL><DEDENT>return self.read_at(d)<EOL>


def extract(self, log, basis, name, function=None):

<EOL>intervals = {}<EOL>previous_ix = -<NUM_LIT:1><EOL>for i, z in enumerate(basis):<EOL><INDENT>ix = self.read_at(z, index=True)<EOL>if ix is None:<EOL><INDENT>continue<EOL><DEDENT>if ix == previous_ix:<EOL><INDENT>intervals[ix].append(log[i])<EOL><DEDENT>else:<EOL><INDENT>intervals[ix] = [log[i]]<EOL><DEDENT>previous_ix = ix<EOL><DEDENT>for ix, data in intervals.items():<EOL><INDENT>f = function or utils.null<EOL>d = f(np.array(data))<EOL>self[ix].data[name] = d<EOL><DEDENT>return None<EOL>

'Extract' a log into the components of a striplog.

Args:
    log (array_like). A log or other 1D data.
    basis (array_like). The depths or elevations of the log samples.
    name (str). The name of the attribute to store in the components.
    function (function). A function that takes an array as the only
        input, and returns whatever you want to store in the 'name'
        attribute of the primary component.
Returns:
    None. The function works on the striplog in place.


def find(self, search_term, index=False):

hits = []<EOL>for i, iv in enumerate(self):<EOL><INDENT>try:<EOL><INDENT>search_text = iv.description or iv.primary.summary()<EOL>pattern = re.compile(search_term, flags=re.IGNORECASE)<EOL>if pattern.search(search_text):<EOL><INDENT>hits.append(i)<EOL><DEDENT><DEDENT>except TypeError:<EOL><INDENT>if search_term in iv.components:<EOL><INDENT>hits.append(i)<EOL><DEDENT><DEDENT><DEDENT>if hits and index:<EOL><INDENT>return hits<EOL><DEDENT>elif hits:<EOL><INDENT>return self[hits]<EOL><DEDENT>else:<EOL><INDENT>return<EOL><DEDENT>

Look for a regex expression in the descriptions of the striplog.
If there's no description, it looks in the summaries.

If you pass a Component, then it will search the components, not the
descriptions or summaries.

Case insensitive.

Args:
    search_term (string or Component): The thing you want to search
        for. Strings are treated as regular expressions.
    index (bool): Whether to return the index instead of the interval.
Returns:
    Striplog: A striplog that contains only the 'hit' Intervals.
        However, if ``index`` was ``True``, then that's what you get.


def __find_incongruities(self, op, index):

if len(self) == <NUM_LIT:1>:<EOL><INDENT>return<EOL><DEDENT>hits = []<EOL>intervals = []<EOL>if self.order == '<STR_LIT>':<EOL><INDENT>one, two = '<STR_LIT>', '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>one, two = '<STR_LIT>', '<STR_LIT>'<EOL><DEDENT>for i, iv in enumerate(self[:-<NUM_LIT:1>]):<EOL><INDENT>next_iv = self[i+<NUM_LIT:1>]<EOL>if op(getattr(iv, one), getattr(next_iv, two)):<EOL><INDENT>hits.append(i)<EOL>top = getattr(iv, one)<EOL>base = getattr(next_iv, two)<EOL>iv_gap = Interval(top, base)<EOL>intervals.append(iv_gap)<EOL><DEDENT><DEDENT>if index and hits:<EOL><INDENT>return hits<EOL><DEDENT>elif intervals:<EOL><INDENT>return Striplog(intervals)<EOL><DEDENT>else:<EOL><INDENT>return<EOL><DEDENT>

Private method. Finds gaps and overlaps in a striplog. Called by
find_gaps() and find_overlaps().

Args:
    op (operator): ``operator.gt`` or ``operator.lt``
    index (bool): If ``True``, returns indices of intervals with
    gaps after them.

Returns:
    Striplog: A striplog of all the gaps. A sort of anti-striplog.


return self.__find_incongruities(op=operator.gt, index=index)<EOL>

Find overlaps in a striplog.

Args:
    index (bool): If True, returns indices of intervals with
    gaps after them.

Returns:
    Striplog: A striplog of all the overlaps as intervals.


return self.__find_incongruities(op=operator.lt, index=index)<EOL>

Finds gaps in a striplog.

Args:
    index (bool): If True, returns indices of intervals with
    gaps after them.

Returns:
    Striplog: A striplog of all the gaps. A sort of anti-striplog.


def prune(self, limit=None, n=None, percentile=None, keep_ends=False):

strip = self.copy()<EOL>if not (limit or n or percentile):<EOL><INDENT>m = "<STR_LIT>"<EOL>raise StriplogError(m)<EOL><DEDENT>if limit:<EOL><INDENT>prune = [i for i, iv in enumerate(strip) if iv.thickness < limit]<EOL><DEDENT>if n:<EOL><INDENT>prune = strip.thinnest(n=n, index=True)<EOL><DEDENT>if percentile:<EOL><INDENT>n = np.floor(len(strip)*percentile/<NUM_LIT:100>)<EOL>prune = strip.thinnest(n=n, index=True)<EOL><DEDENT>if keep_ends:<EOL><INDENT>first, last = <NUM_LIT:0>, len(strip) - <NUM_LIT:1><EOL>if first in prune:<EOL><INDENT>prune.remove(first)<EOL><DEDENT>if last in prune:<EOL><INDENT>prune.remove(last)<EOL><DEDENT><DEDENT>del strip[prune]<EOL>return strip<EOL>

Remove intervals below a certain limit thickness. In place.

Args:
    limit (float): Anything thinner than this will be pruned.
    n (int): The n thinnest beds will be pruned.
    percentile (float): The thinnest specified percentile will be
        pruned.
    keep_ends (bool): Whether to keep the first and last, regardless
        of whether they meet the pruning criteria.


strip = self.copy()<EOL>gaps = strip.find_gaps(index=True)<EOL>if not gaps:<EOL><INDENT>return<EOL><DEDENT>for gap in gaps:<EOL><INDENT>before = strip[gap]<EOL>after = strip[gap + <NUM_LIT:1>]<EOL>if strip.order == '<STR_LIT>':<EOL><INDENT>t = (after.top.z-before.base.z)/<NUM_LIT:2><EOL>before.base = before.base.z + t<EOL>after.top = after.top.z - t<EOL><DEDENT>else:<EOL><INDENT>t = (after.base-before.top)/<NUM_LIT:2><EOL>before.top = before.top.z + t<EOL>after.base = after.base.z - t<EOL><DEDENT><DEDENT>return strip<EOL>

Fill in empty intervals by growing from top and base.

Note that this operation happens in-place and destroys any information
about the ``Position`` (e.g. metadata associated with the top or base).
See GitHub issue #54.


c = [component] if component is not None else []<EOL>gaps = self.find_gaps()<EOL>if not gaps:<EOL><INDENT>return self<EOL><DEDENT>for iv in gaps:<EOL><INDENT>iv.components = c<EOL><DEDENT>return deepcopy(self) + gaps<EOL>

Fill gaps with the component provided.

Example
    t = s.fill(Component({'lithology': 'cheese'}))


if not isinstance(other, self.__class__):<EOL><INDENT>m = "<STR_LIT>"<EOL>raise StriplogError(m)<EOL><DEDENT>result = []<EOL>for iv in deepcopy(self):<EOL><INDENT>for jv in other:<EOL><INDENT>if iv.any_overlaps(jv):<EOL><INDENT>iv = iv.union(jv)<EOL><DEDENT><DEDENT>result.append(iv)<EOL><DEDENT>return Striplog(result)<EOL>

Makes a striplog of all unions.

Args:
    Striplog. The striplog instance to union with.

Returns:
    Striplog. The result of the union.


if not isinstance(other, self.__class__):<EOL><INDENT>m = "<STR_LIT>"<EOL>raise StriplogError(m)<EOL><DEDENT>result = []<EOL>for iv in self:<EOL><INDENT>for jv in other:<EOL><INDENT>try:<EOL><INDENT>result.append(iv.intersect(jv))<EOL><DEDENT>except IntervalError:<EOL><INDENT>pass<EOL><DEDENT><DEDENT><DEDENT>return Striplog(result)<EOL>

Makes a striplog of all intersections.

Args:
    Striplog. The striplog instance to intersect with.

Returns:
    Striplog. The result of the intersection.


overlaps = np.array(self.find_overlaps(index=True))<EOL>if not overlaps.any():<EOL><INDENT>return<EOL><DEDENT>for overlap in overlaps:<EOL><INDENT>before = self[overlap].copy()<EOL>after = self[overlap + <NUM_LIT:1>].copy()<EOL>del self[overlap]<EOL>del self[overlap]<EOL>new_segment = before.merge(after)<EOL>self.__insert(overlap, new_segment)<EOL>overlaps += <NUM_LIT:1><EOL><DEDENT>return<EOL>

Merges overlaps by merging overlapping Intervals.

The function takes no arguments and returns ``None``. It operates on
the striplog 'in place'

TODO: This function will not work if any interval overlaps more than
    one other intervals at either its base or top.


new_strip = [self[<NUM_LIT:0>].copy()]<EOL>for lower in self[<NUM_LIT:1>:]:<EOL><INDENT>touching = new_strip[-<NUM_LIT:1>].touches(lower)<EOL>if strict:<EOL><INDENT>similar = new_strip[-<NUM_LIT:1>].components == lower.components<EOL><DEDENT>else:<EOL><INDENT>similar = new_strip[-<NUM_LIT:1>].primary == lower.primary<EOL><DEDENT>if touching and similar:<EOL><INDENT>new_strip[-<NUM_LIT:1>] = new_strip[-<NUM_LIT:1>].union(lower)<EOL><DEDENT>else:<EOL><INDENT>new_strip.append(lower.copy())<EOL><DEDENT><DEDENT>return Striplog(new_strip)<EOL>

Makes a new striplog in which matching neighbours (for which the
components are the same) are unioned. That is, they are replaced by
a new Interval with the same top as the uppermost and the same bottom
as the lowermost.

Args
    strict (bool): If True, then all of the components must match.
        If False, then only the primary must match.

Returns:
    Striplog. A new striplog.

TODO:
    Might need to be tweaked to deal with 'binary striplogs' if those
    aren't implemented with components.


def thickest(self, n=<NUM_LIT:1>, index=False):

s = sorted(range(len(self)), key=lambda k: self[k].thickness)<EOL>indices = s[-n:]<EOL>if index:<EOL><INDENT>return indices<EOL><DEDENT>else:<EOL><INDENT>if n == <NUM_LIT:1>:<EOL><INDENT>i = indices[<NUM_LIT:0>]<EOL>return self[i]<EOL><DEDENT>else:<EOL><INDENT>return self[indices]<EOL><DEDENT><DEDENT>

Returns the thickest interval(s) as a striplog.

Args:
    n (int): The number of thickest intervals to return. Default: 1.
    index (bool): If True, only the indices of the intervals are
        returned. You can use this to index into the striplog.

Returns:
    Interval. The thickest interval. Or, if ``index`` was ``True``,
    the index of the thickest interval.


def thinnest(self, n=<NUM_LIT:1>, index=False):

s = sorted(range(len(self)), key=lambda k: self[k].thickness)<EOL>indices = s[:n]<EOL>if index:<EOL><INDENT>return indices<EOL><DEDENT>else:<EOL><INDENT>if n == <NUM_LIT:1>:<EOL><INDENT>i = indices[<NUM_LIT:0>]<EOL>return self[i]<EOL><DEDENT>else:<EOL><INDENT>return self[indices]<EOL><DEDENT><DEDENT>

Returns the thinnest interval(s) as a striplog.

Args:
    n (int): The number of thickest intervals to return. Default: 1.
    index (bool): If True, only the indices of the intervals are
        returned. You can use this to index into the striplog.

Returns:
    Interval. The thickest interval. Or, if ``index`` was ``True``,
    the index of the thickest interval.

TODO:
    If you ask for the thinnest bed and there's a tie, you will
    get the last in the ordered list.


<EOL>comps = []<EOL>labels = []<EOL>entries = defaultdict(int)<EOL>for i in self:<EOL><INDENT>if lumping:<EOL><INDENT>k = i.primary[lumping]<EOL><DEDENT>else:<EOL><INDENT>if summary:<EOL><INDENT>k = i.primary.summary()<EOL><DEDENT>else:<EOL><INDENT>k = i.primary<EOL><DEDENT><DEDENT>comps.append(i.primary)<EOL>labels.append(i.primary.summary())<EOL>entries[k] += i.thickness<EOL><DEDENT>if sort:<EOL><INDENT>allitems = sorted(entries.items(), key=lambda i: i[<NUM_LIT:1>], reverse=True)<EOL>ents, counts = zip(*allitems)<EOL><DEDENT>else:<EOL><INDENT>ents, counts = tuple(entries.keys()), tuple(entries.values())<EOL><DEDENT>if plot:<EOL><INDENT>if ax is None:<EOL><INDENT>fig, ax = plt.subplots()<EOL>return_ax = False<EOL><DEDENT>else:<EOL><INDENT>return_ax = True<EOL><DEDENT>ind = np.arange(len(ents))<EOL>bars = ax.bar(ind, counts, align='<STR_LIT>')<EOL>ax.set_xticks(ind)<EOL>ax.set_xticklabels(labels)<EOL>if legend:<EOL><INDENT>colours = [legend.get_colour(c) for c in comps]<EOL>for b, c in zip(bars, colours):<EOL><INDENT>b.set_color(c)<EOL><DEDENT><DEDENT>ax.set_ylabel('<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>bars = []<EOL><DEDENT>if plot and return_ax:<EOL><INDENT>return counts, ents, ax<EOL><DEDENT>return counts, ents, bars<EOL>

Plots a histogram and returns the data for it.

Args:
    lumping (str): If given, the bins will be lumped based on this
        attribute of the primary components of the intervals
        encountered.
    summary (bool): If True, the summaries of the components are
        returned as the bins. Otherwise, the default behaviour is to
        return the Components themselves.
    sort (bool): If True (default), the histogram is sorted by value,
        starting with the largest.
    plot (bool): If True (default), produce a bar plot.
    legend (Legend): The legend with which to colour the bars.
    ax (axis): An axis object, which will be returned if provided.
        If you don't provide one, it will be created but not returned.

Returns:
    Tuple: A tuple of tuples of entities and counts.

TODO:
    Deal with numeric properties, so I can histogram 'Vp' values, say.


def bar(self, height='<STR_LIT>', sort=False, reverse=False,<EOL>legend=None, ax=None, figsize=None, **kwargs):

if sort:<EOL><INDENT>if sort is True:<EOL><INDENT>def func(x): return x.thickness<EOL>reverse = True<EOL><DEDENT>data = sorted(self, key=func, reverse=reverse)<EOL><DEDENT>else:<EOL><INDENT>data = self[:]<EOL><DEDENT>if ax is None:<EOL><INDENT>fig, ax = plt.subplots(figsize=figsize)<EOL><DEDENT>heights = [getattr(i, height) for i in data]<EOL>comps = [i[<NUM_LIT:0>] for i in self.unique]<EOL>if legend is None:<EOL><INDENT>legend = Legend.random(comps)<EOL><DEDENT>colors = [legend.get_colour(i.primary) for i in data]<EOL>bars = ax.bar(range(len(data)), height=heights, color=colors, **kwargs)<EOL>colourables = [i.primary.summary() for i in data]<EOL>unique_bars = dict(zip(colourables, bars))<EOL>ax.legend(unique_bars.values(), unique_bars.keys())<EOL>ax.set_ylabel(height.title())<EOL>return ax<EOL>

Make a bar plot of thickness per interval.

Args:
    height (str): The property of the primary component to plot.
    sort (bool or function): Either pass a boolean indicating whether
        to reverse sort by thickness, or pass a function to be used as
        the sort key.
    reverse (bool): Reverses the sort order.
    legend (Legend): The legend to plot with.
    ax (axis): Optional axis to plot to.
    figsize (tuple): A figure size, (width, height), optional.
    **kwargs: passed to the matplotlib bar plot command, ax.bar().

Returns:
    axis: If you sent an axis in, you get it back.


if copy:<EOL><INDENT>return Striplog([i.invert(copy=True) for i in self])<EOL><DEDENT>else:<EOL><INDENT>for i in self:<EOL><INDENT>i.invert()<EOL><DEDENT>self.__sort()<EOL>o = self.order<EOL>self.order = {'<STR_LIT>': '<STR_LIT>', '<STR_LIT>': '<STR_LIT>'}[o]<EOL>return<EOL><DEDENT>

Inverts the striplog, changing its order and the order of its contents.

Operates in place by default.

Args:
    copy (bool): Whether to operate in place or make a copy.

Returns:
    None if operating in-place, or an inverted copy of the striplog
        if not.


try:<EOL><INDENT>if extent[<NUM_LIT:0>] is None:<EOL><INDENT>extent = (self.start.z, extent[<NUM_LIT:1>])<EOL><DEDENT>if extent[<NUM_LIT:1>] is None:<EOL><INDENT>extent = (extent[<NUM_LIT:0>], self.stop.z)<EOL><DEDENT><DEDENT>except:<EOL><INDENT>m = "<STR_LIT>"<EOL>m += "<STR_LIT>"<EOL>raise StriplogError(m)<EOL><DEDENT>first_ix = self.read_at(extent[<NUM_LIT:0>], index=True)<EOL>last_ix = self.read_at(extent[<NUM_LIT:1>], index=True)<EOL>first = self[first_ix].split_at(extent[<NUM_LIT:0>])[<NUM_LIT:1>]<EOL>last = self[last_ix].split_at(extent[<NUM_LIT:1>])[<NUM_LIT:0>]<EOL>new_list = self.__list[first_ix:last_ix+<NUM_LIT:1>].copy()<EOL>new_list[<NUM_LIT:0>] = first<EOL>new_list[-<NUM_LIT:1>] = last<EOL>if copy:<EOL><INDENT>return Striplog(new_list)<EOL><DEDENT>else:<EOL><INDENT>self.__list = new_list<EOL>return<EOL><DEDENT>

Crop to a new depth range.

Args:
    extent (tuple): The new start and stop depth. Must be 'inside'
        existing striplog.
    copy (bool): Whether to operate in place or make a copy.

Returns:
    Operates in place by deault; if copy is True, returns a striplog.


for base in type.mro(cls):<EOL><INDENT>if '<STR_LIT>' in base.__dict__:<EOL><INDENT>return base.__init__<EOL><DEDENT>if '<STR_LIT>' in base.__dict__:<EOL><INDENT>return base.__new__<EOL><DEDENT><DEDENT>

Find the first __init__ or __new__ method in the given class's MRO.


<EOL>if isinstance(fn, (type(object.__init__), type(object.__call__))):<EOL><INDENT>wrappable_fn = lambda *args, **kwargs: fn(*args, **kwargs)<EOL>wrappable_fn.__name__ = fn.__name__<EOL>wrappable_fn.__doc__ = fn.__doc__<EOL>wrappable_fn.__module__ = '<STR_LIT>'  <EOL>wrappable_fn.__wrapped__ = fn<EOL>return wrappable_fn<EOL><DEDENT>return fn<EOL>

Make sure `fn` can be wrapped cleanly by functools.wraps.


def _decorate_fn_or_cls(decorator, fn_or_cls, subclass=False):

if not inspect.isclass(fn_or_cls):<EOL><INDENT>return decorator(_ensure_wrappability(fn_or_cls))<EOL><DEDENT>construction_fn = _find_class_construction_fn(fn_or_cls)<EOL>if subclass:<EOL><INDENT>class DecoratedClass(fn_or_cls):<EOL><INDENT>__doc__ = fn_or_cls.__doc__<EOL>__module__ = fn_or_cls.__module__<EOL><DEDENT>DecoratedClass.__name__ = fn_or_cls.__name__<EOL>if six.PY3:<EOL><INDENT>DecoratedClass.__qualname__ = fn_or_cls.__qualname__<EOL><DEDENT>cls = DecoratedClass<EOL><DEDENT>else:<EOL><INDENT>cls = fn_or_cls<EOL><DEDENT>decorated_fn = decorator(_ensure_wrappability(construction_fn))<EOL>if construction_fn.__name__ == '<STR_LIT>':<EOL><INDENT>decorated_fn = staticmethod(decorated_fn)<EOL><DEDENT>setattr(cls, construction_fn.__name__, decorated_fn)<EOL>return cls<EOL>

Decorate a function or class with the given decorator.

    When `fn_or_cls` is a function, applies `decorator` to the function and
    returns the (decorated) result.

    When `fn_or_cls` is a class and the `subclass` parameter is `False`, this will
    replace `fn_or_cls.__init__` with the result of applying `decorator` to it.

    When `fn_or_cls` is a class and `subclass` is `True`, this will subclass the
    class, but with `__init__` defined to be the result of applying `decorator` to
    `fn_or_cls.__init__`. The decorated class has metadata (docstring, name, and
    module information) copied over from `fn_or_cls`. The goal is to provide a
    decorated class the behaves as much like the original as possible, without
    modifying it (for example, inspection operations using `isinstance` or
    `issubclass` should behave the same way as on the original class).

    Args:
      decorator: The decorator to use.
      fn_or_cls: The function or class to decorate.
      subclass: Whether to decorate classes by subclassing. This argument is
        ignored if `fn_or_cls` is not a class.

    Returns:
      The decorated function or class.


_validate_skip_unknown(skip_unknown)<EOL>if _REGISTRY.matching_selectors(selector):<EOL><INDENT>return False  <EOL><DEDENT>if isinstance(skip_unknown, (list, tuple, set)):<EOL><INDENT>return selector in skip_unknown<EOL><DEDENT>return skip_unknown<EOL>

Checks whether `selector` should be skipped (if unknown).


literal = repr(value)<EOL>try:<EOL><INDENT>if parse_value(literal) == value:<EOL><INDENT>return literal<EOL><DEDENT><DEDENT>except SyntaxError:<EOL><INDENT>pass<EOL><DEDENT>return None<EOL>

Returns `value` in a format parseable by `parse_value`, or `None`.

    Simply put, This function ensures that when it returns a string value, the
    following will hold:

        parse_value(_format_value(value)) == value

    Args:
      value: The value to format.

    Returns:
      A string representation of `value` when `value` is literally representable,
      or `None`.


return _format_value(value) is not None<EOL>

Returns `True` if `value` can be (parseably) represented as a string.

    Args:
      value: The value to check.

    Returns:
      `True` when `value` can be represented as a string parseable by
      `parse_literal`, `False` otherwise.


_set_config_is_locked(False)<EOL>_CONFIG.clear()<EOL>_SINGLETONS.clear()<EOL>if clear_constants:<EOL><INDENT>_CONSTANTS.clear()<EOL><DEDENT>else:<EOL><INDENT>saved_constants = _CONSTANTS.copy()<EOL>_CONSTANTS.clear()  <EOL>for name, value in six.iteritems(saved_constants):<EOL><INDENT>constant(name, value)<EOL><DEDENT><DEDENT>_IMPORTED_MODULES.clear()<EOL>_OPERATIVE_CONFIG.clear()<EOL>

Clears the global configuration.

    This clears any parameter values set by `bind_parameter` or `parse_config`, as
    well as the set of dynamically imported modules. It does not remove any
    configurable functions or classes from the registry of configurables.

    Args:
      clear_constants: Whether to clear constants created by `constant`. Defaults
        to False.


if config_is_locked():<EOL><INDENT>raise RuntimeError('<STR_LIT>')<EOL><DEDENT>pbk = ParsedBindingKey(binding_key)<EOL>fn_dict = _CONFIG.setdefault(pbk.config_key, {})<EOL>fn_dict[pbk.arg_name] = value<EOL>

Binds the parameter value specified by `binding_key` to `value`.

    The `binding_key` argument should either be a string of the form
    `maybe/scope/optional.module.names.configurable_name.parameter_name`, or a
    list or tuple of `(scope, selector, parameter_name)`, where `selector`
    corresponds to `optional.module.names.configurable_name`. Once this function
    has been called, subsequent calls (in the specified scope) to the specified
    configurable function will have `value` supplied to their `parameter_name`
    parameter.

    Example:

        @configurable('fully_connected_network')
        def network_fn(num_layers=5, units_per_layer=1024):
           ...

        def main(_):
          config.bind_parameter('fully_connected_network.num_layers', 3)
          network_fn()  # Called with num_layers == 3, not the default of 5.

    Args:
      binding_key: The parameter whose value should be set. This can either be a
        string, or a tuple of the form `(scope, selector, parameter)`.
      value: The desired value.

    Raises:
      RuntimeError: If the config is locked.
      ValueError: If no function can be found matching the configurable name
        specified by `binding_key`, or if the specified parameter name is
        blacklisted or not in the function's whitelist (if present).


pbk = ParsedBindingKey(binding_key)<EOL>if pbk.config_key not in _CONFIG:<EOL><INDENT>err_str = "<STR_LIT>"<EOL>raise ValueError(err_str.format(pbk.given_selector))<EOL><DEDENT>if pbk.arg_name not in _CONFIG[pbk.config_key]:<EOL><INDENT>err_str = "<STR_LIT>"<EOL>raise ValueError(err_str.format(pbk.given_selector, pbk.arg_name))<EOL><DEDENT>return _CONFIG[pbk.config_key][pbk.arg_name]<EOL>

Returns the currently bound value to the specified `binding_key`.

    The `binding_key` argument should look like
    'maybe/some/scope/maybe.moduels.configurable_name.parameter_name'. Note that
    this will not include default parameters.

    Args:
      binding_key: The parameter whose value should be set.

    Returns:
      The value bound to the configurable/parameter combination given in
      `binding_key`.

    Raises:
      ValueError: If no function can be found matching the configurable name
        specified by `biding_key`, or if the specified parameter name is
        blacklisted or not in the function's whitelist (if present) or if there is
        no value bound for the queried parameter or configurable.


if inspect.isclass(fn_or_cls):<EOL><INDENT>fn = _find_class_construction_fn(fn_or_cls)<EOL><DEDENT>else:<EOL><INDENT>fn = fn_or_cls<EOL><DEDENT>while hasattr(fn, '<STR_LIT>'):<EOL><INDENT>fn = fn.__wrapped__<EOL><DEDENT>arg_spec = _get_cached_arg_spec(fn)<EOL>if six.PY3:<EOL><INDENT>if arg_spec.varkw:<EOL><INDENT>return True<EOL><DEDENT>return arg_name in arg_spec.args or arg_name in arg_spec.kwonlyargs<EOL><DEDENT>else:<EOL><INDENT>if arg_spec.keywords:<EOL><INDENT>return True<EOL><DEDENT>return arg_name in arg_spec.args<EOL><DEDENT>

Returns True if `arg_name` might be a valid parameter for `fn_or_cls`.

    Specifically, this means that `fn_or_cls` either has a parameter named
    `arg_name`, or has a `**kwargs` parameter.

    Args:
      fn_or_cls: The function or class to check.
      arg_name: The name fo the parameter.

    Returns:
      Whether `arg_name` might be a valid argument of `fn`.


arg_spec = _ARG_SPEC_CACHE.get(fn)<EOL>if arg_spec is None:<EOL><INDENT>arg_spec_fn = inspect.getfullargspec if six.PY3 else inspect.getargspec<EOL>try:<EOL><INDENT>arg_spec = arg_spec_fn(fn)<EOL><DEDENT>except TypeError:<EOL><INDENT>arg_spec = arg_spec_fn(fn.__call__)<EOL><DEDENT>_ARG_SPEC_CACHE[fn] = arg_spec<EOL><DEDENT>return arg_spec<EOL>


arg_spec = _get_cached_arg_spec(fn)<EOL>return arg_spec.args[:len(args)]<EOL>

Returns the names of the supplied arguments to the given function.


arg_spec = _get_cached_arg_spec(fn)<EOL>args = arg_spec.args<EOL>if arg_spec.defaults:<EOL><INDENT>args = args[:-len(arg_spec.defaults)]<EOL><DEDENT>return args<EOL>

Returns the names of all positional arguments to the given function.


def _get_default_configurable_parameter_values(fn, whitelist, blacklist):

arg_vals = _ARG_DEFAULTS_CACHE.get(fn)<EOL>if arg_vals is not None:<EOL><INDENT>return arg_vals.copy()<EOL><DEDENT>arg_spec = _get_cached_arg_spec(fn)<EOL>if arg_spec.defaults:<EOL><INDENT>default_kwarg_names = arg_spec.args[-len(arg_spec.defaults):]<EOL>arg_vals = dict(zip(default_kwarg_names, arg_spec.defaults))<EOL><DEDENT>else:<EOL><INDENT>arg_vals = {}<EOL><DEDENT>if six.PY3 and arg_spec.kwonlydefaults:<EOL><INDENT>arg_vals.update(arg_spec.kwonlydefaults)<EOL><DEDENT>for k in list(six.iterkeys(arg_vals)):<EOL><INDENT>whitelist_fail = whitelist and k not in whitelist<EOL>blacklist_fail = blacklist and k in blacklist<EOL>representable = _is_literally_representable(arg_vals[k])<EOL>if whitelist_fail or blacklist_fail or not representable:<EOL><INDENT>del arg_vals[k]<EOL><DEDENT><DEDENT>_ARG_DEFAULTS_CACHE[fn] = arg_vals<EOL>return arg_vals.copy()<EOL>

Retrieve all default values for configurable parameters of a function.

    Any parameters included in the supplied blacklist, or not included in the
    supplied whitelist, are excluded.

    Args:
      fn: The function whose parameter values should be retrieved.
      whitelist: The whitelist (or `None`) associated with the function.
      blacklist: The blacklist (or `None`) associated with the function.

    Returns:
      A dictionary mapping configurable parameter names to their default values.


try:<EOL><INDENT>valid_value = True<EOL>if isinstance(name_or_scope, list):<EOL><INDENT>new_scope = name_or_scope<EOL><DEDENT>elif name_or_scope and isinstance(name_or_scope, six.string_types):<EOL><INDENT>new_scope = current_scope()  <EOL>new_scope.extend(name_or_scope.split('<STR_LIT:/>'))<EOL><DEDENT>else:<EOL><INDENT>valid_value = name_or_scope in (None, '<STR_LIT>')<EOL>new_scope = []<EOL><DEDENT>_ACTIVE_SCOPES.append(new_scope)<EOL>scopes_are_valid = map(config_parser.MODULE_RE.match, new_scope)<EOL>if not valid_value or not all(scopes_are_valid):<EOL><INDENT>err_str = '<STR_LIT>'<EOL>raise ValueError(err_str.format(name_or_scope))<EOL><DEDENT>yield new_scope<EOL><DEDENT>finally:<EOL><INDENT>_ACTIVE_SCOPES.pop()<EOL><DEDENT>

Opens a new configuration scope.

    Provides a context manager that opens a new explicit configuration
    scope. Explicit configuration scopes restrict parameter bindings to only
    certain sections of code that run within the scope. Scopes can be nested to
    arbitrary depth; any configurable functions called within a scope inherit
    parameters defined by higher level scopes.

    For example, suppose a function named `preprocess_images` is called in two
    places in a codebase: Once when loading data for a training task, and once
    when loading data for an evaluation task:

        def load_training_data():
          ...
          with gin.config_scope('train'):
            images = preprocess_images(images)
          ...

        def load_eval_data():
          ...
          with gin.config_scope('eval'):
            images = preprocess_images(images)
          ...

    By using a `config_scope` to wrap each invocation of `preprocess_images` as
    above, it is possible to use Gin to supply specific parameters to each. Here
    is a possible configuration for the above example:

        preprocess_images.crop_size = [64, 64]
        preprocess_images.normalize_image = True

        train/preprocess_images.crop_location = 'random'
        train/preprocess_images.random_flip_lr = True

        eval/preprocess_images.crop_location = 'center'

    The `crop_size` and `normalize_image` parameters above will be shared by both
    the `train` and `eval` invocations; only `train` will receive
    `random_flip_lr`, and the two invocations receive different values for
    `crop_location`.

    Passing `None` or `''` to `config_scope` will temporarily clear all currently
    active scopes (within the `with` block; they will be restored afterwards).

    Args:
      name_or_scope: A name for the config scope, or an existing scope (e.g.,
        captured from `with gin.config_scope(...) as scope`), or `None` to clear
        currently active scopes.

    Raises:
      ValueError: If `name_or_scope` is not a list, string, or None.

    Yields:
      The resulting config scope (a list of all active scope names, ordered from
      outermost to innermost).


if config_is_locked():<EOL><INDENT>err_str = '<STR_LIT>'<EOL>raise RuntimeError(err_str)<EOL><DEDENT>name = fn_or_cls.__name__ if name is None else name<EOL>if config_parser.IDENTIFIER_RE.match(name):<EOL><INDENT>default_module = getattr(fn_or_cls, '<STR_LIT>', None)<EOL>module = default_module if module is None else module<EOL><DEDENT>elif not config_parser.MODULE_RE.match(name):<EOL><INDENT>raise ValueError("<STR_LIT>".format(name))<EOL><DEDENT>if module is not None and not config_parser.MODULE_RE.match(module):<EOL><INDENT>raise ValueError("<STR_LIT>".format(module))<EOL><DEDENT>selector = module + '<STR_LIT:.>' + name if module else name<EOL>if not _INTERACTIVE_MODE and selector in _REGISTRY:<EOL><INDENT>err_str = "<STR_LIT>"<EOL>raise ValueError(err_str.format(selector))<EOL><DEDENT>if whitelist and blacklist:<EOL><INDENT>err_str = '<STR_LIT>'<EOL>raise ValueError(err_str)<EOL><DEDENT>if whitelist and not isinstance(whitelist, (list, tuple)):<EOL><INDENT>raise TypeError('<STR_LIT>')<EOL><DEDENT>if blacklist and not isinstance(blacklist, (list, tuple)):<EOL><INDENT>raise TypeError('<STR_LIT>')<EOL><DEDENT>_validate_parameters(fn_or_cls, whitelist, '<STR_LIT>')<EOL>_validate_parameters(fn_or_cls, blacklist, '<STR_LIT>')<EOL>def apply_config(fn):<EOL><INDENT>"""<STR_LIT>"""<EOL>@six.wraps(fn)<EOL>def wrapper(*args, **kwargs):<EOL><INDENT>"""<STR_LIT>"""<EOL>scope_components = current_scope()<EOL>new_kwargs = {}<EOL>for i in range(len(scope_components) + <NUM_LIT:1>):<EOL><INDENT>partial_scope_str = '<STR_LIT:/>'.join(scope_components[:i])<EOL>new_kwargs.update(_CONFIG.get((partial_scope_str, selector), {}))<EOL><DEDENT>gin_bound_args = list(new_kwargs.keys())<EOL>scope_str = partial_scope_str<EOL>arg_names = _get_supplied_positional_parameter_names(fn, args)<EOL>for arg in args[len(arg_names):]:<EOL><INDENT>if arg is REQUIRED:<EOL><INDENT>raise ValueError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT><DEDENT>required_arg_names = []<EOL>required_arg_indexes = []<EOL>for i, arg in enumerate(args[:len(arg_names)]):<EOL><INDENT>if arg is REQUIRED:<EOL><INDENT>required_arg_names.append(arg_names[i])<EOL>required_arg_indexes.append(i)<EOL><DEDENT><DEDENT>required_kwargs = []<EOL>for kwarg, value in six.iteritems(kwargs):<EOL><INDENT>if value is REQUIRED:<EOL><INDENT>required_kwargs.append(kwarg)<EOL><DEDENT><DEDENT>for arg_name in arg_names:<EOL><INDENT>if arg_name not in required_arg_names:<EOL><INDENT>new_kwargs.pop(arg_name, None)<EOL><DEDENT><DEDENT>operative_parameter_values = _get_default_configurable_parameter_values(<EOL>fn, whitelist, blacklist)<EOL>operative_parameter_values.update(new_kwargs)<EOL>for k in arg_names:<EOL><INDENT>if k not in required_arg_names:<EOL><INDENT>operative_parameter_values.pop(k, None)<EOL><DEDENT><DEDENT>for k in kwargs:<EOL><INDENT>if k not in required_kwargs:<EOL><INDENT>operative_parameter_values.pop(k, None)<EOL><DEDENT><DEDENT>_OPERATIVE_CONFIG.setdefault((scope_str, selector), {}).update(<EOL>operative_parameter_values)<EOL>new_kwargs = copy.deepcopy(new_kwargs)<EOL>missing_required_params = []<EOL>new_args = list(args)<EOL>for i, arg_name in zip(required_arg_indexes, required_arg_names):<EOL><INDENT>if arg_name not in new_kwargs:<EOL><INDENT>missing_required_params.append(arg_name)<EOL><DEDENT>else:<EOL><INDENT>new_args[i] = new_kwargs.pop(arg_name)<EOL><DEDENT><DEDENT>for kwarg in required_kwargs:<EOL><INDENT>if kwarg not in new_kwargs:<EOL><INDENT>missing_required_params.append(kwarg)<EOL><DEDENT>else:<EOL><INDENT>kwargs.pop(kwarg)<EOL><DEDENT><DEDENT>if missing_required_params:<EOL><INDENT>err_str = '<STR_LIT>'<EOL>minimal_selector = _REGISTRY.minimal_selector(selector)<EOL>err_str = err_str.format(minimal_selector, missing_required_params)<EOL>raise RuntimeError(err_str)<EOL><DEDENT>new_kwargs.update(kwargs)<EOL>try:<EOL><INDENT>return fn(*new_args, **new_kwargs)<EOL><DEDENT>except Exception as e:  <EOL><INDENT>err_str = '<STR_LIT>'<EOL>if isinstance(e, TypeError):<EOL><INDENT>all_arg_names = _get_all_positional_parameter_names(fn)<EOL>if len(new_args) < len(all_arg_names):<EOL><INDENT>unbound_positional_args = list(<EOL>set(all_arg_names[len(new_args):]) - set(new_kwargs))<EOL>if unbound_positional_args:<EOL><INDENT>caller_supplied_args = list(<EOL>set(arg_names + list(kwargs)) -<EOL>set(required_arg_names + list(required_kwargs)))<EOL>fmt = ('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL>canonicalize = lambda x: list(map(str, sorted(x)))<EOL>err_str += fmt.format(<EOL>canonicalize(unbound_positional_args),<EOL>gin_bound_args=canonicalize(gin_bound_args),<EOL>caller_supplied_args=canonicalize(caller_supplied_args))<EOL><DEDENT><DEDENT><DEDENT>err_str += "<STR_LIT>"<EOL>scope_info = "<STR_LIT>".format(scope_str) if scope_str else '<STR_LIT>'<EOL>err_str = err_str.format(name, fn, scope_info)<EOL>utils.augment_exception_message_and_reraise(e, err_str)<EOL><DEDENT><DEDENT>return wrapper<EOL><DEDENT>decorated_fn_or_cls = _decorate_fn_or_cls(<EOL>apply_config, fn_or_cls, subclass=subclass)<EOL>_REGISTRY[selector] = Configurable(<EOL>decorated_fn_or_cls,<EOL>name=name,<EOL>module=module,<EOL>whitelist=whitelist,<EOL>blacklist=blacklist,<EOL>selector=selector)<EOL>return decorated_fn_or_cls<EOL>

Wraps `fn_or_cls` to make it configurable.

    Infers the configurable name from `fn_or_cls.__name__` if necessary, and
    updates global state to keep track of configurable name <-> function
    mappings, as well as whitelisted and blacklisted parameters.

    Args:
      fn_or_cls: The function or class to decorate.
      name: A name for the configurable. If `None`, the name will be inferred from
        from `fn_or_cls`. The `name` may also include module components to be used
        for disambiguation (these will be appended to any components explicitly
        specified by `module`).
      module: The module to associate with the configurable, to help handle naming
        collisions. If `None`, `fn_or_cls.__module__` will be used (if no module
        is specified as part of `name`).
      whitelist: A whitelisted set of parameter names to supply values for.
      blacklist: A blacklisted set of parameter names not to supply values for.
      subclass: If `fn_or_cls` is a class and `subclass` is `True`, decorate by
        subclassing `fn_or_cls` and overriding its `__init__` method. If `False`,
        replace the existing `__init__` with a decorated version.

    Returns:
      A wrapped version of `fn_or_cls` that will take parameter values from the
      global configuration.

    Raises:
      RuntimeError: If the config is locked.
      ValueError: If a configurable with `name` (or the name of `fn_or_cls`)
        already exists, or if both a whitelist and blacklist are specified.


def configurable(name_or_fn=None, module=None, whitelist=None, blacklist=None):

decoration_target = None<EOL>if callable(name_or_fn):<EOL><INDENT>decoration_target = name_or_fn<EOL>name = None<EOL><DEDENT>else:<EOL><INDENT>name = name_or_fn<EOL><DEDENT>def perform_decoration(fn_or_cls):<EOL><INDENT>return _make_configurable(fn_or_cls, name, module, whitelist, blacklist)<EOL><DEDENT>if decoration_target:<EOL><INDENT>return perform_decoration(decoration_target)<EOL><DEDENT>return perform_decoration<EOL>

Decorator to make a function or class configurable.

    This decorator registers the decorated function/class as configurable, which
    allows its parameters to be supplied from the global configuration (i.e., set
    through `bind_parameter` or `parse_config`). The decorated function is
    associated with a name in the global configuration, which by default is simply
    the name of the function or class, but can be specified explicitly to avoid
    naming collisions or improve clarity.

    If some parameters should not be configurable, they can be specified in
    `blacklist`. If only a restricted set of parameters should be configurable,
    they can be specified in `whitelist`.

    The decorator can be used without any parameters as follows:

        @config.configurable
        def some_configurable_function(param1, param2='a default value'):
          ...

    In this case, the function is associated with the name
    `'some_configurable_function'` in the global configuration, and both `param1`
    and `param2` are configurable.

    The decorator can be supplied with parameters to specify the configurable name
    or supply a whitelist/blacklist:

        @config.configurable('explicit_configurable_name', whitelist='param2')
        def some_configurable_function(param1, param2='a default value'):
          ...

    In this case, the configurable is associated with the name
    `'explicit_configurable_name'` in the global configuration, and only `param2`
    is configurable.

    Classes can be decorated as well, in which case parameters of their
    constructors are made configurable:

        @config.configurable
        class SomeClass(object):
          def __init__(self, param1, param2='a default value'):
            ...

    In this case, the name of the configurable is `'SomeClass'`, and both `param1`
    and `param2` are configurable.

    Args:
      name_or_fn: A name for this configurable, or a function to decorate (in
        which case the name will be taken from that function). If not set,
        defaults to the name of the function/class that is being made
        configurable. If a name is provided, it may also include module components
        to be used for disambiguation (these will be appended to any components
        explicitly specified by `module`).
      module: The module to associate with the configurable, to help handle naming
        collisions. By default, the module of the function or class being made
        configurable will be used (if no module is specified as part of the name).
      whitelist: A whitelisted set of kwargs that should be configurable. All
        other kwargs will not be configurable. Only one of `whitelist` or
        `blacklist` should be specified.
      blacklist: A blacklisted set of kwargs that should not be configurable. All
        other kwargs will be configurable. Only one of `whitelist` or `blacklist`
        should be specified.

    Returns:
      When used with no parameters (or with a function/class supplied as the first
      parameter), it returns the decorated function or class. When used with
      parameters, it returns a function that can be applied to decorate the target
      function or class.


return _make_configurable(<EOL>fn_or_cls,<EOL>name=name,<EOL>module=module,<EOL>whitelist=whitelist,<EOL>blacklist=blacklist,<EOL>subclass=True)<EOL>

Allow referencing/configuring an external class or function.

    This alerts Gin to the existence of the class or function `fn_or_cls` in the
    event that it can't be easily annotated with `@configurable` (for instance, if
    it is from another project). This allows `fn_or_cls` to be configured and
    referenced (using the `@name` notation) via parameter binding strings.

    Note that only calls to the return value of this function or resulting from
    references to `fn_or_cls` made through binding strings (configurations) will
    have their parameters injected by Gin---explicit calls to `fn_or_cls` directly
    won't have any parameter bindings applied.

    Args:
      fn_or_cls: The external function or class that should be made configurable.
      name: The configurable name to be associated with `fn_or_cls`. The name may
        also include module components to be used for disambiguation (these will
        be appended to any components explicitly specified by `module`).
      module: The module to associate with the configurable, to help handle naming
        collisions. By default, `fn_or_cls.__module__` will be used (if no
        module is specified as part of the name).
      whitelist: A whitelist of parameter names to allow configuration for.
      blacklist: A blacklist of parameter names not to allow configuration for.

    Returns:
      A decorated version of `fn_or_cls` that permits parameter binding. For
      functions, this is just a wrapped version of the function. For classes, this
      is a carefully constructed subclass of `fn_or_cls` designed to behave nearly
      identically (even under many type inspection operations) save for the
      addition of parameter binding.