a
    jDf                     @  s  U d dl mZ d dlZd dlZd dlZd dlmZmZmZm	Z	m
Z
 d dlmZmZ d dlmZ d dl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mZ d d
l m!Z! edZ"zd dl#Z#W n e$y   dZ#Y n0 erzd 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/m0Z0 d dl1m2Z2m3Z3 zd dl4m5Z6 W n  e$yx   dZ6de7d< Y n0 dZ8dZ9dZ:dd Z;dd Z<d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.d/d0ZAdd1d2d3d4dd5d6d7d8ZBdd5d9d:d;ZCd<d,d=d>d?ZDddAd,d,dBdCdDZEdEdFdGdHdIZFdJdFdGdKdLZGdEdMdNdOdPdQZHdFdFdRdSdTdUdVZIdWdX ZJdYdZd(d[d\d]ZKd^d_ ZLd-d`dadbZMdcdd ZNdedf ZOdgdh ZPdd5dididjdjdkdkdldld-dm
dndoZQddpdqZRddrdsZSddtdudvdwdxZTdydz ZUd{d|dd}d~ fddZVdd ZWdd ZXdd ZYed-dd-dddZZed<dddddZZdAdddddZZG dd de
Z[ddddddddddZ\ddd,dddZ]dd<ddRddddddZ^dd5dd-dddZ_dS )    )annotationsN)HashableIterableMappingMutableMappingSequence)datedatetime)getfullargspec)TYPE_CHECKINGAnyCallableLiteraloverload)PandasMultiIndex)OPTIONS)	is_scalarmodule_available)DuckArrayModulenc_time_axis)Axes)	Normalize)FuncFormatter)	ArrayLike)	DataArray)Dataset)AspectOptionsScaleOptionsr   pltg       @)g      2@g      B@g      R@)      ?r   g      @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_max r'   ^/nfs/NAS7/SABIOD/METHODE/ermites/ermites_venv/lib/python3.9/site-packages/xarray/plot/utils.py_determine_extend2   s    r)   c                 C  s  ddl }t|dkr$|d |d g}|s,d}|dkr:d}n|dv rHd}nd}t|| d }t| |}|jj|||d\}}	t| d	| |_z| tj	tj
gd }
W n ty   Y nV0 | 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_cmap?   s4    




r@   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y   zddlm} || |d}W n, ttfy   || g|d} | |}Y n0 Y q0 n| |}|S )Nr   )ListedColormapg      ?)r8   )color_palette)r=   )matplotlib.pyplotpyplotmatplotlib.colorsrA   r3   linspace
isinstancelisttuplestrZget_cmap
ValueErrorZseabornrB   ImportError)r9   r=   r   rA   Zcolors_ir>   rB   r'   r'   r(   r0   u   s&    


r0   FTc                 C  sT  ddl }t|trt|}t| t|  }|jdkrBtd}|du}d}|du r^d}d}|durr|durrd}|dup|du}d}|du }|du }|du r|rt	|t
}q| }n|rt|| }|du 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u rztt|| t|| }| | }}||7 }||7 }|	dur|	jdu r||	_n |s||	jkrtd|	j}|	jdu r||	_n |s||	jkrtd	|	j}t|	|jjr|	j}|du r@|r8td
 }ntd }|durt|r|rjt|||}n<|dkrt|| d g}n|j|d }|||}|d |d  }}||kr|jd||\}}|du rt|||}|dur.t|	|jjs.t||||\}}|	du r*|n|	}	|	du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&   r9   r,   r:   norm)r.   rG   r   sortedr3   ravelisfinitesizearrayZ
