o
    si&x                     @   s  d Z ddlmZ ddlmZ ddl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mZmZ dd
lmZmZ ddlmZ ddlmZmZ e Zd0ddZ						d1ddZ							d2ddZ G dd deZ!d0ddZ"						d3ddZ#	d4ddZ$	d4ddZ%d5d d!Z&	"		#			$	%	d6d&d'Z'd(d) Z(d*d+ Z)d7d,d-Z*d7d.d/Z+ee(Z,ee)Z-dS )8zDisplay functions    )defaultdict)WeakKeyDictionaryN)spectrogram)	Rectangle)FuncFormatterMultipleLocator)	Formatter)LinearSegmentedColormapLogNormColorConverter)BboxTransformedBbox   )freq_to_voicing)
midi_to_hz
hz_to_midic                 C   sV   d}| du r|du rddl m} | }| sd}| } | tvr't t| < | |fS )a{  Get or construct the target axes object for a new plot.

    Parameters
    ----------
    ax : matplotlib.pyplot.axes, optional
        If provided, return this axes object directly.

    fig : matplotlib.figure.Figure, optional
        The figure to query for axes.

        By default, uses the current figure `plt.gcf()`.

    Returns
    -------
    ax : matplotlib.pyplot.axes
        An axis handle on which to draw the segmentation.
        If none is provided, a new set of axes is created.
    new_axes : bool
        If `True`, the axis object was newly constructed.
        If `False`, the axis object already existed.
    FNr   T)matplotlib.pyplotpyplotgcfget_axesgca__AXMAPdict)axfignew_axesplt r   D/home/ubuntu/.local/lib/python3.10/site-packages/mir_eval/display.py
__get_axes   s   
r   Fc              	   K   s^  |du rt  }|dd |dd |dt ddd	 t| } t d
d}	t|d\}}
|du rKt| dtjd  t| dttjd  ndt| vr_|t| d< t|t| d< t| d }t| d }|
rr|	g  |du r|du rd\}}|
 }n|dur|durd}ntdt  }|D ]V}||v rqzt|}W n ty   t|}|t| d< t|}Y nw dd | D }|d|d  |dd |	 ||< || | || | ||| d< qt| |D ]9\}}|j|d |d
 f||d|| }|| dd |r,|j|f|d |f|ddd|}|| q|S )aU  Plot a segmentation as a set of disjoint rectangles.

    Parameters
    ----------
    intervals : np.ndarray, shape=(n, 2)
        segment intervals, in the format returned by
        :func:`mir_eval.io.load_intervals` or
        :func:`mir_eval.io.load_labeled_intervals`.
    labels : list, shape=(n,)
        reference segment labels, in the format returned by
        :func:`mir_eval.io.load_labeled_intervals`.
    base : number
        The vertical position of the base of the rectangles.
        By default, this will be the bottom of the plot.
    height : number
        The height of the rectangles.
        By default, this will be the top of the plot (minus ``base``).
        .. note:: If either `base` or `height` are provided, both must be provided.
    text : bool
        If true, each segment's label is displayed in its
        upper-left corner
    text_kw : dict
        If ``text == True``, the properties of the text
        object can be specified here.
        See ``matplotlib.pyplot.Text`` for valid parameters
    ax : matplotlib.pyplot.axes
        An axis handle on which to draw the segmentation.
        If none is provided, a new set of axes is created.
    prop_cycle : cycle.Cycler
        An optional property cycle object to specify style properties.
        If not provided, the default property cycler will be retrieved from matplotlib.
    **kwargs
        Additional keyword arguments to pass to
        ``matplotlib.patches.Rectangle``.

    Returns
    -------
    ax : matplotlib.pyplot.axes._subplots.AxesSubplot
        A handle to the (possibly constructed) plot axes
    Nvatopclip_onTbboxroundwhiteboxstyle	facecolorr   	linewidthr   
prop_cycleaxes.prop_cycle	prop_iterr   r   6When specifying base or height, both must be provided.c                 S      i | ]\}}|d v r||qS )colorr(   	edgecolorr*   r   .0kvr   r   r   
<dictcomp>   
    zsegments.<locals>.<dictcomp>r(   r3   labelr   )yminymax   ioffset pointsxyxycoordsxytext
textcoords)r   
setdefaultnp
atleast_2dr   r   mplrcParamsiter
set_yticksget_xaxis_transform
ValueErrornextStopIterationitemspopcopyupdatezipaxvspanannotateset_clip_path)	intervalslabelsbaseheighttexttext_kwr   r,   kwargsseg_def_styler   r.   	transformseg_maplab
propertiesstyleivalrectannr   r   r   segmentsB   sz   3



