o
    #0h>                    @   s|  d Z ddlmZmZ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 ddlmZ ddlZejdd	 d
krCeZeZdd Zd9ddZdd Zd:ddZG dd deZd;ddZG dd deZG dd deZ G dd deZ!G dd  d eZ"	"	d<d%d&Z#d=d*d+Z$d>d,d-Z%G d.d/ d/eZ&d>d0d1Z'd2d3 Z(d;d4d5Z)d>d6d7Z*e+d8krddl,Z,e,-  dS dS )?a  
Several tools for look-up tables management and interpolation

Provides:
    - LUT class: Look-Up Tables
      extends ndarrays for generic look-up table management including dimensions description,
      binary operations, multi-dimensional interpolation, plotting, etc
    - Idx class: find the index of values, for LUT interpolation
    - MLUT class: Multiple Look-Up Tables
      groups several LUTs, provides I/O interfaces with multiple data types
    - merge: MLUT merging
    )print_functiondivisionabsolute_importN)interp1d)exists)remove)OrderedDict)filled   )   r   c                 C   s   t | dkr|S t |dkr| S | d |d kr*| d gt| dd |dd  S | d |dd v rK|d | dd v rFtd| |t|| S | d gt| dd | S )zi
    Interleave 2 sequences (union, preserve order)
    ([1, 3, 4, 6], [2, 3, 6]) -> [1, 2, 3, 4, 6]
    r      Nz-sequences "{}" and "{}" cannot be interleaved)leninterleave_seq
ValueErrorformat)pq r   Z/Users/jing/Downloads/radiative_transfer_demo/ARTDECO/artdeco/pyartdeco/f2py_utils/luts.pyr      s   $
r   Bc                 C   s>   dD ]}t | dk rd| ||f   S | d } qd| d|f S )N) ZKiZMiZGiZTiPiZEiZZig      @z	%3.1f%s%sz%.1f%s%sZYi)abs)numsuffixunitr   r   r   
sizeof_fmt1   s
   
r   c                    s    t    j fdd| D S )z}
    Returns uniques elements from a sequence, whist preserving its order
    http://stackoverflow.com/questions/480214/
    c                    s    g | ]}| v s|s|qS r   r   .0xseenZseen_addr   r   
<listcomp>?   s     zuniq.<locals>.<listcomp>)setadd)seqr   r    r   uniq8   s   r&   c              
   C   s   | j dksJ t| dkrt| d | d g}n.d| d  | d  d }d| d  | d  d }tt|d| dd | dd   |}|durQt||}|dur[t||}|S )	z9
    calculate n+1 bin edges from n bin centers in x
    r         ?r   r   g       @N)ndimr   nparrayappendmaximumminimum)r   minmaxretfirstlastr   r   r   	bin_edgesB   s   ,r5   c                   @   s4  e Zd ZdZdHddZdIddZdJdd	Zd
d ZdJddZdd Z	dKddZ
dd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 ZdLd3d4ZdId5d6Zd7d8 Zd9d: Z		dMd;d<Z			dNd>d?Z d@dA Z!dBdC Z"dDdE Z#dFdG Z$dS )OLUTaQ  
    Look-up table storage with generic multi-dimensional interpolation.
    Extends the __getitem__ method of ndarrays to float and float arrays (index
    tables with floats)
    The LUT axes can be optionally provided so that values can be interpolated
    into float indices in a first step, using the Idx class.
    Other features:
        * binary operations between LUTs and with scalars
        * automatic broadcasting:
          binary operations between LUTs with different axes
          the LUTs are broadcasted together according to their common axes
        * apply functions, dimension reduction (apply a function along a given axis)
        * equality testing
        * plotting

    Arguments:
        * data is a n-dimension array containing the LUT data
        * axes is a list representing each dimension, containing for each
          dimension:
            - a 1-d array or list containing the tabulated values of the dimension
            - or None, if there are no values associated with this dimension
        * names is an optional list of names for each axis (default: None)
          it is necessary for storing the LUT
        * attr is a dictionary of additional attributes, useful for merging LUTs
        * desc is a string describing the parameter stored (default None)
          when using save(), desc is used as the hdf dataset name to store the LUT

    Attributes: axes, shape, data, ndim, attrs, names, desc

    Example 1
    ---------
    Basic usage, without axes and in 1D:
    >>> data = np.arange(10)**2
    >>> L = LUT(data)
    >>> L[1], L[-1], L[::2]    # standard indexing is possible
    (1, 81, array([ 0,  4, 16, 36, 64]))
    >>> L[1.5]    # Indexing with a float: interpolation
    2.5
    >>> L[np.array([[0.5, 1.5], [2.5, 9.]])]    # interpolate several values at once
    array([[  0.5,   2.5],
           [  6.5,  81. ]])

    Example 2
    ---------
    Interpolation of the atmospheric pressure
    >>> z = np.linspace(0, 120., 80)
    >>> P0 = np.linspace(980, 1030, 6)
    >>> Pdata = P0.reshape(1,-1)*np.exp(-z.reshape(-1,1)/8) # dimensions (z, P0)

    A 2D LUT with attached axes.  Axes names can optionally be provided.
    >>> P = LUT(Pdata, axes=[z, P0], names=['z', 'P0'])
    >>> P[Idx(8.848), Idx(1013.)]  # standard pressure at mount Everest
    336.09126751112842
    >>> z = np.random.rand(50, 50)  # now z is a 2D array of elevations between 0 and 1 km
    >>> P0 = 1000+20*np.random.rand(50, 50)  # and P0 is a 2D array of pressures at z=0
    >>> P[Idx(z), Idx(P0)].shape    # returns a 2D array of corresponding pressures
    (50, 50)

    In Idx, the values can optionally be passed using keyword notation.
    In this case, there is a verification that the argument corresponds to the right axis name.
    >>> P[:, Idx(1013., 'P0')].shape   # returns the (shape of) standard vertical pressure profile
    (80,)
    Nc                 C   s`  || _ || _|d u rt | _n|| _t| j j| _|j| _|d u r)| jd g | _nZ|| _t|| jks5J t|D ]I\}}t	|t
jrV|jdksJJ t||j| ksUJ q9t	|trgt||j| ksfJ q9|d u rlq9|d d  jdkswJ t||j| ksJ q9|d u r| jd g | _n|| _t|| jksJ | j jtt
jt
jfv rd| _d S d| _d S )Nr   z{:3g}z{})datadescr   attrsr   shaper*   axes	enumerate
isinstancer+   ndarraylistnamesdtypefloatfloat32float64	formatter)selfr7   r;   r@   r8   r9   iaxr   r   r   __init__   s6   




zLUT.__init__Fc                    s   |du rt | S | jdkr|r| S td| tdg| j }t| j}t| j}g  | D ]\}}t	|t
r<|}n t	|tsEJ d|| jv rQ| j|}n|rTq0td|| t	|trr|| j| }	|| j| }
n|}	d}
t|	jdkrt	|ts | nI|| du rd||< n>t	|tr|| | ||< n0t|	jdkr|
dur|
||< n|jjdv r|| | ||< nd||< ntdt|	j|	||< q0 fd	d
t|D } fdd
t|D }| t| }t|||t| j| jdS )a  
        returns a subset LUT of current LUT along several axes

        * d is a dictionary of {ax: value}, where:

            - ax is the name (string) or index (integer) of the axis to consider

            - value can be:
                * scalar integer (axis is removed)
                * float index (axis is removed with interpolation)
                * slice (axis is subsetted)
                * 1-d array (axis is subsetted)
                * Idx

        * ignore: if True, return full LUT if axis is not present in LUT

        Examples:
          lut.sub({'axis1': 1.5})
             returns the lut stripped from 'axis1', for which we use the index 1.5
          lut.sub({2: Idx(42.)})
          lut.sub({'ax': arange(5)})   # first 5 values
          lut.sub({'z': slice(None,None,2)})   # every other value
          lut.sub({'wav': lut.axis('wav')<500.})   # array of booleans
          lut.sub({'wav': Idx(lambda x: x<500.)})  # select wav < 500
        Nr   zCannot subset scalar LUT {}zax should be str or intzGsub is not possible on axis "{}" because this axis is not present in {}r   )urG   z)Cannot use a {}-dim array to subset a LUTc                       g | ]
\}}| vr|qS r   r   r   rG   aZdims_to_remover   r   r"         zLUT.sub.<locals>.<listcomp>c                    rK   r   r   rL   rN   r   r   r"     rO   r;   r@   r9   r8   )	Subsetterr*   	Exceptionr   slicer?   r@   r;   itemsr=   intstrindexIdx_baseapplyr+   r,   r-   rA   kindr<   tupler6   dictr9   r8   )rF   dignorekeysr@   r;   rH   viaxidxZnewaxr7   r   rN   r   sub   s`   










