U
    Cvf                     @  s  U d dl mZ d dlZd dlZd dlZd dlm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 d dlZd dlZd dlmZ d dlmZ d dlmZ d d	lmZmZ ed
Zzd dlZW n e k
r   dZY nX e	rjd 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/ zd dl0m1Z2 W n" e k
rh   dZ2de3d< Y nX dZ4dZ5dZ6dd Z7dd Z8dd Z9dd Z:dd!d"Z;d#d$d$d$d%d&d'd(Z<dd#d$d$d)d$d%d*d+d,Z=d#d$d-d.d/d0d1Z>dd2d3d4d5dd6d7d8d9Z?dd6d:d;d<Z@d-d=d>d?ZAdd-d-dAdBdCZBdDdEdFdGdHZCdIdEdFdJdKZDdDdLdMdNdOdPZEdEdEdQdRdSdTdUZFdVdW ZGdXdYd)dZd[d\ZHd]d^ ZId.d=d_d`ZJdadb ZKdcdd ZLdedf ZMdd6dgdgdhdhdidididid.dj
dkdlZNddmdnZOddodpZPddqdrdsdtduZQdvdw ZRdxdyddzd{ fd|d}ZSd~d ZTdd ZUdd ZVed.dd.dddZWeddddddZWddddddZWG dd deZXddddddddddZYddd-dddZZdS )    )annotationsN)datetime)getfullargspec)TYPE_CHECKINGAnyCallableHashableIterableMappingSequenceoverload)PandasMultiIndex)OPTIONS)DuckArrayModule)	is_scalarmodule_availablenc_time_axis)Axes)	Normalize)FuncFormatter)	ArrayLike)	DataArray)Dataset)AspectOptionsScaleOptionsr   pltg       @)g      2@g      B@g      R@)      ?r   g      @c                  C  s   ddl m}  | S )zimport pyplotr   N)matplotlib.pyplotpyplotr    r    5/tmp/pip-unpacked-wheel-h316xyqg/xarray/plot/utils.pyimport_matplotlib_pyplot:   s    r"   c                 C  s<   |   |k }|  |k}|r$|r$dS |r,dS |r4dS dS d S )NbothminmaxZneitherr$   r%   )	calc_datavminvmaxZ
extend_minZ
extend_maxr    r    r!   _determine_extendB   s    r*   c                 C  s  ddl }t|dkr$|d |d g}|s,d}|dkr:d}n|dkrHd}nd}t|| d }t| |}|jj|||d\}}	t| d	| |_z| tj	tj
gd }
W n tk
r   Y nVX | tj }| tj}||
 || dkr|| || | jd kr|| ||	fS )
zB
    Build a discrete colormap and normalization of the data.
    r   N   r%   r#      r&   )extendname)
matplotliblen_color_palettecolorsZfrom_levels_and_colorsgetattrr.   npmaZmasked_invalidnan	TypeErrorinfZset_badZ	set_underNZset_over)cmaplevelsr-   filledmplZext_nn_colorspalZnew_cmapZcnormbadZunderZoverr    r    r!   _build_discrete_cmapO   s4    




rA   c                 C  s   dd l m} ddlm} tdd|}t| ttfrJ|| |d} | |}nt| t	rz|
| } | |}W q tk
r   zddlm} || |d}W n. ttfk
r   || g|d} | |}Y nX Y qX n| |}|S )Nr   )ListedColormapg      ?)r9   )color_palette)r>   )r   r   matplotlib.colorsrB   r4   linspace
isinstancelisttuplestrZget_cmap
ValueErrorZseabornrC   ImportError)r:   r>   r   rB   Zcolors_ir?   rC   r    r    r!   r1      s&    


r1   FTc                 C  sT  ddl }t|trt|}t| t|  }|jdkrBtd}|dk	}d}|dkr^d}d}|dk	rr|dk	rrd}|dk	p|dk	}d}|dk}|dk}|dkr|rt	|t
}q| }n|rt|| }|dkr|rt	|dt
 }n| }n|rt|| }|rLt|to(|d |d  dk }|dk r>|dkpH| pH|}nd}|r|dkrztt|| t|| }| | }}||7 }||7 }|	dk	r|	jdkr||	_n |s||	jkrtd|	j}|	jdkr||	_n |s||	jkrtd	|	j}t|	|jjr|	j}|dkr@|r8td
 }ntd }|dk	rt|r|rjt|||}n<|dkrt|| d g}n|j|d }|||}|d |d  }}||kr|jd||\}}|dkrt|||}|dk	s
t|	|jjr.t||||\}}|	dkr*|n|	}	|	dk	r@d}d}t||||||	dS )a  
    Use some heuristics to set good defaults for colorbar and range.

    Parameters
    ----------
    plot_data : Numpy array
        Doesn't handle xarray objects

    Returns
    -------
    cmap_params : dict
        Use depends on the type of the plotting function
    r   N        FTd   z4Cannot supply vmin and a norm with a different vmin.z4Cannot supply vmax and a norm with a different vmax.Zcmap_divergentZcmap_sequentialr+   r,   r(   r)   r:   r-   r;   norm)r/   rF   r	   sortedr4   ravelisfinitesizearrayZ