&

ri   Tc	                 K   s  t |d\}}
|du r$t| dtjd  t| dttjd  ndt| vr8|t| d< t|t| d< t| d }t| d }t| } |du rVt| dg }nt	|}d}|rw|t
t|t|  }||krvt|dkrvd	}n|r||}nt
t|}|t| d< td
d}zt|}W n ty   t|}|t| d< t|}Y nw dd | D }|d|d  |dd ||	 |du rtt|}|du rd
}t|r|t| }t }t|||D ]\}}}||f||< qtt	}t| |D ]\}}||vrq|| |d |d
 |d  f q|D ]}|j|| || fi | |dd q"|rG|jt|ddd |rk|jd	dd |g  || |j|dd |jt || |S )ab  Plot labeled intervals with each label on its own row.

    Parameters
    ----------
    intervals : np.ndarray, shape=(n, 2)
        segment intervals, in the format returned by
        :func:`mir_eval.io.load_intervals` or
        :func:`mir_eval.io.load_labeled_intervals`.

    labels : list, shape=(n,)
        reference segment labels, in the format returned by
        :func:`mir_eval.io.load_labeled_intervals`.

    label_set : list
        An (ordered) list of labels to determine the plotting order.
        If not provided, the labels will be inferred from
        ``ax.get_yticklabels()``.
        If no ``yticklabels`` exist, then the sorted set of unique values
        in ``labels`` is taken as the label set.

    base : np.ndarray, shape=(n,), optional
        Vertical positions of each label.
        By default, labels are positioned at integers
        ``np.arange(len(labels))``.

    height : scalar or np.ndarray, shape=(n,), optional
        Height for each label.
        If scalar, the same value is applied to all labels.
        By default, each label has ``height=1``.

    extend_labels : bool
        If ``False``, only values of ``labels`` that also exist in
        ``label_set`` will be shown.

        If ``True``, all labels are shown, with those in `labels` but
        not in `label_set` appended to the top of the plot.
        A horizontal line is drawn to indicate the separation between
        values in or out of ``label_set``.

    ax : matplotlib.pyplot.axes
        An axis handle on which to draw the intervals.
        If none is provided, a new set of axes is created.

    tick : bool
        If ``True``, sets tick positions and labels on the y-axis.

    prop_cycle : cycle.Cycler
        An optional property cycle object to specify style properties.
        If not provided, the default property cycler will be retrieved from matplotlib.

    **kwargs
        Additional keyword arguments to pass to
        `matplotlib.collection.PolyCollection`.

    Returns
    -------
    ax : matplotlib.pyplot.axes._subplots.AxesSubplot
        A handle to the (possibly constructed) plot axes
    r+   Nr,   r-   r.   rZ   Fr   Tr   r)   c                 S   r1   r2   r   r5   r   r   r   r9   ;  r:   z%labeled_intervals.<locals>.<dictcomp>r(   r3   r;   r7         ?)r3   alphay)axisbottom)r    )!r   r   rF   rI   rJ   rK   rG   rH   getlistsortedsetlenr   rO   rP   rQ   rR   rT   arangeisscalar	ones_likerU   r   appendbroken_barhaxhlinegridrL   set_yticklabelsyaxisset_major_formatterIntervalFormatter)rY   rZ   	label_setr[   r\   extend_labelsr   tickr,   r_   r   r.   extendedticksre   rd   seg_yybaseyheightrc   xvalsrf   r   r   r   labeled_intervals   s~   H




&

r   c                   @   s"   e Zd ZdZdd ZdddZdS )r~   zTicker formatter for labeled interval plots.

    Parameters
    ----------
    base : array-like of int
        The base positions of each label

    ticks : array-like of string
        The labels for the ticks
    c                 C   s   dd t ||D | _d S )Nc                 S   s   i | ]	\}}t ||qS r   )intr5   r   r   r   r9   y  s    z.IntervalFormatter.__init__.<locals>.<dictcomp>)rU   _map)selfr[   r   r   r   r   __init__x  s   zIntervalFormatter.__init__Nc                 C   s   | j t|dS )z:Map the input position to its corresponding interval label )r   ro   r   )r   xposr   r   r   __call__{  s   zIntervalFormatter.__call__N)__name__