zLUT.subc                 C   s`   t |tr| j|}nt |tr|}ntd|r+| j| }t||g| j| gdS | j| S )z
        returns axis referred to by a (string or integer)
        aslut:
            False: returns the values
            True: returns axis a a LUT
                (containing itself as only axis)
        z.argument of LUT.axis() should be int or string)r;   r@   )r=   rV   r@   rW   rU   	TypeErrorr;   r6   )rF   rM   aslutrW   r7   r   r   r   axis  s   



zLUT.axisc                 O      | j |i |S NdescriberF   argskwargsr   r   r   
print_info2     zLUT.print_infoc              
   C   s   zd t| jt| j}W n   d}Y td dd | jd| jdu  | jj| tt	| jj
D ]@}| j| du rBd}n| j| }| j| du r\td ||| jj
|  q6td	 ||t	| j| | j| d
 | j| d  q6|rtd | j D ]\}}td|d| q| S )z
        Prints the LUT informations
        arguments:
            show_attrs: show LUT attributes (default: False)

        returns self
        z between {:.3g} and {:.3g}r   zLUT {}({}{}):z"{}" TFNNoNamez*  Dim {} ({}): {} values, no axis attachedz$  Dim {} ({}): {} values in [{}, {}]r   r(    Attributes: :)r   r+   aminr7   amaxprintr8   rA   xranger   r:   r@   r;   r9   rT   )rF   
show_attrsrngrG   namekr`   r   r   r   rj   6  s6   
zLUT.describec                 C   s  | j jjdv r| j | S t|ts|f}t|}t|}|| jkr*td	| j|t
|D ].}|| }t|tr\|jd| j| fvrRd}t|	|| j| |j|| j| ||< q.d}g }t
|D ]F}|| }t|tjr|jdkr|tj|dd |du r|j}qe||jksJ d	t|t|jqet|tr|| qe|d qetd	d	g| j t| j}g }	g }
g }t
|D ]u}|| }d
}t|tjr|jtdtdfv rd}|d}||| j j| d	 k  d	8  < || }|jdkr
||}nt|tr*d}t|}|| j j| d	 kr&|d	8 }|| }|r<|
| || |	| qt|	}d}t
d| D ]<}d	}t
|D ]'}d	|> |@ |? }|| }|rg||9 }n|d	| 9 }|
| | ||	| < qQ||| j t|  7 }qI|S )a  
        Get items from the LUT, with possible interpolation

        Indexing works mostly like a standard array indexing, with the following differences:
            - float indexes can be provided, they will result in an
              interpolation between bracketing integer indices for this dimension
            - float arrays can be provided, they will result in an
              interpolation between bracketing integer arrays for this dimension
            - Idx objects can be provided, they are first converted into indices
            - basic indexing and slicing, and advanced indexing (indexing with
              an ndarray of int or bool) can still be used
              (see http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html)
            - if arrays are passed as arguments, they must all have the same shape
            - Unlike ndarrays, the number of dimensions in keys should be
              identical to the dimension of the LUT
              >>> LUT(np.zeros((2, 2)))[:]
              Traceback (most recent call last):
              ...
              Exception: Incorrect number of dimensions in __getitem__

        Returns: a scalar or ndarray
        )SUzDIncorrect number of dimensions in __getitem__ (expecting {}, got {})NzAError, wrong parameter passed at position {}, expected {}, got {}r   rU   rA   z<LUTS.__getitem__: all arrays must have same shape ({} != {})r   FrC   rD   Tr
   )r7   rA   charr=   r[   r?   r   r*   rR   r   rx   rX   r{   r@   rW   r;   r+   r>   r-   
zeros_liker:   rV   rS   zerosreshapeastyperB   rU   )rF   r_   NrG   r|   msgZ
dims_arrayZindex0Zshp_resZinterpolate_axisZinf_listZx_listinterpolateinfr   nresultbcoefbbr   r   r   __getitem__^  s   




&
"
 




zLUT.__getitem__Tc                 C   s   t |tsdS t| jD ]*\}}|du r|j| du rq|du s'|j| du r* dS t||j| s6 dS q| jj|jjksAdS |rUt| j|jsMdS | j|jkrUdS dS )z
        Checks equality between two LUTs:
            - same axes
            - same shape
            - same values (if strict)
        FNT)	r=   r6   r<   r;   r+   allcloser7   r:   r9   )rF   otherstrictrG   rH   r   r   r   equal  s$   
z	LUT.equalc                 C   s  g g }}g }t | j|j}t|D ]G\}}|| jv rA|| j| j|  |td ||jv r;|td q|d q||j|j|  |d |td qi }	| jD ]>}
|
|jvrgq_t| j|
 t	j
rt|j|
 t	j
szq_t	| j|
 |j|
 sq_n| j|
 |j|
 krq_|	|
| j|
 i q_| j|jkr| j}nt|}t|| jt| |jt| |||	|dS )z
        apply fn(self, other) where other is a LUT
        the result is determined by using common axes between self and other
        and using appropriate broadcasting
        NrP   )r   r@   r<   r-   r;   rW   rS   r9   r=   r+   r>   r   updater8   rV   r6   r7   r[   )rF   r   fnshp1shp2r;   r@   rG   rM   r9   r|   r8   r   r   r   __binary_operation_lut__  sH   