percentileROBUST_PERCENTILEr!   absr"   r%   rK   r&   r1   ZBoundaryNormZ
boundariesr   r   rF   asarraytickerMaxNLocatortick_valuesLinearLocatorr)   r@   dict)	plot_datar%   r&   r9   centerrobustr,   r:   r;   rQ   _is_facetgridr<   r$   Zpossibly_divergentZcenter_is_noneZuser_minmaxZvlimZvmin_was_noneZvmax_was_noneZlevels_are_divergentZ	divergentrZ   Znewnormr'   r'   r(   _determine_cmap_params   s    














rc   zDataArray | DatasetzHashable | Noneztuple[Hashable, Hashable])darrayxyrgbreturnc                   st  |du s|ksJ |du s(|ks(J  j dks6J dd |fD }tt|t|k rztddd|d|D ]}| jvr~t|d	q~ fd
d jD }|du r|std|du rt|dkr|d }|dur | jdvrtd|d | j d|du rPt|dv s6J |d }td|d |dus^J 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 ur|qS Nr'   .0ar'   r'   r(   
<listcomp>J      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 v r|fvr|qS )ri      )rU   )rl   labelrd   re   rf   r'   r(   rn   U  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   rq   zCannot interpret dim z	 of size z as RGB or RGBA.)r+   ri   rO   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.)
ndimr/   setrK   dimsrU   warningswarn_infer_xy_labelsZisel)rd   re   rf   rg   Znot_noners   Zcould_be_colorr'   rt   r(   _infer_xy_labels_3d:  sP    

r{   bool)rd   re   rf   imshowrg   rh   c                 C  s*  |dur||krt d|r4| jdkr4t| |||S |du rb|du rb| jdkrVt d| j\}}n|du rt| |d || jd kr| jd n| jd }n|du rt| |d	 || jd kr| jd n| jd }nPt| |d	 t| |d | j|d| j|du 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.ri   r+   zDataArray must be 2drf   r*   r   re   z/x and y cannot be levels of the same MultiIndex)	rK   ru   r{   rw   _assert_valid_xyZ_indexesgetrG   r   )rd   re   rf   r}   rg   r'   r'   r(   rz   x  s(    
$$rz   rJ   None)rd   xyr-   rh   c                 C  sv   dd | j  D }t| jt| jB | }|durr||v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'   )rG   r   dim)rl   idxr'   r'   r(   	<setcomp>  s   
z#_assert_valid_xy.<locals>.<setcomp>Nz', 'c                 s  s   | ]}t |V  qd S rj   rJ   rl   vr'   r'   r(   	<genexpr>  ro   z#_assert_valid_xy.<locals>.<genexpr>z must be one of None, 'z'. Received '
' instead.)	ZxindexesZ
get_uniquerv   rw   coordsjoinrR   rI   rK   )rd   r   r-   Zmultiindex_dimsZvalid_xyZvalid_xy_strr'   r'   r(   r~     s    r~   zIterable[float] | Nonezfloat | Noner   zAxes | Noner   )figsizerU   aspectaxsubplot_kwsrh   c                 K  s*  zdd l }dd lm} W n ty2   tdY n0 | d urr|d urLtd|d ur\td|j| |d\}}|S |d ur|d urtd|d u s|dkr|jd \}}	||	 }
n|d	krd
}
n|}
||
 |f} |j| |d\}}|S |d urtd|r|d urtd|d u r&tf i |}|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.   rC   rD   rL   rK   ZsubplotsrcParams
