

Yc           @` s2  d  Z  d d l m Z m Z m Z d d l m Z m Z d d l m Z d d l	 Z	 d d l
 Z
 d d l m Z m Z d d l m Z d d l Z d d l m Z d d l Z d d	 l m Z d d
 l m Z m Z m Z m Z m Z m Z m Z m  Z  m! Z! m" Z" m# Z# m$ Z$ m% Z% d d l& m' Z' d d l( m) Z) d Z* e d e f d e! f d e$ f d e f d e  f d e f d e f d e% f d e f d e f d e# f d e" f d e f g  Z+ d   Z, e' d  Z- d   Z. d   Z/ d   Z0 e1 d   Z2 d!   Z3 d"   Z4 d# d$  Z5 i e4 d% 6e5 d& 6Z6 d'   Z7 d(   Z8 d) d*  Z9 d+ e: f d,     YZ; d-   Z< d.   Z= d d/ d0 d1 d2  Z? d3   Z@ d4   ZA d d/ d0 d5  ZB d6   ZC d7 d8 d9 d:  ZD d;   ZE d<   ZF d=   ZG d d d>  ZH d d d d?  ZI eJ d@  ZK dA   ZL dB dC dD  ZM dE   ZN d S(F   sn    This is the utils module that collects convenience functions and code that are
useful for charts ecosystem.

i    (   t   absolute_importt   divisiont   print_function(   t   OrderedDictt   defaultdict(   t   copyN(   t   cost   sin(   t
   hsv_to_rgb(   t   json_normalize(   t	   iteritems(   t   Asteriskt   Circlet   CircleCrosst   CircleXt   Crosst   Diamondt   DiamondCrosst   InvertedTrianglet   Squaret   SquareCrosst   SquareXt   Trianglet   X(   t   DEFAULT_PALETTE(   t   ColumnDataSourcet   abcdefghijklmnopqrstuvwxyzt   circlet   squaret   trianglet   diamondt   inverted_trianglet   asteriskt   crosst   xt   circle_crosst   circle_xt   square_xt   square_crosst   diamond_crossc         C` s   t  j | |   S(   s/   Return first n items of the iterable as a list.(   t	   itertoolst   islice(   t   nt   iterable(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   take1   s    c         C` sI   g  } t  j |  } x- t t |    D] } | j t |   q( W| S(   s    Build a color list just cycling through a given palette.

    Args:
        chuck (seq): the chunk of elements to generate the color list
        palette (seq[color]) : a palette of colors to cycle through

    Returns:
        colors

    (   R(   t   cyclet   ranget   lent   appendt   next(   t   chunkt   palettet   colorst   gt   i(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   cycle_colors6   s
    c         C` s]   d   } g  } xA t  |  | |  D]- \ }  } } | j | |  | | d   q" Wt  |   S(   s   Translate polar coordinates to cartesian.

    Args:
    r (float): radial coordinate
    start_angles (list(float)): list of start angles
    end_angles (list(float)): list of end_angles angles

    Returns:
        x, y points
    c         S` s   |  t  |  |  t |  f S(   N(   R   R   (   t   rt   alpha(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   <lambda>U   s    i   (   t   zipR0   (   R8   t   start_anglest
   end_anglest	   cartesiant   pointst   startt   end(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   polar_to_cartesianJ   s
    	""c         C` sG   i  } g  } x4 |  D], } | | k r d | | <| j  |  q q W| S(   s   Creates an ordered list from strings, tuples or other hashable items.

    Returns:
        list of unique and ordered values
    i   (   R0   (   R+   t   mmapt   ord_sett   item(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   ordered_set]   s    
c          K` sT   d   t  |   D } t t j j g  | j   D] } | j ^ q/   } t |  S(   s   Collect list of unique and ordered columns across attribute specifications.

    Args:
        specs (dict): attribute name, :class:`AttrSpec` mapping

    Returns:
        list of columns in order as they appear in attr spec and without duplicates
    c         S` s(   i  |  ] \ } } | j  r | |  q S(    (   t   columns(   t   .0t	   spec_namet   spec(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pys
   <dictcomp>z   s   	 	(   R
   t   listR(   t   chaint   from_iterablet   valuesRG   RF   (   t   specst   selected_specsRJ   t	   spec_cols(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   collect_attribute_columnso   s    %c         K` s   d } t |  t  r< t |    } t j |  }  Wd QXn  t |  t  rZ t |   } nM t |  t  r x; t	 |   D]* \ } } t | t  rv t |  } qv qv Wn  | r | d k	 r t
 |  } n  | S(   s  Attempt to produce :class:`pandas.DataFrame` from hierarchical json-like data.

    This utility wraps the :func:`pandas.io.json.json_normalize` function and by
    default will try to rename the columns produced by it.

    Args:
        data (str or list(dict) or dict(list(dict))): a path to json data or loaded json
            data. This function will look into the data and try to parse it correctly
            based on common structures of json data.
        rename (bool, optional: try to rename column hierarchy to the base name. So
            medals.bronze would end up being bronze. This will only rename to the base
            column name if the name is unique, and only if the pandas json parser
            produced columns that have a '.' in the column name.
        **kwargs: any kwarg supported by :func:`pandas.io.json.json_normalize`

    Returns:
        a parsed pandas dataframe from the json data, unless the path does not exist,
            the input data is nether a list or dict. In that case, it will return `None`.
    N(   t   Nonet
   isinstancet   strt   opent   jsont   loadRK   R	   t   dictR
   t   denormalize_column_names(   t   datat   renamet   kwargst   parsedt	   data_filet   kt   v(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   df_from_json   s    c         C` s   |  j  j   } t t  } x; | D]3 } d | k r" | | j | j d  d  q" q" Wi  } x= t |  D]/ \ } } t |  d k rl | d | | <ql ql Wt t | j     d k r |  j	 d |  S|  Sd S(   s  Attempts to remove the column hierarchy if possible when parsing from json.

    Args:
        parsed_data (:class:`pandas.DataFrame`): df parsed from json data using
            :func:`pandas.io.json.json_normalize`.

    Returns:
        dataframe with updated column names
    t   .ii   i    RG   N(
   RG   t   tolistR   RK   R0   t   splitR
   R/   t   keysR\   (   t   parsed_datat   colst   base_columnst   colR\   t   new_cols(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyRZ      s    
%c         C` s   |  j  S(   s(  A generic function to return the index from values.

    Should be used to abstract away from specific types of data.

    Args:
        data (:class:`pandas.Series`, :class:`pandas.DataFrame`): a data source to
            return or derive an index for.

    Returns:
        a pandas index
    (   t   index(   R[   (    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt	   get_index   s    i   c         C` s   |  j    } | | d <| d S(   s  Returns a column of ones with the same length as input data.

    Useful for charts that need this special data type when no input is provided
    for one of the dimensions.

    Args:
        data (:class:`pandas.DataFrame`): the data to add constant column to.
        value (str, int, object): a valid value for a dataframe, used as constant value
            for each row.

    Returns:
        a copy of `data` with a column of '_charts_ones' added to it
    t   _charts_ones(   R   (   R[   t   valuet	   data_copy(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt	   get_unity   s    
Rl   t   unityc         C` sZ   |  d k	 rR t |   } t | t  s3 | g } n  t d j |  j    j   Sd Sd S(   sd   Creates standard string representation of columns.

    If cols is None, then None is returned.
    s   , N(   RS   R   RT   RK   RU   t   joint   title(   Rh   t
   cols_title(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   title_from_columns   s    c         C` s   t  t  } |  t |  k  r1 t  t |  |   S|  t |  } g  t | t j t t   D] } d j |  ^ q] } | j |  | Sd S(   s   Produces list of unique column names of length n.

    Args:
        n (int): count of column names to provide

    Returns:
        list(str) of length `n`
    t    N(   RK   t   DEFAULT_COLUMN_NAMESR/   R,   R(   t   productRs   t   extend(   R*   t	   col_namest   n_leftRE   t   labels(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   gen_column_names   s    	%g        c         C` sr   |  j  }  | j  } t j | d |  } t j | |  } t j |  d |  d  } t j | | d  } | | f S(   sO   Adds base to the start and end of y, and extends x to match the length.

    Args:
        x (`pandas.Series`): x values for the area chart
        y (`pandas.Series`): y values for the area chart
        base (float): the flat side of the area glyph

    Returns:
        x, y: tuple containing padded x and y as `numpy.ndarray`
    i    i(   RN   t   npt   insertR0   (   R"   t   yt   baset   y0t   x0(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   generate_patch_base  s    		t	   ChartHelpc           B` s    e  Z d  Z d   Z d   Z RS(   s9   Builds, formats, and displays help for the chart functionc         G` s   | |  _  d  S(   N(   t   builders(   t   selfR   (    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   __init__1  s    c         C` s.   d } x! |  j  D] } | | j   7} q W| S(   NRw   (   R   t   generate_help(   R   t   help_strt   builder(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   __repr__4  s    (   t   __name__t
   __module__t   __doc__R   R   (    (    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyR   /  s   	c          ` s     f d   } | S(   s>   Adds a ChartHelp object to the help attribute of the function.c         ` s   t      |  _ |  S(   N(   R   t   help(   t   f(   R   (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   add_help>  s    (    (   R   R   (    (   R   s-   lib/python2.7/site-packages/bkcharts/utils.pyR   <  s    c         C` st   |  d k s$ | d k s$ |  d k r3 d } d } n7 | d k rj t |  t  r[ |  d } n |  } d } n  | | f S(   s:  Produces consistent aggregation spec from optional column specification.

    This utility provides some consistency to the flexible inputs that can be provided
    to charts, such as not specifying dimensions to aggregate on, not specifying an
    aggregation, and/or not specifying a column to aggregate on.
    Rl   i    t   countN(   RS   RT   RK   (   t   dim_colst   agg_colt   agg(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   derive_aggregationE  s    $		t   meang      ?g{Gz?c         C` s   t  |  | | | |  }  t |  |  |  d |  d |  d d |  d <t | t  s| |  j |  d d k d f c d 9<n  |  S(   Nt   outerst   innersg       @t   centerst   leveli    g      ?(   t   cat_to_polart   add_wedge_spacingRT   RK   t   ix(   t   dft   cat_colsR   R   t   level_widtht   level_spacing(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   build_wedge_sourceY  s    "&c         C` s,   |  j    } | j d  } d | j d <| S(   sG   Produces a copy of the provided series shifted by one, starting with 0.i   g        i    (   R   t   shiftt   iloc(   t   st   s0(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   shift_seriesg  s    c         C` sb   |  d j    } x |  d D] } | | } q W| d t j 9} | j   } t |  } | | f S(   s   Produces wedge start and end values from list of dataframes for each level.

    Returns:
        start, end: two series describing starting and ending angles in radians

    i    i   i   (   R   R   t   pit   cumsumR   (   t   levelst   radsR   RA   R@   (    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   _create_start_endo  s    c         C` s  t  | | |  \ } } d   } g  } g  } g  } g  }	 g  }
 xMt d t |   D]6} | | d  } | d k	 r | d k	 r t t |  j |  |  |    } n6 g  |  j D] } | d k r | ^ q } |  | d } | d } | d k r|	 j | j d |  j |   n |	 j | |   t	 |	  } | j | d  | j | d  |
 j |  | d j
   } | | (| j |  qU Wt j i t j |  d 6t j |  d 6t j |  d 6t j |
  d 6 }  t |  d k rn|  j j
   j } xE t |  j  D]4 \ } } t | t  s<| d	 f } n  | | | <qWt j j |  |  _ | |  j _ n  t |  d |  \ } } | |  d
 <| |  d <|  S(   s   Return start and end angles for each index in series.

    Returns:
        df: a `pandas.DataFrame` describing each aggregated wedge

    c         S` s   |  |  j    S(   s*   How much of the circle should be assigned.(   t   sum(   R[   (    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   calc_span_proportion  s    i    i   Rl   R   R@   RA   RN   Rw   R   R   N(   R   R.   R/   RS   t   getattrt   groupbyRG   R0   t   applyR   R   t   pdt	   DataFramet   concatRl   RN   t	   enumerateRT   t   tuplet
   MultiIndext   from_tuplest   namest   calc_wedge_bounds(   R   R   R   R   R   R   t   levels_colst   startst   endsR   t
   agg_valuesR6   t
   level_colst   gbRj   Rh   t   group_levelt
   start_endst
   this_levelt   idxt   valR   R   (    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyR     sP    	'(
%

c         C` s   g  } x |  j  D]u } d } t | t  rl xJ t |  D]- } | d k	 r8 | d k r8 t |  } q8 q8 Wn t |  } | j |  q W| |  d <|  S(   s  Add column for text label, based on level-oriented index.

    This is used for the donut chart, where there is a hierarchy of categories,
    which are separated and encoded into the index of the data. If there are
    3 levels (columns) used, then a 3 level multi-index is used. Level 0 will
    have each of the values of the first column, then NaNs for the next two. The
    last non-empty level is used for the label of that row.
    Rw   t   text(   Rl   RT   R   t   reversedRU   R0   (   R   R   R   t   row_textt   lev(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   add_text_label_from_index  s    	
R@   RA   R   c         C` s   t  |  | |  | |  |  \ } } t |   }  t |  d |  d  |  d <d |  j |  j d k d f <t t d |  d d | d | d |  d   } | S(	   s   Generate `ColumnDataSource` for text representation of donut levels.

    Returns a data source with 3 columns, 'text', 'x', and 'y', where 'text'
    is a derived label from the `~pandas.MultiIndex` provided in `df`.
    R@   RA   t
   text_angleg        i    R   R"   R   (   RB   R   t   calc_text_angleR   R   R   RY   (   R   t	   start_colt   end_colt
   center_colR"   R   t   text_source(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   build_wedge_text_source  s    $c         C` sO   |  | d } | t  j d k | d t  j d k  @} | | t  j | | <| S(   sG   Produce a column of text angle values based on the bounds of the wedge.g       @i   i   (   R   R   (   R@   RA   R   t   shift_angles(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyR     s    (c         C` s   |  | } | | } | | f S(   sK   Calculate inner and outer radius bounds of the donut wedge based on levels.(    (   R   R   R   R   (    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyR     s    

c         C` sy   t  | t  rR xc t |  D]/ \ } } |  j |  d | k d f c | 7<q Wn# |  j |  d d k d f c | 7<d S(   sG   Add spacing to the `inners` column of the provided data based on level.R   R   i    N(   RT   RK   R   R   (   R   t   spacingR6   t   space(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyR     s    *c         C` sx   t  |  t  r5 g  | D] } | d | f ^ q } n? t  |  d t  rQ |  } n# g  |  D] } | d | f ^ qX } | S(   s  Produce tooltips for column dimensions used in chart configuration.

    Provides convenience for producing tooltips for data with labeled columns. If you
    had two bars in a bar chart, one for female and one for male, you may also want to
    have the tooltip say "Sex: female" and "Sex: male" when hovering.

    Args:
        hover_spec (bool, list(tuple(str, str), list(str), optional): either can be a
            valid input to the `HoverTool` tooltips kwarg, or a boolean `True` to have
            all dimensions specified in chart be added to the tooltip, or a list of
            columns that you do want to be included in the tooltips.
        chart_cols:

    Returns:
        list(tuple(str, str)): list of tooltips

    t   @i    (   RT   t   boolR   (   t
   hover_spect
   chart_colsRj   t   tooltips(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   build_hover_tooltips  s    &	#c         C` st   |  d k rd | d k r9 t | t  r0 | }  qa d }  qd | }  t | t  rd d |  | f }  qd n  |  j   d f S(   s  Produce a consistent tooltip based on available chart configuration.

    Args:
        hover_text (str, optional): the desired label for the value to be shown in the
            tooltip
        agg_text (str, optional): any aggregation text used for the chart
        aggregated_col (str, optional): any column name used for aggregation

    Returns:
        tuple(str, str): a single tooltip

    Ro   s   %s of %ss   @valuesN(   RS   RT   RU   Rt   (   t
   hover_textt   agg_textt   aggregated_col(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   build_agg_tooltip6  s    		c         C` s   t  |  t  r |  S|  d k r# d St  |  t  r | rs d j g  t |   D] \ } } d | | f ^ qK  } n1 t |  j    } t |  d k r | d } n  | St	 d t
 |     d S(   sa  

    Args:
        chart_index (dict(str, any) or str or None): identifier for the data group,
            representing either the value of a column (str), no grouping (None), or a dict
            where each key represents a column, and the value is the unique value.

    Returns:
        str: a derived label representing the chart index value

    RS   s   , s   %s=%si   i    sI   chart_index type is not recognized,                           received %sN(   RT   RU   RS   RY   Rs   R
   R   RN   R/   t
   ValueErrort   type(   t   chart_indext   include_colsRj   R   t   label(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   label_from_index_dictQ  s    /c          G` s)   g  |  D] } | j  ^ q } t j |  S(   N(   R   R   R   (   t   comp_glyphst   glypht   dfs(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   comp_glyphs_to_dfo  s    g?gffffff@c         C` sK   d d d } |  | 7}  |  d ;}  d j  t d   t |  | |  D    S(   s   

    Args:
        hue (int or double): a numerical value that you want to assign a color

    Returns:
        str: hexadecimal color value to a given number

    i   i   g      ?i   s   #{:02X}{:02X}{:02X}c         s` s   |  ] } t  | d   Vq d S(   id   N(   t   int(   RH   t   a(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pys	   <genexpr>  s    gw@(   t   formatR   R   (   t   huet
   saturationRo   t   golden_ratio(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   color_in_equal_spaceu  s    


c         C` s   |  j  j j   } t | d t  rQ g  | D] } | d j d d  ^ q, } n" t | d t  rm | } n g  } xN | D]F } | | k r qz n d | k r qz n  |  j  j | j |  |  qz W|  S(   sg  

    Args:
        renderer (GlyphRenderer): renderer for the glyph to be modified.
        tooltips (bool, list(str), list(tuple)): valid tooltips string as
            defined in the builder class.
        group (DataGroup): group of data containing missing columns.

    Returns:
        renderer (GlyphRenderer): renderer with missing columns added

    i    i   R   Rw   t   $(	   t   data_sourceR[   Rf   RT   R   t   replaceRU   t   addt
   get_values(   t   rendererR   t   groupt   current_columnst   pairt   tooltips_columnst   column(    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   add_tooltips_columns  s    ,	 (O   R   t
   __future__R    R   R   t   collectionsR   R   R   R(   RW   t   mathR   R   t   colorsysR   t   pandasR   t   pandas.io.jsonR	   t   numpyR   t   sixR
   t   bokeh.models.glyphsR   R   R   R   R   R   R   R   R   R   R   R   R   t   bokeh.plotting.helpersR   t   bokeh.models.sourcesR   Rx   t   marker_typesR,   R7   RB   RF   RR   t   TrueRb   RZ   Rm   Rq   t   special_columnsRv   R~   R   t   objectR   R   R   RS   R   R   R   R   R   R   R   R   R   R   R   t   FalseR   R   R   R   (    (    (    s-   lib/python2.7/site-packages/bkcharts/utils.pyt   <module>   s~   X																(		

								K			
		