dbt-selly/dbt-env/lib/python3.8/site-packages/leather/series/base.py

142 lines
4.0 KiB
Python
Raw Normal View History

2022-03-22 15:13:27 +00:00
#!/usr/bin/env python
try:
from collections.abc import Iterable, Sequence, Mapping
except ImportError:
from collections import Iterable, Sequence, Mapping
from functools import partial
import six
from leather.data_types import DataType
from leather.utils import DIMENSION_NAMES, X, Y, Datum
class Series(object):
"""
A series of data and its associated metadata.
Series object does not modify the data it is passed.
:param data:
A sequence (rows) of sequences (columns), a.k.a. :func:`csv.reader`
format. If the :code:`x` and :code:`y` are not specified then the first
column is used as the X values and the second column is used for Y.
Or, a sequence of (rows) of dicts (columns), a.k.a.
:class:`csv.DictReader` format. If this format is used then :code:`x`
and :code:`y` arguments must specify the columns to be charted.
Or, a custom data format, in which case :code:`x` and :code:`y` must
specify :func:`.key_function`.
:param x:
If using sequence row data, then this may be either an integer index
identifying the X column, or a :func:`.key_function`.
If using dict row data, then this may be either a key name identifying
the X column, or a :func:`.key_function`.
If using a custom data format, then this must be a
:func:`.key_function`.`
:param y:
See :code:`x`.
:param name:
An optional name to be used in labeling this series. This will be
used as the chart title if rendered in a :class:`.Lattice`.
"""
def __init__(self, data, x=None, y=None, name=None):
self._data = data
self._name = name
self._keys = [
self._make_key(x if x is not None else X),
self._make_key(y if y is not None else Y)
]
self._types = [
self._infer_type(X),
self._infer_type(Y)
]
def _make_key(self, key):
"""
Process a user-specified data key and convert to a function if needed.
"""
if callable(key):
return key
else:
return lambda row, index: row[key]
def _infer_type(self, dimension):
"""
Infer the datatype of this column by sampling the data.
"""
key = self._keys[dimension]
for i, row in enumerate(self._data):
v = key(row, i)
if v is not None:
break
if v is None:
raise ValueError('All values in %s dimension are null.' % DIMENSION_NAMES[dimension])
return DataType.infer(v)
@property
def name(self):
return self._name
def data_type(self, dimension):
"""
Return the data type for a dimension of this series.
"""
return self._types[dimension]
def data(self):
"""
Return data for this series.
"""
x = self._keys[X]
y = self._keys[Y]
for i, row in enumerate(self._data):
yield Datum(i, x(row, i), y(row, i), None, row)
def values(self, dimension):
"""
Get a flattened list of values for a given dimension of the data.
"""
key = self._keys[dimension]
return [key(row, i) for i, row in enumerate(self._data)]
def min(self, dimension):
"""
Compute the minimum value of a given dimension.
"""
return min(v for v in self.values(dimension) if v is not None)
def max(self, dimension):
"""
Compute the minimum value of a given dimension.
"""
return max(v for v in self.values(dimension) if v is not None)
def key_function(row, index):
"""
This example shows how to define a function to extract X and Y values
from custom data.
:param row:
The function will be called with the row data, in whatever format it
was provided to the :class:`.Series`.
:param index:
The row index in the series data will also be provided.
:returns:
The function must return a chartable value.
"""
pass