B
    }dPA                 @   sX  d Z ddlmZ ddlmZ ddlZddlmZ ddlm	Z	m
Z
mZ ddlmZ yddlmZ W n  ek
r   dd	lmZ Y nX ydd
lmZ W n> ek
r   yddlmZ W n ek
r   dZY nX Y nX ddlmZ ddlmZmZ dZejejejejejejejej ej!ej"ej#ej$gZ%i Z&dd Z'dd Z(G dd de)Z*G dd de*eZ+G dd de+Z,G dd de,Z-G dd de)Z.G dd dej/Z0G d d! d!e.ej1Z2G d"d# d#ej3Z4G d$d% d%e*e
Z5e'e5 d&d' Z6x(e%D ] Z7e7ej"krP e'e6e7 qW y,ej8j9d(:d)d* e D e ; d+ W n e<k
rR   Y nX dS ),zBThis module defines locators/formatters and a scale for GPS data.
    )Decimal)NumberN)ticker)register_scaleLinearScaleget_scale_names)	Transform)_get_scale_docs)get_scale_docs)
_docstring)	docstring)units   )to_gpsfrom_gpsz(Duncan Macleod <duncan.macleod@ligo.org>c             C   s   t |  | t| j< dS )zURegister a new GPS scale.

    ``scale_class`` must be a subclass of `GPSScale`.
    N)r   
GPS_SCALESname)Zscale_class r   Z/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/gwpy/plot/gps.pyregister_gps_scaleB   s    r   c             C   sV   t | }d|ksd|kr(| d| dS |d\}}}d||d|  d| gS )zTruncates/pads a float `f` to `n` decimal places without rounding

    From https://stackoverflow.com/a/783927/1307974 (CC-BY-SA)
    eE.f0N)str	partitionjoin)r   nsipdr   r   r   	_truncateK   s
    r#   c                   s~   e Zd ZdZ fddZdd Zdd ZeeeejdZd	d
 Z	dd Z
ee	e
e	jdZdd Zdd ZeeejdZ  ZS )GPSMixinz6Mixin adding GPS-related attributes to any class.
    c                sP   |  |dd  | |dd  yt j|| W n tk
rJ   Y nX d S )Nunitepoch)set_unitpop	set_epochsuper__init__	TypeError)selfargskwargs)	__class__r   r   r+   \   s    zGPSMixin.__init__c             C   s   | j S )zThe GPS epoch
        )_epoch)r-   r   r   r   	get_epochd   s    zGPSMixin.get_epochc             C   s>   |dkrd| _ dS t|ttfr,t|| _ ntt|| _ dS )zSet the GPS epoch
        N)r1   
isinstancer   r   floatr   )r-   r&   r   r   r   r)   i   s    zGPSMixin.set_epoch)fgetfsetdocc             C   s   | j S )zGPS step scale
        )_unit)r-   r   r   r   get_unitw   s    zGPSMixin.get_unitc             C   s  |dkst |tjr(|jdkr(|| _dS t |trBt|tj }yt|}W nT tk
r } z6ytt	|
d}W n tk
r   |Y nX W dd}~X Y nX | }|jtjgkrtd| dx&tD ]}| j|jkr|| _dS qW td| ddS )zSet the GPS step scale
        Ntimer   zcannot set GPS unit to ''zunrecognised unit ')r3   r   Z	NamedUnitZphysical_typer8   r   Unitsecond
ValueErrorr   rstrip	decomposebases
TIME_UNITSscale)r-   r%   excdecotherr   r   r   r'   |   s,    


zGPSMixin.set_unitc             C   s&   | j s
dS t| j jtdd }|d S )zReturns the name of the unit for this GPS scale

        Note that this returns a simply-pluralised version of the name.
        N)keyr   )r%   sortednameslen)r-   r   r   r   r   get_unit_name   s    zGPSMixin.get_unit_namec             C   s   | j dkrdS | j  jS )z8The scale (in seconds) of the current GPS unit.
        N   )r%   r@   rC   )r-   r   r   r   	get_scale   s    
zGPSMixin.get_scale)r5   r7   )__name__
__module____qualname____doc__r+   r2   r)   propertyr&   r9   r'   r%   rL   rN   rC   __classcell__r   r   )r0   r   r$   Y   s   
!

r$   c                   sT   e Zd ZdZdZdZdZdZdZ fddZ	dd Z
edd	 Zed
d Z  ZS )GPSTransformBasea  `Transform` to convert GPS times to time since epoch (and vice-verse)

    This class uses the `decimal.Decimal` object to protect against precision
    errors when converting to and from GPS times that may have 19 significant
    digits, which is more than `float` can handle.

    There is some logic to _only_ use the slow decimal transforms when
    absolutely necessary, normally when transforming tick positions.
    rM   Tc                s0   t |ttfr$| || jpd| jS t |S )Nr   )r3   r   r   _transform_decimalr&   rC   r*   	transform)r-   values)r0   r   r   rW      s    zGPSTransformBase.transformc                s~   j pdjpd t|}js4 dkrJdkrJ|t tS | } fdd}ttt	||