zLUT.__binary_operation_lut__c                 C   s"   t || j|| j| j| j| jdS )NrP   )r6   r7   r;   r@   r9   r8   rF   r   r   r   r   r   __binary_operation_scalar__-  s   zLUT.__binary_operation_scalar__c                 C   s"   t |tr| ||S | ||S rh   )r=   r6   r   r   r   r   r   r   __binary_operation__2  s   
zLUT.__binary_operation__c                 C      |  |dd S )Nc                 S      | | S rh   r   r   yr   r   r   <lambda>9      zLUT.__add__.<locals>.<lambda>r   rF   r   r   r   r   __add__8     zLUT.__add__c                 C   r   )Nc                 S   r   rh   r   r   r   r   r   r   <  r   zLUT.__radd__.<locals>.<lambda>r   r   r   r   r   __radd__;  r   zLUT.__radd__c                 C   r   )Nc                 S   s   | | S rh   r   r   r   r   r   r   ?  r   zLUT.__sub__.<locals>.<lambda>r   r   r   r   r   __sub__>  r   zLUT.__sub__c                 C   r   )Nc                 S   s   ||  S rh   r   r   r   r   r   r   B  r   zLUT.__rsub__.<locals>.<lambda>r   r   r   r   r   __rsub__A  r   zLUT.__rsub__c                 C   r   )Nc                 S      | | S rh   r   r   r   r   r   r   E  r   zLUT.__mul__.<locals>.<lambda>r   r   r   r   r   __mul__D  r   zLUT.__mul__c                 C   r   )Nc                 S   r   rh   r   r   r   r   r   r   H  r   zLUT.__rmul__.<locals>.<lambda>r   r   r   r   r   __rmul__G  r   zLUT.__rmul__c                 C   r   )Nc                 S      | | S rh   r   r   r   r   r   r   K  r   zLUT.__div__.<locals>.<lambda>r   r   r   r   r   __div__J  r   zLUT.__div__c                 C   r   )Nc                 S      ||  S rh   r   r   r   r   r   r   N  r   zLUT.__rdiv__.<locals>.<lambda>r   r   r   r   r   __rdiv__M  r   zLUT.__rdiv__c                 C   r   )Nc                 S   r   rh   r   r   r   r   r   r   Q  r   z!LUT.__truediv__.<locals>.<lambda>r   r   r   r   r   __truediv__P  r   zLUT.__truediv__c                 C   r   )Nc                 S   r   rh   r   r   r   r   r   r   T  r   z"LUT.__rtruediv__.<locals>.<lambda>r   r   r   r   r   __rtruediv__S  r   zLUT.__rtruediv__c                 C   
   |  |S rh   r   r   r   r   r   __eq__V     
z
LUT.__eq__c                 C      |  | S rh   r   r   r   r   r   __neq__Y     zLUT.__neq__c                 C   s   t  }| jdur+tt| jD ]}| j| }| j| }|du s#|du r$q||| q|j| j| j| j| j	d |
| j	 |S )z#
        convert to a MLUT
        Naxnamesr9   )MLUTr;   rx   r   r@   add_axisadd_datasetr8   r7   r9   	set_attrs)rF   mrG   r{   rf   r   r   r   to_mlut]  s   


zLUT.to_mlutc                 C   s6   |du r| j dur| j }t|| j| j| j| j|dS )z
        returns a LUT whose content is obtained by applying function fn
        if desc is provided, use this description
        NrP   )r8   r6   r7   r;   r@   r9   )rF   r   r8   r   r   r   rY   t  s   
z	LUT.applyc                 K   sz  t |tr| j|}n|}|du rLt| j}t| j}|| || | jdkr8|s8|| jfd|i|S t	|| jfd|i|||| j
| jdS t|t| j| ksYJ t| jj}	t|}
t|
|	|< tj|	| jjd}tdg| j }tdg| j }t|
D ]!\}}|||< ||k||< || jt| fd|i||t|< qt| j}|
||< t	||| j| j
| jdS )a)  
        apply function fn to a given axis
        fn: function to apply
            should be applicable to a numpy.ndarray and support argument axis
            (example: numpy.sum)
        axis: name (str) or index of axis
        grouping: iterable of same size as axis
                  fn is applied by groups corresponding to identical values in
                  grouping
                      example: grouping = [0, 0, 0, 1, 1, 2]
                      results in fn(3 first elements), fn(2 next), then fn(last)
                    the axis of the reduced axis takes the values of grouping
                  default None (apply to all elements, remove axis)
        as_lut: if axis reduction results in a scalar, returns a dimensionless LUT
                default False (returns a scalar)

        Nr   rf   rP   r   )r=   rV   r@   rW   r?   r;   popr*   r7   r6   r9   r8   r   r:   r&   r+   r   rA   rS   r<   r[   )rF   r   rf   groupingZas_lutrm   rW   r;   r@   shpr~   r7   ind1ind2rG   rJ   r   r   r   reduce  s>   




(
z
LUT.reducec                 C   s   t |tr| j|}t |tr| j|}g g }}t| jD ]}|| j|  || j|  q || || ||< ||< || || ||< ||< t| j	
||||| j| jdS )z
        Swaps two axes of the LUT

        Arguments:
            axis1 and axis2 (int or str): the name or index of the axes to swap

        Returns: the swapped LUT
        rP   )r=   rV   r@   rW   rx   r*   r-   r;   r6   r7   swapaxesr9   r8   )rF   axis1axis2r@   r;   rG   r   r   r   r     s   
	

zLUT.swapaxesc                 O   s   | j dkr$| jdu rt| j| j | S td| j | j| j | S | j dkr3| j|i | | S | j dkrB| j|i | | S | j|i | | S )a  
        Plot a 1 or 2-dimension LUT
        Note:
        in 2-dim, creates a new figure

        Arguments:
            * swap: swap x and y axes
            * show_grid
            * fmt: format for plotting 1d data

            Only in 2-dim:
            * vmin, vmax: color scale extent (default: from min/max)
            * cmap: colormap instance
            * index: index (or Idx instance) for plotting transect
        r   Nz{}: r   r
   )	r*   r8   rw   rE   r   r7   _LUT__plot_1d_LUT__plot_2dplot_ndrk   r   r   r   plot  s   




zLUT.plotc	                 K   s  ddl m}
m}m}m}m} ddl }|du r|j}| jjj	dkr't
d dS | jd }|du r7t| jd }|du rHt| jt| j  }|du rYt| jt| j  }|si|}| j}| jd }| j}n| j}|}| j}| jd }|du r||||d n|||||d ||| |dur|
| |dur|s|| ||jkr|ddd	d
 || |r|jddd}| d dS dS )z
        plot a 1-dimension LUT, returns self

        arguments:
            plot: custom plot function (defaults to plot)
                  example: plot=semilogy
        r   )xlabelylabelgridylimticklabel_formatNr}   z'1D plot does not work for string arrays)labelr   scir)   r
   rf   style	scilimitsbestT)locfancyboxr'   )pylabr   r   r   r   r   r   r7   rA   r   warningswarnr;   ranger:   r+   ru   isnanrv   r@   r8   legend	get_frame	set_alpha)rF   	show_gridswapfmtr   vminvmaxr   r   rm   r   r   r   r   r   plrH   xxyyZxlabZylablegr   r   r   Z	__plot_1d  sL   	





zLUT.__plot_1dk-c	                 K   s4  ddl m}
 |du rt| jt| j  }|du r(t| jt| j  }|du r?|
jj}|	d |
d |d |s[| jd | jd }}| jd | jd }}| j}n| jd | jd }}t| jdd}| jd | jd }}|du rt|jd }|du rt|jd }|du r|
jddd\}}n|
jddd	d
\}\}}t|}t|}t||\}}|
| |
j|||||d}|
| |
t|t|t|t|g |g d}|du r| j}|dur|j| jdddd |
j|dd|d |du r|
| |
| |
| nst|tr)|j }n|| }|!t|t|g||gd |j"dddd |sW|!|| |ddf | n|!|| dd|f | || |
| |
| |
| |
| j |
| |j||d |j"dddd |j#dd dS )zU
        Plot a 2-dimension LUT, with optional transect
        returns self
        r   Nblackwhite0.5r   )nrowsncolsr
   T)r   r   sharex)r   r   )gq=