percentileROBUST_PERCENTILEr$   absr%   r(   rJ   r)   r2   ZBoundaryNormZ
boundariesr   r   rE   asarraytickerMaxNLocatortick_valuesLinearLocatorr*   rA   dict)	plot_datar(   r)   r:   centerrobustr-   r;   r<   rP   _is_facetgridr=   r'   Zpossibly_divergentZcenter_is_noneZuser_minmaxZvlimZvmin_was_noneZvmax_was_noneZlevels_are_divergentZ	divergentrY   Znewnormr    r    r!   _determine_cmap_params   s    














     rb   zDataArray | DatasetzHashable | Noneztuple[Hashable, Hashable])darrayxyrgbreturnc                   st  |dks|kst |dks(|ks(t  jdks6t dd |fD }tt|t|k rztddd|d|D ]}| jkr~t|d	q~ fd
d jD }|dkr|std|dkrt|dkr|d }|dk	r | jdkrtd|d | j d|dkrPt|dks6t |d }td|d |dk	s^t t	 
|diS )z
    Determine x and y labels for showing RGB images.

    Attempts to infer which dimension is RGB/RGBA by size and order of dims.

    N   c                 S  s   g | ]}|d k	r|qS Nr    .0ar    r    r!   
<listcomp>Z  s      z'_infer_xy_labels_3d.<locals>.<listcomp>zHDimension names must be None or unique strings, but imshow was passed x=z, y=z
, and rgb=.z is not a dimensionc                   s*   g | ]"} | j d kr|fkr|qS )rh      )rT   )rk   labelrc   rd   re   r    r!   rm   e  s    zA 3-dimensional array was passed to imshow(), but there is no dimension that could be color.  At least one dimension must be of size 3 (RGB) or 4 (RGBA), and not given as x or y.r+   r   ro   zCannot interpret dim z	 of size z as RGB or RGBA.)r,   rh   rN   z`Several dimensions of this array could be colors.  Xarray will use the last possible dimension (zo) to match matplotlib.pyplot.imshow.  You can pass names of x, y, and/or rgb dimensions to override this guess.)AssertionErrorndimr0   setrJ   dimsrT   warningswarn_infer_xy_labelsZisel)rc   rd   re   rf   Znot_nonerq   Zcould_be_colorr    rr   r!   _infer_xy_labels_3dJ  s@    


rz   bool)rc   rd   re   imshowrf   rg   c                 C  s*  |dk	r||krt d|r4| jdkr4t| |||S |dkrb|dkrb| jdkrVt d| j\}}n|dkrt| |d || jd kr| jd n| jd }n|dkrt| |d	 || jd kr| jd n| jd }nPt| |d	 t| |d | j|d| j|dkr"t| j| tr"t d
||fS )z}
    Determine x and y labels. For use in _plot2d

    darray must be a 2 dimensional data array, or 3d for imshow only.
    Nzx and y cannot be equal.rh   r,   zDataArray must be 2dre   r+   r   rd   z/x and y cannot be levels of the same MultiIndex)	rJ   rt   rz   rv   _assert_valid_xyZ_indexesgetrF   r   )rc   rd   re   r|   rf   r    r    r!   ry     s(    
$$ry   rI   None)rc   xyr.   rg   c                 C  sv   dd | j  D }t| jt| jB | }|dk	rr||krrdttdd |D }t| d| d| d	dS )
zB
    make sure x and y passed to plotting functions are valid
    c                 S  s   h | ]}t |tr|jqS r    )rF   r   Zdim)rk   idxr    r    r!   	<setcomp>  s   
z#_assert_valid_xy.<locals>.<setcomp>Nz', 'c                 s  s   | ]}t |V  qd S ri   rI   rk   vr    r    r!   	<genexpr>  s     z#_assert_valid_xy.<locals>.<genexpr>z must be one of None, 'z'. Received '
' instead.)	ZxindexesZ
get_uniqueru   rv   ZcoordsjoinrQ   rH   rJ   )rc   r   r.   Zmultiindex_dimsZvalid_xyZvalid_xy_strr    r    r!   r}     s    r}   zIterable[float] | Nonezfloat | Noner   zAxes | Noner   )figsizerT   aspectaxsubplot_kwsrg   c                 K  s(  zdd l }dd lm} W n tk
r4   tdY nX | d k	rt|d k	rNtd|d k	r^td|j| |d\}}|S |d k	r|d k	rtd|d ks|dkr|jd \}}	||	 }
n|d	krd
}
n|}
||
 |f} |j| |d\}}|S |d k	rtd|r|d k	rtd|d kr$tf |}|S )Nr   z.matplotlib is required for plot.utils.get_axisz0cannot provide both `figsize` and `ax` argumentsz2cannot provide both `figsize` and `size` arguments)r   Z
subplot_kwz-cannot provide both `size` and `ax` argumentsautozfigure.figsizeequalr+   z/cannot provide `aspect` argument without `size`z'cannot use subplot_kws with existing ax)r/   r   r   rK   rJ   ZsubplotsrcParams
_maybe_gca)r   rT   r   r   r   r=   r   _widthheightZfaspectr    r    r!   get_axis  s>    


r   )r   rg   c                  K  s.   dd l m} | }|jr"| S |jf | S Nr   )r   r   ZgcfZaxesZgca)r   r   fr    r    r!   r     s
    r   rg   c                 C  sr   t dj}d}t| j|r.|t| jj}n@| jdrL|| jd }n"| jdrj|| jd }nd}|S )z6Extracts and formats the unit/units from a attributes.pintz [{}]unitsunit )	r   typerF   dataformatrI   r   attrsr~   )dapint_array_typer   r    r    r!   _get_units_from_attrs  s    
