B
    Yw                 @   sj  d Z ddlmZ ddlmZ ddlmZ ddlmZ ddlZ	ddl
ZddlmZ ddlmZ dd	lmZ dd
lmZmZmZmZmZ ddlmZ ddlmZmZ ddlmZmZ ddl m!Z!m"Z"m#Z# dgZ$e%e&e	j'ej(gZ)e*ej+gZ,ddgZ-dgdgddggZ.G dd deZ/G dd de/Z0G dd de/Z1G dd deZ2G dd de3Z4dd Z5G dd  d e3Z6dS )!zS The classes and functionality used to transform data inputs to consistent
types.

    )absolute_import)copy)chain)
itemgetterN)	iteritems)zip)HasProps)bokeh_integer_typesDatetimeFloatListString)ColumnDataSource   )ColumnColumnLabel)BinsStat)collect_attribute_columnsgen_column_namesspecial_columnsZ_charts_onesxyc                   sD   e Zd ZdZeeddZeeddZd
 fdd	Zddd	Z	  Z
S )ColumnAssignera  Defines behavior for assigning columns to dimensions.

    This class is used to collect assignments between columns and :class:`Builder`
    dimensions when none are provided. The :class:`ChartDataSource` receives a
    ColumnAssigner from each :class:`Builder`, which can implement custom behavior.

    Each subclass must implement the :meth:`get_assignment` method, which returns
    a `dict` mapping between each dimension in `dims` and one or more column names,
    or `None` if no assignment is made for the associated dimension.

    z
        The list of dimension names that are associated with the :class:`Builder`. The
        ColumnAssigner should return a dict with each dimension as a key when the
        :meth:`get_assignment` method is called.
        )helpz
        This list of attribute names that are associated with the :class:`Builder`. These
        can be used to alter which dimensions are assigned which columns, versus which
        attributes are assigned which columns.
        Nc                s$   |dk	r|| _ tt| jf | dS )zCreate the assigner.

        Args:
            df (:class:`pandas.DataFrame`, optional): the data source to use for
                assigning columns from
            **properties: any attribute of the ColumnAssigner

        N)_dfsuperr   __init__)selfdf
properties)	__class__ 3lib/python3.7/site-packages/bkcharts/data_source.pyr   6   s    	zColumnAssigner.__init__c             C   s   t dd S )Nz3You must return map between each dim and selection.)NotImplementedError)r   
selectionsr"   r"   r#   get_assignmentC   s    zColumnAssigner.get_assignment)N)N)__name__
__module____qualname____doc__r   r   dimsattrsr   r&   __classcell__r"   r"   )r!   r#   r      s   r   c               @   s   e Zd ZdZdddZdS )OrderedAssignerzAssigns one column for each dimension that is not an attribute, in order.

    This is the default column assigner for the :class:`Builder`.

    Nc                sT   |dkst t| dkrL fdd jD }dd t| jj D S |S dS )zEGet a mapping between dimension and selection when none are provided.Nr   c                s   g | ]}| j kr|qS r"   )r,   ).0dim)r   r"   r#   
<listcomp>Q   s    z2OrderedAssigner.get_assignment.<locals>.<listcomp>c             S   s   i | ]\}}||qS r"   r"   )r/   r0   selr"   r"   r#   
<dictcomp>R   s    z2OrderedAssigner.get_assignment.<locals>.<dictcomp>)lenlistkeysr+   r   r   columnstolist)r   r%   r+   r"   )r   r#   r&   N   s
    zOrderedAssigner.get_assignment)N)r'   r(   r)   r*   r&   r"   r"   r"   r#   r.   G   s   r.   c               @   s   e Zd ZdZdddZdS )NumericalColumnsAssignerz1Assigns all numerical columns to the y dimension.Nc                s   t |tr |d |d}nd  d }i }| j }|j } d k	rd|d krd fdd|D }n d kr|d |d kr||} |d< ||d< |S )Nr   r   c                s   g | ]}|t  kr|qS r"   )r5   )r/   col)r   r"   r#   r1   i   s    z;NumericalColumnsAssigner.get_assignment.<locals>.<listcomp>index)