|jS )a  Transform an array of GPS times.

        This method is designed to filter out transformations that will
        generate text elements that require exact precision, and use
        `Decimal` objects to do the transformation, and simple `float`
        otherwise.
        rM   r   c                s    |  S )N)rV   )x)r&   rC   r-   r   r   _trans   s    z5GPSTransformBase.transform_non_affine.<locals>._trans)rC   r&   numpyZasarray_parents
_transformr4   flattenlistmapZreshapeshape)r-   rX   ZflatrZ   r   )r&   rC   r-   r   transform_non_affine   s    


z%GPSTransformBase.transform_non_affinec             C   s   t d S )N)NotImplementedError)valuer&   rC   r   r   r   r]      s    zGPSTransformBase._transformc             C   s@   t t|d}t t|d}t t|d}t|| |||S )zDTransform to/from GPS using `decimal.Decimal` for precision
           )r   r#   typer]   )clsrd   r&   rC   ZvdecZedecZsdecr   r   r   rV      s    z#GPSTransformBase._transform_decimal)rO   rP   rQ   rR   Z
input_dimsZoutput_dimsZis_separableZ	is_affineZhas_inverserW   rb   staticmethodr]   classmethodrV   rT   r   r   )r0   r   rU      s   	rU   c               @   s$   e Zd ZdZedd Zdd ZdS )GPSTransformz2Transform GPS time into N * scale from epoch.
    c             C   s   | | | S )Nr   )rd   r&   rC   r   r   r   r]      s    zGPSTransform._transformc             C   s   t | j| jdS )N)r%   r&   )InvertedGPSTransformr%   r&   )r-   r   r   r   inverted   s    zGPSTransform.invertedN)rO   rP   rQ   rR   rh   r]   rl   r   r   r   r   rj      s   rj   c               @   s$   e Zd ZdZedd Zdd ZdS )rk   z<Transform time (scaled units) from epoch into GPS time.
    c             C   s   | | | S )Nr   )rd   r&   rC   r   r   r   r]     s    zInvertedGPSTransform._transformc             C   s   t | j| jdS )N)r%   r&   )rj   r%   r&   )r-   r   r   r   rl     s    zInvertedGPSTransform.invertedN)rO   rP   rQ   rR   rh   r]   rl   r   r   r   r   rk     s   rk   c               @   s    e Zd ZdZdd Zdd ZdS )GPSLocatorMixinz#Metaclass for GPS-axis locator
    c             C   sB   | j  \}}| j  }||}||}| | ||S )N)axisget_view_intervalget_transformrW   rl   tick_values)r-   vminvmaxtransr   r   r   __call__  s
    


zGPSLocatorMixin.__call__c             C   s   |  S )z:refresh internal information based on current lim
        r   )r-   r   r   r   refresh  s    zGPSLocatorMixin.refreshN)rO   rP   rQ   rR   ru   rv   r   r   r   r   rm     s   rm   c                   s.   e Zd ZdZd fdd	Z fddZ  ZS )	GPSAutoLocatorzFind the best position for ticks on a given axis from the data.

    This auto-locator gives a simple extension to the matplotlib
    `~matplotlib.ticker.AutoLocator` allowing for variations in scale
    and zero-time epoch.
    re   Nc                s   t  jf ||d| dS )zInitialise a new `AutoTimeLocator`, optionally with an `epoch`
        and a `scale` (in seconds).

        Each of the `epoch` and `scale` keyword arguments should match those
        passed to the `GPSFormatter`
        )nbinsstepsN)r*   r+   )r-   rx   ry   r/   )r0   r   r   r+   *  s    zGPSAutoLocator.__init__c                s   | j  }| }| j}|||f\}}|d krZ|tjkrZ|| dkrZ| jddgd n| jd d zt 	||}W d || _X |
 |S )N   rM   
   )ry   )rn   rp   r9   Z_stepsrW   r   weekZ
set_paramsr*   rq   rl   )r-   rr   rs   rW   r%   ry   Zticks)r0   r   r   rq   3  s    
zGPSAutoLocator.tick_values)re   N)rO   rP   rQ   rR   r+   rq   rT   r   r   )r0   r   rw   #  s   	rw   c               @   s   e Zd ZdZdd ZdS )GPSAutoMinorLocatorzGFind the best position for minor ticks on a given GPS-scaled axis.
    c             C   s  | j  }| j  }y|d |d  }W n tk
r@   d}Y nX | jdkr|dkrZd}q| }|| }ttdt	|d  }|j
tjkr|dkrd}q|j
tjkr|dkrd}q|j
tjkr|dkrd}qd	}n| j}|| }| j  \}	}
|	|
kr|
|	 }	}
t|r|d }t|	| | | }t|
| | | }t|||| }t|| | |d
 k}||}ng }| t|S )z*Return the locations of the ticks
        rM   r   Nr{      rz   )rM      r{   r      g      $@)rn   Zget_majorticklocsrp   