r   r   )extrarg   c                 C  s   d}| j dr"|| j d }n:| j dr@|| j d }n| jdk	rX|| j}nd}t| }|dr|dd dkrd	tj	|| | d
ddS dt	|| | dS dS )zQMakes informative labels if variable metadata (attrs) follows
    CF conventions.z{}Z	long_nameZstandard_nameNr   $r,   r   z$
$<   F)break_long_words
   )
r   r~   r   r.   r   
startswithcountr   textwrapwrap)r   r   r.   r   r    r    r!   label_from_attrs  s    
r   zIterable[pd.Interval]
np.ndarray)rU   rg   c                 C  s   t dd | D S )zT
    Helper function which returns an array
    with the Intervals' mid points.
    c                 S  s   g | ]
}|j qS r    )Zmidrk   rd   r    r    r!   rm   2  s     z+_interval_to_mid_points.<locals>.<listcomp>)r4   rU   )rU   r    r    r!   _interval_to_mid_points,  s    r   zSequence[pd.Interval]c                 C  s4   t dd | D }t |t | d jgf}|S )zT
    Helper function which returns an array
    with the Intervals' boundaries.
    c                 S  s   g | ]
}|j qS r    leftr   r    r    r!   rm   ;  s     z-_interval_to_bound_points.<locals>.<listcomp>rN   )r4   rU   concatenateright)rU   Zarray_boundariesr    r    r!   _interval_to_bound_points5  s    r   r	   ztuple[np.ndarray, np.ndarray])xarrayyarrayrg   c                 C  sh   t dd | D }t dd | D }t ttjt||}t ttjt||}||fS )z
    Helper function to deal with a xarray consisting of pd.Intervals. Each
    interval is replaced with both boundaries. I.e. the length of xarray
    doubles. yarray is modified so it matches the new shape of xarray.
    c                 S  s   g | ]
}|j qS r    r   r   r    r    r!   rm   J  s     z4_interval_to_double_bound_points.<locals>.<listcomp>c                 S  s   g | ]
}|j qS r    )r   r   r    r    r!   rm   K  s     )r4   rU   rG   	itertoolschainfrom_iterablezip)r   r   Zxarray1Zxarray2Z
xarray_outZ
yarray_outr    r    r!    _interval_to_double_bound_pointsA  s
    	r   r]   z-tuple[np.ndarray, np.ndarray, str, str, dict])xvalyvalkwargsrg   c                 C  s   d}d}| dddrd}t| tj}t|tj}|rH|rHtdn.|r`t| |\} }d}n|rvt|| \}} d}|r|d= n0t| tjrt| } d}t|tjrt|}d}| ||||fS )z
    Helper function to replace the values of x and/or y coordinate arrays
    containing pd.Interval with their mid-points or - for step plots - double
    points which double the length.
    r   Z	drawstylezsteps-Fz,Can't step plot intervals against intervals.T_center)r~   r   _valid_other_typepdIntervalr7   r   r   )r   r   r   Zx_suffixZy_suffixZremove_drawstyleZx_is_intervalZy_is_intervalr    r    r!   _resolve_intervals_1dplotS  s.    
r   c                 C  s6   d}t | tjr.|dkr"t| } nt| } d}| |fS )z
    Helper function to replace the values of a coordinate array containing
    pd.Interval with their mid-points or - for pcolormesh - boundaries which
    increases length by 1.
    r   Z
pcolormeshr   )r   r   r   r   r   )val	func_nameZlabel_extrar    r    r!   _resolve_intervals_2dplot  s    
r   r   z'type[object] | tuple[type[object], ...])rd   typesrg   c                   s   t  fddt| D S )z6
    Do all elements of x have a type from types?
    c                 3  s   | ]}t | V  qd S ri   )rF   )rk   elr   r    r!   r     s     z$_valid_other_type.<locals>.<genexpr>)allr4   rR   )rd   r   r    r   r!   r     s    r   c                   s2   |D ]}t t j|rtqt fdd|D S )zC
    Is any dtype from numpy_types superior to the dtype of x?
    c                 3  s   | ]}t  j|V  qd S ri   )r4   
issubdtypedtype)rk   trd   r    r!   r     s     z(_valid_numpy_subdtype.<locals>.<genexpr>)r4   r   Zgenericrs   any)rd   numpy_typesr   r    r   r!   _valid_numpy_subdtype  s    r   c                  G  s   t jt jt jt jt jt jf}tf}tdkr.dntjf}||7 }| D ]b}t	t 
||s~tt 
||s~tdt 
|j dtt 
||rBtrddl}qBtdqBdS )zj
    Raise exception if there is anything in args that can't be plotted on an
    axis by matplotlib.
    Nr    zPlotting requires coordinates to be numeric, boolean, or dates of type numpy.datetime64, datetime.datetime, cftime.datetime or pandas.Interval. Received data of type 	 instead.r   zPlotting of arrays of cftime.datetime objects or arrays indexed by cftime.datetime objects requires the optional `nc-time-axis` (v1.2.0 or later) package.)r4   floatingintegerZtimedelta64Z
datetime64Zbool_Zstr_r   cftimer   rX   r   r7   r   nc_time_axis_availabler   rK   )argsr   Zother_typesZcftime_datetime_typesrd   r   r    r    r!   _ensure_plottable  s2    
r   c                 C  s   t jt jg}t| |S ri   )r4   r   r   r   )arrr   r    r    r!   _is_numeric  s    r   c                 C  s`   | d|d  |d kr&| d| n| d| t| drF|d | }|j| f|}|S )Nr-   r   Zcax)
setdefaulthasattrpopZ
get_figureZcolorbar)	primitiver   Zcbar_axcbar_kwargscmap_paramsZfigZcbarr    r    r!   _add_colorbar  s    