isinstancedictgetr   Z_get_numeric_datar7   r8   )r   r%   r   r   Znum_colsr"   )r   r#   r&   [   s"    



z'NumericalColumnsAssigner.get_assignment)N)r'   r(   r)   r*   r&   r"   r"   r"   r#   r9   X   s   r9   c               @   s0   e Zd ZdZee dddZdd Zdd ZdS )	DataOperatorzAAn operation that transforms data before it is used for plotting.Nz1
        List of columns to perform operation on.)defaultr   c             C   s   t dd S )Nz3Each data operator must implement the apply method.)r$   )r   datar"   r"   r#   applyz   s    zDataOperator.applyc             C   s   d | j}d| jj|f S )Nz, z%s(%s))joinr7   r!   r'   )r   Zcol_strr"   r"   r#   __repr__}   s    zDataOperator.__repr__)	r'   r(   r)   r*   r   r   r7   rB   rD   r"   r"   r"   r#   r?   u   s
   r?   c               @   sX   e Zd ZdZdd Zdd Zedd Zdd	 Zd
d Z	dd Z
edd Zdd ZdS )	DataGroupzContains subset of data and metadata about it.

    The DataGroup contains a map from the labels of each attribute
    associated with an :class:`AttrSpec` to the value of the attribute assigned to the
    DataGroup.
    c             C   s   || _ || _|| _dS )a  Create a DataGroup for the data, with a label and associated attributes.

        Args:
            label (str): the label for the group based on unique values of each column
            data (:class:`pandas.DataFrame`): the subset of data associated with the group
            attr_specs dict(str, :class:`AttrSpec`): mapping between attribute name and
                the associated :class:`AttrSpec`.

        N)labelrA   