__module____qualname____doc__r   r   r   r   r   r   r~   l  s    r~   c           
      K   s   |du rt tt| }t|d\}}t|j}t| ddd |ddd |ddd D ]\}}}	t||f|	|d| q-|S )ap  Plot a hierarchical segmentation

    Parameters
    ----------
    intervals_hier : list of np.ndarray
        A list of segmentation intervals.  Each element should be
        an n-by-2 array of segment intervals, in the format returned by
        :func:`mir_eval.io.load_intervals` or
        :func:`mir_eval.io.load_labeled_intervals`.
        Segmentations should be ordered by increasing specificity.
    labels_hier : list of list-like
        A list of segmentation labels.  Each element should
        be a list of labels for the corresponding element in
        `intervals_hier`.
    levels : list of string
        Each element ``levels[i]`` is a label for the ```i`` th segmentation.
        This is used in the legend to denote the levels in a segment hierarchy.
    ax : matplotlib.pyplot.axes
        An axis handle on which to draw the intervals.
        If none is provided, a new set of axes is created.
    **kwargs
        Additional keyword arguments to `labeled_intervals`.

    Returns
    -------
    ax : matplotlib.pyplot.axes._subplots.AxesSubplot
        A handle to the (possibly constructed) plot axes
    Nr+   )r;   r   )rp   rangers   r   patchesrU   r   )
intervals_hierlabels_hierlevelsr   r_   _	n_patchesintslabskeyr   r   r   	hierarchy  s   
4r   c                 K   s  |du rt  }|dd |dd |dt ddd	 t| } t|d
\}}|du rFt| dtjd  t| dttjd  ndt| vrZ|t| d< t|t| d< t| d }t| d }	|du rw|du rwd\}}|	 }
n|dur|durd}
nt
dzt|	}W n ty   t|}	|	t| d< t|	}Y nw dd | D }|| d|v r|dd |j| ||| fd|
i|}|rt| |D ]\}}|j|f|jd d |f|
ddd| q|r|g  |S )a  Plot event times as a set of vertical lines

    Parameters
    ----------
    times : np.ndarray, shape=(n,)
        event times, in the format returned by
        :func:`mir_eval.io.load_events` or
        :func:`mir_eval.io.load_labeled_events`.
    labels : list, shape=(n,), optional
        event labels, in the format returned by
        :func:`mir_eval.io.load_labeled_events`.
    base : number
        The vertical position of the base of the line.
        By default, this will be the bottom of the plot.
    height : number
        The height of the lines.
        By default, this will be the top of the plot (minus `base`).
        .. note:: If either `base` or `height` are provided, both must be provided.
    ax : matplotlib.pyplot.axes
        An axis handle on which to draw the segmentation.
        If none is provided, a new set of axes is created.
    text_kw : dict
        If `labels` is provided, the properties of the text
        objects can be specified here.
        See `matplotlib.pyplot.Text` for valid parameters
    prop_cycle : cycle.Cycler
        An optional property cycle object to specify style properties.
        If not provided, the default property cycler will be retrieved from matplotlib.
    **kwargs
        Additional keyword arguments to pass to
        `matplotlib.pyplot.vlines`.

    Returns
    -------
    ax : matplotlib.pyplot.axes._subplots.AxesSubplot
        A handle to the (possibly constructed) plot axes
    Nr    r!   r"   Tr#   r$   r%   r&   r+   r,   r-   r.   r/   r0   c                 S   r1   ))r3   	linestyler*   r   r5   r   r   r   r9     s    zevents.<locals>.<dictcomp>colorsr3   ra   r   r>   r@   rA   )r   rF   rG   asarrayr   r   rI   rJ   rK   rM   rN   rO   rP   rQ   rT   rR   vlinesrU   	get_pathsrW   verticesrL   )timesrZ   r[   r\   r   r^   r,   r_   r   r.   ra   rd   re   linespathrc   r   r   r   events  sd   /


	
r   c                 K   s8  t |d\}}|du r$t| dtjd  t| dttjd  ndt| vr8|t| d< t|t| d< t| d }t| d }t| } ttj|tj	d\}}	|	
t}	dt|	dd |	dd k }
ttd	g|
t|	gg}
g g }}t|
|
dd D ]\}}t||}|	| r|| q||  r|| qzt|}W n ty   t|}|t| d< t|}Y nw || |r|d	k}t|| ||< |jtd |D ]}|j| | || fi | |d
d q|r|ddd |d< |D ]}|j| | || fi | q|S )a  Visualize pitch contours

    Parameters
    ----------
    times : np.ndarray, shape=(n,)
        Sample times of frequencies

    frequencies : np.ndarray, shape=(n,)
        frequencies (in Hz) of the pitch contours.
        Voicing is indicated by sign (positive for voiced,
        non-positive for non-voiced).

    midi : bool
        If `True`, plot on a MIDI-numbered vertical axis.
        Otherwise, plot on a linear frequency axis.

    unvoiced : bool
        If `True`, unvoiced pitch contours are plotted and indicated
        by transparency.

        Otherwise, unvoiced pitch contours are omitted from the display.

    ax : matplotlib.pyplot.axes
        An axis handle on which to draw the pitch contours.
        If none is provided, a new set of axes is created.

    prop_cycle : cycle.Cycler
        An optional property cycle object to specify style properties.
        If not provided, the default property cycler will be retrieved from matplotlib.

    **kwargs
        Additional keyword arguments to `matplotlib.pyplot.plot`.

    Returns
    -------
    ax : matplotlib.pyplot.axes._subplots.AxesSubplot
        A handle to the (possibly constructed) plot axes
    r+   Nr,   r-   r.   dtyper   r   r   r;   rk         ?rj   )r   r   rF   rI   rJ   rK   rG   r   r   float64astypeboolflatnonzerouniqueconcatenaters   rU   slicerw   allrO   rP   rT   r   r|   set_minor_locatorr   plotrR   ro   )r   frequenciesmidiunvoicedr   r,   r_   r   r.   voicings	v_changesv_slicesu_slicesstartendidxre   r   r   r   pitch!  sT   )

"



 r   c                 K   s  t |d\}}|du r$t| dtjd  t| dttjd  ndt| vr8|t| d< t|t| d< t| d }t| d }zt|}	W n tya   t|}|t| d< t|}	Y nw |	| |		 }
|

dd |
ddd	 |
d< g }g }g }g }t| |D ]S\}}t|sqttj|tjd
\}}|dk}|| }|| t}|rt|}t|}||gt|  |||  ||gt||   |||   q|j||fi |	 |r|j||fi |
 |r|jtd |S )a  Visualize multiple f0 measurements

    Parameters
    ----------
    times : np.ndarray, shape=(n,)
        Sample times of frequencies

    frequencies : list of np.ndarray
        frequencies (in Hz) of the pitch measurements.
        Voicing is indicated by sign (positive for voiced,
        non-positive for non-voiced).

        `times` and `frequencies` should be in the format produced by
        :func:`mir_eval.io.load_ragged_time_series`

    midi : bool
        If `True`, plot on a MIDI-numbered vertical axis.
        Otherwise, plot on a linear frequency axis.

    unvoiced : bool
        If `True`, unvoiced pitches are plotted and indicated
        by transparency.

        Otherwise, unvoiced pitches are omitted from the display.

    ax : matplotlib.pyplot.axes
        An axis handle on which to draw the pitch contours.
        If none is provided, a new set of axes is created.

    prop_cycle : cycle.Cycler
        An optional property cycle object to specify style properties.
        If not provided, the default property cycler will be retrieved from matplotlib.

    **kwargs
        Additional keyword arguments to `plt.scatter`.

    Returns
    -------
    ax : matplotlib.pyplot.axes._subplots.AxesSubplot
        A handle to the (possibly constructed) plot axes
    r+   Nr,   r-   r.   r;   rk   r   rj   r   r   r   )r   r   rF   rI   rJ   rK   rO   rP   rT   rS   rR   ro   rU   rs   r   rG   r   r   r   r   r   sumextendr   scatterr|   r   r   )r   r   r   r   r   r,   r_   r   r.   style_voicedstyle_unvoicedvoiced_timesvoiced_freqsunvoiced_timesunvoiced_freqstfreqsr   r   n_voicedr   r   r   
multipitch  sX   -
r   c                 K   sd   |du r|du rt dt|}td}t| t|tf|d|d|}|j	t
d |S )a  Plot a quantized piano roll as intervals

    Parameters
    ----------
    intervals : np.ndarray, shape=(n, 2)
        timing intervals for notes

    pitches : np.ndarray, shape=(n,), optional
        pitches of notes (in Hz).

    midi : np.ndarray, shape=(n,), optional
        pitches of notes (in MIDI numbers).

        At least one of ``pitches`` or ``midi`` must be provided.

    ax : matplotlib.pyplot.axes
        An axis handle on which to draw the intervals.
        If none is provided, a new set of axes is created.

    **kwargs
        Additional keyword arguments to :func:`labeled_intervals`.

    Returns
    -------
    ax : matplotlib.pyplot.axes._subplots.AxesSubplot
        A handle to the (possibly constructed) plot axes
    Nz5At least one of `midi` or `pitches` must be provided.   F)r   r   r   r   )rN   r   rG   rt   r   r$   r   r   r|   r   r   )rY   pitchesr   r   r_   scaler   r   r   
piano_roll  s"   

r   "V        ?Nonegouraudc	                 K   s  t |d\}}
t| } |du rdd tt| D }|	dd d}g }t| D ]#\}}t|fd|i|	\}}}|| |du rH|	 }q)||7 }q)|
 }|d }t }|du rut| d	tjd
  t| dttjd
  ndt| vr|t| d	< t|t| d< t| d	 }t| d }t|D ]Z\}}zt|}W n ty   t|}|t| d< t|}Y nw |j|d |d}t|| d|g}|j||||t||d|||d |t| | fdd||| d q|S )a  Source-separation visualization

    Parameters
    ----------
    sources : np.ndarray, shape=(nsrc, nsampl)
        A list of waveform buffers corresponding to each source
    fs : number > 0
        The sampling rate
    labels : list of strings
        An optional list of descriptors corresponding to each source
    alpha : float in [0, 1]
        Maximum alpha (opacity) of spectrogram values.
    ax : matplotlib.pyplot.axes
        An axis handle on which to draw the spectrograms.
        If none is provided, a new set of axes is created.
    rasterized : bool
        If `True`, the spectrogram is rasterized.
    edgecolors : str or None
        The color of the edges of the spectrogram patches.
        Set to "None" (default) to disable edge coloring.
    shading : str
        The shading method to use for the spectrogram.
        See `matplotlib.pyplot.pcolormesh` for valid options.
    prop_cycle : cycle.Cycler
        An optional property cycle object to specify colors for each signal.
        If not provided, the default property cycler will be retrieved from matplotlib.
    **kwargs
        Additional keyword arguments to ``scipy.signal.spectrogram``

    Returns
    -------
    ax
        The axis handle for this plot
    r+   Nc                 S   s   g | ]}d |dqS )zSource dr   )r6   r   r   r   r   
<listcomp>^  s    zseparation.<locals>.<listcomp>scalingspectrumfsgư>r,   r-   r.   r3   )rk   )r   r   r   g        )vminvmax)cmapnorm
rasterized
edgecolorsshadingr   )r3   r;   )r   rG   rH   r   rs   rF   	enumerater   rw   rS   maxr   r   rI   rJ   rK   rO   rP   to_rgbar	   	from_list
pcolormeshr
   	add_patchr   min)sourcesr   rZ   rk   r   r   r   r   r,   r_   r   cumspecspecsisrcr   r   specref_maxref_min
color_convr.   rd   r3   r   r   r   r   
separation)  sd   /




 r   c                 C   s   g d}t t| d}|dkr|d }| d } t| d }t| d d }|dkr4|| d|dS || d|dt|d	 d
S )zFormat midi notes for ticker decoration.

    Inputs x are interpreted as midi numbers, and converted
    to [NOTE][OCTAVE]+[cents].
    )CzC#DzD#EFzF#GzG#AzA#Br   rj      r   r   s2dd   z+02d)floatrG   modr   )r   r   NOTEScentsr   octaver   r   r   __ticker_midi_note  s   "r  c                 C   s   t | dS )zwFormat midi pitches for ticker decoration.

    Inputs x are interpreted as midi numbers, and converted
    to Hz.
    g)r   )r   r   r   r   r   __ticker_midi_hz  s   r  c                 C   s8   t | d\} }| jt | j D ]}|d qdS )zSet the y-axis of the given axes to MIDI notes

    Parameters
    ----------
    ax : matplotlib.pyplot.axes
        The axes handle to apply the ticker.
        By default, uses the current axes handle.

    r+   baselineN)r   r|   r}   FMT_MIDI_NOTEget_ticklabelsset_verticalalignment)r   r   r   r   r   r   ticker_notes  s
   
r  c                 C   s   t | d\} }| jt dS )zSet the y-axis of the given axes to MIDI frequencies

    Parameters
    ----------
    ax : matplotlib.pyplot.axes
        The axes handle to apply the ticker.
        By default, uses the current axes handle.
    r+   N)r   r|   r}   FMT_MIDI_HZ)r   r   r   r   r   ticker_pitch  s   	r  )NN)NNFNNN)NNNTNTN)NNNNNN)FFNN)NNN)r   Nr   NTr   r   Nr   ).r   collectionsr   weakrefr   numpyrG   scipy.signalr   
matplotlibrI   matplotlib.patchesr   matplotlib.tickerr   r   r   matplotlib.colorsr	   r
   r   matplotlib.transformsr   r   melodyr   utilr   r   r   r   ri   r   r~   r   r   r   r   r   r   r  r  r  r  r
  r  r   r   r   r   <module>   sz    
,
 
 '
/
u
h

o4
{
	
