B
    }d6Z                 @   s4  d Z ddlZddlm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 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mZ ddlmZmZ ddl m!Z! ddl"m#Z# ddl$m%Z% ddl&m'Z' dZ(dd Z)dd Z*dd Z+dd Z,dd Z-G d d! d!eZee G d"d# d#eZ.dS )$z.Extension of `~matplotlib.axes.Axes` for gwpy
    N)wraps)log)Number)Time)__version__rcParams)allow_rasterization)Axes)_process_plot_var_args)PolyCollection)Line2D)register_projection   )Plotcolorbar)format_norm)
GPS_SCALES)HandlerLine2D   )to_gpsz(Duncan Macleod <duncan.macleod@ligo.org>c                s   t   fdd}|S )zIWrap ``func`` to handle custom gwpy keywords for a LogNorm colouring
    c                 s   t |\}}||d<  | |S )Nnorm)r   )argskwargsr   )func [/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/gwpy/plot/axes.pydecorated_func6   s    z log_norm.<locals>.decorated_func)r   )r   r   r   )r   r   log_norm3   s    r   c                s   t  d fdd	}|S )zIWrap ``func`` to handle pass limit inputs through `gwpy.time.to_gps`
    Nc          	      s   |d krt |r|\}}||d< ||d< |  tk}xDdD ]<}|r<yt tt|| ||< W q< tk
rv   Y q<X q<W  | f|S )Nleftright)r   r   )numpyiterable
get_xscaler   Z
longdoublestrr   	TypeError)selfr   r   kwZgpsscalekey)r   r   r   wrapped_funcA   s    

z!xlim_as_gps.<locals>.wrapped_func)NN)r   )r   r(   r   )r   r   xlim_as_gps>   s    r)   c                s$   t dkr S t  fdd}|S )zWrap ``func`` to preserve the Axes current grid settings.

    Prior to matplotlib 3.7.0 (unreleased ATOW) pcolor() and pcolormesh()
    automatically removed a grid on a set of Axes. This decorator just
    undoes that.
    z3.7.0c          
      s   y0| j jd | j jd | jjd | jjd f}W n0 tk