r   c                 C  s   |s|d k	s|d k	st |rJ|d kr4t| dt }|d krt| t}nd|d krt| jtjrfdnd}||k rtd|d|dn$|d krd}||krtd|d	| d
| ||  d} t	t
| ddS )NrM      r+   zvmin=z  is less than the default vmax (z/) - you must supply a vmax > vmin in this case.r   zvmax=zP is less than the default vmin (0) - you must supply a vmin < vmax in this case.Zf8Zf4)rs   r4   ZnanpercentilerV   r   r   r   rJ   astypeZminimummaximum)rc   r(   r)   r`   r    r    r!   _rescale_imshow_rgb  s(    
r   zbool | Noner   zArrayLike | None)
r   	xincrease	yincreasexscaleyscalexticksyticksxlimylimrg   c	           	      C  s   |dkr
n*|r |   r |   n|s4|   s4|   |dkr>n*|rT|  rT|   n|sh|  sh|   |dk	rz| | |dk	r| | |dk	r| | |dk	r| | |dk	r| | |dk	r| 	| dS )z.
    Update axes with provided parameters
    N)
Zxaxis_invertedZinvert_xaxisZyaxis_invertedZinvert_yaxisZ
set_xscaleZ
set_yscaleZ
set_xticksZ
set_yticksZset_xlimZset_ylim)	r   r   r   r   r   r   r   r   r   r    r    r!   _update_axes  s0    






r   c                 C  s   | j | dk rdS | j | }| jtd||d| jtd|d |dk}| jtd||d| jtd|d |dk}t|pt|S dS )z
    >>> _is_monotonic(np.array([0, 1, 2]))
    True
    >>> _is_monotonic(np.array([2, 1, 0]))
    True
    >>> _is_monotonic(np.array([0, 2, 1]))
    False
    rh   Tr+   axisr   N)shapetaker4   aranger   )coordr   nZ	delta_posZ	delta_negr    r    r!   _is_monotonic>  s    	
  r   c           	        s  t | } |r&t|  ds&td  |dkrL| dk rBtdt | } dt j|  d }|jdkrrt d}t j	| dg dt j	|dg d }t j	| dg dt j	|dg d }t
 fd	d
t| jD }t j|| | | |g d}|dkrt d|S |S )a  
    >>> _infer_interval_breaks(np.arange(5))
    array([-0.5,  0.5,  1.5,  2.5,  3.5,  4.5])
    >>> _infer_interval_breaks([[0, 1], [3, 4]], axis=1)
    array([[-0.5,  0.5,  1.5],
           [ 2.5,  3.5,  4.5]])
    >>> _infer_interval_breaks(np.logspace(-2, 2, 5), scale="log")
    array([3.16227766e-03, 3.16227766e-02, 3.16227766e-01, 3.16227766e+00,
           3.16227766e+01, 3.16227766e+02])
    r   a"  The input coordinate is not sorted in increasing order along axis %d. This can lead to unexpected results. Consider calling the `sortby` method on the input DataArray. To plot data with categorical axes, consider using the `heatmap` function from the `seaborn` statistical plotting library.logr   z\Found negative or zero value in coordinates. Coordinates must be positive on logscale plots.      ?rL   rN   c                 3  s(   | ] }| krt d dnt d V  qd S )NrN   )slice)rk   r   r   r    r!   r   y  s    z)_infer_interval_breaks.<locals>.<genexpr>
   )r4   rX   r   rJ   r   log10ZdiffrT   rU   r   rH   rangert   r   power)	r   r   ZscaleZcheck_monotonicZdeltasfirstlastZ	trim_lastZinterval_breaksr    r   r!   _infer_interval_breaksT  s8    




$$ 
r  z4Iterable[tuple[str, Any]] | Mapping[str, Any] | Nonez%tuple[dict[str, Any], dict[str, Any]])r   rg   c           
        s   | j dkr(|d< fdddD i fS |dkr4i nt|}d| j krR|dkrRd}|rb|rbtd	|rd| j kr|dkrtd
t|ttfrtd|||r|n|| j dkd ttj} 	fdd|D  |stf  }	n fdddD }	|	|fS )z
    Parameters
    ----------
    func : plotting function
    data : ndarray,
        Data values

    Returns
    -------
    cmap_params : dict
    cbar_kwargs : dict
    Zsurfacer:   c                   s   i | ]}|  |d qS ri   )r~   rk   kr   r    r!   
<dictcomp>  s    z-_process_cmap_cbar_kwargs.<locals>.<dictcomp>rO   NZcontour   z#Can't specify both cmap and colors.z.Can only specify colors with contour or levelszNSpecifying a list of colors in cmap is deprecated. Use colors keyword instead.)r^   r;   r:   r<   c                 3  s"   | ]}| kr| | fV  qd S ri   r    rj   r  r    r!   r     s      z,_process_cmap_cbar_kwargs.<locals>.<genexpr>c                   s   i | ]}| | qS r    r    r  )cmap_kwargsr    r!   r    s    )
__name__r]   rJ   rF   rG   rH   r   rb   r   update)
funcr   r:   r2   r   r;   ra   r   Z	cmap_argsr   r    )r  r   r!   _process_cmap_cbar_kwargs  s>    




r  c                 C  sB   dd l }|jd}tt|  | }|d|d }|S )Nr   rh   )r/   rY   rZ   r4   meanhypotto_numpyr[   )ur   r=   rY   r  Z	magnituder    r    r!   _get_nice_quiver_magnitude  s
    r  r2   r   c                 C  s   | S ri   r    r   r    r    r!   <lambda>      r  c                   s  ddl }ddl}|j}g }	g }
|dkrj }|dkrH|d |	|
fS |d|jd fdd}nR|d	krt|jj	r
 }n }|d
d  fdd}ntd| dt|}t||}t|jtj}|dkr|r|jjddd}n6|dkr$|s$|jd}nt|tr<|j|}|  |dkrdd}t||krdd}|rb| }| }|j|| |j|| |dk	rt||jjr|}nHt|r|j |}n.t!|}|jj"||d ddddddddgd}|#||}||k||k@ }|| }t$| | d}||}t%|}t&||| || }n^|dk	r|st'|t!kr|j(|}ntd|#dt|d )t!}|| }|| }t*|d r|+| t,
 d - d!}|.| t/||D ]\}}||\}}t|jj0r@|j.d"1 d |d# n&t|jj	rf|j.2 d |d$ |j3dgdgfd
|i|}|	4| |
4|| q|	|
fS )%a9  
    Create legend handles and labels for a PathCollection.

    Each legend handle is a `.Line2D` representing the Path that was drawn,
    and each label is a string what each Path represents.

    This is useful for obtaining a legend for a `~.Axes.scatter` plot;
    e.g.::

        scatter = plt.scatter([1, 2, 3],  [4, 5, 6],  c=[7, 2, 3])
        plt.legend(*scatter.legend_elements())

    creates three legend elements, one for each color with the numerical
    values passed to *c* as the labels.

    Also see the :ref:`automatedlegendcreation` example.


    Parameters
    ----------
    prop : {"colors", "sizes"}, default: "colors"
        If "colors", the legend handles will show the different colors of
        the collection. If "sizes", the legend will show the different
        sizes. To set both, use *kwargs* to directly edit the `.Line2D`
        properties.
    num : int, None, "auto" (default), array-like, or `~.ticker.Locator`
        Target number of elements to create.
        If None, use all unique elements of the mappable array. If an
        integer, target to use *num* elements in the normed range.
        If *"auto"*, try to determine which option better suits the nature
        of the data.
        The number of created elements may slightly deviate from *num* due
        to a `~.ticker.Locator` being used to find useful locations.
        If a list or array, use exactly those elements for the legend.
        Finally, a `~.ticker.Locator` can be provided.
    fmt : str, `~matplotlib.ticker.Formatter`, or None (default)
        The format or formatter to use for the labels. If a string must be
        a valid input for a `~.StrMethodFormatter`. If None (the default),
        use a `~.ScalarFormatter`.
    func : function, default: ``lambda x: x``
        Function to calculate the labels.  Often the size (or color)
        argument to `~.Axes.scatter` will have been pre-processed by the
        user using a function ``s = f(x)`` to make the markers visible;
        e.g. ``size = np.log10(x)``.  Providing the inverse of this
        function here allows that pre-processing to be inverted, so that
        the legend labels have the correct values; e.g. ``func = lambda
        x: 10**x``.
    **kwargs
        Allowed keyword arguments are *color* and *size*. E.g. it may be
        useful to set the color of the markers if *prop="sizes"* is used;
        similarly to set the size of the markers if *prop="colors"* is
        used. Any further parameters are passed onto the `.Line2D`
        instance. This may be useful to e.g. specify a different
        *markeredgecolor* or *alpha* for the legend handles.

    Returns
    -------
    handles : list of `.Line2D`
        Visual representation of each element of the legend.
    labels : list of str
        The string labels for elements of the legend.
    r   Nr2   zfCollection without array used. Make sure to specify the values to be colormapped via the `c` argument.rT   zlines.markersizec                   s    |  fS ri   )r:   rP   value)_sizeselfr    r!   _get_color_and_size-  s    z,legend_elements.<locals>._get_color_and_sizesizescolorr  c                   s    t | fS ri   )r4   sqrtr  )_colorr    r!   r  7  s    z?Valid values for `prop` are 'colors' or 'sizes'. You supplied 'r   FT)Z	useOffsetZuseMathTextz{x}r   	   r+   r,   g      @rh            r   )ZnbinsZmin_n_ticksZsteps   z4`num` only supports integers for non-numeric labels.set_locs)Zmarkeredgewidthalphar   )	linestylemarkerZ
markersize)r$  Z	linewidth)5rw   r/   linesZ	get_arrayrx   r   r   rF   collectionsZLineCollectionZget_linewidthsZ	get_sizesrJ   r4   uniquerX   r   r   numberrY   ZScalarFormatterZStrMethodFormatterrI   Zcreate_dummy_axisr0   r$   r%   r   Zset_view_intervalZset_data_intervalLocatoriterableZFixedLocatorintrZ   r[   rE   argsortZinterpr   r\   r   r   r"  r]   Z	get_alphar	  r   ZPathCollection	get_pathsZget_linestyleLine2Dappend)r  propnumfmtr
  r   rw   r=   Zmlineshandleslabelsr   r  valuesZlabel_valuesZlabel_values_are_numericZlabel_values_minZlabel_values_maxlocZcondZvalues_interpZlabel_values_interpixindkwr   Zlabr  rT   hr    )r  r  r  r!   legend_elements  s    A




  



r<  c                 C  sL   t  }|rDt| dkrD|jg g |d}|d |g|  } |g| }| |fS )z!Add a subtitle to legend handles.r+   )rq   F)r"   r0   r/  Zset_visible)r4  r5  textr   Zblank_handler    r    r!   _legend_add_subtitle  s    


r>  c           	        s   t    jdd}|  jjjd  } fdd|D }|D ]f}| }t|dk r\qB|\}}| }t	dd |D sB|
d | D ]}|dk	r|| qqBdS )	z@Make invisible-handle "subtitles" entries look more like titles.zlegend.title_fontsizeNr   c                   s    g | ]}t | jjjr|qS r    )rF   r/   	offsetboxZHPackerr   r   r    r!   rm     s      z,_adjust_legend_subtitles.<locals>.<listcomp>r,   c                 s  s   | ]}|  V  qd S ri   )Zget_visible)rk   Zartistr    r    r!   r     s     z+_adjust_legend_subtitles.<locals>.<genexpr>)r"   r   r~   Zfindobjr/   r?  ZVPackerZget_childrenr0   r   Z	set_widthZset_size)	legendZ	font_sizeZhpackersZhpackZareasZ	draw_areaZ	text_arear4  r=  r    r   r!   _adjust_legend_subtitles  s    
rA  c              	   C  s.  t | j }ddttdd |D  d}||krPtd| d| d||krntd	| d| d|d k	r||krtd
| d| d|rt| | j}	|d kr|	rdnd}|	s|dkrtd| |d ks|dkr|dkrdnd}
|dkrdnd}nd}
d}n$|dkr2|dkr2tdd}d}
|sJ|d kr|dkrd}|rd}
|snd}n|dkrtdnd}|s|d kr|dkr|rd}
|sd}n|dkrtd|d k	r|dkrtd|r t	| | }| | }nd }d }|
||||t	| | t	| | |dS )Nz must be one of (z, c                 s  s   | ]}t |V  qd S ri   r   r   r    r    r!   r     s     z#_infer_meta_data.<locals>.<genexpr>)zExpected 'x' z. Received r   zExpected 'y' zExpected 'hue' 
continuousdiscretez7Cannot create a colorbar for a non numeric coordinate: TF)quiver
streamplotz&Cannot set add_guide when hue is None.rE  zKhue_style must be 'continuous' or None for .plot.quiver or .plot.streamplotrF  )rD  rC  z:hue_style must be either None, 'discrete' or 'continuous'.)add_colorbar
add_legendadd_quiverkey	hue_label	hue_styleZxlabelZylabelhue)
ru   	variableskeysr   rQ   rH   rJ   r   r6  r   )Zdsrd   re   rL  rK  Z	add_guidefuncnameZdvars	error_msgZhue_is_numericrG  rH  rI  rJ  r    r    r!   _infer_meta_data  sz    $




rQ  z:tuple[float | None, float | None, bool] | Normalize | None)r   rP   rg   c                 C  s   d S ri   r    r   rP   r    r    r!   _parse_size  s    rS  r   	pd.Seriesc                 C  s   d S ri   r    rR  r    r    r!   rS  %  s    DataArray | NonezNone | pd.Seriesc                 C  s.  dd l }| d krd S | j }t|sPt|}tddt| d d d }ntt| }}t	\}}}|d kr|j
 }n2t|tr|j
j| }nt||j
jsd}	t|	t||j
jstd|_| s|t| ||}
t||
||   }|
j rd||
j< tt||}t|S )Nr   r+   rN   z7``size_norm`` must be None, tuple, or Normalize object.T)r/   r6  flattenr   r4   r(  r   r0   sort_MARKERSIZE_RANGEr2   r   rF   rH   rJ   rs   ZclipZscaledrX   maskr   r]   r   r   Series)r   rP   r=   Zflatdatar;   ZnumbersZ	min_widthZdefault_width	max_widtherrZsclwidthsr  r    r    r!   rS  .  s4    

 


c                   @  s  e Zd ZU dZded< ded< ded< ded< ded	< d
ed< dZd@dd
dddddZddddZddddZdd Z	e
ddddZe
ddddZeddd d!d"Zed#d#d d$d"Zd%d%d d&d"Zeddd'd(d)Zed#d#d'd*d)Zd%d%d'd+d)Ze
ddd,d-Ze
d.dd/d0Ze
d.dd1d2Ze
ddd3d4Ze
d5dd6d7Zddd8d9Ze
d:dd;d<Ze
d=dd>d?ZdS )A
_Normalizea  
    Normalize numerical or categorical values to numerical values.

    The class includes helper methods that simplifies transforming to
    and from normalized values.

    Parameters
    ----------
    data : DataArray
        DataArray to normalize.
    width : Sequence of three numbers, optional
        Normalize the data to these (min, default, max) values.
        The default is None.
    rU  _datar   _data_unique_data_unique_index_data_unique_inverser{   _data_is_numericz!tuple[float, float, float] | None_width)r_  r`  ra  rb  rc  rd  NFr   )r   r   ra   rg   c                 C  s   || _ |s|nd | _tdj}t|d kr,|n|j|r>| n|}tj|dd\}}|| _	t