ףp?g      ?gQ?r'   boldleft)        g333333ÿ)weighthorizontalalignmentpositionbothvertical)extendorientationcaxw--r   r   r   r   )yminymaxr   )hspace)$matplotlib.pyplotpyplotr+   ru   r7   r   rv   cmjet	set_underset_overset_badr;   r@   r   aranger:   subplotsr5   meshgridsca
pcolormeshr   rf   add_axesr8   	set_titlecolorbarr   r   r=   Idxvaluer   r   subplots_adjust)rF   r   r   r   r   r   cmaprW   r   rm   pltr   r   Zlab1Zlab2r7   figax1ax2XYimZcbar_axr`   r   r   r   Z	__plot_2d,  s~   








"




zLUT.__plot_2dc                    sx  zddl m}m}m}m}m} ddlm}m W n t	y#   t
dw g }	g g g tjD ]Y}
j|
 }j|
 }|}|d u rGd}|d urW|d|d |d 7 }||dd	}|dj|
 d
 d}d|_|dd}d|_| | | |	||||g q3 fdd}tjD ]}
|
 |d |
 |d q|||	 |  d S )Nr   )VBoxHBoxCheckbox	IntSliderHTMLdisplayclear_outputzOIPython notebook widgets are required to plot a LUT with more than 2 dimensionsrq    [{:.5g}, {:.5g}]r(   Fdescriptionr  r   r0   r1   r   r  c                     s     g } d}t jD ]A}| j| _| j| _| jrB| j}| | j| d krAdj| | | _q| td  |d7 }q|dkrc 	t
| j i  d S td|d  d S )Nr   &nbsp;&nbsp;{:.5g}&nbsp;&nbsp;r   r
   z&Please select at least {} dimension(s))rx   r*   r  visibler-   r;   r   rS   rc   r   r[   r   rw   )r_   r*   rG   rW   rl   Zchksr#  rm   rF   Zsliderstextsr   r   r     s"   



"zLUT.plot_nd.<locals>.updater  )
ipywidgetsr  r  r  r  r   IPython.displayr"  r#  ImportErrorrR   rx   r*   r@   r;   r   r:   r*  r-   on_trait_change)rF   rl   rm   r  r  r  r  r   r"  widrG   r{   rH   r8   chkslidertextr   r   r+  r   r     s>   






zLUT.plot_ndc                 O      t | g|R i | | S rh   
plot_polarrk   r   r   r   r7       zLUT.plot_polarc                 O   s"   d|d< t | g|R i | | S )NTsemir6  rk   r   r   r   	plot_semi  s   zLUT.plot_semic                 O   r5  rh   )
transect2Drk   r   r   r   r;    r8  zLUT.transect2D)NNNN)NFF)Trh   )TFNNNNFN)r   TFNNNNN)%__name__
__module____qualname____doc__rI   rc   rf   rn   rj   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rY   r   r   r   r   r   r   r7  r:  r;  r   r   r   r   r6   V   sP    
@
'
_
(
|8

8
;
[;r6   Fc                 C   s&   t | drt| |dS t| |||dS )a  
    Calculate the indices of values by interpolation in a LUT axis
    The index method is typically called when indexing a dimension of a LUT
    object by a Idx object.
    The round attribute (boolean) indicates whether the resulting index should
    be rounded to the closest integer.

    Idx value can be of several kinds:
    - scalar (int or float)
     => index return scalar float index
    - array-like
      => index return array-like float index
    - callable (ex: lambda x: x<5)
      => index returns callable applied to axis

    Example: find the float index of 35. in an array [0, 10, ..., 100]
    >>> Idx(35.).index(np.linspace(0, 100, 11))
    array(3.5)

    Find the indices of several values in the array [0, 10, ..., 100]
    >>> Idx(np.array([32., 45., 72.])).index(np.linspace(0, 100, 11))
    array([ 3.2,  4.5,  7.2])

    Optionally, the name of the parameter can be provided as a keyword
    argument.
    Example: Idx(3., 'a') instead of Idx(3.)
    This allows verifying that the parameter is used in the right axis.

    Options:
        - fill_value are passed to interp1d (implies bounds_error=False)
          Special value for fill_value='extrema': fill with extrema values, don't extrapolate

    NOTE: this function is a factory that returns an Idx_* instance based on input type

    Method apply(axis):
        returns the Idx values applied to axis instead of their index
    __call__)r{   )r{   round
fill_value)hasattr
Idx_filterIdx_arrr  r{   rB  rC  r   r   r   r    s
   
&r  c                   @   s   e Zd ZdZdddZdS )rX   z$
    Base class for Idx objects
    NFc                 C   s(   |d ur|| _ || _|| _|| _d S d S rh   rG  )rF   r  r{   rB  rC  r   r   r   rI     s   
zIdx_base.__init__NFN)r=  r>  r?  r@  rI   r   r   r   r   rX     s    rX   c                   @   s"   e Zd ZdZdd ZdddZdS )rF  z)
    Idx class for array-like values
    c                 C   sF  t |dkrtt| j|d std| j|dS | jdkr+dt |d f}nK| jdkrsdt |d f}t| jt|krUt	
dt| jt|| j t| jt|k rrt	
dt| jt|| j n| j}| jdu }t|tt |||d	| j}| jrt|tjr| t}|S t|}|S )
zK
        Return the floating point index of the values in the axis
        r   r   z+(Idx) Out of axis value (value={}, axis={})extremazextrema,warnz5(Idx) Value {} is above the axis maximum {} (axis {})z5(Idx) Value {} is under the axis minimum {} (axis {})N)bounds_errorrC  )r   r+   r   r,   r  r   r   rC  rv   r   r   r{   ru   r   r	  rB  r=   r>   r   rU   )rF   rf   fvberesr   r   r   rW     s>   


zIdx_arr.indexNc                 C   s   | j S rh   r(  rF   rf   r   r   r   rY   1  s   zIdx_arr.applyrh   r=  r>  r?  r@  rW   rY   r   r   r   r   rF  	  s    $rF  c                   @       e Zd ZdZdd Zdd ZdS )rE  z+
    Idx class for filtering functions
    c                 C   r   rh   r(  rN  r   r   r   rW   8  s   
zIdx_filter.indexc                 C   s   ||  | S rh   )rW   rN  r   r   r   rY   =  s   zIdx_filter.applyNrO  r   r   r   r   rE  4  s    rE  c                   @   rP  )rQ   zb
    A conveniency class to use the syntax like:
    LUT.sub()[:,:,0]
    for subsetting LUTs
    c                 C   s
   || _ d S rh   )r6   )rF   r6   r   r   r   rI   G  r   zSubsetter.__init__c                 C   s   | j tt|S )z#
        subset parent LUT
        )r6   rc   r\   r<   )rF   r_   r   r   r   r   J  s   zSubsetter.__getitem__N)r=  r>  r?  r@  rI   r   r   r   r   r   rQ   A  s    rQ   211212Tautoc           3   	      s  ddl m}m} ddlm  m} ddlm} ddlm	} ddl
m} d}|
r)d}| jd	ks0J |du}|du rE|r@|d
d}n|dd}|dkr`d| jd  v r^d| jd  vr^d}nd}|r| jd | jd }}| jd | jd }}t| jdd}n| jd | jd }}| jd | jd }}| j}|du rt| jt| j  }|du rt| jt| j  }||kr|d8 }|d7 }||kr||}}|}|}t|t| |    d }|}|jddd|
 dd}| }G dd dt}G  fdddt}dk r,dkr, dkr, dkr,|d} | }!n| } | }!| dd}"| tjd d}#|"|# |  }$|j|$d |d df|| ||!d!}%|j|||%d"}&||& |& d |&j!d# "d$ |&j!d% "d& |&j!d$ #d |&j!d& "d$ |&j!d& j$ddd' |&j!d& j%"d& |&j!d& j&"d& |&j!d& jj'd(d)||&j(d#d$d* |&j!d# jj'd+d,||&j(d-d&d* |&)|$}'|&j*|'_*d.|&j*_+|r||}(|r|(,    n|(,  |(-|| |(j.d/d0d1d2 |( d |	du r|j/}	|	0d3 |	1d4 |	2d5 t3t4|ddd6t4|\})}*tj56t|t7|B |}+|'j8|*|)|+|	||d7},|rt9|t:rVt;|<|=t>}-n|}-t?|-D ]\}.}|