_maybe_gca)r   rU   r   r   r   r<   r   _widthheightZfaspectr'   r'   r(   get_axis  s>    

r   )r   rh   c                  K  s2   dd l m} | }|jr"| S |jf i | S Nr   )rC   rD   ZgcfZaxesZgca)r   r   fr'   r'   r(   r     s
    r   r   )darh   c                 C  sd   t dj}d}t| j|r,|t| jjS d| jv rF|| jd S d| jv r`|| jd S dS )z6Extracts and formats the unit/units from a attributes.pintz [{}]unitsunit )r   typerG   dataformatrJ   r   attrs)r   pint_array_typer   r'   r'   r(   _get_units_from_attrs  s    


r   r   DataArray | None)r   extrarh   c                 C  s   | du rdS d}d| j v r,|| j d }n8d| j v rH|| j d }n| jdur`|| 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.Nr   z{}Z	long_nameZstandard_name$r+   r   z$
$<   F)break_long_words
   )	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)rV   rh   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rl   re   r'   r'   r(   rn   "  ro   z+_interval_to_mid_points.<locals>.<listcomp>)r3   rV   )rV   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(   rn   +  ro   z-_interval_to_bound_points.<locals>.<listcomp>rO   )r3   rV   concatenateright)rV   Zarray_boundariesr'   r'   r(   _interval_to_bound_points%  s    r   r   ztuple[np.ndarray, np.ndarray])xarrayyarrayrh   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(   rn   :  ro   z4_interval_to_double_bound_points.<locals>.<listcomp>c                 S  s   g | ]
}|j qS r'   )r   r   r'   r'   r(   rn   ;  ro   )r3   rV   rH   	itertoolschainfrom_iterablezip)r   r   Zxarray1Zxarray2Z
xarray_outZ
yarray_outr'   r'   r(    _interval_to_double_bound_points1  s
    	r   r^   z-tuple[np.ndarray, np.ndarray, str, str, dict])xvalyvalkwargsrh   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Intervalr6   r   r   )r   r   r   Zx_suffixZy_suffixZremove_drawstyleZx_is_intervalZy_is_intervalr'   r'   r(   _resolve_intervals_1dplotC  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_2dplotp  s    
r   r   z'type[object] | tuple[type[object], ...])re   typesrh   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 rj   )rG   )rl   elr   r'   r(   r     ro   z$_valid_other_type.<locals>.<genexpr>)allr3   rS   )re   r   r'   r   r(   r     s    r   c                   s2   |D ]}t t j|rJ 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 rj   )r3   
issubdtypedtype)rl   tre   r'   r(   r     ro   z(_valid_numpy_subdtype.<locals>.<genexpr>)r3   r   Zgenericany)re   numpy_typesr   r'   r   r(   _valid_numpy_subdtype  s    r   rh   c                  G  s   t jt jt jt jt jt jf}ttf}t	du r0dnt	jf}||7 }| D ]b}t
t ||stt ||stdt |j dtt ||rDtrddl}qDtdqDd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.)r3   floatingintegerZtimedelta64Z
datetime64Zbool_Zstr_r	   r   cftimer   rY   r   r6   r   nc_time_axis_availabler   rL   )argsr   Zother_typesZcftime_datetime_typesre   r   r'   r'   r(   _ensure_plottable  s6    

r   c                 C  s   t jt jg}t| |S rj   )r3   r   r   r   )arrr   r'   r'   r(   _is_numeric  s    r   c                 C  sd   | d|d  |d u r&| d| n| d| t| drF|d | }|j| fi |}|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 us|d usJ |rJ|d u r4t | dt }|d u rt | t}nd|d u rt | jt jrfdnd}||k rtd|d|dn$|d u rd}||krtd|d	| d
| ||  d} t t 	| ddS )NrN      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)
r3   ZnanpercentilerW   r   r   r   rK   astypeZminimummaximum)rd   r%   r&   ra   r'   r'   r(   _rescale_imshow_rgb  s(    
r   zbool | Noner   zArrayLike | Noneztuple[float, float] | None)
r   	xincrease	yincreasexscaleyscalexticksyticksxlimylimrh   c	           	      C  s   |du r
n*|r |   r |   n|s4|   s4|   |du r>n*|rT|  rT|   n|sh|  sh|   |durz| | |dur| | |dur| | |dur| | |dur| | |du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
    ri   Tr*   axisr   N)shapetaker3   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.      ?rM   rO   c                 3  s(   | ] }| krt d dnt d V  qd S )NrO   )slice)rl   r   r   r'   r(   r   f  s   z)_infer_interval_breaks.<locals>.<genexpr>
   )r3   rY   r   rK   r   log10diffrU   rV   r   rI   rangeru   r   power)	r   r   ZscaleZcheck_monotonicZdeltasfirstlastZ	trim_lastZinterval_breaksr'   r   r(   _infer_interval_breaksA  s6    




$$
r  z4Iterable[tuple[str, Any]] | Mapping[str, Any] | Nonez%tuple[dict[str, Any], dict[str, Any]])r   rh   c           
        s  | j dkr(|d< fdddD i fS |du r4i nt|}d| j v rR|du rRd}|rb|rbtd	|rd| j vr|du rtd
t|ttfrtd|||r|n|| j dkd ttj} 	fdd|D  |stf i  }	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surfacer9   c                   s   i | ]}|  |d qS rj   r   rl   kr   r'   r(   
<dictcomp>  s   z-_process_cmap_cbar_kwargs.<locals>.<dictcomp>rP   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:   r9   r;   c                 3  s"   | ]}| v r| | fV  qd S rj   r'   rk   r
  r'   r(   r     ro   z,_process_cmap_cbar_kwargs.<locals>.<genexpr>c                   s   i | ]}| | qS r'   r'   r  )cmap_kwargsr'   r(   r    s   )
__name__r^   rK   rG   rH   rI   r
   rc   r   update)