attr_specs)r   rF   rA   rG   r"   r"   r#   r      s    
zDataGroup.__init__c             C   s`   t |tr| j| S t |tr8t|dkr8| j|d  S t |trXt|dkrX| j| S dS dS )zGet the data associated with the selection of columns.

        Args:
            selection (List(Str) or Str): the column or columns selected

        Returns:
            :class:`pandas.DataFrame`

        r   r   N)r<   strrA   r5   r4   )r   	selectionr"   r"   r#   
get_values   s    



zDataGroup.get_valuesc             C   s
   t | jS )z>The :class:`ColumnDataSource` representation of the DataFrame.)r   rA   )r   r"   r"   r#   source   s    zDataGroup.sourcec             C   s
   | j | S )zCGet the value of the :class:`AttrSpec` associated with `spec_name`.)rG   )r   	spec_namer"   r"   r#   __getitem__   s    zDataGroup.__getitem__c             C   s   dt | j| jf S )Nz <DataGroup(%s) - attributes: %s>)rH   rF   rG   )r   r"   r"   r#   rD      s    zDataGroup.__repr__c             C   s   t | jjS )N)r4   rA   r;   )r   r"   r"   r#   __len__   s    zDataGroup.__len__c             C   s   t | j S )N)r5   rG   r6   )r   r"   r"   r#   
attributes   s    zDataGroup.attributesc             C   sF   i }| j d k	r.|| j  t| j  |d< nd |d< || j |S )NZchart_index)rF   updatetupleitemsrG   )r   rowr"   r"   r#   to_dict   s    
zDataGroup.to_dictN)r'   r(   r)   r*   r   rJ   propertyrK   rM   rD   rN   rO   rT   r"   r"   r"   r#   rE      s   rE   c             +   sF  t f |  r
x| j ddD ]\}}i }i }xt|D ]\}}|jdk	rt fdd|jD }t|trt| |}	t|  }
n|}	 d }
t|	ts|	f}	t|
tst|
ts|
g}
x$t|
|	D ]\}}|||< qW nd}	||	 ||< q:W t	|||dV  q W n8i }x"t|D ]\}}|d ||< qW t	d| |dV  dS )a  Convenience iterator around pandas groupby and attribute specs.

    Args:
        df (:class:`~pandas.DataFrame`): The entire data source being
            used for the Chart.
        **specs: Name, :class:`AttrSpec` pairing, used to identify the lowest
            level where the data is grouped.

    Yields:
        :class:`DataGroup`: each unique group of data to be used to produce glyphs

    F)sortNc                s   g | ]}  |qS r"   )r;   )r/   r:   )	spec_colsr"   r#   r1      s    zgroupby.<locals>.<listcomp>r   )rF   rA   rG   )
r   groupbyr   r7   rQ   r<   r   r5   r   rE   )r   specsnamerA   r,   Zgroup_labelrL   specZname_idxrF   colsr:   valuer"   )rW   r#   rX      s4    



rX   c               @   sT  e Zd ZdZdddedfddZedd Zdd Zd	d
 Z	dd Z
dd Zdd Zd?ddZdd Zdd Zedd Zedd Zedd Zedd  Zed!d" Zed@d#d$Zed%d& Zed'd( Zed)d* Zed+d, Zed-d. Zd/d0 Zed1d2 Zed3d4 Zed5d6 Z ed7d8 Z!ed9d: Z"ed;d< Z#ed=d> Z$dS )AChartDataSourcea  Validates, normalizes, groups, and assigns Chart attributes to groups.

    Supported inputs are:

    - **Array-like**: list, tuple, :class:`numpy.ndarray`, :class:`pandas.Series`
    - **Table-like**:
        - records: list(dict)
        - columns: dict(list), :class:`pandas.DataFrame`, or blaze resource

    Converts inputs that could be treated as table-like data to pandas DataFrame,
    which is used for assigning attributes to data groups.

    Nc             K   s   |dkrt }|dkrt}|dd| _|p,g | _|jdd| _|| _g | _|| _	|| jt
| j| jd| _| j|f|| _|   |   | || _|   dS )a5  Create a :class:`ChartDataSource`.

        Args:
            df (:class:`pandas.DataFrame`): the original data source for the chart
            dims (List(Str), optional): list of valid dimensions for the chart.
            required_dims (List(List(Str)), optional): list of list of valid dimensional
                selections for the chart.
            selections (Dict(String, List(Column)), optional): mapping between a
                dimension and the column name(s) associated with it. This represents what
                the user selected for the current chart.
            column_assigner (:class:`ColumnAssigner`, optional): a reference to a
                ColumnAssigner class, which is used to collect dimension column
                assignment when keyword arguments aren't provided. The default value is
                :class:`OrderedAssigner`, which assumes you want to assign each column
                or array to each dimension of the chart in order that they are received.
            attrs (list(str)): list of attribute names the chart uses

        N
input_typeF)Zdeep)r   r+   r,   )DEFAULT_DIMSDEFAULT_REQ_DIMSpopr_   r,   r   _data_dims
operations_required_dimsr5   column_assignerget_selections_selectionssetup_derived_columnsapply_operationscollect_metadatameta_validate_selections)r   r   r+   required_dimsr%   rg   r,   kwargsr"   r"   r#   r     s&    
zChartDataSource.__init__c                s    fddt  jD S )Nc                s    i | ]\}}| j kr||qS r"   )r,   )r/   r0   val)r   r"   r#   r3   I  s    z.ChartDataSource.attr_specs.<locals>.<dictcomp>)r   ri   )r   r"   )r   r#   rG   G  s    zChartDataSource.attr_specsc             K   s   i }x*| j D ] }||d}|dk	r|||< qW t| dkr~|dkrT| j }qt|trtt| dkr||}qtdn| jj|d}x| j D ]}||krd||< qW |S )a  Maps chart dimensions to selections and checks input requirements.

        Returns:
            mapping between each dimension and the selected columns. If no selection is
            made for a dimension, then the dimension will be associated with `None`.

        Nr   zfselections input must be provided as:                                  dict(dimension: column) or None)r%   )	rd   rb   r4   r6   rg   r&   r<   r=   
ValueError)r   r%   rp   Z
select_mapr0   Z
dim_selectr"   r"   r#   rh   K  s$    
zChartDataSource.get_selectionsc             C   s   | j  }xt| j D ]r\}}t|tr>|| | _|j||< t|tr|t|t	rj|| | _|j
||< ntd|j|f | j| qW || _ dS )zApplies each data operation.z)Stat input of %s for %s is not supported.N)ri   r   r   r<   r?   rB   rc   rZ   r   r   Zcenters_column	TypeErrorr!   re   append)r   r%   r0   Zselectr"   r"   r#   rk   u  s    




z ChartDataSource.apply_operationsc             C   sZ   xT| j D ]J}| | }|dk	rt|tr|tkr|| jj krt| | j| j|< qW dS )zEAttempt to add special case columns to the DataFrame for the builder.N)rd   r<   rH   r   r   r7   r8   rc   )r   r0   Zdim_selectionr"   r"   r#   rj     s    
z%ChartDataSource.setup_derived_columnsc             C   s   || j kr| j | S dS dS )zGet the columns selected for the given dimension name.

        e.g. dim='x'

        Returns:
            the columns selected as a str or list(str). If the dimension is not in
            `_selections`, `None` is returned.

        N)ri   )r   r0   r"   r"   r#   rM     s    


zChartDataSource.__getitem__c             C   s   || j |< |   d S )N)ri   rj   )r   r0   r]   r"   r"   r#   __setitem__  s    
zChartDataSource.__setitem__variabler]   c                s   x j D ]} j| }t|tr(|j}n|}| jj krD|d7 }||kr| j|< |dk	rt fdd|D rtj	 j
||||d _
qtt j
jt| }tj	 j
||||d _
qW dS )a	  De-pivots `_data` from a 'wide' to 'tall' layout.

        A wide table is one where the column names represent a categorical variable
        and each contains only the values associated with each unique value of the
        categorical variable.

        This method uses the :func:`pandas.melt` function with additional logic
        to make sure that the same data source can have multiple operations applied,
        and so all other columns are maintained through the stacking process.

        Example:

            .. note::

                This example is fairly low level and is not something the typical
                user should worry about. The interface for data transformations from
                the user perspective are the :ref:`bkcharts_functions`.

            >>> data = {'a': [1, 2, 3, 4],
            ...         'b': [2, 3, 4, 5],
            ...         'month': ['jan', 'jan', 'feb', 'feb']
            ...         }

            >>> ds = ChartDataSource.from_data(data)
            >>> ds['x'] =['a', 'b'] # say we selected a and b for dimension x

            We may want to combine 'a' and 'b' together. The final
            data would look like the following:

            >>> ds.stack_measures(['c', 'd'], var_name='c_d_variable',
            ...                   value_name='c_d_value')
            >>> ds.df
            Out[35]:
                  month a_b_variable  a_b_value
                0   jan            a          1
                1   jan            a          2
                2   feb            a          3
                3   feb            a          4
                4   jan            b          2
                5   jan            b          3
                6   feb            b          4
                7   feb            b          5

            The transformed data will use the `var_name` and `value_name` inputs to
            name the columns. These derived columns can then be used as a single column
            to reference the values and the labels of the data. In the example, I could
            plot a_b_value vs month, and color by a_b_variable.

            What this does for you over the :meth:`pandas.melt` method is that it will
            apply the :class:`DataOperator` for a dimension if it exists (e.g.
            :class:`Blend`, generated by :func:`blend`), and it will try to handle the id
            columns for you so you don't lose other columns with the melt transformation.

        Returns:
            None

        _Nc                s   g | ]}| j j kqS r"   )r   r7   r8   )r/   Zmeasure)r   r"   r#   r1     s    z2ChartDataSource.stack_measures.<locals>.<listcomp>)Zid_varsZ
value_varsvar_name
value_name)rd   ri   r<   r?   r7   r   r8   allpdZmeltrc   r5   set)r   ZmeasuresZidsrx   ry   r0   rI   dim_colsr"   )r   r#   stack_measures  s     <


zChartDataSource.stack_measuresc             K   s"   t |dkrtdt| jf|S )aN   Iterable of chart attribute specifications, associated with columns.

        Iterates over DataGroup, which represent the lowest level of data that is assigned
        to the attributes for plotting.

        Yields:
            a DataGroup, which contains metadata and attributes
            assigned to the group of data

        r   zBYou must provide one or more Attribute Specs to support iteration.)r4   rr   rX   rc   )r   rY   r"   r"   r#   rX     s    zChartDataSource.groupbyc       	      K   s   | j  }|s| j}g }g }d}x:| jf |D ]*}|jdkr@d}|| ||  q.W |rtj	|d  g}d|d< d|d< tj
||dd}|d= n0tj	|}t|d j }tj
||d|d	}|S )
al  Produce new DataFrame from source data and `AttrSpec` provided.

        Args:
            **attr_specs (str, `AttrSpec`, optional): pairs of names and attribute spec
              objects. This is optional and not required only if the `ChartDataSource`
              already contains references to the attribute specs.

        Returns:
            pd.DataFrame: a new dataframe that includes a column for each of the
                attribute specs joined in, plus one special column called
                `chart_index`, which contains the unique items between the different
                attribute specs.

        FNTr   Z
join_valueZjoin_column)onleft)Zhowr   )rc   r   rG   rX   rF   rt   rT   r{   	DataFramefrom_recordsmerger5   r6   )	r   rG   r   groupsZrowsZno_indexgroupZ	attr_datar\   r"   r"   r#   
join_attrs  s*    


zChartDataSource.join_attrsc          	      s   dd  dk	r& fdd|D }fdd|D }fdd|D }t|dkrjt|dkrjtdt|dkrt|dkrfd	dtD }t|dkrfd
d|D }|rtt|}tt|}	 }x|D ]}g }	| }
|
s(t
fdd|
D s(|
g}
xP|
D ]H}x@t||D ]2\}}tj
t|t|kr>|	| q>W q.W t|	dkr|	d }	|	||< qW ||d< nfdd|D } dk	rΈ d< t|dkrdd< j|fS t|dkrt|dkrtdn|d }t|trvt
fdd| D rldd< f dtjj|diS tdnh|rdd< f dtjj|diS t|tjrdd< f d|iS tdt| dS )a1  Automatically handle all valid inputs.

        Attempts to use any data that can be represented in a Table-like format,
        along with any generated requirements, to produce a
        :class:`ChartDataSource`. Internally, these data types are generated, so that a
        :class:`pandas.DataFrame` can be generated.

        Identifies inputs that are array vs table like, handling them accordingly. If
        possible, existing column names are used, otherwise column names are generated.

        Returns:
            :class:`ColumnDataSource`

        r,   Nc                s,   g | ]$}t |tr$t |tr| kr|qS r"   )r<   rH   )r/   arg)r,   r"   r#   r1   W  s    z-ChartDataSource.from_data.<locals>.<listcomp>c                s   g | ]}  |r|qS r"   )is_array)r/   r   )clsr"   r#   r1   Z  s    c                s$   g | ]}  |s |r|qS r"   )is_tableis_list_dicts)r/   r   )r   r"   r#   r1   [  s    r   z&Only input either array or table data.c                s8   g | ]0\}}  |s  |r|d k	r|dk	r|qS )r+   ro   )is_list_arraysr   )r/   kv)r   r"   r#   r1   e  s    
c                s   g | ]} | qS r"   r"   )r/   r0   )rp   r"   r#   r1   i  s    c                s   g | ]}  |qS r"   )r   )r/   	dim_input)r   r"   r#   r1   s  s   r   r7   c                s   g | ]}  |r|qS r"   )r   )r/   r   )r   r"   r#   r1     s    Z
iter_arrayr_   zInput a single table data type.c                s   g | ]}  |qS r"   )r   )r/   r:   )r   r"   r#   r1     s    Z
dict_arrayr   )rA   z1Input of table-like dict must be column-oriented.Z
list_dictsr   z=Unable to recognize inputs for conversion to dataframe for %s)rb   r4   rs   r   r   r5   r   from_iterabler   r   rz   r   r{   Seriesrt   from_arraysr<   r=   valuesr   	from_dictr   r   type)r   argsrp   arraysZtablesZ	list_dimsZ	col_namesZ
new_kwargsr0   r}   Z
dim_inputsr   arrayZcol_nametabler"   )r,   r   rp   r#   	from_data@  sl    






zChartDataSource.from_datac             C   s   d}t | trPt| dkrPt | d trPt | d d tsPt| d d sP|S t | trrtdd | D rd}nt | tjrt| jdkrd}|S )z_Verify if input data is a list of array-like data.

        Returns:
            bool

        Fr   r   c             S   s   g | ]}t |qS r"   )r^   r   )r/   r:   r"   r"   r#   r1     s    z2ChartDataSource.is_list_arrays.<locals>.<listcomp>T   )	r<   r5   r4   r^   r   rz   npndarrayshape)rA   Zvalidr"   r"   r#   r     s    $$
zChartDataSource.is_list_arraysc             C   s   | j S )N)rc   )r   r"   r"   r#   r     s    zChartDataSource.dfc             C   s
   t | jS )N)r   r   )r   r"   r"   r#   rK     s    zChartDataSource.sourcec              K   s   |  | d}|sdS |S dS )zReturns dimensions by name from kwargs.

        Returns:
            iterable(str): iterable of dimension names as strings

        N)r   r   )rb   )rp   r+   r"   r"   r#   _collect_dimensions  s    z#ChartDataSource._collect_dimensionsc                s  t  fdd|D rt|}tt|}|p:tt|}t||dt}xBt	||D ]"\}}fdd|D }|||< q\W n|ptt|}x>t
|D ]2\}	}
t|
tjr|
j}||kr|dk	r|||	< qW dd t	||D } f d	tjj|d
i|S )zyProduce :class:`ColumnDataSource` from array-like data.

        Returns:
            :class:`ColumnDataSource`

        c             3   s   | ]}  |V  qd S )N)r   )r/   r   )r   r"   r#   	<genexpr>  s    z.ChartDataSource.from_arrays.<locals>.<genexpr>r+   c                s   g | ]}  d qS )r   )rb   )r/   rw   )r\   r"   r#   r1     s    z/ChartDataSource.from_arrays.<locals>.<listcomp>Nc             S   s   i | ]\}}||qS r"   r"   )r/   Zcolumn_namer   r"   r"   r#   r3     s    z/ChartDataSource.from_arrays.<locals>.<dictcomp>r   )rA   )anyr   r5   r   r   r   r4   r>   r`   r   	enumerater<   r{   r   rZ   r   r   )r   r   Zcolumn_namesrp   Zlist_of_arraysr+   r0   Zlist_of_arrayr2   ir   rZ   r   r"   )r   r\   r#   r     s"    	zChartDataSource.from_arraysc             K   s   | f dt j|i|S )zyProduce :class:`ColumnDataSource` from table-like dict.

        Returns:
            :class:`ColumnDataSource`

        r   )r{   r   r   )r   rA   rp   r"   r"   r#   r     s    zChartDataSource.from_dictc             C   s   t | tpt | S )z}Verify if data is table-like.

        Inspects the types and structure of data.

        Returns:
            bool

        )r^   	_is_validTABLE_TYPESr   )rA   r"   r"   r#   r     s    