IndexErrorndivsrN   introundr[   log10r%   r   r|   yeardayro   sizefloorceilZarangeabscompressZraise_if_exceedsarray)r-   Z	majorlocsrt   Z	majorstepr   Zscale_ZgpssteprY   Z	minorsteprr   rs   r&   ZtminZtmaxlocsZcondr   r   r   ru   J  sB    





zGPSAutoMinorLocator.__call__N)rO   rP   rQ   rR   ru   r   r   r   r   r}   G  s   r}   c               @   s   e Zd ZdZdddZdS )GPSFormatterz%Locator for astropy Time objects
    Nc             C   s,   | j  }|t|}| r(t|S |S )N)rn   rp   rW   r4   
is_integerr   )r-   tposrt   Zfltr   r   r   ru     s
    
zGPSFormatter.__call__)N)rO   rP   rQ   rR   ru   r   r   r   r   r   ~  s   r   c                   sZ   e Zd ZdZdZeZeZd fdd	Zdd Ze	dd	 Z
d
d Zdd Zdd Z  ZS )GPSScalez?A GPS scale, displaying time (scaled units) from an epoch.
    zauto-gpsNc                s4   t  j||d || _t|jd|j dd dS )zS
        unit:
            either name (`str`) or scale (float in seconds)
        )r%   r&   set_marginr   N)r*   r+   rn   getattraxes	axis_name)r-   rn   r%   r&   )r0   r   r   r+     s    zGPSScale.__init__c             C   s6   | t  |t  |t  |t  d S )N)	Zset_major_locatorrw   Zset_major_formatterr   Zset_minor_locatorr}   Zset_minor_formatterr   ZNullFormatter)r-   rn   r   r   r   #set_default_locators_and_formatters  s    z,GPSScale.set_default_locators_and_formattersc             C   sB   t |  }t| jd| j d r6t| s6|S t |  S )NZget_autoscaleZ_on)	tupleZget_data_intervalr   r   r   r[   isinfanyro   )rn   Zdlimr   r   r   _lim  s
    zGPSScale._limc             C   s   t | |d }|  }t|}d}x^t|dd  D ]J\}}|t|k rPP |dkrn|jf || di}q8|jf || di}q8W tt	|S )Nr   )r=   minutehourr   rM   )r   )
r   r   r9   r   	enumerater   r<   replacer   r   )r-   rn   r&   r%   datefieldsr    ur   r   r   _auto_epoch  s    zGPSScale._auto_epochc             C   sf   |  |\}}|| }xHtd d d D ]6}| j}|tjkrH|d9 }n|d9 }||kr&|S q&W tjS )NrH   r   g{Gz?)r   rB   r@   rC   r   r=   )r-   rn   rr   rs   durationrC   baser   r   r   
_auto_unit  s    


zGPSScale._auto_unitc          	   C   sv   |   }|  }|d kr*| | | j |d krD| | | j z| j|  |   dS | | | | X d S )N)r%   r&   )r2   r9   r'   r   rn   r)   r   rj   )r-   r&   r%   r   r   r   rp     s    

zGPSScale.get_transform)NN)rO   rP   rQ   rR   r   rj   rk   r+   r   rh   r   r   r   rp   rT   r   r   )r0   r   r     s   
r   c                s   G  fdddt }|S )z'Construct a GPSScale for this unit
    c                   s8   e Zd ZdZjpjd d Zd fdd	Z  ZS )z)_gps_scale_factory.<locals>.FixedGPSScalez0`GPSScale` for a specific GPS time unit
        r   r   Nc                s   t  j||d dS )z
            )r&   r%   N)r*   r+   )r-   rn   r&   )r0   r%   r   r   r+     s    z2_gps_scale_factory.<locals>.FixedGPSScale.__init__)N)	rO   rP   rQ   rR   Z
long_namesrJ   r   r+   rT   r   )r%   )r0   r   FixedGPSScale  s   r   )r   )r%   r   r   )r%   r   _gps_scale_factory  s    	r   z | c             C   s   g | ]}t |qS r   )repr).0rY   r   r   r   
<listcomp>  s    r   )rC   Z
scale_docs)=rR   decimalr   numbersr   r[   Z
matplotlibr   Zmatplotlib.scaler   r   r   Zmatplotlib.transformsr   r	   r
   ImportErrorr   r   Zastropyr   r:   r   r   
__author__Z
nanosecondmicrosecondZmillisecondr=   r   r   r   r|   r   ZkiloyearZmegayearZgigayearrB   r   r   r#   objectr$   rU   rj   rk   rm   ZMaxNLocatorrw   ZAutoMinorLocatorr}   	Formatterr   r   r   r8   Zinterpdupdater   r?   AttributeErrorr   r   r   r   <module>   sp   	]B$7W