rhd8| }/n|j@d d	 | |j@d  }/tAddg||  gg}0tAddg||/  gg}1|'B|0dddf |0dddf d9 |r|'jB|1dddf |1dddf d:d	d; g d<|.d=  }2|(B|||ddf d>|2  |r|(B| ||/ddf d?|2  q\|jC|,d@dAtD||dBdCdD | jEdur|&jF| jEdEdFdG dS dS )Ha  
    Contour and eventually transect of 2D LUT on a semi polar plot, with
    dimensions (angle, radius)

    lut: 2D look-up table to display
            with axes (radius, angle) (unless swapped)
            angle is assumed to be in degrees and is not scaled
    index: index of the item to transect in the 'angle' dimension
           can be an Idx instance of several values or a list of indices
           if None (default), no transect
    vmin, vmax: range of values
                default None: determine min/max from values
    rect: subplot position of the main plot ('111' for example)
    sub: subplot position of the transect
    sym: the transect uses symmetrical axis (boolean)
         if None (default), use symmetry iff axis is 'zenith'
    swap: swap the order of the 2 axes to (radius, angle)
          if 'auto', searches for 'azi' in both axes names
    fig : destination figure. If None (default), create a new figure.
    cmap: color map
    semi: polar by default, otherwise semi polar if lut is computed for 360 deg
    r   )figurer  N)Affine2D)floating_axes)	PolarAxesg     v@g     f@r
   )      @rX  figsize)rX     rS  azir   TFMbP?g     V@      rp   )Zinclude_lastc                   @   s   e Zd Zdd ZdS )zplot_polar.<locals>.Locatorc                 W   s   t g dddgS )N)r      <   Z   r^        ?)r+   r,   rF   rl   r   r   r   rA    s   z$plot_polar.<locals>.Locator.__call__Nr=  r>  r?  rA  r   r   r   r   Locator  s    rf  c                       s   e Zd Z fddZdS )zplot_polar.<locals>.Formatterc                    s   t dd t dS )Nc                 S   s
   d | S )Nz{:.3g}r   r   r   r   r   r        
 z8plot_polar.<locals>.Formatter.__call__.<locals>.<lambda>r^  )mapr+   linspacerd  ax2_maxax2_minr   r   rA    s   z&plot_polar.<locals>.Formatter.__call__Nre  r   rl  r   r   	Formatter  s    ro  g      $@rb  P   rc  r   )Zextremesgrid_locator1grid_locator2tick_formatter1tick_formatter2)grid_helperr   bottomrighttop)
ticklabelsr   g
ףp=
?g\(\?)	transformhavag?gQcenterg?r   r   r   r   r   r   r   r'  )r  r   r   r(   wr   )	linewidth)r|   rgr   r   r   r[  -z--
horizontalr      gffffff?)r   r   ticksshrinkr   )g?g
ףp=
?)r   r   )Gr   rT  r  Z$mpl_toolkits.axisartist.angle_helperZ
axisartistangle_helpermatplotlib.transformsrU  Zmpl_toolkits.axisartistrV  matplotlib.projectionsrW  r*   r@   lowerr;   r+   r   r7   ru   r   rv   Z
LocatorDMSZFormatterDMSobject	translatescalepiPolarTransformZGridHelperCurveLinearZFloatingSubplotadd_subplotr   rf   Zset_axis_directionset_visibletoggleZmajor_ticklabelsr   r4  	transAxesZget_aux_axespatchzorderset_xlimset_ylimr   rainbowr  r  r  r  r5   mamasked_whereisinfr  r=   rX   rB  rW   r   rU   r<   r:   r,   r   r  rk  r8   r  )3lutrW   r   r   rectrc   symr   r  r  r9  rT  r  r  rU  rV  rW  ZPhimaxZshow_subr  r  name1name2r7   
ax1_scaledlabel1Z
ax2_scaledlabel2rq  rs  rf  ro  rr  rt  Z	tr_rotateZtr_scaletrru  Zax_polarZaux_ax_polarax_cartr  tZmasked_datar  Zindexesiimirror_indexZvertex0Zvertex1colorr   rl  r   r7  Q  s   
$














&* r7  y   r|   r  c                 C   s  ddl m} | jdksJ |du r|dd}|dkr1d| jd	  v r/d| jd  vr/d
}nd}|rR| jd	 | jd }}| jd	 | jd }}t| jdd	}n| jd | jd	 }}| jd | jd	 }}| j}|du r|t	| jt
| j  }|du rt| jt
| j  }||kr|d8 }|d7 }||kr||}}|	rd}d}|}|}t|trtt||}|jd d | |jd  }|r| jd	 | }n| jd | }t	|}t|}|d| }||}|d
 |r|| | n||| ||| |jdddd |d
 || |j|||ddf |
|d |r?|j| ||ddf |
|d | jdurM|| j dS dS )a  
    Transect of 2D LUT

    lut: 2D look-up table to display
            with axes (radius, angle) (unless swapped)
            angle is assumed to be in degrees and is not scaled
    index: index of the item to transect in the 'angle' dimension
           can be an Idx instance
           if None (default), no transect
    vmin, vmax: range of values
                default None: determine min/max from values
    sym: the transect uses symmetrical axis (boolean)
         if None (default), use symmetry if axis is 'zenith'
    swap: swap the order of the 2 axes to (radius, angle)
          if 'auto', searches for 'azi' in both axes names
    fig : destination figure. If None (default), create a new figure.
    color : color of the transect
    percent: if True set scale to 0 to 100%
    r   )rT  r
   N)rX  g      @rY  rS  r\  r   TFr]  r   g      Y@z {:7.2f}r   r   r   r   )r  )r   rT  r*   r@   r  r;   r+   r   r7   ru   r   rv   r=   rX   rU   aroundrW   r:   r   r  r   r  r  r   
set_xlabelr   r8   r  )r  rW   r   r   r  r   r  rc   r  percentr   rT  r  r  r  r  r7   r  r  r  titlern  rm  r  r  r   r   r   r;  #  sh   
$






 r;  c                    sP  t  }| d }tdt| D ]}|j| | ddddsJ q|j D ]
\}}||| q#g }g }	|D ]/}g }| D ]}
|
j| }|durI||}||vrR|| q:||| || |	| q4|	 D ]}}t
tt||| j }|| jj}tj||d}z|tj7 }W n   Y | D ]:}
d}t|D ]\}}|
j| }|dur||}||| |f7 }q|| jjdkr|tdf7 }|
| j||< q|| j}|du r||| qh||||	|  qh|j D ]:\ dt fd	d
| v rqttjrdt fdd
| v rqndt fdd
| v rq|  q|S )aK  
    Merge several luts

    Arguments:
        - M is a list of MLUT objects to merge
        - axes is a list of axes names to merge
          these names should be present in each LUT attribute
        - dtype is the data type of the new axes
          ex: dtype=float
          if None, no data type conversion

    Returns a MLUT for which each dataset has new axes as defined in list axes
    (list of strings)
    The attributes of the merged mlut consists of the common attributes with
    identical values.

    >>> np.random.seed(0)

    Example: merge two MLUTS
    (also using attribute to dataset promotion)
    >>> M = []
    >>> for b in range(4):
    ...     M1 = MLUT()
    ...     M1.add_axis('ax1', np.arange(4))
    ...     M1.add_axis('ax2', np.arange(5)+10)
    ...     M1.add_dataset('a', np.random.randn(4, 5), ['ax1', 'ax2'])
    ...     M1.set_attrs({'b':b, 'c':b*10})
    ...     M1.promote_attr('b')  # attribute 'b' is converted to a scalar dataset
    ...     M.append(M1)
    >>> merged = merge(M, ['c'])
    >>> _=merged.print_info(show_self=False)
     Datasets:
      [0] a (float64 between -2.55 and 2.27), axes=('c', 'ax1', 'ax2')
      [1] b (float64 between 0 and 3), axes=('c',)
     Axes:
      [0] ax1: 4 values between 0 and 3
      [1] ax2: 5 values between 10 and 14
      [2] c: 4 values between 0 and 30

    r   r   FT)content