zChartDataSource.is_tablec             C   s   t | totdd | D S )z]Verify if data is row-oriented, table-like data.

        Returns:
            bool

        c             S   s   g | ]}t |tqS r"   )r<   r=   )r/   rS   r"   r"   r#   r1   *  s    z1ChartDataSource.is_list_dicts.<locals>.<listcomp>)r<   r5   rz   )rA   r"   r"   r#   r   "  s    zChartDataSource.is_list_dictsc             C   s   t | rdS t | tS dS )zJVerify if data is array-like.

        Returns:
            bool

        FN)r^   r   r   ARRAY_TYPES)rA   r"   r"   r#   r   ,  s    
zChartDataSource.is_arrayc                s   t  fdd|D S )zChecks for each type against data.

        Args:
            data: a generic source of data
            types: a list of classes

        Returns:
            bool

        c                s   g | ]}t  |qS r"   )r<   )r/   Z
valid_type)rA   r"   r#   r1   F  s    z-ChartDataSource._is_valid.<locals>.<listcomp>)r   )rA   typesr"   )rA   r#   r   :  s    zChartDataSource._is_validc                s   j }j}dd t|D }jdk	r:fdd|D }t|dkrx8|D ]0 t|t k rbqLt fdd|D rLdS qLW d}dd |D }d	d t|D }t|d
|d|djf ndS dS )zyRaises selection error if selections are not valid compared to requirements.

        Returns:
            None

        c             S   s   g | ]\}}|d k	r|qS )Nr"   )r/   r0   r2   r"   r"   r#   r1   R  s    z8ChartDataSource._validate_selections.<locals>.<listcomp>Nc                s   g | ]}| j kr|qS r"   )r,   )r/   r0   )r   r"   r#   r1   T  s    r   c                s   g | ]}| kqS r"   r"   )r/   r0   )reqr"   r#   r1   _  s    zDid not receive a valid combination of selections.