funcr   r9   r1   r   r:   rb   r   Z	cmap_argsr   r'   )r  r   r(   _process_cmap_cbar_kwargsr  s>    




r  c                 C  sB   dd l }|jd}tt|  | }|d|d }|S )Nr   ri   )r.   rZ   r[   r3   meanhypotto_numpyr\   )ur   r<   rZ   r  Z	magnituder'   r'   r(   _get_nice_quiver_magnitude  s
    r  r1   r   c                 C  s   | S rj   r'   r   r'   r'   r(   <lambda>  ro   r  c                   s  ddl }ddl}|j}g }	g }
|dkrj }|du 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u r|r|jjddd}n6|du r$|s$|jd}nt|tr<|j|}|  |dkrdd}t||krdd}|rV| }| }|j|| |j|| |durt||jjr|}n<t|r|j |}n"t!|}|jj"||d g dd}|#||}||k||k@ }|| }t$| | d}||}t%|}t&||| || }n^|dur|st'|t!kr|j(|}ntd|#dt|d )t!}|| }|| }t*|dr|+| t,
 d - d}|.| t/||D ]\}}||\}}t|jj0r4|j.d1 d |d n&t|jj	rZ|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   Nr1   zfCollection without array used. Make sure to specify the values to be colormapped via the `c` argument.rU   zlines.markersizec                   s    |  fS rj   )r9   rQ   value)_sizeselfr'   r(   _get_color_and_size  s    z,legend_elements.<locals>._get_color_and_sizesizescolorr	  c                   s    t | fS rj   )r3   sqrtr  )_colorr'   r(   r  $  s    z?Valid values for `prop` are 'colors' or 'sizes'. You supplied 'r   FT)Z	useOffsetZuseMathTextz{x}r   	   r*   )r*   r+   g      @ri            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)5rx   r.   linesZ	get_arrayry   r   r   rG   collectionsZLineCollectionZget_linewidthsZ	get_sizesrK   r3   uniquerY   r   r   numberrZ   ZScalarFormatterZStrMethodFormatterrJ   Zcreate_dummy_axisr/   r!   r"   r   Zset_view_intervalZset_data_intervalLocatoriterableZFixedLocatorintr[   r\   rF   argsortZinterpr   r]   r   r   r'  r^   Z	get_alphar  r   ZPathCollection	get_pathsZget_linestyleLine2Dappend)r  propnumfmtr  r   rx   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  rU   hr'   )r!  r  r  r(   legend_elements  s    A







rA  c                 C  sR   ddl m} |rJt| dkrJ|jg g |d}|d |g|  } |g| }| |fS )z!Add a subtitle to legend handles.r   Nr*   )rs   F)rC   rD   r/   r4  Zset_visible)r9  r:  textr   Zblank_handler'   r'   r(   _legend_add_subtitle  s    


rC  c           	        s   ddl m   jdd}|  jjjd  } fdd|D }|D ]f}| }t	|dk rbqH|\}}| }t
dd |D sH|d | D ]}|dur|| qqHdS )	z@Make invisible-handle "subtitles" entries look more like titles.r   Nzlegend.title_fontsizec                   s    g | ]}t | jjjr|qS r'   )rG   r.   	offsetboxZHPackerr   r   r'   r(   rn     ro   z,_adjust_legend_subtitles.<locals>.<listcomp>r+   c                 s  s   | ]}|  V  qd S rj   )Zget_visible)rl   Zartistr'   r'   r(   r     ro   z+_adjust_legend_subtitles.<locals>.<genexpr>)rC   rD   r   r   Zfindobjr.   rD  ZVPackerZget_childrenr/   r   Z	set_widthZset_size)	legendZ	font_sizeZhpackersZhpackZareasZ	draw_areaZ	text_arear9  rB  r'   rE  r(   _adjust_legend_subtitles  s    
rG  c              	   C  s.  t | j }ddttdd |D  d}||vrPtd| d| d||vrntd	| d| d|d ur||vrtd
| d| d|rt| | j}	|d u r|	rdnd}|	s|dkrtd| |d u s|du r|dkrdnd}
|dkrdnd}nd}
d}n$|du r2|dvr2tdd}d}
|sJ|d u r|dkrd}|rd}
|snd}n|dkrtdnd}|s|d u r|dkr|rd}
|sd}n|dkrtd|d ur|dv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 rj   r   r   r'   r'   r(   r     ro   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.rK  zKhue_style must be 'continuous' or None for .plot.quiver or .plot.streamplotrL  )rJ  rI  z:hue_style must be either None, 'discrete' or 'continuous'.)add_colorbar
add_legendadd_quiverkey	hue_label	hue_styleZxlabelZylabelhue)
rv   	variableskeysr   rR   rI   rK   r   r;  r   )Zdsre   rf   rR  rQ  Z	add_guidefuncnameZdvars	error_msgZhue_is_numericrM  rN  rO  rP  r'   r'   r(   _infer_meta_data  sz    $




rW  z:tuple[float | None, float | None, bool] | Normalize | None)r   rQ   rh   c                 C  s   d S rj   r'   r   rQ   r'   r'   r(   _parse_size
  s    rY  	pd.Seriesc                 C  s   d S rj   r'   rX  r'   r'   r(   rY    s    zNone | pd.Seriesc                 C  s.  dd l }| d u rd S | j }t|sPt|}tddt| d d d }ntt| }}t	\}}}|d u r|j
 }n2t|tr|j