d|j| _|| _|d kr|dnt|| _d S )Nr   T)Zreturn_inverser   F)r_  rd  r   r   rF   r   r  r4   r(  r`  r   rT   ra  rb  r   rc  )r  r   r   ra   r   Z	to_uniqueZdata_uniqueZdata_unique_inverser    r    r!   __init__z  s    

z_Normalize.__init__rI   r   c              
   C  sD   t jdddd* d| j d| j d| j W  5 Q R  S Q R X d S )Nrp   Tr  )Z	precisionsuppress	thresholdz<_Normalize(data, width=z)>
z -> )r4   Zprintoptionsrd  r`  _values_uniquer  r    r    r!   __repr__  s    z_Normalize.__repr__r,  c                 C  s
   t | jS ri   )r0   r`  ri  r    r    r!   __len__  s    z_Normalize.__len__c                 C  s
   | j | S ri   )r`  )r  keyr    r    r!   __getitem__  s    z_Normalize.__getitem__c                 C  s   | j S ri   )r_  ri  r    r    r!   r     s    z_Normalize.datac                 C  s   | j S )a+  
        Check if data is numeric.

        Examples
        --------
        >>> a = xr.DataArray(["b", "a", "a", "b", "c"])
        >>> _Normalize(a).data_is_numeric
        False

        >>> a = xr.DataArray([0.5, 0, 0, 0.5, 2, 3])
        >>> _Normalize(a).data_is_numeric
        True
        )rc  ri  r    r    r!   data_is_numeric  s    z_Normalize.data_is_numeric)re   rg   c                 C  s   d S ri   r    r  re   r    r    r!   _calc_widths  s    z_Normalize._calc_widthsr   c                 C  s   d S ri   r    ro  r    r    r!   rp    s    znp.ndarray | DataArrayc                 C  sj   | j dkr|S | j \}}}t|t| }|dkrD|d|  }n"|t| | }||||   }|S )zH
        Normalize the values so they're inbetween self._width.
        Nr   )rd  r4   r%   r$   )r  re   ZxminZxdefaultZxmaxZdiff_maxy_minyr]  r  r    r    r!   rp    s    
)rd   rg   c                 C  s   d S ri   r    r  rd   r    r    r!   _indexes_centered  s    z_Normalize._indexes_centeredc                 C  s   d S ri   r    rq  r    r    r!   rr    s    c                 C  s   |d d S )zv
        Offset indexes to make sure being in the center of self.levels.
        ["a", "b", "c"] -> [1, 3, 5]
        r,   r+   r    rq  r    r    r!   rr    s    c                 C  sJ   | j dkrdS | jr| j }n$| | j}| j j|| j jd}| |S )a9  
        Return a normalized number array for the unique levels.

        Examples
        --------
        >>> a = xr.DataArray(["b", "a", "a", "b", "c"])
        >>> _Normalize(a).values
        <xarray.DataArray (dim_0: 5)>
        array([3, 1, 1, 3, 5])
        Dimensions without coordinates: dim_0

        >>> _Normalize(a, width=(18, 36, 72)).values
        <xarray.DataArray (dim_0: 5)>
        array([45., 18., 18., 45., 72.])
        Dimensions without coordinates: dim_0

        >>> a = xr.DataArray([0.5, 0, 0, 0.5, 2, 3])
        >>> _Normalize(a).values
        <xarray.DataArray (dim_0: 6)>
        array([0.5, 0. , 0. , 0.5, 2. , 3. ])
        Dimensions without coordinates: dim_0

        >>> _Normalize(a, width=(18, 36, 72)).values
        <xarray.DataArray (dim_0: 6)>
        array([27., 18., 18., 27., 54., 72.])
        Dimensions without coordinates: dim_0

        >>> _Normalize(a * 0, width=(18, 36, 72)).values
        <xarray.DataArray (dim_0: 6)>
        array([36., 36., 36., 36., 36., 36.])
        Dimensions without coordinates: dim_0

        N)r   )r   rn  rr  rb  copyZreshaper   rp  )r  r   r   r    r    r!   r6    s    #