Valid configurations are: %s
Received inputs are: %s

Available columns are: %sc             S   s    g | ]}d  dd |D qS )z and c             S   s   g | ]}d | qS )z%s = <Any Column>r"   )r/   r0   r"   r"   r#   r1   h  s    zCChartDataSource._validate_selections.<locals>.<listcomp>.<listcomp>)rC   )r/   Zrequired_dimr"   r"   r#   r1   h  s   c             S   s,   g | ]$\}}|d k	rdt |t |f qS )Nz%s = %s)rH   )r/   r0   r2   r"   r"   r#   r1   j  s    z or z, )	rf   ri   r   r,   r4   rz   rr   rC   r7   )r   ro   r%   r+   Z	error_strZreq_strZselection_strr"   )r   r   r#   rn   H  s&    

$z$ChartDataSource._validate_selectionsc             C   s2   t | tjrtt| S tft }t | |S dS )zUVerifies that value is a numerical type.

        Returns:
            bool

        N)r<   r{   r   r   r   Zis_validfloatr	   )r]   Znumbersr"   r"   r#   	is_numbers  s    
zChartDataSource.is_numberc             C   s*   yt | }| dS  tk
r$   dS X dS )zuVerifies that value is a valid Datetime type, or can be converted to it.

        Returns:
            bool

        TFN)r
   rr   )r]   Zdtr"   r"   r#   is_datetime  s    zChartDataSource.is_datetimec             C   s   i S )z6Introspect which columns match to which types of data.r"   )rA   r"   r"   r#   rl     s    z ChartDataSource.collect_metadatac             C   s   | j jS )z\All column names associated with the data.

        Returns:
            List(Str)

        )rc   r7   )r   r"   r"   r#   r7     s    zChartDataSource.columnsc             C   s   | j jS )z8The index for the :class:`pandas.DataFrame` data source.)rc   r;   )r   r"   r"   r#   r;     s    zChartDataSource.indexc             C   s   | j jS )N)rc   r   )r   r"   r"   r#   r     s    zChartDataSource.valuesc             C   s   | t krdS dS dS )zmVerify if the column provided matches to known computed columns.

        Returns:
            bool

        TFN)COMPUTED_COLUMN_NAMES)columnr"   r"   r#   is_computed  s    zChartDataSource.is_computed)Nrv   r]   )N)%r'   r(   r)   r*   r.   r   rU   rG   rh   rk   rj   rM   ru   r~   rX   r   classmethodr   staticmethodr   r   rK   r   r   r   r   r   r   r   rn   r   r   rl   r7   r;   r   r   r"   r"   r"   r#   r^     sB   **
 
X-x 

+
r^   )7r*   Z
__future__r   r   	itertoolsr   operatorr   Znumpyr   Zpandasr{   Zsixr   Z	six.movesr   Zbokeh.core.has_propsr   Zbokeh.core.propertiesr	   r
   r   r   r   Zbokeh.models.sourcesr   r    r   r   Zstatsr   r   Zutilsr   r   r   r   rQ   r5   r   r   r   r=   r   r   r`   ra   r   r.   r9   r?   objectrE   rX   r^   r"   r"   r"   r#   <module>   s4   
(HC