r`   | j j| j j| jj| jjf}Y nX | d z | f||S | j j|d dd | j j|d dd | jj|d dd | jj|d	 dd X d S )
NZgridOnFr   minor)whichr   majorr      )xaxisZ_minor_tick_kwZ_major_tick_kwyaxisKeyErrorZ_gridOnMinorZ_gridOnMajorgrid)r%   r   r   r1   )r   r   r   r(   \   s    



z"restore_grid.<locals>.wrapped_func)matplotlib_versionr   )r   r(   r   )r   r   restore_gridR   s    r3   c                s   t   fdd}|S )zgWrap ``func`` to replace the deprecated ``c_sort`` keyword.

    This was renamed ``sortbycolor``.
    c                s@   d|kr0t d j dt |d|d  | f||S )NZc_sortzthe `c_sort` keyword for z[ was renamed `sortbycolor`, this warning will result in an error in future versions of GWpysortbycolor)warningswarn__name__DeprecationWarning
setdefaultpop)r%   r   r   )r   r   r   wrapped}   s    z!deprecate_c_sort.<locals>.wrapped)r   )r   r;   r   )r   r   deprecate_c_sortx   s    r<   c             '   s@   t j| td   fdd}x| f| D ]}||V  q*W dS )zDSort a set of arrays by the first one (including the first one)
    )Zdtypec                s$   | d kst | tr| S t|   S )N)
isinstancer   r    asarray)arr)sortidxr   r   _sort   s    z_sortby.<locals>._sortN)r    Z
asanyarrayfloatZargsort)ZsortbyZarraysrA   r?   r   )r@   r   _sortby   s    rC   c                   s  e Zd Z fddZe fddZdd Zdd Zee	j
Z
d	d
 Zdd Zed. fdd	Ze	jjdde_e fddZd/ddZee fddZdd Z fddZe	jjdd e_d0d!d"Zed1d&d'Z fd(d)Ze	jjd*d+e_d2d,d-Z  ZS )3r	   c                s,   t  j|| t| | _| j| _| j| _d S )N)super__init__PlotArgsProcessorZ
_get_lines
_fmt_xdataZ	fmt_xdata
_fmt_ydataZ	fmt_ydata)r%   r   r   )	__class__r   r   rE      s    
zAxes.__init__c       
   
      s   i }x| j | jfD ]|}| tkr|jr| ||< | }t| }|	 }t
|dddj}|dd}	|d| d|	 d|d	 qW zt j|| W d x|D ]
}d
|_qW X d S )Ngpsutc)formatscale0.zTime [z] from z UTC ()T)r.   r/   Z	get_scaler   ZisDefault_labelZget_label_textget_transformrB   	get_epochZget_unit_namer   isorstripZset_label_textrD   draw)
r%   r   r   labelsaxZtransepochunitrS   rK   )rI   r   r   rU      s    "
z	Axes.drawc             C   s(   |   tkrtt|S | j |S )N)r"   r   r#   r   r.   get_major_formatterformat_data_short)r%   xr   r   r   rG      s    zAxes._fmt_xdatac             C   s(   |   tkrtt|S | j |S )N)
get_yscaler   r#   r   r/   rZ   r[   )r%   yr   r   r   rH      s    zAxes._fmt_ydatac             C   s   |   }| j||dS )aw  Set the epoch for the current GPS scale.

        This method will fail if the current X-axis scale isn't one of
        the GPS scales. See :ref:`gwpy-plot-gps` for more details.

        Parameters
        ----------
        epoch : `float`, `str`
            GPS-compatible time or date object, anything parseable by
            :func:`~gwpy.time.to_gps` is fine.
        )rX   )r"   
set_xscale)r%   rX   rM   r   r   r   	set_epoch   s    zAxes.set_epochc             C   s   |     S )zReturn the epoch for the current GPS scale/

        This method will fail if the current X-axis scale isn't one of
        the GPS scales. See :ref:`gwpy-plot-gps` for more details.
        )Z	get_xaxisrQ   rR   )r%   r   r   r   rR      s    zAxes.get_epochNc          
      sv   | ddrZ|d k	rZyt||||\}}}}W n* tk
rX } zd|_ W d d }~X Y nX t j||f||d|S )Nr4   F)zjAxes.scatter argument 'sortbycolor' can only be used with a simple array of floats in the colour array 'c')sc)r:   rC   
ValueErrorr   rD   scatter)r%   r\   r^   ra   rb   r   exc)rI   r   r   rd      s    zAxes.scatterzmarker :znsortbycolor : `bool`, optional, default: False
    Sort scatter points by `c` array value, if given.

marker :c                sD   t |dr| j|f||S t j|f||}| jdddd |S )a  Display an image, i.e. data on a 2D regular raster.

        If ``array`` is a :class:`~gwpy.types.Array2D` (e.g. a
        :class:`~gwpy.spectrogram.Spectrogram`), then the defaults are
        _different_ to those in the upstream
        :meth:`~matplotlib.axes.Axes.imshow` method. Namely, the defaults are

        - ``origin='lower'`` (coordinates start in lower-left corner)
        - ``aspect='auto'`` (pixels are not forced to be square)
        - ``interpolation='none'`` (no image interpolation is used)

        In all other usage, the defaults from the upstream matplotlib method
        are unchanged.

        Parameters
        ----------
        array : array-like or PIL image
            The image data.

        *args, **kwargs
            All arguments and keywords are passed to the inherited
            :meth:`~matplotlib.axes.Axes.imshow` method.

        See also
        --------
        matplotlib.axes.Axes.imshow
            for details of the image rendering
        yspanNZboth)enableZaxisZtight)hasattr_imshow_array2drD   imshowZ	autoscale)r%   arrayr   r   image)rI   r   r   rj     s
    
zAxes.imshowlowernoneautoc             K   s   t |jt |j }|  dkr<|d dkr<d|dd  }|  dkrp|d dkrp|dd d |dd  }|d	| | j|jjf|||d
|S )z<Render an `~gwpy.types.Array2D` using `Axes.imshow`
        r   r   g        )gYnr   Nr   r-   extent)originaspectinterpolation)	tuplexspanrf   r"   r]   r9   rj   valueT)r%   rk   rq   rs   rr   r   rp   r   r   r   ri   &  s    zAxes._imshow_array2dc                s4   t |dkr&t|d dr&| j||S t j||S )a  Create a pseudocolor plot with a non-regular rectangular grid.

        When using GWpy, this method can be called with a single argument
        that is an :class:`~gwpy.types.Array2D`, for which the ``X`` and ``Y``
        coordinate arrays will be determined from the indexing.

        In all other usage, all ``args`` and ``kwargs`` are passed directly
        to :meth:`~matplotlib.axes.Axes.pcolormesh`.

        Notes
        -----
        Unlike the upstream :meth:`matplotlib.axes.Axes.pcolormesh`,
        this method respects the current grid settings.

        See also
        --------
        matplotlib.axes.Axes.pcolormesh
        r   r   yindex)lenrh   _pcolormesh_array2drD   
pcolormesh)r%   r   r   )rI   r   r   r{   8  s    zAxes.pcolormeshc             O   sh   t |jj|jdd f}t |jj|jdd f}t j||ddd\}}| j|||jj	f||S )z@Render an `~gwpy.types.Array2D` using `Axes.pcolormesh`
        NFT)copysparse)
r    Zconcatenatexindexrv   ru   rx   rf   Zmeshgridr{   rw   )r%   rk   r   r   r\   r^   ZxcoordZycoordr   r   r   rz   Q  s    zAxes._pcolormesh_array2dc       	   
      sT  t |}|dd }t|tr2t || |d< |ddr@t |dd s@|dd pjtdd}|dd }|d kryt 	|t 
|f}W n8 tk
r } zt|drd	|_ W d d }~X Y nX |d
dkr| jddd | jjj}n| jddd | jjj}t jt|d |t|d ||d dd|d< t j|f||S )NweightsZlogbinsFZbinsz	hist.bins   rangezzero-size array)zecannot generate log-spaced histogram bins for zero-size array, please pass `bins` or `range` manuallyZorientation
horizontalr   Zclip)nonpositiver   r   T)Zendpoint)r    r>   getr=   r   Z	ones_liker:   r!   r   minmaxrc   r#   
startswithr   Z
set_yscaler/   Z_scalebaser_   r.   Zlogspacer   rD   hist)	r%   r\   r   r   r   ZnbinsZhrangere   Zlogbase)rI   r   r   r   Y  s0    


z	Axes.histzcolor :zzlogbins : boolean, optional
    If ``True``, use logarithmically-spaced histogram bins.

    Default is ``False``

color :c          
   K   s   | dd}| j|f|\}|g}|d| d | |d d |jj|j|jg}xBt||fD ]2\}	}
|
dk	rf|| j|
f| |
j||	d < qfW |	| j
|||d |d	d
d |S )a  Plot a `Series` as a line, with a shaded region around it.

        The ``data`` `Series` is drawn, while the ``lower`` and ``upper``
        `Series` are plotted lightly below and above, with a fill
        between them and the ``data``.

        All three `Series` should have the same `~Series.index` array.

        Parameters
        ----------
        data : `~gwpy.types.Series`
            Data to plot normally.

        lower : `~gwpy.types.Series`
            Lower boundary (on Y-axis) for shade.

        upper : `~gwpy.types.Series`
            Upper boundary (on Y-axis) for shade.

        **kwargs
            Any other keyword arguments acceptable for
            :meth:`~matplotlib.Axes.plot`.

        Returns
        -------
        artists : `tuple`
            All of the drawn artists:

            - `~matplotlib.lines.Line2d` for ``data``,
            - `~matplotlib.lines.Line2D` for ``lower``, if given
            - `~matplotlib.lines.Line2D` for ``upper``, if given
            - `~matplitlib.collections.PolyCollection` for shading

        See also
        --------
        matplotlib.axes.Axes.plot
            for a full description of acceptable ``*args`` and ``**kwargs``
        alphag? r   )label	linewidthcolorr   Nr   r   
rasterizedT)r   r   r   )r:   ZplotupdateZget_linewidth	get_colorr   rv   	enumerateextendappendZfill_betweenr   )r%   datarm   upperr   r   lineoutfilliboundr   r   r   plot_mmm  s"    '

zAxes.plot_mmmcenterface皙?c	          
      s:  |	 ddr^|dk	r^yt|||||\}}}}}W n* tk
r\ }
 zd|
_ W dd}
~
X Y nX |dkrpdd  nX|dkrd	d  nF|d
krdd  n4|dkrdd  n"|dkrdd  ntd| d|	 dtd }t fddt||||D f||d|	}|dk	r$|| || | 	|}| 
  |S )a  Plot rectanguler tiles based onto these `Axes`.

        ``x`` and ``y`` give the anchor point for each tile, with
        ``w`` and ``h`` giving the extent in the X and Y axis respectively.

        Parameters
        ----------
        x, y, w, h : `array_like`, shape (n, )
            Input data

        color : `array_like`, shape (n, )
            Array of amplitudes for tile color

        anchor : `str`, optional
            Anchor point for tiles relative to ``(x, y)`` coordinates, one of

            - ``'center'`` - center tile on ``(x, y)``
            - ``'ll'`` - ``(x, y)`` defines lower-left corner of tile
            - ``'lr'`` - ``(x, y)`` defines lower-right corner of tile
            - ``'ul'`` - ``(x, y)`` defines upper-left corner of tile
            - ``'ur'`` - ``(x, y)`` defines upper-right corner of tile

        **kwargs
            Other keywords are passed to
            :meth:`~matplotlib.collections.PolyCollection`

        Returns
        -------
        collection : `~matplotlib.collections.PolyCollection`
            the collection of tiles drawn

        Examples
        --------
        >>> import numpy
        >>> from matplotlib import pyplot
        >>> import gwpy.plot  # to get gwpy's Axes

        >>> x = numpy.arange(10)
        >>> y = numpy.arange(x.size)
        >>> w = numpy.ones_like(x) * .8
        >>> h = numpy.ones_like(x) * .8

        >>> fig = pyplot.figure()
        >>> ax = fig.gca()
        >>> ax.tile(x, y, w, h, anchor='ll')
        >>> pyplot.show()
        r4   FN)zdAxes.tile argument 'sortbycolor' can only be used with a simple array of floats in the `color` arrayllc             S   s,   | |f| || f| | || f| | |ffS )Nr   )r\   r^   whr   r   r   _poly  s    zAxes.tile.<locals>._polylrc             S   s,   | | |f| | || f| || f| |ffS )Nr   )r\   r^   r   r   r   r   r   r     s    Zulc             S   s,   | || f| |f| | |f| | || ffS )Nr   )r\   r^   r   r   r   r   r   r     s    urc             S   s,   | | || f| | |f| |f| || ffS )Nr   )r\   r^   r   r   r   r   r   r     s    r   c             S   s\   | |d  ||d  f| |d  ||d  f| |d  ||d  f| |d  ||d  ffS )Ng       @r   )r\   r^   r   r   r   r   r   r     s    ,zUnrecognised tile anchor ''cmapz
image.cmapc             3   s   | ]} | V  qd S )Nr   ).0tile)r   r   r   	<genexpr>   s    zAxes.tile.<locals>.<genexpr>)
edgecolorsr   )r:   rC   rc   r   r   r   zipZ	set_arrayZset_cmapZadd_collectionZautoscale_view)r%   r\   r^   r   r   r   anchorr   r   r   re   r   Zcollr   r   )r   r   r     s6    3








z	Axes.tilec                s6   | dt }t|tr(| ttd t j||S )Nhandler_map   )r9   dictr=   r   r   rD   legend)r%   r   r   r   )rI   r   r   r   -  s    
zAxes.legendzCall signaturesah  .. note::

   This method uses a custom default legend handler for
   `~matplotlib.lines.Line2D` objects, with increased linewidth relative
   to the upstream :meth:`~matplotlib.axes.Axes.legend` method.
   To disable this, pass ``handler_map=None``, or create and pass your
   own handler class.  See :ref:`gwpy-plot-legend` for more details.

Call signaturesc             K   sx   |   }|ddr |dd |dddkr<|dd tj|f|| d|\}}t|trjd|d< |j|f|S )ax  Add a `~matplotlib.colorbar.Colorbar` to these `Axes`

        Parameters
        ----------
        mappable : matplotlib data collection, optional
            collection against which to map the colouring, default will
            be the last added mappable artist (collection or image)

        fraction : `float`, optional
            fraction of space to steal from these `Axes` to make space
            for the new axes, default is ``0.`` if ``use_axesgrid=True``
            is given (default), otherwise default is ``.15`` to match
            the upstream matplotlib default.

        **kwargs
            other keyword arguments to be passed to the
            :meth:`Plot.colorbar` generator

        Returns
        -------
        cbar : `~matplotlib.colorbar.Colorbar`
            the newly added `Colorbar`

        See also
        --------
        Plot.colorbar
        Zuse_axesgridTfractiong        )mappablerW   F)Z
get_figurer   r9   gcbarZprocess_colorbar_kwargsr=   r   r   )r%   r   r   Zfigr   r   r   r   C  s    
zAxes.colorbar)NN)rm   rn   ro   )NN)Nr   r   r   )N)r7   
__module____qualname__rE   r   rU   rG   rH   r)   _AxesZset_xlimr`   rR   r<   rd   __doc__replacer   rj   ri   r3   r{   rz   r   r   r   r   r   __classcell__r   r   )rI   r   r	      s>   

% 
'
C _		r	   c                   s    e Zd ZdZ fddZ  ZS )rF   z,This class controls how ax.plot() works
    c                s   g }x|r|dd |dd  }}t |d drX|d jdkrX|d jj|d jf}n||dd 7 }|dd }|rt|d tr||d f7 }|dd }|| qW t j||S )z7Find `Series` data in `plot()` args and unwrap
        Nr   r   r   )	rh   ndimr   rv   r=   r#   r   rD   __call__)r%   r   r   Znewargsthis)rI   r   r   r   z  s    zPlotArgsProcessor.__call__)r7   r   r   r   r   r   r   r   )rI   r   rF   w  s   rF   )/r   r5   	functoolsr   mathr   numbersr   r    Zastropy.timer   Z
matplotlibr   r2   r   Zmatplotlib.artistr   Zmatplotlib.axesr	   r   Zmatplotlib.axes._baser
   Zmatplotlib.collectionsr   Zmatplotlib.linesr   Zmatplotlib.projectionsr   r   r   r   r   colorsr   rJ   r   r   r   timer   
__author__r   r)   r3   r<   rC   rF   r   r   r   r   <module>   s<   &   U