z_Normalize.valuesznp.ndarray | Nonec                 C  s2   | j dkrdS | jr| j}n| | j}| |S )a  
        Return unique values.

        Examples
        --------
        >>> a = xr.DataArray(["b", "a", "a", "b", "c"])
        >>> _Normalize(a)._values_unique
        array([1, 3, 5])

        >>> _Normalize(a, width=(18, 36, 72))._values_unique
        array([18., 45., 72.])

        >>> a = xr.DataArray([0.5, 0, 0, 0.5, 2, 3])
        >>> _Normalize(a)._values_unique
        array([0. , 0.5, 2. , 3. ])

        >>> _Normalize(a, width=(18, 36, 72))._values_unique
        array([18., 27., 54., 72.])
        N)r   rn  r`  rr  ra  rp  r  r   r    r    r!   rh  
  s    
z_Normalize._values_uniquec                 C  s   | j rd}n| | j}|S )z
        Return ticks for plt.colorbar if the data is not numeric.

        Examples
        --------
        >>> a = xr.DataArray(["b", "a", "a", "b", "c"])
        >>> _Normalize(a).ticks
        array([1, 3, 5])
        N)rn  rr  ra  rt  r    r    r!   ticks*  s    z_Normalize.ticksc                 C  s   t | jt | jd d S )a  
        Return discrete levels that will evenly bound self.values.
        ["a", "b", "c"] -> [0, 2, 4, 6]

        Examples
        --------
        >>> a = xr.DataArray(["b", "a", "a", "b", "c"])
        >>> _Normalize(a).levels
        array([0, 2, 4, 6])
        r+   r,   )r4   r0  ra  r%   ri  r    r    r!   r;   =  s    z_Normalize.levelsrT  c                 C  s*   | j d krtdttt| j | jS )Nzself.data can't be None.)rh  rJ   r   rZ  r]   r   r`  ri  r    r    r!   _lookupM  s    