attributes	show_diffNr   r   c                    s
    | j v S rh   r9   rh  )r|   r   r   r     ri  zmerge.<locals>.<lambda>c                    s   t | j  S rh   )r+   r   r9   rh  r|   r`   r   r   r     s    c                    s   | j   kS rh   r  rh  r  r   r   r     s    )r   rx   r   r   r;   rT   r   r9   r-   datasetsr[   rj  r:   r7   rA   r+   r   NaNr<   rW   r*   rS   r@   r   r=   r>   set_attr)Mr;   rA   r   r3   rG   axnamerf   ZnewaxesZ
newaxnamesZmlutr  r{   	new_shape_dtypenewdatarW   jrM   r   r   r  r   merge  sj   *




r  c                   @   s   e Zd ZdZdd Zdd Zdd Zdi fd	d
Zd1ddZdd Z	dd Z
		d2ddZ		d3ddZd3ddZdd Zdd Zdd Zd4dd Zd!d" Zd#d$ Zd%d& Zd5d'd(Zd)d* Zd+d, Zd6d-d.Zd7d/d0ZdS )8r   aJ  
    A class to store and manage multiple look-up tables

    How to create a MLUT:
    >>> m = MLUT()
    >>> m.add_axis('a', np.linspace(100, 150, 5))
    >>> m.add_axis('b', np.linspace(5, 8, 6))
    >>> m.add_axis('c', np.linspace(0, 1, 7))
    >>> np.random.seed(0)
    >>> m.add_dataset('data1', np.random.randn(5, 6), ['a', 'b'])
    >>> m.add_dataset('data2', np.random.randn(5, 6, 7), ['a', 'b', 'c'])
    >>> # Add a dataset without associated axes
    >>> m.add_dataset('data3', np.random.randn(10, 12))
    >>> m.set_attr('x', 12)   # set MLUT attributes
    >>> m.set_attrs({'y':15, 'z':8})
    >>> _=m.print_info(show_self=False)
     Datasets:
      [0] data1 (float64 between -2.55 and 2.27), axes=('a', 'b')
      [1] data2 (float64 between -2.22 and 2.38), axes=('a', 'b', 'c')
      [2] data3 (float64 between -2.77 and 2.3), axes=(None, None)
     Axes:
      [0] a: 5 values between 100.0 and 150.0
      [1] b: 6 values between 5.0 and 8.0
      [2] c: 7 values between 0.0 and 1.0

    Use bracket notation to extract a LUT
    Note that you can use a string or integer.
    data1 is the first dataset in this case, we could use m[0]
    >>> _=m['data1'].print_info()  # or m[0]
    LUT "data1" (float64 between -2.55 and 2.27):
      Dim 0 (a): 5 values betweeen 100.0 and 150.0
      Dim 1 (b): 6 values betweeen 5.0 and 8.0
    c                 C   s   t  | _g | _t  | _d S rh   )r   r;   r7   r9   rF   r   r   r   rI      s   zMLUT.__init__c                 C   s   dd | j D S )z& returns a list of the datasets names c                 S      g | ]}|d  qS r   r   r   r   r   r   r"   *      z!MLUT.datasets.<locals>.<listcomp>r7   r  r   r   r   r  (  ro   zMLUT.datasetsc                 C   s\   t |tsJ || jvsJ d|t |trt|}n|}|jdks'J || j|< dS )z Add an axis to the MLUT zAxis "{}" already in MLUTr   N)r=   rV   r;   r   r?   r+   r,   r*   )rF   r{   rf   rH   r   r   r   r   ,  s   
zMLUT.add_axisNc                 C   s   |dd | j D vsJ d||durCt|t|jks J t|D ]\}}|du r-q$|| jvr3q$|j| t| j| ksAJ q$ndg|j }| j ||||f dS )z
        Add a dataset to the MLUT
        name (str): name of the dataset
        dataset (np.array)
        axnames: list of (strings or None), or None
        attrs: dataset attributes
        c                 S   r  r  r   r   r   r   r   r"   @  r  z$MLUT.add_dataset.<locals>.<listcomp>zError, "{}" already in MLUTN)r7   r   r   r:   r<   r;   r*   r-   )rF   r{   datasetr   r9   rG   rH   r   r   r   r   8  s   "
zMLUT.add_datasetc                 C   s   |du r|j }|dusJ t|jD ]S}|j| }|j| }|| jv rP|durOt| j| jt|jksDJ d|| j| j|jt	| j| |sOJ q|du r[|du sZJ q|dure| 
|| q| j||j|j|jd | S )z=
        Add a LUT to the MLUT

        returns self
        Nz+Inconsistent shapes for axis "{}": {} != {}r   )r8   rx   r*   r@   r;   r+   r,   r:   r   r   r   r   r7   r9   )rF   r  r8   ra   r  rH   r   r   r   add_lutM  s,   


 zMLUT.add_lutc                 C   s~   z	t |tsJ W n ty   t |ttfsJ Y nw zdd | jD |}W n ty6   td|| w | j	| dS )z remove a LUT c                 S   r  r  r   r   r   r   r   r"   r  r  zMLUT.rm_lut.<locals>.<listcomp>z{} is not in {}N)
r=   
basestring	NameErrorrV   bytesr7   rW   r   rR   r   )rF   r{   rW   r   r   r   rm_lutj  s   zMLUT.rm_lutc                 C   sP   t  }|D ]	}t|tsJ q|  D ]}|| | j|dd q| j|_|S )z
        The MLUT equivalent of LUT.sub

        returns a MLUT where each LUT is subsetted using dictionary d
        keys should only be strings
        values can be int, float, slice, Idx, array (bool or int)
        T)r^   )r   r=   rV   r  r  rc   r9   )rF   r]   r   ddr   r   r   rc   x  s   zMLUT.subFTc                 C   s   t |r|rt| ntd|}t|d| ||r%td| || |du r@|dr1d}n|dr9d}ntd	||dkrO| j||||d
 dS |dkr^| j	||||d
 dS td|)z
        Save a MLUT to filename
        fmt: output format: hdf4, netcdf4,
             or None (determine from filename extension)
        zFile {} existsfilenamez Writing "{}" to "{}" ({} format)N.hdfhdf4.ncnetcdf40Cannot determine desired format of filename "{}")	overwriteverbosecompressInvalid format {})
r   r   rR   r   setattrrw   endswithr   _MLUT__save_netcdf4_MLUT__save_hdf)rF   r  r   r  r  r  exr   r   r   save  s2   




z	MLUT.savec                 C   sf  ddl m} ||ddd}d}| j D ]!\}}	||t|	 |j||	j|g|d}
|	d d  |
d d < q| jD ]a\}}}}|rLt	d
||j|j tt|D ]0}|| d u re|d7 }d	
|||< || |jvr|rwt	d

||  ||| |j|  qR|j||j||d}
|
| |d |
d d < q9|rt	d
t| j || j |  d S )Nr   Datasetr~  NETCDF4rg  )zlib   Write data "{}" ({}, {})r   z	dummy{:d}z   Create dimension {}.   Write {} attributes)netCDF4r  r;   rT   createDimensionr   createVariablerA   r7   rw   r   r:   rx   
dimensions	setncattsr9   close)rF   r  r  r  r  r  rootZ
dummycountr  rH   varr{   r7   r   r  rG   r   r   r   Z__save_netcdf4  s4   
zMLUT.__save_netcdf4c                 C   s  ddl m}m} ddlm} dd }td|jtd|jtd|j	td	|j
td
|j	td|j
td|jtd|jtd|jtd|ji
}	|||j|jB }
| jdur| j D ]4\}}|rqtd|| |	|j }|
|||j}|r||jd ||dd |dd< |  qc| jD ]z\}}}}||}|rtd||j|j |	|j }|jdkr|
||d}t|dd n|
|||j}|r||jd |d |dd< |dg fvrt|ddtt| d|v rt d|| D ]\}}t||| q|  q|r#tdt!| j" | j" D ]"\}}z	t|
|| W q( |yJ   t|
t|t| Y q(w |
#  dS )z+
        Save a MLUT to a hdf file
        r   )SDSDC)	HDF4Errorc                 S   sd   | j t dkrt| | dsJ | dS | j t dkr0t| | ds+J | dS | S )Nuint64uint32int64int32)rA   r+   r   r   r  r   r   r   safecast  s   

z!MLUT.__save_hdf.<locals>.safecastrC   rD   r  r  r  r  uint16int16uint8int8Nz   Write axis "{}" in "{}"	   r  )r   
lut:scalarTrue.r  ,z1Error writing {}, "dimensions" attribute conflictr  )$pyhdf.SDr  r  Zpyhdf.errorr  r+   rA   ZFLOAT32ZFLOAT64ZUINT32ZINT32ZUINT16ZINT16ZUINT8ZINT8WRITEZCREATEr;   rT   rw   r   creater:   ZsetcompressZCOMP_DEFLATEZ	endaccessr7   r*   r  joinrj  rV   rR   r   r9   end)rF   r  r  r  r  r  r  r  r  Ztypeconvhdfr{   rH   typesdsr7   r   r9   r|   r`   r   r   r   Z
__save_hdf  sj   