j| }nt||j
jsd}	t|	t||j
jsJ d|_| s|t| ||}
t||
||   }|
j rd||
j< tt||}t|S )Nr   r*   rO   z7``size_norm`` must be None, tuple, or Normalize object.T)r.   r;  flattenr   r3   r-  r   r/   sort_MARKERSIZE_RANGEr1   r   rG   rI   rK   ZclipZscaledrY   maskr   r^   r   r   Series)r   rQ   r<   Zflatdatar:   ZnumbersZ	min_widthZdefault_width	max_widtherrZsclwidthsr  r'   r'   r(   rY    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.
    r   _datar   _data_unique_data_unique_index_data_unique_inverser|   _data_is_numericz!tuple[float, float, float] | None_width)rd  re  rf  rg  rh  ri  NFr   )r   r   rb   rh   c                 C  s   || _ |s|nd | _tdj}t|d u r,|n|j|r>| n|}tj|dd\}}|| _	t
d|j| _|| _|d u r|dnt|| _d S )Nr   T)Zreturn_inverser   F)rd  ri  r   r   rG   r   r  r3   r-  re  r   rU   rf  rg  r   rh  )r  r   r   rb   r   Z	to_uniqueZdata_uniqueZdata_unique_inverser'   r'   r(   __init__d  s    

z_Normalize.__init__rJ   r   c                 C  sP   t jdddd, d| j d| j d| j W  d    S 1 sB0    Y  d S )Nrr   Tr#  )Z	precisionsuppress	thresholdz<_Normalize(data, width=z)>
z -> )r3   Zprintoptionsri  re  _values_uniquer  r'   r'   r(   __repr__y  s    
z_Normalize.__repr__r1  c                 C  s
   t | jS rj   )r/   re  rn  r'   r'   r(   __len__  s    z_Normalize.__len__c                 C  s
   | j | S rj   )re  )r  keyr'   r'   r(   __getitem__  s    z_Normalize.__getitem__c                 C  s   | j S rj   )rd  rn  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

        >>> # TODO: Datetime should be numeric right?
        >>> a = xr.DataArray(pd.date_range("2000-1-1", periods=4))
        >>> _Normalize(a).data_is_numeric
        False

        # TODO: Timedelta should be numeric right?
        >>> a = xr.DataArray(pd.timedelta_range("-1D", periods=4, freq="D"))
        >>> _Normalize(a).data_is_numeric
        True
        )rh  rn  r'   r'   r(   data_is_numeric  s    z_Normalize.data_is_numeric)rf   rh   c                 C  s   d S rj   r'   r  rf   r'   r'   r(   _calc_widths  s    z_Normalize._calc_widthsr   c                 C  s   d S rj   r'   rt  r'   r'   r(   ru    s    znp.ndarray | DataArrayc                 C  sj   | j du r|S | j \}}}t|t| }|dkrD|d|  }n"|t| | }||||   }|S )zI
        Normalize the values so they're in between self._width.
        Nr   )ri  r3   r"   r!   )r  rf   ZxminZxdefaultZxmaxZdiff_maxy_minyrb  r	  r'   r'   r(   ru    s    
)re   rh   c                 C  s   d S rj   r'   r  re   r'   r'   r(   _indexes_centered  s    z_Normalize._indexes_centeredc                 C  s   d S rj   r'   rv  r'   r'   r(   rw    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'   rv  r'   r'   r(   rw    s    c                 C  sJ   | j du rdS | jr| j }n$| | j}| j j|| j jd}| |S )ak  
        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)> Size: 40B
        array([3, 1, 1, 3, 5])
        Dimensions without coordinates: dim_0

        >>> _Normalize(a, width=(18, 36, 72)).values
        <xarray.DataArray (dim_0: 5)> Size: 40B
        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)> Size: 48B
        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)> Size: 48B
        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)> Size: 48B
        array([36., 36., 36., 36., 36., 36.])
        Dimensions without coordinates: dim_0

        N)r   )r   rs  rw  rg  copyZreshaper   ru  )r  r   r   r'   r'   r(   r;    s    #
z_Normalize.valuesznp.ndarray | Nonec                 C  s2   | j du 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   rs  re  rw  rf  ru  r  r   r'   r'   r(   rm    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)rs  rw  rf  ry  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+   )r3   r5  rf  r"   rn  r'   r'   r(   r:   -  s    z_Normalize.levelsrZ  c                 C  s*   | j d u rtdttt| j | jS )Nzself.data can't be None.)rm  rK   r   r_  r^   r   re  rn  r'   r'   r(   _lookup=  s    
z_Normalize._lookupc                 C  s   | j  j|dd S )NZnearest)method)r{  Z
sort_indexZreindexr  rv  r'   r'   r(   _lookup_arrD  s    z_Normalize._lookup_arrr   c                   s,   ddl m} 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'
        r   Nr   
None | Anyre   posc                   s     | gd  S r   r}  r  rn  r'   r(   _func`  s    z _Normalize.format.<locals>._func)N)rC   rD   r   )r  r   r  r'   rn  r(   r   K  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   r~  r  c                   s
     | S rj   r  r  rn  r'   r(   r  y  s    z_Normalize.func.<locals>._func)Nr'   )r  r  r'   rn  r(   r  e  s    z_Normalize.func)NF)r  