z_Normalize._lookupc                 C  s   | j  j|dd S )NZnearest)method)rv  Z
sort_indexZreindexr  rq  r    r    r!   _lookup_arrT  s    z_Normalize._lookup_arrr   c                   s&   t  }dddd fdd}||S )a  
        Return a FuncFormatter that maps self.values elements back to
        the original value as a string. Useful with plt.colorbar.

        Examples
        --------
        >>> a = xr.DataArray([0.5, 0, 0, 0.5, 2, 3])
        >>> aa = _Normalize(a, width=(0, 0.5, 1))
        >>> aa._lookup
        0.000000    0.0
        0.166667    0.5
        0.666667    2.0
        1.000000    3.0
        dtype: float64
        >>> aa.format(1)
        '3.0'
        Nr   
None | Anyrd   posc                   s     | gd  S r   rx  rz  ri  r    r!   _funcp  s    z _Normalize.format.<locals>._func)N)r"   r   )r  r   r}  r    ri  r!   r   [  s    z_Normalize.formatz Callable[[Any, None | Any], Any]c                   s   dddd fdd}|S )a  
        Return a lambda function that maps self.values elements back to
        the original value as a numpy array. Useful with ax.legend_elements.

        Examples
        --------
        >>> a = xr.DataArray([0.5, 0, 0, 0.5, 2, 3])
        >>> aa = _Normalize(a, width=(0, 0.5, 1))
        >>> aa._lookup
        0.000000    0.0
        0.166667    0.5
        0.666667    2.0
        1.000000    3.0
        dtype: float64
        >>> aa.func([0.16, 1])
        array([0.5, 3. ])
        Nr   ry  rz  c                   s
     | S ri   r|  rz  ri  r    r!   r}    s    z_Normalize.func.<locals>._func)Nr    )r  r}  r    ri  r!   r
  u  s    z_Normalize.func)NF)r  