zMLUT.__save_hdfc                 C   s   || j |< | S )z0
        Set one attribute key -> value
        r  )rF   keyr  r   r   r   r  *  s   
zMLUT.set_attrc                 C   s   | j | | S )zK
        Set multiple attributes to attrs
        attributes: dict
        )r9   r   )rF   r  r   r   r   r   2  s   zMLUT.set_attrsc                 O   rg   rh   ri   rk   r   r   r   rn   ;  ro   zMLUT.print_infoc              
   C   s  d}|r
t t|  t d t| jD ]\}\}	}
}}d}|d ur-|r-|dtt| 7 }|r7|d|
j7 }|rUt|
tj	rUzdt
|
t|
}W n	   d}Y nd}|rbdt|
j}nd}t d||	|
j||
j| |  ||
j7 }|rt|dkrt d	 | D ]\}}t d
|| qqt d t| j D ]\}\}	}t d||	t||d |d  q|rt d | j D ]\}}t d|d| q|rt dt| | S )Nr   z
 Datasets:r   z, axes=z
, shape={}z in [{:.3g}, {:.3g}]z, {}z  [{}] {} ({}{})z    Attributes:z      {}: {}z Axes:z   [{}] {}: {} values in [{}, {}]r(   rr   rs   rt   zTotal memory usage: {})rw   rV   r<   r7   r[   r   r:   r=   r+   r>   ru   rv   r   nbytesrA   r   rT   r;   r9   )rF   Z
show_rangeZ	show_selfry   Z
show_shapeZ	show_axesZmemZ
total_sizerG   r{   r  r;   r9   Zaxdescrz   Zmemdescr|   r`   valuesr   r   r   rj   ?  sH   "
$zMLUT.describec                    s   t  }| j D ]\}}| vr||| q| jD ](\}}}} fdd|D }	 fddt||jD }
|j|||
|	|d q| j	|_	|S )z
        drop axes of size 1

        example:
            m.dropaxis('a')   # remove axis 'a' of size 1
            m.dropaxis('a', 'b')   # remove 'a' and 'b'
        c                    s   g | ]}| vr|qS r   r   r   
ax_to_dropr   r   r"   y  s    z!MLUT.dropaxis.<locals>.<listcomp>c                    rK   r   r   )r   r   sr  r   r   r"   z  rO   r   )
r   r;   rT   r   r7   zipr:   r   r   r9   )rF   r  r   r  rH   r{   r7   r   r  r;   r   r   r  r   dropaxish  s   zMLUT.dropaxisc                 C   s<   t |tsJ || jv sJ t| j| }| || dS )z:
        Create a new dataset from attribute name
        N)r=   rV   r9   r+   r,   r   )rF   r{   r  r   r   r   promote_attr  s   zMLUT.promote_attrc                 C   s   t |ttfr+d}t| jD ]\}\}}}}||kr|} nq|dkr*td|nt |tr3|}ntd| j| \}}}}|du rGd}	ng }	|D ]}
|
du sV|
| jvr\|		d qK|		| j|
  qKt
|||	||dS )zE
        return the LUT corresponding to key (int or string)
        r(   zCannot find dataset {}zFmulti-dimensional LUTs should only be indexed with strings or integersN)r8   r7   r;   r@   r9   )r=   rV   unicoder<   r7   rR   r   rU   r;   r-   r6   )rF   r   rW   rG   r{   _r  r   r9   r;   rH   r   r   r   r     s,   
zMLUT.__getitem__c           
      C   s  d}t |ts|dt|7 }t| dS d}t| j|jD ]?}||jvs-|| jvr6|d|7 }d}| j| j|j| jkrK|d|7 }d}t	
| j| |j| s`|d|7 }d}q!t|  t| kr|d7 }|d	t|  7 }|d	t| 7 }d}|  D ]}| | j|| |d
s|d|| | j|| j7 }d}q|rt| j |j D ]2}	|	| jvs|	|jvr|d|	7 }d}q| j|	 |j|	 kr|d|	| j|	 |j|	 7 }d}qq|r|st| |S )z
        Test equality between two MLUTs
        Arguments:
         * show_diff: print their differences
         * content: check LUT content (otherwise only axes and shapes)
         * attributes: check global attributes
        zMLUTs diff:z  other is not a MLUT ({})FTz  axis {} missing in either
z  axis {} shape mismatch
z  axis {} is different
z  Datasets are different
z   -> {})r   z,  dataset {} differs (shapes are {} and {})
z&  attribute {} missing in either MLUT
z,  value of attribute {} differs ({} and {})
)r=   r   r   rV   rw   r#   r;   unionr:   r+   r   r  r   r9   r_   )
rF   r   r  r  r  r   eqr|   r{   rM   r   r   r   r     sR   
z
MLUT.equalc                 C   r   rh   r   r   r   r   r   r     r   zMLUT.__eq__c                 C   r   rh   r   r   r   r   r   r     r   zMLUT.__neq__c                 C   s&   | j | }|rt|||g|gdS |S )zd
        returns an axis
        if aslut: returns it as a LUT
        otherwise, as values
        )r8   r7   r;   r@   )r;   r6   )rF   r  re   r7   r   r   r   rf     s   
z	MLUT.axisc              
      s  z"ddl m}m}m}m}m}	m}