__module____qualname____doc____annotations__	__slots__rj  ro  rp  rr  propertyr   rs  r   ru  rw  r;  rm  rz  r:   r{  r}  r   r  r'   r'   r'   r(   rc  D  sV   
  .rc  zNone | boolz
str | Noneztuple[bool, bool])hueplt_normsizeplt_normrM  rN  plotfunc_namerh   c                 C  s   |dkrdS |r"| j d u r"td|d u r>| j d ur:d}nd}|r^| j d u r^|j d u r^td|d u r|s~| j d ur~| jdu s|j d u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   KeyErrorrs  )r  r  rM  rN  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 u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 )	Nr1   r  r   )r7  r  T)Zreturn_indexr   )Z
framealpha)rG   rH   r   rA  r  r3   r-  r2  tolistrV   rC  r   rF  rG  )r  r  r   Z	legend_axr  r9  r:  Z
huesizepltr6  hdlZlblpZhdl_Zlbl_r  r>  rF  r'   r'   r(   _add_legend  s*    





r  r   r'   z$MutableMapping[str, Hashable | None]ztuple[str, ...]ztuple[tuple[str, ...], ...]zMutableMapping[str, Hashable])rd   coords_to_plotr   default_guessignore_guess_kwargsrh   c           	        s   dd |  D  t fdd| j D }t|||D ]8\}}}||ddu r:tfdd|D r:|||< q:|  D ]\}}t| || q||S )u  
    Guess what coords to plot if some of the values in coords_to_plot are None which
    happens when the user has not defined all available ways of visualizing
    the data.

    Parameters
    ----------
    darray : DataArray
        The DataArray to check for available coords.
    coords_to_plot : MutableMapping[str, Hashable]
        Coords defined by the user to plot.
    kwargs : dict
        Extra kwargs that will be sent to matplotlib.
    default_guess : Iterable[str], optional
        Default values and order to retrieve dims if values in dims_plot is
        missing, default: ("x", "hue", "size").
    ignore_guess_kwargs : tuple[tuple[str, ...], ...]
        Matplotlib arguments to ignore.

    Examples
    --------
    >>> ds = xr.tutorial.scatter_example_dataset(seed=42)
    >>> # Only guess x by default:
    >>> xr.plot.utils._guess_coords_to_plot(
    ...     ds.A,
    ...     coords_to_plot={"x": None, "z": None, "hue": None, "size": None},
    ...     kwargs={},
    ... )
    {'x': 'x', 'z': None, 'hue': None, 'size': None}

    >>> # Guess all plot dims with other default values:
    >>> xr.plot.utils._guess_coords_to_plot(
    ...     ds.A,
    ...     coords_to_plot={"x": None, "z": None, "hue": None, "size": None},
    ...     kwargs={},
    ...     default_guess=("x", "hue", "size"),
    ...     ignore_guess_kwargs=((), ("c", "color"), ("s",)),
    ... )
    {'x': 'x', 'z': None, 'hue': 'y', 'size': 'z'}

    >>> # Don't guess ´size´, since the matplotlib kwarg ´s´ has been defined:
    >>> xr.plot.utils._guess_coords_to_plot(
    ...     ds.A,
    ...     coords_to_plot={"x": None, "z": None, "hue": None, "size": None},
    ...     kwargs={"s": 5},
    ...     default_guess=("x", "hue", "size"),
    ...     ignore_guess_kwargs=((), ("c", "color"), ("s",)),
    ... )
    {'x': 'x', 'z': None, 'hue': 'y', 'size': None}

    >>> # Prioritize ´size´ over ´s´:
    >>> xr.plot.utils._guess_coords_to_plot(
    ...     ds.A,
    ...     coords_to_plot={"x": None, "z": None, "hue": None, "size": "x"},
    ...     kwargs={"s": 5},
    ...     default_guess=("x", "hue", "size"),
    ...     ignore_guess_kwargs=((), ("c", "color"), ("s",)),
    ... )
    {'x': 'y', 'z': None, 'hue': 'z', 'size': 'x'}
    c                 S  s   i | ]\}}|d ur||qS rj   r'   )rl   r	  r   r'   r'   r(   r    ro   z)_guess_coords_to_plot.<locals>.<dictcomp>c                 3  s   | ]}|   vr|V  qd S rj   )r;  r  )coords_to_plot_existr'   r(   r     s   z(_guess_coords_to_plot.<locals>.<genexpr>Nc                 3  s   | ]}  |d d u V  qd S rj   r  )rl   Zign_kwr
  r'   r(   r     s   )itemsrI   r   rT  r   r   r   r~   )	rd   r  r   r  r  Zavailable_coordsr	  r   Zign_kwsr'   )r  r   r(   _guess_coords_to_plot  s    D
r  re   zLiteral['x', 'y', 'z'])r   r   rh   c                 C  sF   ddl m} | }||}t| | d}|| || dS )a  
    Use ConciseDateFormatter which is meant to improve the
    strings chosen for the ticklabels, and to minimize the
    strings used in those tick labels as much as possible.

    https://matplotlib.org/stable/gallery/ticks/date_concise_formatter.html

    Parameters
    ----------
    ax : Axes
        Figure axes.
    axis : Literal["x", "y", "z"], optional
        Which axis to make concise. The default is "x".
    r   Nr   )Zmatplotlib.datesdatesZAutoDateLocatorZConciseDateFormatterr2   Zset_major_locatorZset_major_formatter)r   r   Zmdateslocator	formatterZ_axisr'   r'   r(   _set_concise_date"  s    

r  )
NNNNFNNTNF)FN)NNNN)r   )NNNNNN)r   )r   NF)NNNNF)NNN)r   r  )re   )`
__future__r   r   r   rx   collections.abcr   r   r   r   r   r	   r   inspectr
   typingr   r   r   r   r   numpyr3   Zpandasr   Zxarray.core.indexesr   Zxarray.core.optionsr   Zxarray.core.utilsr   r   Zxarray.namedarray.pycompatr   r   r   rL   Zmatplotlib.axesr   rE   r   Zmatplotlib.tickerr   Znumpy.typingr   Zxarray.core.dataarrayr   Zxarray.core.datasetr   Zxarray.core.typesr   r   rC   rD   r   r  rW   r]  Z_LINEWIDTH_RANGEr)   r@   r0   rc   r{   rz   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  rA  rC  rG  rW  rY  rc  r  r  r  r  r'   r'   r'   r(   <module>   s   
6'          
 !B  (    /	-	-%      "1

4     H
 DS+  @   !-  Y