__module____qualname____doc____annotations__	__slots__re  rj  rk  rm  propertyr   rn  r   rp  rr  r6  rh  ru  r;   rv  rx  r   r
  r    r    r    r!   r^  Z  sV   
  .r^  zNone | boolz
str | Noneztuple[bool, bool])hueplt_normsizeplt_normrG  rH  plotfunc_namerg   c                 C  s   |dkrdS |r"| j d kr"td|d kr>| j d k	r:d}nd}|r^| j d kr^|j d kr^td|d kr|s~| j d k	r~| jdks|j d k	rd}nd}||fS )Nhist)FFz*Cannot create a colorbar when hue is None.TFz7Cannot create a legend when hue and markersize is None.)r   KeyErrorrn  )r  r  rG  rH  r  r    r    r!   _determine_guide  s,    
r  )r  r  plotfuncc                 C  s   t |tr|n|g}g g  }}| df|dffD ]\}}|jd k	r.g g  }	}
|D ]*}t||d|jd\}}|	|7 }	|
|7 }
qNtj|
dd\}}t|}||  }
t	|	|  }	t
|	|
t|j\}	}
||	7 }||
7 }q.|j||dd}t| |S )	Nr2   r  r   )r2  r
  T)Zreturn_indexr   )Z
framealpha)rF   rG   r   r<  r
  r4   r(  r-  tolistrU   r>  r   r@  rA  )r  r  r   Z	legend_axr  r4  r5  Z
huesizepltr1  hdlZlblpZhdl_Zlbl_r  r9  r@  r    r    r!   _add_legend  s*    





r  )
NNNNFNNTNF)FN)NNNN)r   )NNNNNN)r   )r   NF)NNNNF)NNN)[
__future__r   r   r   rw   r   inspectr   typingr   r   r   r   r	   r
   r   r   Znumpyr4   Zpandasr   Zxarray.core.indexesr   Zxarray.core.optionsr   Zxarray.core.pycompatr   Zxarray.core.utilsr   r   r   r   rK   Zmatplotlib.axesr   rD   r   Zmatplotlib.tickerr   Znumpy.typingr   Zxarray.core.dataarrayr   Zxarray.core.datasetr   Zxarray.core.typesr   r   r   r   r   r  rV   rX  Z_LINEWIDTH_RANGEr"   r*   rA   r1   rb   rz   ry   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r<  r>  rA  rQ  rS  r^  r  r  r    r    r    r!   <module>   s    (
6'          
 !B  (    /	/	-%      "1

4     H   
 DS,  :   !