m} ddlm	 ddl
m}m W n ty-   tdw du r6 g }i i dv rEd }nd}dv rPd }nd	}|
d|d
|
d|d
|ddd
|
ddd
|
dd	d
g	D ]}||dd
|< t| jD ]s\}}|du rtd|v rq| j| }|}|dur|d|d |d 7 }||dd
}|d| j| d	 d}d|_|	dd}d|_|dd}t|d| |dd}t|d| |||||||g |||||f|< qqor|d|	dd |d|  |d|	dd |d|	  	f
dd}dd }d d! } D ] \}\}}}}}||d" ||d" || || q7	D ]	}||d" qZ D ]	}||d" qh||| |  dS )#a3  
        display all datasets in the MLUT
        * datasets: list of datasets to display
                    if None, display all datasets
        * extra_widgets: show extra widgets for:
                 1) interactive selection of datasets to display
                 2) choice of min/max values
        r   )r  r  r  r  r   	FloatTextButton)rf   r!  z4IPython notebook widgets are required to plot a MLUTNr   r   r   r%  z	xmin/xmaxFxminxmaxz)Does not work with unnamed axes, sorry :/r$  r(   Tr'  r   r(  r  )r&  r3  +z<b>AXES:</b>z<b>DATASETS:</b>c                     s    r#	d j d< 	d j d< 	d j 	d _	d j 	d _ D ]\} \}}}}}|j |_|j |_|j |_|j |_q'D ]}| j sKqCg }d}t| jD ]:\}	}
|
 \}}}}}|j r|j }|| | j|	 d krd| j|	 | |_ qV|td  |d7 }qV|dkr| 	 
t|j |d	d
 	d j r	d j 	d j d qCtd||d  qCd S )Nr   r   r   r   r
   r   r^  r)  T)r   r   )r  r  z*{}: Please select at least {} dimension(s))r  r*  rT   r<   r@   r-   r;   r   rS   rc   r   r[   r   rw   )rM   r2  r3  r4  button_minusbutton_plusr]   r_   r*   rG   r{   r
  rW   
rl   r;   rf   r#  r  Zdstchkextra_widgetsrm   rF   Zvminmaxr   r   r   <  sB   



(
zMLUT.plot.<locals>.updatec                 S   s   | j  jd8  _d S Nr   r3  r  r   r   r   r   	decrementi     zMLUT.plot.<locals>.decrementc                 S   s   | j  jd7  _d S r  r  r  r   r   r   	incrementk  r  zMLUT.plot.<locals>.incrementr  )r-  r  r  r  r  r   r  r  r   rf   r.  r"  r#  r/  rR   r  r<   r@   r;   r   r:   r*  r  r-   insertr  rT   r0  Zon_click)rF   r  r  rl   rm   r  r  r  r  r   r  r  r"  r1  r   r   r]   ra   r{   rH   r8   r2  r3  r4  r  r  r   r  r  rM   Zflr   r  r   r     s   	$









-

z	MLUT.plotrh   )NFFT)FFT)TTFFTF)TTFr<  )NT)r=  r>  r?  r@  rI   r  r   r   r  r  rc   r  r  r  r  r   rn   rj   r  r  r   r   r   r   rf   r   r   r   r   r   r     s8    !

%

&T	
)

8
r   c                 C   st   |du r|  drd}n|  drd}ntd| |dkr#t| S |dkr+t| S |dkr3t| S td|)	zn
    Read a MLUT (multi-format)
    fmt: netcdf4, hdf4
         or None (determine format from extension)
    Nr  r  r  r  r  hdf5r  )r  r   r   read_mlut_netcdf4read_mlut_hdfread_mlut_hdf5)r  r   r   r   r   	read_mlut|  s   

r!  c           	      C   s   t  }ddlm} || ddd}|jD ]}|ds0||jv r0|t|t|j| dd  q|jD ]2}||j	v r<q4|j| }i }|
 D ]	}||||< qG|j|t|dd dd	 |jD |d
 q4|
 D ]}|||| qk|  |S )z&
    Read a MLUT (netcdf4 format)
    r   r  r  r  rg  dummyNc                 S   s   g | ]}t |qS r   )rV   r   r   r   r   r"     r  z%read_mlut_netcdf4.<locals>.<listcomp>r  )r   r  r  r  
startswith	variablesr   rV   r	   r;   ncattrs	getncattrr   r  r  )	r  r   r  r  dimvarnamer  r9   rM   r   r   r   r    s&   
"


,r  c                 C   sP  ddl }|| d}|r|| }n|}|du r t|d  }n|}g }g }	|D ]l}
|
t|d  v ru|d |
 jdsItd|
 td|d |
 j	d}t
|tr`| d}n|d}|	| |D ]}|| qlq(td	|
 td
|  |d  D ]}td| qtdtt|}t }|D ]}|d | d }||| qtt|D ]g}|| }
|r|d |
 }n|d |
 d }i }|d |
 jdr|d |
 j	d|d< |d |
 jdr|d |
 j	d|d< |d |
 jdr|d |
 j	d|d< |j|
||	| |d q|s&|  |S )a  
    read a MLUT from a hdf5 file (filename)
    datasets: list of datasets to read:
        * None (default): read all datasets, including axes as indicated by the
          attribute 'dimensions'
        * a list of:
            - dataset names (string)
            - or a tuple (dataset_name, axes) where axes is a list of
              dimensions (strings), overriding the attribute 'dimensions'
    r   Nr  r7   r  z*Missing -dimensions- Attr in dataset "{}" z"Missing dimensions Attr in datasetr  zdataset "{}" not available.z#{} contains the following datasets:z  *zMissing datasetrf   .
_FillValue
add_offsetscale_factorr   )h5pyFiler?   r_   r9   __contains__rw   r   rR   getr=   r  decodesplitr-   r#   r   r   rx   r   r   r  )r  r  lazygroupr,  fffls_datasetsZls_axisZ	axis_datar  r  aar]   r   rH   rf   idatar7   r9   r   r   r   r     sb   



r   c                 C   s   ddl m} || }g }g }|du rtt| }n	t|ts$J d|D ]g}t|tr7|\}}||}	nd}||}	|		 d }
|du red|	
 v re|	
 d d}dd |D }d	d |D }|durn|| |	 }|	
 }d
|v r|d
 |d}||
|||f q&d|v r|d d|v st }t|D ]?}dd |D  |dd |D vr|| v r||}	|||	  qdd |D |}||\}}}}||| q|D ]\}}}}d|v r|d ||||| q|
  D ]\}}||| q|S )a  
    read a MLUT from a hdf file (filename)
    datasets: list of datasets to read:
        * None (default): read all datasets, including axes as indicated by the
          attribute 'dimensions'
        * a list of:
            - dataset names (string)
            - or a tuple (dataset_name, axes) where axes is a list of
              dimensions (strings), overriding the attribute 'dimensions'
    r   )r  Nz%datasets should be provided as a listr  r  c                 S   s   g | ]}|  qS r   )stripr   r   r   r   r"   +	  r  z!read_mlut_hdf.<locals>.<listcomp>c                 S   s   g | ]
}|d kr
dn|qS )NoneNr   r   r   r   r   r"   .	  rO   r  r   c                 S   r  r  r   r   r   r   r   r"   A	  r  c                 S   r  r  r   r   r   r   r   r"   D	  r  c                 S   r  r  r   r   r   r   r   r"   I	  r  )r  r  rx   r   r  r=   r?   r[   selectinfor  r1  r   r/  r   r   r-   r   r   r#   r   rW   r   rT   r  )r  r  r  r  Zls_axesr6  rG   r{   r;   r  Zsdsnamer7   r9   r   rH   r
  r   r|   r`   r   r   r   r  		  s^   







r  __main__)r   )NNrH  )
NNNrQ  rR  TrS  NNF)
NNNTrS  Nr  r|   Fr  rh   ).r@  
__future__r   r   r   sysnumpyr+   scipy.interpolater   os.pathr   osr   collectionsr   numpy.mar	   r   version_inforV   r	  r   rx   r   r   r&   r5   r  r6   r  rX   rF  rE  rQ   r7  r;  r  r   r!  r  r   r  r=  doctesttestmodr   r   r   r   <module>   sd   


       
-+
 
S
hs     

$
OR