
    rh0                   "   S r SSKJr  SSKrSSKrSSKrSSKrSSKrSSK	r	SSK
Jr  SSK
Jr  SSK
Jr  SSK
Jr  SSKJr  SS	KJr  SS
KJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJrJ r   \RB                  " S5      r" " S S\RF                  5      r$ " S S\RJ                  \$5      r& " S S\RN                  \$5      r( " S S\(5      r) " S S \)5      r* " S! S"\(5      r+ " S# S$\(5      r, " S% S&\RZ                  \$5      r. " S' S(\.5      r/ " S) S*\.5      r0 " S+ S,\.5      r1 " S- S.\Rd                  \$5      r3 " S/ S0\35      r4 " S1 S2\35      r5 " S3 S4\35      r6 " S5 S6\Rn                  \$5      r8 " S7 S8\85      r9 " S9 S:\85      r: " S; S<\Rv                  \$5      r< " S= S>\<5      r= " S? S@\<5      r> " SA SB\R~                  \$5      r@ " SC SD\@5      rA " SE SF\R                  \$5      rC " SG SH\C5      rD " SI SJ\R                  \$5      rF " SK SL\F5      rG " SM SN\	R                  5      rI " SO SP\	R                  5      rJ\/\0\1\9\:\)\*\+\,\>\=\A\4\5\6\D/rK\LSQ:X  a  SSKr\R                  " \J5        gg)Ra!  
Object definitions for plotting :class:`~music21.stream.Stream` objects.

The :class:`~music21.graph.plot.PlotStream`
object subclasses combine a Graph object with the PlotStreamMixin to give
reusable approaches to graphing data and structures in
:class:`~music21.stream.Stream` objects.
    )annotationsN)	correlate)discrete)	reduction)windowed)base)chord)common)corpus)	converter)dynamics)environment)features)note)prebase)stream)axis)
primitives)GraphExceptionPlotStreamExceptionz
graph.plotc                      \ rS rSr% Sr\R                  \R                  S.rS\S'   SS jr	SS	 jr
\S
 5       rSS.SS jjrS rS rSS jr        SS jrS r\S 5       rS r\SS j5       r\S 5       rSrg)PlotStreamMixin=   z^
This Mixin adds Stream extracting and Axis holding features to any
class derived from Graph.
xydict[str, type[axis.Axis]]axesClassesNTc                6   Ub  [        US5      (       d  [        SU 35      eXl        X l        SS/U l        SU l        S U l        U R                  R                  5        H0  u  pEUc  M
  U" X5      n[        U SUR                  5       -   U5        M2     X0l        g )Nelementsz!non-stream provided as argument: NoteChordTr   )hasattrr   	streamObjrecurseclassFilterListmatchPitchCountForChordsdatar   itemssetattruppersavedKeywords)selfr$   r%   keywordsaxisName	axisClassaxisObjs          L/home/james-whalen/.local/lib/python3.13/site-packages/music21/graph/plot.py__init__PlotStreamMixin.__init__D   s     J)G)G%(I)&UVV" &0(,%	#'#3#3#9#9#;H$#D3fx~~'77A $<
 &    c                F    U R                   nUb  [        U5      nOSnSU 3$ )a  
The representation of the Plot shows the stream repr
in addition to the class name.

>>> st = stream.Stream()
>>> st.id = 'empty'
>>> plot = graph.plot.ScatterPitchClassQuarterLength(st)
>>> plot
<music21.graph.plot.ScatterPitchClassQuarterLength for <music21.stream.Stream empty>>

>>> plot = graph.plot.ScatterPitchClassQuarterLength(None)
>>> plot
<music21.graph.plot.ScatterPitchClassQuarterLength for (no stream)>

>>> plot.axisX
<music21.graph.axis.QuarterLengthAxis: x axis for ScatterPitchClassQuarterLength>

>>> plot.axisY
<music21.graph.axis.PitchClassAxis: y axis for ScatterPitchClassQuarterLength>

>>> axIsolated = graph.axis.DynamicsAxis(axisName='z')
>>> axIsolated
<music21.graph.axis.DynamicsAxis: z axis for (no client)>
z(no stream)zfor )r$   repr)r-   s
streamNames      r2   _reprInternalPlotStreamMixin._reprInternalV   s-    4 NN=aJ&Jj\""r5   c                t    / nS H/  n[        X5      (       d  M  UR                  [        X5      5        M1     U$ )aA  
return a list of axisX, axisY, axisZ if any are defined in the class.

Some might be None.

>>> s = stream.Stream()
>>> p = graph.plot.ScatterPitchClassOffset(s)
>>> p.allAxes
[<music21.graph.axis.OffsetAxis: x axis for ScatterPitchClassOffset>,
 <music21.graph.axis.PitchClassAxis: y axis for ScatterPitchClassOffset>]
)axisXaxisYaxisZ)r#   appendgetattr)r-   allAxesListr/   s      r2   allAxesPlotStreamMixin.allAxesx   s9     3Ht&&""74#:; 4 r5   callProcessc                  [         R                  (       a-  SSKJn  [	        X5      (       a  [	        U [
        5      (       d   eU R                  5         U R                  5         [        U S5      (       aa  U R                  (       aP  U R                  SU R                  R                  5       5        U R                  SU R                  R                  5        [        U S5      (       aa  U R                  (       aP  U R                  SU R                  R                  5       5        U R                  SU R                  R                  5        U(       a  U R                  5         gg)z
main routine to extract data, set axis labels, run process() on the underlying
Graph object, and if self.doneAction is not None, either write or show the graph.
r   )Graphr>   r   r=   r   N)tTYPE_CHECKINGmusic21.graph.primitivesrH   
isinstancer   setAxisKeywordsextractDatar#   r>   setTickstickssetAxisLabellabelr=   process)r-   rF   r.   rH   s       r2   runPlotStreamMixin.run   s    
 ??6d**z$/P/PPP4!!djjMM#tzz//12c4::#3#344!!djjMM#tzz//12c4::#3#34LLN r5   c                L   U R                    H  nUc  M  UR                  nU R                   Hp  nUR                  U5      (       d  M  [	        U5      S:  a  M,  US   R                  5       USS -   n[        X5      (       d  MW  [        XU R                  U   5        Mr     M     g)a  
Configure axis parameters based on keywords given when creating the Plot.

Looks in self.savedKeywords, in case any post creation manipulation needs
to happen.

Finds keywords that begin with x, y, z and sets the remainder of the
keyword (lowercasing the first letter) as an attribute.  Does not
set any new attributes, only existing ones.

>>> b = corpus.parse('bwv66.6')
>>> hist = graph.plot.HistogramPitchSpace(b, xHideUnused=False)
>>> hist.axisX.hideUnused
True
>>> hist.setAxisKeywords()
>>> hist.axisX.hideUnused
False
N         )rC   r/   r,   
startswithlenlowerr#   r*   )r-   thisAxisthisAxisLetterkwshortKws        r2   rM   PlotStreamMixin.setAxisKeywords   s    & H%..N((}}^44r7Q;Q%++-"QR&0x114+=+=b+AB )	 %r5   c                b   S U R                   ;   a  [        S5      eU R                  (       a  U R                  R                  5       nOU R                  R	                  5       nU R
                  (       a  UR                  U R
                  5      n/ U l        U H4  nU R                  U5      nUc  M  U R                  R                  U5        M6     U R                  5         [        U R                   5       H3  u  pEUR                  U R                   Vs/ s H  ofU   PM	     sn5        M5     g s  snf )Nz3Set all axes before calling extractData() via run())rC   r   r%   r$   iterr&   getElementsByClassr(   processOneElementextendpostProcessData	enumeratesetBoundariesFromData)r-   sItereldataListir]   ds          r2   rN   PlotStreamMixin.extractData   s    4<<%&[\\<<NN**,ENN'')E,,T-A-ABE	B--b1H#		  * 
 	$T\\2KA**$))+D)QaD)+DE 3+Ds   D,
c                   [        [        U R                  5      5       Vs/ s H  n/ PM     nn0 n[        U[        R
                  5      (       dO  [        U R                  5       H5  u  pVUR                  X5      n[        U[        5      (       d  Ub  U/nXsU'   M7     OU R                  X5      nU R                  " X/UQ76   SU;   a  g[        U Vs/ s H  n[        U5      PM     sn5      n	[        U	5       Vs/ s H  o$R                  5       PM     n
nUR                  U
5        [        [        U6 5      nU$ s  snf s  snf s  snf )a^  
Get a list of data from a single element (generally a Note or chord):

>>> n = note.Note('C#4')
>>> n.offset = 10.25
>>> s = stream.Stream([n])
>>> pl = graph.plot.ScatterPitchClassOffset(s)
>>> pl.processOneElement(n)
[(10.25, 1, {})]

>>> c = chord.Chord(['D4', 'E5'])
>>> s.insert(5.0, c)
>>> pl.processOneElement(c)
[(5.0, 2, {}), (5.0, 4, {})]
N)ranger[   rC   rL   r	   r"   rh   extractOneElementlistextractChordDataMultiAxispostProcessElementmaxcopyr@   zip)r-   rk   _elementValues
formatDictrm   r]   	axisValueevelementValueLengthformatDictList
returnLists               r2   re   !PlotStreamMixin.processOneElement   s)     9>c$,,>O8P+Q8P1B8P+Q)+
 "ekk**(6$66rF	
 ")T22y7L!*I#,a   7 !::2JM??=  M!BMb#b'M!BC5:;M5NO5N//+5NO^,#}-.
3 ,R* "COs   D;E <Ec                    g)z
Any processing that needs to take place for each element, independent
of what the axis is finding can go here.  For chords, a single
formatDict applies to all pitches/notes in the chord.
N )r-   rk   r{   valuess       r2   ru   "PlotStreamMixin.postProcessElement  s     	r5   c                J    U R                    H  nUR                  5         M     g)>
Call any post data processing routines here and on any axes.
N)rC   rg   )r-   r]   s     r2   rg   PlotStreamMixin.postProcessData  s     H$$& %r5   c                   / nSn U R                  X5      nUb  UR                  U5        U(       d3  U H-  nSn U R                  XR5      nUc  M  UR                  U5        M/     U$ ! [         a     N\f = f! [         a       U$ f = f)z
Look for Note-like attributes in a Chord. This is done by first
looking at the Chord, and then, if attributes are not found, looking at each pitch.

Returns a list of values.
N)rr   AttributeErrorr@   )axcr{   r   valuens         r2   extractChordDataOneAxis'PlotStreamMixin.extractChordDataOneAxis  s     	((7E MM% 00?E $MM%(  #  		 &  s"   A' A7'
A43A47
BBc                   U R                    Vs/ s H  o0R                  X1U5      PM     nn/ n[        U R                   U5       H   u  pgU(       a  M  UR                  Xg45        M"     U H6  u  phU H+  n	 UR	                  X5      n
U
c  M  UR                  U
5        M-     M8     U R                  (       a  U R                  U5        U$ s  snf ! [
         a     Mi  f = f)z2
Returns a list of lists of values for each axis.
)rC   r   rx   r@   rr   r   r'   fillValueLists)r-   r   r{   r   rz   lookIntoChordForNotesGroupsr]   r   
destValuesr   targets              r2   rt   )PlotStreamMixin.extractChordDataMultiAxis:  s     TXS_S_`S_R55bZHS_`&(# #DLL- @H6+22H3EF !A %@ H%77FF %%%f-  %@ ((.1 a & s   C5C
CCc                    [        U  Vs/ s H  n[        U5      PM     sn5      nU  H1  nU[        U5      -
  nU(       a  US   nOUnU(       d  M)  X%/U-  -  nM3     gs  snf )a  
pads a list of lists so that each list has the same length.
Pads with the first element of the list or nullFillValue if
the list has no elements.   Modifies in place so returns None

Used by extractChordDataMultiAxis

>>> l0 = [2, 3, 4]
>>> l1 = [10, 20, 30, 40, 50]
>>> l2 = []
>>> listOfLists = [l0, l1, l2]
>>> graph.plot.PlotStream.fillValueLists(listOfLists)
>>> listOfLists
[[2,   3,  4,  2,  2],
 [10, 20, 30, 40, 50],
 [0,   0,  0,  0,  0]]
r   N)rv   r[   )rz   nullFillValueval	maxLengthshortAmountfillVals         r2   r   PlotStreamMixin.fillValueListsX  sc    & ];]cS];<	 C#c#h.Ka&'{y;.. ! <s   Ac                |    U R                   nU R                   H  nUc  M  UR                  S   nUSU-   -  nM!     U$ )z
Each PlotStream has a unique id that consists of its class name and
the class names of the axes:

>>> s = stream.Stream()
>>> pScatter = graph.plot.ScatterPitchClassQuarterLength(s)
>>> pScatter.id
'scatter-quarterLength-pitchClass'
r   -)	graphTyperC   
quantities)r-   idNamer1   r/   s       r2   idPlotStreamMixin.idv  sH     ||G))!,HcHn$F	 $ r5   )r&   r(   r'   r%   r,   r$   )NT)returnstrrF   bool)rk   base.Music21Object)rk   r   r{   dict[t.Any, t.Any]r   list[numbers.Real]r   None)r   )__name__
__module____qualname____firstlineno____doc__r   Axisr   __annotations__r3   r:   propertyrC   rT   rM   rN   re   ru   rg   staticmethodr   rt   r   r   __static_attributes__r   r5   r2   r   r   =   s     59IIDII.NK+N&$ #D  $ *. , CHF0)V	1	'9	 %7	 <@	'  << / /:  r5   r   c                  "    \ rS rSrSrSS jrSrg)
PlotStreami  z
A generic stream plotter.
Nc                    [         R                  R                  " U 40 UD6  [        R                  " X40 UD6  [        R
                  " U S5      U l        g )Nr   )r   rH   r3   r   r   
OffsetAxisr=   r-   r$   r.   s      r2   r3   PlotStream.__init__  s@    !!$3(3  =H=__T3/
r5   )r=   Nr   r   r   r   r   r3   r   r   r5   r2   r   r     s    0r5   r   c                  "    \ rS rSrSrSS jrSrg)Scatteri  z"
Base class for 2D scatter plots.
Nc                t    [         R                  R                  " U 40 UD6  [        R                  " X40 UD6  g r   )r   GraphScatterr3   r   r   s      r2   r3   Scatter.__init__  s.    ((::  =H=r5   r   r   r   r   r5   r2   r   r     s    >r5   r   c                  n   ^  \ rS rSr% Sr\R                  \R                  S.rS\	S'   SU 4S jjr
SrU =r$ )	ScatterPitchSpaceQuarterLengthi  a0  
A scatter plot of pitch space and quarter length

>>> s = corpus.parse('bach/bwv324.xml')
>>> p = graph.plot.ScatterPitchSpaceQuarterLength(s)
>>> p.doneAction = None #_DOCS_HIDE
>>> p.id
'scatter-quarterLength-pitchSpace'
>>> p.run()

.. image:: images/ScatterPitchSpaceQuarterLength.*
    :width: 600
r   r   r   c                   > [         TU ]  " U40 UD6  SU R                  l        SU;  a  SU l        SU;  a  SU l        g g )NT
figureSize   r   titlezPitch by Quarter Length Scatter)superr3   r=   useLogScaler   r   r-   r$   r.   	__class__s      r2   r3   'ScatterPitchSpaceQuarterLength.__init__  sD    /h/!%

x'$DO(":DJ #r5   r   r   r   )r   r   r   r   r   r   QuarterLengthAxisPitchSpaceAxisr   r   r3   r   __classcell__r   s   @r2   r   r     s5     ##  /K+ 
; ;r5   r   c                  n   ^  \ rS rSr% Sr\R                  \R                  S.rS\	S'   SU 4S jjr
SrU =r$ )	ScatterPitchClassQuarterLengthi  a  
A scatter plot of pitch class and quarter length

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.ScatterPitchClassQuarterLength(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('bach/bwv57.8')
>>> #_DOCS_SHOW p = graph.plot.ScatterPitchClassQuarterLength(s)
>>> p.id
'scatter-quarterLength-pitchClass'
>>> p.run()

.. image:: images/ScatterPitchClassQuarterLength.*
    :width: 600
r   r   r   c                D   > [         TU ]  " U40 UD6  SU;  a  SU l        g g )Nr   z%Pitch Class by Quarter Length Scatter)r   r3   r   r   s      r2   r3   'ScatterPitchClassQuarterLength.__init__  s)    /h/("@DJ #r5   r   r   )r   r   r   r   r   r   r   PitchClassAxisr   r   r3   r   r   r   s   @r2   r   r     s7     ##  /K+ 
A Ar5   r   c                  n   ^  \ rS rSr% Sr\R                  \R                  S.rS\	S'   SU 4S jjr
SrU =r$ )	ScatterPitchClassOffseti  a  
A scatter plot of pitch class and offset

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.ScatterPitchClassOffset(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('bach/bwv57.8')
>>> #_DOCS_SHOW p = graph.plot.ScatterPitchClassOffset(s)
>>> p.id
'scatter-offset-pitchClass'
>>> p.run()

.. image:: images/ScatterPitchClassOffset.*
    :width: 600
r   r   r   c                x   > [         TU ]  " U40 UD6  SU;  a  SU l        SU;  a  SU l        SU;  a  SU l        g g )Nr   )
      r   zPitch Class by Offset Scatteralphaffffff?r   r3   r   r   r   r   s      r2   r3    ScatterPitchClassOffset.__init__  sI    /h/ x'%DO("8DJ("DJ #r5   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   r3   r   r   r   s   @r2   r   r     s3     __  /K+ 
	 	r5   r   c                  x   ^  \ rS rSr% SrSr\R                  \R                  S.r	S\
S'   S
U 4S jjrS rS	rU =r$ )ScatterPitchSpaceDynamicSymboli  a  
A graph of dynamics used by pitch space.

>>> s = converter.parse('tinynotation: 4/4 C4 d E f', makeNotation=False) #_DOCS_HIDE
>>> s.insert(0.0, dynamics.Dynamic('pp')) #_DOCS_HIDE
>>> s.insert(2.0, dynamics.Dynamic('ff')) #_DOCS_HIDE
>>> p = graph.plot.ScatterPitchSpaceDynamicSymbol(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('schumann_robert/opus41no1/movement2.xml')
>>> #_DOCS_SHOW p = graph.plot.ScatterPitchSpaceDynamicSymbol(s)
>>> p.run()

.. image:: images/ScatterPitchSpaceDynamicSymbol.*
    :width: 600
)   r   r   r   r   c                   > [         TU ]  " U40 UD6  SU R                  l        SU;  a  U R                  U l        SU;  a  SU l        SU;  a  SU l        g g )NFr   r   zDynamics by Pitch Scatterr   r   )r   r3   r=   showEnharmonicfigureSizeDefaultr   r   r   r   s      r2   r3   'ScatterPitchSpaceDynamicSymbol.__init__  sY    /h/$)

!x'"44DO("4DJ("DJ #r5   c                   [         R                  " U R                  5      nUR                  SS9n/ U l        U H"  u  p4U R                  R                  X40 45        M$     U R                   Vs/ s H  oUS   PM	     nnU R                   Vs/ s H  oUS   PM	     nnU R                  R                  U5        U R                  R                  U5        U R                  5         g s  snf s  snf )NT
dataPointsr   rX   )
r   ActivityMatchr$   pitchToDynamicr(   r@   r=   ri   r>   rg   )r-   amamDatar   r   rn   xValsyValss           r2   rN   *ScatterPitchSpaceDynamicSymbol.extractData   s    $$T^^4""d"3	DAIIaBZ(   $yy)y!1y)#yy)y!1y)

((/

((/ *)s   -C"C')r   r(   r   r   r   )r   r   r   r   r   r   r   r   DynamicsAxisr   r   r3   rN   r   r   r   s   @r2   r   r     s@        /K+ 

 r5   r   c                  x    \ rS rSr% Sr\R                  \R                  S.rS\	S'   SS jr
SS	.SS
 jjrS rSrg)	Histogrami2  z@
Base class for histograms that plot one axis against its count
r   r   r   Nc                    [         R                  R                  " U 40 UD6  [        R                  " X40 UD6  SU;  a  SU l        g g )Nr         ?)r   GraphHistogramr3   r   r   r   s      r2   r3   Histogram.__init__;  sB    !!**4<8<  =H=("DJ #r5   TrE   c                  [         R                  (       a$  [        U S5      (       a  [        U S5      (       d   eU R                  5         U R	                  5         U R                  SU R                  R                  5       5        U R                  5       nU R                  SU5        U R                  SU R                  R                  5        U R                  SU R                  R                  5        U(       a  U R                  5         gg)z;
Override run method to remap X data into individual bins.
r=   r>   r   r   N)rI   rJ   r#   rM   rN   rO   r>   rP   remapXTicksDatarQ   rR   r=   rS   )r-   rF   r.   	xTicksNews       r2   rT   Histogram.runB  s     ??4))gdG.D.DDDc4::++-.((*	c9%#tzz//0#tzz//0LLN r5   c                   U R                   R                  5       nU Vs0 s H  o"S   US   _M     nn/ n[        U R                   S5      (       aG  U R                   R                  SL d.  U R                   R                  b  U R                   R
                  cu  [        [        U R                  5      5       HQ  nU R                  U   nUS   nUS-   4USS -   U R                  U'   Xs;   d  M7  US-   X7   4nUR                  U5        MS     U$ SSK
Jn	  [        [        U R                   R                  5      [        U R                   R
                  5      S-   5       Hu  nXS;   a  X5   n
OT[        U R                   S5      (       a7  U R                   R                  (       d  U	R                  U5      R                  n
OSn
XZ4nUR                  U5        Mw     U$ s  snf )	zC
Changes the ticks and data so that they both run
1, 2, 3, 4, etc.
r   rX   
hideUnusedTN)pitchblankLabelUnused )r=   rP   r#   r  minValuemaxValuerq   r[   r(   r@   music21r  intr  Pitchname)r-   
xTicksOrigv	xTickDictr   rm   dataValxDataValnewTickr  rR   s              r2   r   Histogram.remapXTicksDataT  s    ZZ%%'
)34AqT1Q4Z	4	\22djj6K6Kt6S::&&.::&&.3tyy>*))A,"1: !Ax'!"+5		!( 1ui&9:G$$W- +&  &3tzz223S9L9L5MPQ5QR>%LETZZ);<<TZZE`E`!KKN//EE*  ) S 3 5s   G)r   r   r   )r   r   r   r   r   r   r   CountingAxisr   r   r3   rT   r   r   r   r5   r2   r   r   2  s<     YY/K+ 
 *. $ r5   r   c                  t   ^  \ rS rSr% Sr0 \R                  ES\R                  0ErS\	S'   SU 4S jjr
SrU =r$ )	HistogramPitchSpaceiw  a  
A histogram of pitch space.

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.HistogramPitchSpace(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('bach/bwv57.8')
>>> #_DOCS_SHOW p = graph.plot.HistogramPitchSpace(s)
>>> p.id
'histogram-pitchSpace-count'
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/HistogramPitchSpace.*
    :width: 600
r   r   r   c                   > [         TU ]  " U40 UD6  SU R                  l        SU;  a  SU l        SU;  a  SU l        g g )NFr   r   r   r   zPitch Histogram)r   r3   r=   r   r   r   r   s      r2   r3   HistogramPitchSpace.__init__  sD    /h/$)

!x'%DO("*DJ #r5   r   r   )r   r   r   r   r   r   r   r   r   r   r3   r   r   r   s   @r2   r  r  w  s?    /


/T  /K+ 
+ +r5   r  c                  t   ^  \ rS rSr% Sr0 \R                  ES\R                  0ErS\	S'   SU 4S jjr
SrU =r$ )	HistogramPitchClassi  a  
A histogram of pitch class

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.HistogramPitchClass(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('bach/bwv57.8')
>>> #_DOCS_SHOW p = graph.plot.HistogramPitchClass(s)
>>> p.id
'histogram-pitchClass-count'
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/HistogramPitchClass.*
    :width: 600

r   r   r   c                f   > [         TU ]  " U40 UD6  SU R                  l        SU;  a  SU l        g g )NFr   zPitch Class Histogram)r   r3   r=   r   r   r   s      r2   r3   HistogramPitchClass.__init__  s5    /h/$)

!("0DJ #r5   r   r   )r   r   r   r   r   r   r   r   r   r   r3   r   r   r   s   @r2   r  r    s?    /


/T  /K+ 
1 1r5   r  c                  t   ^  \ rS rSr% Sr0 \R                  ES\R                  0ErS\	S'   SU 4S jjr
SrU =r$ )	HistogramQuarterLengthi  a  
A histogram of pitch class.

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.HistogramQuarterLength(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('bach/bwv57.8')
>>> #_DOCS_SHOW p = graph.plot.HistogramQuarterLength(s)
>>> p.id
'histogram-quarterLength-count'
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/HistogramQuarterLength.*
    :width: 600

r   r   r   c                   > [         TU ]  " U40 UD6  [        R                  " U S5      U l        SU R                  l        SU;  a  SU l        g g )Nr   Fr   zQuarter Length Histogram)r   r3   r   r   r=   r   r   r   s      r2   r3   HistogramQuarterLength.__init__  sI    /h/++D#6
!&

("3DJ #r5   )r=   r   r   )r   r   r   r   r   r   r   r   r   r   r3   r   r   r   s   @r2   r  r    s?    /


/T##/K+ 
4 4r5   r  c                  v    \ rS rSr% Sr\R                  \R                  \R                  S.rS\	S'   S	S jr
Srg)
ScatterWeightedi  z
Base class for histograms that plot one axis against its count.

The count is stored as the Z axis, though it is represented as size.
r   r   zr   r   Nc                    [         R                  R                  " U 40 UD6  [        R                  " X40 UD6  SU R                  l        g Nr   )r   GraphScatterWeightedr3   r   r?   	countAxesr   s      r2   r3   ScatterWeighted.__init__  s:    ''00BB  =H=)

r5   r   r   )r   r   r   r   r   r   r   r  r   r   r3   r   r   r5   r2   r"  r"    s4     YYYY/K+ *r5   r"  c                     ^  \ rS rSr% Sr0 \R                  E\R                  \R                  S.ErS\
S'   SU 4S jjrSrU =r$ )	&ScatterWeightedPitchSpaceQuarterLengthi  a  
A graph of event, sorted by pitch, over time.

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.ScatterWeightedPitchSpaceQuarterLength(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('bach/bwv57.8')
>>> #_DOCS_SHOW p = graph.plot.ScatterWeightedPitchSpaceQuarterLength(s)
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/ScatterWeightedPitchSpaceQuarterLength.*
    :width: 600
r   r   r   c                x   > [         TU ]  " U40 UD6  SU;  a  SU l        SU;  a  SU l        SU;  a  SU l        g g )Nr      r.  r   z!Count of Pitch and Quarter Lengthr   皙?r   r   s      r2   r3   /ScatterWeightedPitchSpaceQuarterLength.__init__  sO    	#!	# x'$DO("<DJ("DJ #r5   r   r   )r   r   r   r   r   r"  r   r   r   r   r   r3   r   r   r   s   @r2   r+  r+    sF    /

%
%/##  /K+ 	 	r5   r+  c                     ^  \ rS rSr% Sr0 \R                  E\R                  \R                  S.ErS\
S'   SU 4S jjrSrU =r$ )	&ScatterWeightedPitchClassQuarterLengthi  a  
A graph of event, sorted by pitch class, over time.

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.ScatterWeightedPitchClassQuarterLength(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('bach/bwv57.8')
>>> #_DOCS_SHOW p = graph.plot.ScatterWeightedPitchClassQuarterLength(s)
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/ScatterWeightedPitchClassQuarterLength.*
    :width: 600

r   r   r   c                x   > [         TU ]  " U40 UD6  SU;  a  SU l        SU;  a  SU l        SU;  a  SU l        g g )Nr   r-  r   'Count of Pitch Class and Quarter Lengthr   r/  r   r   s      r2   r3   /ScatterWeightedPitchClassQuarterLength.__init__  sO    	#!	# x'$DO("BDJ("DJ #r5   r   r   )r   r   r   r   r   r"  r   r   r   r   r   r3   r   r   r   s   @r2   r2  r2    sF    /

%
%/##  /K+ 
 
r5   r2  c                     ^  \ rS rSr% Sr0 \R                  E\R                  \R                  S.ErS\
S'   S	U 4S jjrS rSrU =r$ )
&ScatterWeightedPitchSpaceDynamicSymboli$  ap  
A graph of dynamics used by pitch space.

>>> #_DOCS_SHOW s = corpus.parse('schumann_robert/opus41no1/movement2.xml')
>>> s = converter.parse('tinynotation: 4/4 C4 d E f', makeNotation=False) #_DOCS_HIDE
>>> s.insert(0.0, dynamics.Dynamic('pp')) #_DOCS_HIDE
>>> s.insert(2.0, dynamics.Dynamic('ff')) #_DOCS_HIDE
>>> p = graph.plot.ScatterWeightedPitchSpaceDynamicSymbol(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW p = graph.plot.ScatterWeightedPitchSpaceDynamicSymbol(s)
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/ScatterWeightedPitchSpaceDynamicSymbol.*
    :width: 600

r   r   r   c                   > [         TU ]  " U40 UD6  SU R                  l        SU;  a  SU l        SU;  a  SU l        SU;  a  SU l        SU;  a  S	U l        g g )
NFr   )r   r   r   r4  r   r/  tickFontSizer.  )r   r3   r=   r   r   r   r   r9  r   s      r2   r3   /ScatterWeightedPitchSpaceDynamicSymbol.__init__:  sm    	#!	# %*

! x'&DO("BDJ("DJ) !D *r5   c                   [         R                  " U R                  5      nUR                  SS9U l        U R                   VVs/ s H  u  p#UPM	     nnnU R                   VVs/ s H  u  pVUPM	     nnnU R                   VVs/ s H	  u  p&X&S/PM     snnU l        U R
                  R                  U5        U R                  R                  U5        U R                  5         g s  snnf s  snnf s  snnf )NTr   rX   )	r   r   r$   r   r(   r=   ri   r>   rg   )r-   r   r   unused_yr   unused_xr   r   s           r2   rN   2ScatterWeightedPitchSpaceDynamicSymbol.extractDataK  s    $$T^^4%%%6	&*ii0i{qi0&*ii0i{xi0+/995941aAY95	

((/

((/ 105s   C$$C*C0)r   r(   r   r9  r   r   )r   r   r   r   r   r"  r   r   r   r   r   r3   rN   r   r   r   s   @r2   r7  r7  $  sK    /

%
%/  /K+ ""
 
r5   r7  c                     ^  \ rS rSr% SrSr\R                  R                  S-   rS\	R                  0rS\S'   \R                  rS\S	'   SS
 jr\S 5       rSS.SS jjrS rS rSU 4S jjrSrU =r$ )WindowedAnalysisi\  zK
Base Plot for windowed analysis routines such as Key Analysis or Ambitus.
	colorGrid)	minWindow	maxWindow
windowStep
windowTypecompressLegendprocessorClassgraphLegendr   r   r   ztype[discrete.DiscreteAnalysis]processorClassDefaultc                0   U R                   U l        S U l        S U l        SU l        S U l        SU l        SU l        SU l        [        R                  R                  " U 40 UD6  [        R                  " X40 UD6  [        R                  " U S5      U l        g )NrX   pow2overlapTr   )rI  rG  
_processorrH  rB  rC  rD  rE  rF  r   GraphColorGridr3   r   r   r   r=   r   s      r2   r3   WindowedAnalysis.__init__i  s    "88 #"!!**4<8<  =H=__T3/
r5   c                    U R                   (       d  g U R                  (       d   U R                  U R                  5      U l        U R                  $ r   )rG  rM  r$   )r-   s    r2   	processorWindowedAnalysis.processory  s5    """11$..ADOr5   TrE   c                  U R                   S:X  aK  U R                  (       a:  U R                  R                  SU R                  R                  5        S3-   U l         U R	                  5       u  p4X0l        U R                  SU5        U R                  R                  5         U R                  R                  5       n[        U5      S:  a  SUS   S   4SUS   S   4/n[        R                  S	U/5        U R                  S
U5        U R                  SS5        U R                  S
SU R                  R                   S35        U R                  5       U l        U(       a  U R#                  5         gg)z
Actually creates the graph.
zMusic21 Graphz ()r   rY   r   rX   xTicksr   zWindow Size
(Quarter Lengths)z	Windows (z Span)N)r   rQ  r  solutionUnitStringrN   r(   rO   r=   ri   rP   r[   environLocal
printDebugrQ   rR   
_getLegendrH  rS   )r-   rF   r.   r(   yTicksrV  s         r2   rT   WindowedAnalysis.run  s4    ::(T^^..-- !B!B!D EQGHDJ '')	c6"

((*!!#v;!&)A,'!VBZ]);<F6 23c6"#?@#4::+;+;*<FCD??,LLN r5   c                T   [         R                  " U R                  U R                  5      nUR	                  U R
                  U R                  U R                  U R                  S9u  p#n[        U5      S:  a#  [        S[        U5      [        U5      S-  5      nO[        [        U5      5      n[        R                  SU/5        Sn/ nU HW  nXH   S   n	UR                  US/5        UR                  US-   [        U	5      /5        UR                  US-   S/5        US	-  nMY     X74$ )
z~
Extract data actually calls the processing routine.

Returns two element tuple of the data (colorMatrix) and the yTicks list
)rE  r   r   	tickRange
windowSizer  rX   rY   rW   )r   r@  r$   rQ  rS   rB  rC  rD  rE  r[   rq   rX  rY  r@   r   )
r-   waunused_solutionMatrixcolorMatrix
metaMatrixr^  posr[  r   thisWindowSizes
             r2   rN   WindowedAnalysis.extractData  s    &&t~~t~~F9;DNNDHNNDHOOOS :D :`6J z?RaZ#j/R2GHIc*o.Ii 89 A']<8NMM3)$MM37C$789MM37B-(1HC  ""r5   c                    [         R                  " SU R                  S9nU R                  R	                  U R
                  S9nX!l        U$ )z2
Returns a solution legend for a WindowedAnalysis
N
doneActionr   )compress)r   GraphColorGridLegendr   rQ  solutionLegendrF  r(   )r-   rH  	graphDatas      r2   rZ  WindowedAnalysis._getLegend  sG     !55<@JJHNN114;N;N1O	$r5   c                p  > [         TU ]  U5        Uc  [        R                  SSS9nO[        R
                  " USS9n[        R                  R                  U5      u  p#[        R                  R                  USU-   5      nU R                  R                  5         U R                  R                  U5        g)z9
Overrides the normal write method here to add a legend.
N.pngT)returnPathlibzlegend-)r   writerX  getTempFiler
   	cleanpathospathsplitjoinrH  rS   )r-   fp	directoryfnfpLegendr   s        r2   rr  WindowedAnalysis.write  s    
 	b:))&)EB!!"D9Bb)	77<<	9r>:  "x(r5   )rM  r=   rF  r(   rH  rC  rB  rG  r   rD  rE  r   r   )r   r   r   r   r   formatr   rN  keywordConfigurablesr   r   r   r   r   KrumhanslSchmucklerrI  r3   r   rQ  rT   rN   rZ  rr  r   r   r   s   @r2   r@  r@  \  s     F%44II M) ) 03DOO.DK+D=E=Y=Y:Y0    *. 8!#F) )r5   r@  c                  0    \ rS rSrSr\R                  rSrg)WindowedKeyi  aZ  
Stream plotting of windowed version of Krumhansl-Schmuckler analysis routine.
See :class:`~music21.analysis.discrete.KrumhanslSchmuckler` for more details.


>>> s = corpus.parse('bach/bwv66.6')
>>> p = graph.plot.WindowedKey(s.parts[0])
>>> p.doneAction = None #_DOCS_HIDE
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/WindowedKrumhanslSchmuckler.*
    :width: 600

.. image:: images/legend-WindowedKrumhanslSchmuckler.*

Set the processor class to one of the following for different uses:

>>> p = graph.plot.WindowedKey(s.parts.first())
>>> p.processorClass = analysis.discrete.AardenEssen
>>> p.processorClass = analysis.discrete.SimpleWeights
>>> p.processorClass = analysis.discrete.BellmanBudge
>>> p.processorClass = analysis.discrete.TemperleyKostkaPayne
>>> p.doneAction = None #_DOCS_HIDE
>>> p.run()

r   N)	r   r   r   r   r   r   r  rI  r   r   r5   r2   r  r    s    4 %88r5   r  c                  0    \ rS rSrSr\R                  rSrg)WindowedAmbitusi  aM  
Stream plotting of basic pitch span.

>>> s = corpus.parse('bach/bwv66.6')
>>> p = graph.plot.WindowedAmbitus(s.parts.first())
>>> p.doneAction = None #_DOCS_HIDE
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/WindowedAmbitus.*
    :width: 600

.. image:: images/legend-WindowedAmbitus.*

r   N)	r   r   r   r   r   r   AmbitusrI  r   r   r5   r2   r  r    s     %,,r5   r  c                     ^  \ rS rSr% Sr\R                  \R                  S.rS\	S'    SSS.   SS jjjr
S	S
.SU 4S jjjrSS jr      SU 4S jjrU 4S jrSrU =r$ )HorizontalBari  z
A graph of events, sorted by pitch, over time.

If colorByPart is True, then each part will get its own color from
`self.colors` (unless there are more parts than colors).
r   r   r   FcolorByPartc                   X l         0 U l        U   [        R                  R                  " U 40 UD6  [
        R                  " X40 UD6  SU R                  l        g )NF)r  _partsToColorr   GraphHorizontalBarr3   r   r>   r  )r-   r$   r  r.   s       r2   r3   HorizontalBar.__init__  sM     '57%%..t@x@  =H= %

r5   TrE   c               l   > U R                   (       a  U R                  5         [        TU ]  " SSU0UD6  g)zF
Optionally assign colors to Part objects and then do the normal run.
rF   Nr   )r  assignColorsToPartsr   rT   )r-   rF   r.   r   s      r2   rT   HorizontalBar.run-  s.     $$&88x8r5   c                    U R                   n[        U R                  5      n[        U[        R
                     5       H#  u  p4U R                  X2-     U R                  U'   M%     U R                  $ )a  
Give a different color for each part, if self.colorByPart is True.

Returns the assignment for any further manipulation.

Currently, two piano hands (PartStaff objects) get different colors.

>>> bach = corpus.parse('bwv66.6')
>>> plot = graph.plot.HorizontalBar(bach, colorByPart=True)
>>> plot.assignColorsToParts()
{<music21.stream.Part Soprano>: '#605c7f',
 <music21.stream.Part Alto>: '#5c7f60',
 <music21.stream.Part Tenor>: '#988969',
 <music21.stream.Part Bass>: '#628297'}
)r$   r[   colorsrh   r   Partr  )r-   r8   	numColorsrm   ps        r2   r  !HorizontalBar.assignColorsToParts5  s[      NN$	an-DA$(KK$>Dq! .!!!r5   c                   > [         TU ]  " X/UQ76   U R                  (       aP  UR                  [        R
                  5      nUb-  U R                  R                  UU R                  S   5      US'   ggg)z7
Assign colors to each element if colorByPart is True.
Nr   color)	r   ru   r  getContextByClassr   r  r  getr  )r-   rk   r{   r   partr   s        r2   ru    HorizontalBar.postProcessElementL  sm     	"2;F;''4D&*&8&8&<&<T=A[[^'M
7#   r5   c                0  > [         TU ]  5         U R                  R                  U R                   Vs/ s H  oS   PM	     sn5        U R                  R                  5       n0 n/ n0 nU R                   H-  u  pgnXs;  a  / X7'   0 XW'   / UQUP7n	X7   R                  U	5        M/     UR                  5        H  u  pUR                  S S9  M     U H8  u  pX;   a  UR                  UX<   X\   /5        M$  UR                  U/ 0 /5        M:     X@l        gs  snf )r   rX   c                    U S   U S   4$ )Nr   rX   r   )points    r2   <lambda>/HorizontalBar.postProcessData.<locals>.<lambda>s  s    eAha%9r5   )keyN)	r   rg   r>   ri   r(   rP   r@   r)   sort)r-   rn   r[  pitchSpanDictnewDatadictOfFormatDictspositionData	pitchDatar{   positionDataWithFormatDictunused_kr  numericValuerR   r   s                 r2   rg   HorizontalBar.postProcessDataZ  s%    	!

((		)B	1A$	)BC!!#3799/LZ-+-(/1!,)D<)D)D&$++,FG 4= )..0KHFF9F: 1 $*L , - ; 1 ? A B r2/ $** 	[ *Cs   D)r  r  r(   r   )r$   zstream.Stream | Noner   r   r   )r   zdict[stream.Part, str])rk   r   r{   r   r   r   )r   r   r   r   r   r   OffsetEndAxisr   r   r   r3   rT   r  ru   rg   r   r   r   s   @r2   r  r    s       /K+  )-& 	&%& 
&" *. 9 9".M1M'9M %7M2 2r5   r  c                  |   ^  \ rS rSr% Sr0 \R                  ES\R                  0ErS\	S'   S
SS.U 4S jjjr
S	rU =r$ )HorizontalBarPitchClassOffseti  a  
A graph of events, sorted by pitch class, over time.

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.HorizontalBarPitchClassOffset(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('bach/bwv57.8')
>>> #_DOCS_SHOW p = graph.plot.HorizontalBarPitchClassOffset(s)
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/HorizontalBarPitchClassOffset.*
    :width: 600

r   r   r   Fr  c                  > [         TU ]  " U4SU0UD6  [        R                  " U S5      U l        SU R                  l        SU;  a  SU l        SU;  a  SU l        g g )Nr  r   Fr   r      r   z-Note Quarter Length and Offset by Pitch Class)r   r3   r   r   r>   r  r   r   r-   r$   r  r.   r   s       r2   r3   &HorizontalBarPitchClassOffset.__init__  s_    HHxH((s3
 %

 x'%DO("HDJ #r5   )r>   r   r   r   )r   r   r   r   r   r  r   r   r   r   r3   r   r   r   s   @r2   r  r    sI    /

#
#/T  /K+ 
	Ie 	I 	Ir5   r  c                  8   ^  \ rS rSrSrSSS.U 4S jjjrSrU =r$ )HorizontalBarPitchSpaceOffseti  a  
A graph of events, sorted by pitch space, over time, generally called
a "piano roll".

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.HorizontalBarPitchSpaceOffset(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW s = corpus.parse('bach/bwv57.8')
>>> #_DOCS_SHOW p = graph.plot.HorizontalBarPitchSpaceOffset(s)
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/HorizontalBarPitchSpaceOffset.*
    :width: 600
Fr  c               b   > [         TU ]  " U4SU0UD6  SU;  a  SU l        SU;  a  SU l        g g )Nr  r   r  r   zNote Quarter Length by Pitchr   r3   r   r   r  s       r2   r3   &HorizontalBarPitchSpaceOffset.__init__  s=    HHxHx'%DO("7DJ #r5   r   r   )r   r   r   r   r   r3   r   r   r   s   @r2   r  r    s    8e 8 8r5   r  c                      \ rS rSr% SrS\R                  0rS\S'   \	R                  R                  S-   rSS jrS	 rS
rg)HorizontalBarWeightedi  z
A base class for plots of Scores with weighted (by height) horizontal bars.
Many weighted segments represent a dynamic parameter of a Part.
r   r   r   )fillByMeasurenormalizeByPart
partGroupssegmentByTargetNc                    SU l         SU l        SU l        S U l        [        R
                  R                  " U 40 UD6  [        R                  " X40 UD6  g )NFT)r  r  r  r  r   GraphHorizontalBarWeightedr3   r   r   s      r2   r3   HorizontalBarWeighted.__init__  sM    "#$--66tHxH  =H=r5   c                Z   [        U R                  [        R                  5      (       d  [	        S5      e[
        R                  " U R                  U R                  U R                  U R                  U R                  S9nUR                  5         UR                  5       n/ nU HK  u  pEU H@  nUS   nUS   nXs;  a  UR                  U5        Xx-   U;  d  M-  UR                  Xx-   5        MB     MM     [        U5      U R                  l        [#        U5      U R                  l        X l        g)z#
Extract the data from the Stream.
zprovided Stream must be Score)r  r  r  r  r   rX   N)rL   r$   r   Scorer   r   PartReductionr  r  r  r  rS   !getGraphHorizontalBarWeightedDatar@   minr=   r  rv   r  r(   )	r-   prr(   uniqueOffsets
unused_keyr   rl   startdurs	            r2   rN   !HorizontalBarWeighted.extractData  s     $..&,,77 !@AA$$NN,, 00 002 	

335!%J! qk-!((/;m3!((5 " "& "-0

!-0

	r5   )r(   r  r  r  r  r   )r   r   r   r   r   r   r   r   r   r   r  r  r3   rN   r   r   r5   r2   r  r    sD     03DOO.DK+D%@@UU Y >r5   r  c                  6   ^  \ rS rSrSrSU 4S jjrS rSrU =r$ )Dolani  a  
A graph of the activity of a parameter of a part (or a group of parts) over time.
The default parameter graphed is Dynamics. Dynamics are assumed to extend activity
to the next change in dynamics.

Numerous parameters can be configured based on functionality encoded in
the :class:`~music21.analysis.reduction.PartReduction` object.


If the `fillByMeasure` parameter is True, and if measures are available, each part
will segment by Measure divisions, and look for the target activity only once per
Measure. If more than one target is found in the Measure, values will be averaged.
If `fillByMeasure` is False, the part will be segmented by each Note.

The `segmentByTarget` parameter is True, segments, which may be Notes or Measures,
will be divided if necessary to show changes that occur over the duration of the
segment by a target object.

If the `normalizeByPart` parameter is True, each part will be normalized within the
range only of that part. If False, all parts will be normalized by the max of all parts.
The default is True.

>>> s = corpus.parse('bwv66.6')
>>> dyn = ['p', 'mf', 'f', 'ff', 'mp', 'fff', 'ppp']
>>> i = 0
>>> for p in s.parts:
...     for m in p.getElementsByClass(stream.Measure):
...         m.insert(0, dynamics.Dynamic(dyn[i % len(dyn)]))
...         i += 1
...
>>> #_DOCS_SHOW s.plot('dolan', fillByMeasure=True, segmentByTarget=True)

.. image:: images/Dolan.*
    :width: 600

c                z  > [         TU ]  " U40 UD6  Ub  U R                  5         SU;  a  SU l        SU;  au  SU l        U R
                  (       a]  U R
                  R                  bF  U R
                  R                  R                  b%  U R
                  R                  R                  U l        SU;  a  SU l        g g )Nr   r  r   Instrumentation	hideYGridT)r   r3   _getPartGroupsr   r   r$   metadatar  r   s      r2   r3   Dolan.__init__"  s    /h/
  !x'%DO("*DJ~~$.."9"9"E>>**00<!%!8!8!>!>DJh&!DN 'r5   c                   SSK Jn  U R                  (       a  gU R                  (       a  gU R                  R	                  5       R                  UR                  5      nU(       d  g[        U5      S:X  a?  U R                  R                  S5      b#  SSSS/S	.S
SSS/S	.SSS/S	.SSS/S	./nX0l        g[        U5      S:X  a@  U R                  R                  S5      b$  SS/ SQS	.SS/ SQS	.SSS/S	.SS/ SQS	./nX0l        g[        U5      S:  aX  SSSS /S	.S!S"S#S$/S	.S%SS&S'/S	.S(SS)S*/S	.S+SS,S-/S	.S.S// S0QS	.S1S/S2/S	.S3S4SS	.S5SS6S7/S	.S8S9S:S;/S	.SS<SS	.S=S>S?S@/S	./nX0l        gg)Azs
Examine the instruments in the Score and determine if there
is a good match for a default configuration of parts.
r   )
instrumentNr  Sopranopurplesoprano0)r  r  matchAltoorangealto1Tenor
lightgreentenorBass
mediumbluebassViolaz
1st Violin)z
1st violinr  zviolin 1violin iz
2nd Violin)z
2nd violinr  zviolin 2	violin iiviolaCello)cellovioloncelloz'cellor   Flutez#C154C1flautozflute \dOboeblueoboezoboe \dClarinet
clarinettozclarinet in \w* \dBassoonfagottoz
bassoon \dHornscornozhorn in \w* \dTrumpetred)trombaz
trumpet \dztrumpet in \w* \dTromboneztrombone \dTimpaniz#5C3317zViolin Iz	violino ir  z	Violin IIgreenz
violino iir  forestgreenzVioloncello & CBz
dark greenr  contrabasso)	r  r  r  r$   flattenrd   
Instrumentr[   getElementById)r-   r  
instStreampgOrcs       r2   r  Dolan._getPartGroups6  s   
 	'??>>^^++-@@AVAVW
z?aDNN$A$A)$L$X"XC@PQ(fc]K <7)L,&J	E $O_!dnn&C&CG&L&X%HJ%IK <7)L <?AE $O_r! 9+?VW&FJ;OP#l')>?A"XM@Z[ 8wHY>Z["UIK#e~>NO"YF $lkS]E^_$w,P[A\] =4H+l(-8:#E* $O- "r5   )r   r  r  r   r   )	r   r   r   r   r   r3   r  r   r   r   s   @r2   r  r    s    #J"(:$ :$r5   r  c                  v    \ rS rSr% Sr\R                  \R                  \R                  S.r	S\
S'   S	S jrSrg)

Plot3DBarsiv  z)
Base class for Stream plotting classes.
r#  r   r   Nc                    [         R                  R                  " U 40 UD6  [        R                  " X40 UD6  SU R                  l        g r&  )r   Graph3DBarsr3   r   r?   r(  r   s      r2   r3   Plot3DBars.__init__  s:    ''99  =H=)

r5   r   r   )r   r   r   r   r   r   r   r   r  r   r   r3   r   r   r5   r2   r  r  v  s8     ##  /K+ *r5   r  c                  t   ^  \ rS rSr% Sr0 \R                  ES\R                  0ErS\	S'   SU 4S jjr
SrU =r$ )	!Plot3DBarsPitchSpaceQuarterLengthi  a5  
A scatter plot of pitch and quarter length

>>> s = corpus.parse('bach/bwv324.xml') #_DOCS_HIDE
>>> p = graph.plot.Plot3DBarsPitchSpaceQuarterLength(s, doneAction=None) #_DOCS_HIDE
>>> #_DOCS_SHOW from music21.musicxml import testFiles
>>> #_DOCS_SHOW s = converter.parse(testFiles.mozartTrioK581Excerpt)
>>> #_DOCS_SHOW p = graph.plot.Plot3DBarsPitchSpaceQuarterLength(s)
>>> p.id
'3DBars-quarterLength-pitchSpace-count'
>>> p.run()  # with defaults and proper configuration, will open graph

.. image:: images/Plot3DBarsPitchSpaceQuarterLength.*
    :width: 600
r   r   r   c                ^   > [         TU ]  " U40 UD6  SU;  a  SU l        SU;  a  SU l        g g )Nr   r   r   zPitch by Quarter Length Countr  r   s      r2   r3   *Plot3DBarsPitchSpaceQuarterLength.__init__  s:    /h/ x'$DO("8DJ #r5   r   r   )r   r   r   r   r   r  r   r   r   r   r3   r   r   r   s   @r2   r  r    s?    /

 
 /T  /K+ 
9 9r5   r  c                  8    \ rS rSr% Sr0 rS\S'   S	S jrS rSr	g)
MultiStreami  a  
Approaches to plotting and graphing multiple Streams.
A base class from which Stream plotting Classes inherit.

Not yet integrated into the 2017 system, unfortunately.

Provide a list of Streams as an argument. Optionally
provide an additional list of labels for each list.
r   r   Nc                   [         R                  R                  " U 40 UD6  [        R                  U S 5        Uc  / nS U l        U R                  U5      nU(       d  [        U5      [        U5      :X  a  X@l        OX l        S U l        g r   )	r   GraphGroupedVerticalBarr3   r   
streamListparseStreamsr[   	labelListr(   )r-   r  r  r.   
foundPathss        r2   r3   MultiStream.__init__  sr    **33DEHE  t,I&&z2
 S_J?'N&N	r5   c                   / U l         / nU GH0  n[        U[        5      (       a  UR                  [        R
                  R                  U5      5        [        R
                  R                  U5      (       a  [        R                  " U5      nO[        R                  " U5      nO|[        U[        R                  5      (       a]  UR                  UR                  5        UR                  5       (       a  [        R                  " U5      nO[        R                  " U5      nU R                   R                  U5        GM3     U$ r   )r  rL   r   r@   ru  rv  basenameexistsr   parser   pathlibPathr  )r-   r  r  r8   s       r2   r  MultiStream.parseStreams  s    
A!S!!!!"''"2"21"5677>>!$$!*AQAAw||,,!!!&&)88::!*AQAOO""1%   r5   )r(   r  r  r   )
r   r   r   r   r   r   r   r3   r  r   r   r5   r2   r  r    s     /1K+0"r5   r  c                  L   ^  \ rS rSrSrSrS
U 4S jjrSS.SS jjrS rS	r	U =r
$ )Featuresi  z\
Plots the output of a set of feature extractors.

FeatureExtractors can be ids or classes.
r   c                   > Uc  / n[         TU ]  " X40 UD6  X l        SU l        SU l        SU l        SU;  a  SU l        SU;  a  S U l        g g )NZ   lefttopr   r  r   )r   r3   featureExtractorsxTickLabelRotationxTickLabelHorizontalAlignmentxTickLabelVerticalAlignmentr   r   )r-   r  r&  r  r.   r   s        r2   r3   Features.__init__  sc    I;(;!2"$-3*+0( x'%DO("DJ #r5   TrE   c                   U R                  5         U R                  5       u  U l        p4SU l        U R	                  SU5        U R	                  SU5        U(       a  U R                  5         g g )NFr   r   )rM   rN   r(   gridrO   rS   )r-   rF   r.   rV  r[  s        r2   rT   Features.run  sW    $($4$4$6!	6	c6"c6"LLN r5   c                
   [        U R                  5      [        U R                  5      :w  a1  [        [        U R                  5      5       Vs/ s H  oS-   PM	     nnOU R                  n/ nU R                   He  n[        U[        5      (       a7  [        R                  " U5      nU H  nUR                  U" 5       5        M     MO  UR                  U" 5       5        Mg     / nU R                   H*  n[        R                  " U5      n	UR                  U	5        M,     / n
[        U5       H  u  p[        R                  " 5       nU Hh  nXl        UR                  5       R                   n[        U5      S:X  a  US   XdR"                  '   ME  [%        U5      [        U5      -  XdR"                  '   Mj     X+   U/nU
R                  U5        M     / n[        U5       H  u  pUR                  US-   U /5        M     / nXU4$ s  snf )NrX   r         ?)r[   r  r  rq   r&  rL   r   r   extractorsByIdr@   DataInstancerh   collectionsOrderedDictr(   extractvectorr  sum)r-   r   r  feListfepostsubdiListr8   dir(   rm   r  	dataPointrV  rR   r[  s                    r2   rN   Features.extractData  s   t~~#doo"66(-c$//.B(CD(C1Q(CIDII((B"c""..r2CMM#%(   bd# ) A&&q)BMM" ! v&EA))+CJJL''q6Q;#$Q4CL $'q6CF?CL  #s+IKK	" ' !),HA MM1s7ug/0 -
 V##U Es   H )r(   r&  r   r,  r   r(  r'  r)  r   r   )r   r   r   r   r   r~  r3   rT   rN   r   r   r   s   @r2   r!  r!    s(    
 F* *. ,$ ,$r5   r!  c                  V    \ rS rSrS rS rS rS rS rS r	S r
S	 rS
 rS rS rSrg)TestExternalManuali8  c                    [         R                  " S5      n[        UR                  S   SS9nUR	                  5         [        USS9nUR	                  5         g )Nbach/bwv57.8r   Bach (soprano voice)r   zBach (all parts))r   r  r  partsrT   r-   abs      r2   !testHorizontalBarPitchSpaceOffset4TestExternalManual.testHorizontalBarPitchSpaceOffset:  sD    LL()!''!*<RS	)!3EF	r5   c                   [         R                  " S5      n[        UR                  S   SS9nUR	                  5         [         R                  " S5      n[        UR                  S   R                  SS5      SS9nUR	                  5         g )NrB  r   rC  r   rW   r   zBach (soprano voice, mm 3-6))r   r  r  rD  rT   measuresrE  s      r2   !testHorizontalBarPitchClassOffset4TestExternalManual.testHorizontalBarPitchClassOffsetC  sj    LL()!''!*<RS	LL()!''!**=*=a*C4RT	r5   c                    [         R                  " S5      R                  S   R                  5       nS HW  n[	        USS9nX#R
                  l        UR                  5         [        USS9nX#R
                  l        UR                  5         MY     g )NrB  r   TFz Pitch Space Bach (soprano voice)r   z Pitch Class Bach (soprano voice))	r   r  rD  r  r+  r=   r   rT   r2  )r-   rF  xLogrG  s       r2   *testScatterWeightedPitchSpaceQuarterLength=TestExternalManual.testScatterWeightedPitchSpaceQuarterLengthM  sx    LL(..q199;!D6;A #'GGEEG6;A #'GGEEG "r5   c                    [         R                  " S5      n[        UR                  S   R	                  5       SS9nUR                  5         g NrB  r   rC  r   r   r  r  rD  r  rT   rE  s      r2   testPitchSpace!TestExternalManual.testPitchSpace\  7    LL(
 2 2 4<RS	r5   c                    [         R                  " S5      n[        UR                  S   R	                  5       SS9nUR                  5         g rT  r   r  r  rD  r  rT   rE  s      r2   testPitchClass!TestExternalManual.testPitchClassa  rX  r5   c                    [         R                  " S5      n[        UR                  S   R	                  5       SS9nUR                  5         g rT  r   r  r  rD  r  rT   rE  s      r2   testQuarterLength$TestExternalManual.testQuarterLengthf  s7    LL("1771:#5#5#7?UV	r5   c                V   S H  n[         R                  " S5      n[        UR                  S   R	                  5       SS9nXR
                  l        UR                  5         [        UR                  S   R	                  5       SS9nXR
                  l        UR                  5         M     g )NrO  rB  r   rC  r   )	r   r  r   rD  r  r=   r   rT   r   )r-   rP  rF  rG  s       r2   "testScatterPitchSpaceQuarterLength5TestExternalManual.testScatterPitchSpaceQuarterLengthk  s    !D^,A.qwwqz/A/A/CKa 1A"&GGEEG.qwwqz/A/A/CKa 1A"&GGEEG "r5   c                    [         R                  " S5      n[        UR                  S   R	                  5       SS9nUR                  5         g rT  )r   r  r   rD  r  rT   rE  s      r2   testScatterPitchClassOffset.TestExternalManual.testScatterPitchClassOffsety  s7    LL(#AGGAJ$6$6$8@VW	r5   c                   [         R                  " SS5      n[        UR                  S   R	                  5       SS9nUR                  5         [        UR                  S   R	                  5       SS9nUR                  5         g )Nschumann_robert/opus41no1rY   r   zRobert Schumann (soprano voice)r   r   r  r   rD  r  rT   r7  rE  s      r2   "testScatterPitchSpaceDynamicSymbol5TestExternalManual.testScatterPitchSpaceDynamicSymbol~  sk    LL4a8*GGAJ 3
 	
2GGAJ 35 	
r5   c                    [         R                  " SS5      n[        UR                  5       R	                  5       SS9nUR                  5         g )Nschoenberg/opus19r   zSchoenberg pitch spacer   )r   r  r  r  	stripTiesrT   rE  s      r2   &testPlot3DPitchSpaceQuarterLengthCount9TestExternalManual.testPlot3DPitchSpaceQuarterLengthCount  s;    LL,a0-aiik.C.C.E4LN	r5   c                @   SSK Jn  [        SS4[        SS4[        SS4[
        SS4[        SS4[        SS4[        [        R                  " SS5      S4[        SS4[        SS4[        SS4[        SS4[        [        R                  " SS5      S4[         UR"                  S4[$        [        R                  " S5      S	4[&        [        R                  " S5      S	4/n[        R(                  " S
5      nU H  u  pEnUc  UnO[*        R(                  " U5      nUb	  U" USUS9nOU" USS9nUR-                  5         UR.                  R0                  S-   n	[3        [4        R7                  5       U	-  5      n
[4        R9                  SU
/5        UR;                  U
5        M     g)z
Write a graphic file for all graphs, naming them after the appropriate class.
This is used to generate documentation samples.
r   )	testFilesNrh  rY   zRobert Schumann Opus 41 No 1zMozart Trio K581 Excerptzbach/bwv66.6.xmlzBach BWV 66.6rB  rh  ri  rp  zwriting fp:)music21.musicxmlrr  r  r  r  r   r   r   r   r   getWorkr  r  r+  r2  r7  r  mozartTrioK581Excerptr  r  r  r   rT   r   r   r   rX  getRootTempDirrY  rr  )r-   rr  plotClassessDefaultplotClassNameworktitleStrr8   objr{  ry  s              r2   writeAllPlots TestExternalManual.writeAllPlots  s    	/ !$- $-#T40+T48+T48$dD1./ / +D$7*D$73T4@3T4@3^^7;+- /,,') &..);<oNfnn-?@/RE$
L <</-8)M| OOD)##A$hG#A$7GGI''&0B\002R78B##]B$78IIbM! .9r5   r   N)r   r   r   r   rH  rL  rQ  rV  r[  r_  rb  re  rj  ro  r~  r   r   r5   r2   r@  r@  8  s:    



@r5   r@  c                      \ rS rSrS rS rS rS rS rS r	SS	 jr
S
 rS rS rS rS rS rS rS rS rS rS rSrg)Testi  c                2    SSK Jn  U" U [        5       5        g )Nr   )testCopyAll)music21.test.commonTestr  globals)r-   r  s     r2   testCopyAndDeepcopyTest.testCopyAndDeepcopy  s    7D')$r5   c                    [         R                  " S5      n[        UR                  S   R	                  5       S SS9nUR                  5         g NrB  r   rC  rh  )r   r  r+  rD  r  rT   rE  s      r2   testPitchSpaceDurationCount Test.testPitchSpaceDurationCount  s=    LL(21771:3E3E3GTX9OQ	r5   c                    [         R                  " S5      n[        UR                  S   R	                  5       S SS9nUR                  5         g )Nbachr   rC  rh  rU  rE  s      r2   rV  Test.testPitchSpace  s9    LL 
 2 2 4Mcd	r5   c                    [         R                  " S5      n[        UR                  S   R	                  5       S SS9nUR                  5         g r  rZ  rE  s      r2   r[  Test.testPitchClass  s>    LL(
 2 2 4+/&<> 	
r5   c                    [         R                  " S5      n[        UR                  S   R	                  5       S SS9nUR                  5         g r  r^  rE  s      r2   r_  Test.testQuarterLength  s?    LL("1771:#5#5#7.2)?A 	
r5   c                
   [         R                  " SS5      n[        UR                  S   R	                  5       S SS9nUR                  5         [        UR                  S   R	                  5       S SS9nUR                  5         g )Nrm  rY   r   zSchoenberg (piano)rh  ri  rE  s      r2   testPitchDurationTest.testPitchDuration  sq    LL,a0*1771:+=+=+?6:1EG 	
21771:3E3E3G>B9MO 	
r5   Nc           	         [         R                  " S5      nSnSn[        UR                  5       USUUSS9nUR	                  5         U R                  UR                  R                  S/ SQ/S/ S	Q//5        g )
Nbach/bwv66.6   rX   i,  )r   rB  rD  ri  dpiMajor))zC#z#f0727a)Dz#ffd752)Ez#eeff9a)zF#z#b9f0ff)Az#bb9aff)Bz#ffb5ffMinor))c#z#8c0e16r  z#ffffffr  )zf#z#558caar  )rG  z#9b519b)r   r  r  r  rT   assertEqualrH  r(   )r-   ri  rF  r{  rD  rG  s         r2   testWindowedTest.testWindowed  s    LL(
 		2"#
#-38 	
++
 	
r5   c                H    / SQn/ SQn[        XS S9nUR                  5         g )N)r  zschoenberg/opus19/movement2zcorelli/opus3no1/1grave)ql1ql2ql3)r&  ri  )r!  rT   )r-   r  r7  r  s       r2   testFeaturesTest.testFeatures  s!    _
&ZdK	r5   c                    [         R                  " S5      nUR                  5       n[        US S9nUR	                  5         g )Nz0josquin/laDeplorationDeLaMorteDeJohannesOckeghemrs  )r   r  mergeScoresr  rT   )r-   or8   rG  s       r2   testPianoRollFromOpusTest.testPianoRollFromOpus#  s1    LLKLMMO)!=	r5   c           
     :   SSK Jn  UR                  S5      n[        [        R
                  " 5       S S9n[        R                  " / SQ5      n[        R                  " US5      Ul
        U R                  UR                  UR                  U0 5      / SQ5        [        R
                  " 5       nUR                  [        R                  " / SQ5      5        UR                  [        R                  " S	5      5        UR                  [        R                  " S
5      5        [!        US S9nUR#                  5         U R                  UR$                  SS0 4SS0 4SS0 4SS0 4SS0 4/5        [        R
                  " 5       nUR                  UR'                  SS5      5        UR                  [        R                  " S	5      5        UR                  [        R                  " S	5      5        [)        US S9nUR#                  5         U R                  UR$                  SS0 4SS0 4SS0 4SS0 4SS0 4/5        [        R
                  " 5       nUR                  UR'                  SSSS95        UR                  [        R                  " S	SS95        [+        US S9nUR#                  5         U R                  UR$                  SS0 4SS0 4/5        [-        [        R
                  " 5       S S9n[        R                  " US5      Ul
        [        R.                  " US5      Ul        SUR0                  l        [        R                  " / SQSS9nU R                  UR5                  U0 5      / SQ/ SQ/5        SUl        U R                  UR5                  U0 5      / SQS//5        g )Nr   scalec4rs  )rG  r   rn   r   )G   <   >   )rG  r  rn   c3c5rX   rY   rW   r  r   e3a3quarterLengthr/  r   F)r/  r/  r/  )r  r  
MajorScaler   r   Streamr	   r"   r   r   r=   r  r   r@   r   r!   r  rT   r(   getChordr  r  r   r   r>   r   rt   r'   )r-   r  scrG  r   r8   s         r2   testChordsATest.testChordsA*  s   !d#fmmo$7KK(%%a-22177ArBLQMMO	-./	4!	4!d3	 	1a*q!Rj1a*q!RjSTVWY[R\!]^MMO	T4()	4!	4!d3	 	1a*q!Rj1a*q!RjSTVWY[R\!]^MMO	T4q9:	4s34"16	 	1a*q!Rj!9: FMMO5%%a-((C0#KKs;44Q;&8	: &+"44Q;lSE=RSr5   c                &   SSK Jn  UR                  S5      n[        R                  " 5       nUR                  UR                  SSSS95        UR                  UR                  SS	S
S95        UR                  [        R                  " SSS95        [        US S9nSUR                  l        UR                  5         SS0 4SS0 4SS0 4SS0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4SS0 4/nU R                  UR                  U5        g )Nr   r  r  r  r  r/  r  b3r        ?r  rY   rs  F      J@     J@     K@     L@     M@      N@      O@      P@     @P@     P@     @Q@     Q@      R@       @      H@)r  r  r  r   r  r@   r  r   r!   r   r=   r   rT   r  r(   r-   r  r  r8   rG  r  s         r2   testChordsA2Test.testChordsA2_  s"   !d#MMO	T4s;<	T4s;<	4q12*1>#	tR3b/Cr?S$PROtR3b/tR3b/tR3b/tR3b/Cr?tR" 	'r5   c                &   SSK Jn  UR                  S5      n[        R                  " 5       nUR                  UR                  SSSS95        UR                  UR                  SS	S
S95        UR                  [        R                  " SSS95        [        US S9nSUR                  l        UR                  5         SS0 4SS0 4SS0 4SS0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4S
S0 4SS0 4/nU R                  UR                  U5        g )Nr   r  r  r  r  r/  r  r  r  r  r  rY   rs  Fr  r   r.  	      r  )r  r  r  r   r  r@   r  r   r!   r   r=   r   rT   r  r(   r  s         r2   testChordsA3Test.testChordsA3t  s!   !d#MMO	T4s;<	T4s;<	4q12*1>#	q"Q|c1b\CB<r2asArlS!RL3PQSU,q"Q|c2r]S!RLq" 	'r5   c                   SSK Jn  UR                  S5      n[        R                  " 5       nUR                  UR                  SSSS95        UR                  [        R                  " SS	S95        UR                  UR                  S
SSS95        UR                  [        R                  " SS	S95        U R                  U Vs/ s H  oDR                  PM     sn/ SQ5        [        US S9nUR                  5         SS0 4SS0 4SS0 4SS0 4SS0 4SS0 4SS0 4SS	0 4SS0 4SS	0 4/
nU R                  UR                  U5        g s  snf )Nr   r  r  r  r  r/  r  r  rY   r  e4r  d3)        r/        @      @rs  r  r  r   r.  r  r  r  r  )r  r  r  r   r  r@   r  r   r!   r  offsetr   rT   r(   )r-   r  r  r8   erG  r  s          r2   testChordsA4Test.testChordsA4  s3   !d#MMO	T4s;<	4q12	T4s;<	4q12A.Aq((A.0DE $A$7	q"Q|c1b\CB<q"r2asArlS!RLq" 	' /s   Ec                <   SSK Jn  UR                  S5      n[        R                  " 5       nUR                  [        R                  " S5      5        UR                  UR                  SSSS95        UR                  [        R                  " S	5      5        UR                  UR                  S
SSS95        [        US S9nUR                  5         U R                  UR                  SS0 4SS0 4SS0 4SS0 4SS0 4SS0 4SS0 4SS0 4SS0 4SS0 4SS0 4SS0 4/5        g )Nr   r  r  fr  r  r/  r  r  r  r  r  rs  4      5   7   9   ;   r   r  r  @   )r  r  r  r   r  r@   r   Dynamicr  r   rT   r  r(   r-   r  r  r8   rG  s        r2   testChordsA5Test.testChordsA5  s   !d#MMO	!!#&'	T4s;<	!!#&'	T4s;< +1>	2q"+Ar{RBK#%q"+Ar{RBK#%q"+Ar{RBK#%q"+Ar{RBK"I 	Jr5   c                	   SSK Jn  UR                  S5      n[        R                  " 5       nUR                  [        R                  " S5      5        UR                  UR                  SSSS95        UR                  UR                  S	S
SS95        [        US S9nUR                  5         SSS0 4SS0 4/0 /S/ 0 /SSS0 4/0 /S/ 0 /SSS0 4SS0 4/0 /SSS0 4/0 /S/ 0 /SSS0 4/0 /S/ 0 /SSS0 4/0 /S/ 0 /SSS0 4/0 //nU R                  UR                  U5        [        R                  " 5       nUR                  [        R                  " S5      5        UR                  UR                  SSSS95        UR                  UR                  S	S
SS95        [        US S9nUR                  5         SSS0 4/0 /S/ 0 /S/ 0 /S/ 0 /SSS0 4/0 /SSS0 4/0 /S/ 0 /SSS0 4/0 /S/ 0 /SSS0 4/0 /S/ 0 /SSS0 4/0 /SSS0 4/0 /S/ 0 /SSS0 4/0 /S/ 0 /SSS0 4/0 //nU R                  UR                  U5        [        R                  " 5       nUR                  [        R                  " S5      5        UR                  UR                  SSSS95        UR                  UR                  S	S
SS95        UR                  UR                  SSSS95        UR                  UR                  SSSS95        UR                  [        R                  " SSS95        [        US S9nS UR                  l        UR                  5         U R                  UR                  SS! SS"S#0 4SS$S#0 4SS%S#0 4SS&S#0 4SS'S#0 4SS(S#0 4SS)S#0 4/5        [        R                  " 5       nUR                  [        R                  " S5      5        UR                  UR                  SSSS95        UR                  UR                  S	S
SS95        UR                  UR                  SSSS95        UR                  UR                  SSSS95        UR                  [        R                  " SSS95        [#        US S9nS UR                  l        UR                  5         U R                  UR                  SS* SS+S#0 4SS,S#0 4SS!S#0 4SS-S#0 4SSS#0 4SSS#0 4SS.S#0 4SS+S#0 4/5        g )/Nr   r  r  r  r  r  r/  r  r  r  r  rs  Cr  g      ?g      ?r  r  r  r   g      ?FGr  r  C3C4f4g5rW   r  Fr.  r  rX   r  r  r  r  r  r  r  r  r   r  rY   )r  r  r  r   r  r@   r   r!   r  r  rT   r  r(   r  r+  r=   r   r2  r  s         r2   testChordsBTest.testChordsB  sd   !d#MMO	4!	T4s;<	T4s;<)!=	fb)C+<=rBb"fb)*B/b"fb)C+<=rBfb)*B/b"fb)*B/b"fb)*B/b"fb)*B/1 	' MMO	4!	T4s;<	T4s;<)!=	#vr*+R0b"b"b"fb)*B/fb)*B/b"fb)*B/b"fb)*B/b"fb)*B/#vr*+R0b"fb)*B/b"fb)*B/!1$ 	' MMO	4!	T4s;<	T4s;<	T4q9:	T4q9:	4q1221F#	!T1b'9Cq";MPSUY[\^`Oa(+T1b'9Cq";MPSUY[\^`Oa(+T1b'9'; 	<
 MMO	4!	T4s;<	T4s;<	T4q9:	T4q9:	4q1221F#	!Q2aB#qRSUW(+Q2(+Q2(+Q2aB#qRSUW'Z 	[r5   c           !        SSK Jn  UR                  S5      n[        R                  " 5       nUR                  [        R                  " S5      5        UR                  SSSS9nU R                  [        U5      S	5        U R                  U Vs/ s H  oUR                  R                  PM     sn/ S
Q5        UR                  U5        UR                  [        R                  " S5      5        UR                  UR                  SSSS95        UR                  [        R                  " S5      5        UR                  UR                  SSSS95        UR                  UR                  SSSS95        UR                  [        R                  " SSS95        [        US S9nSUR                   l        UR%                  5         SSS0 4SSS0 4SSS0 4SSS0 4SSS0 4SSS0 4SSS0 4SSS0 4SSS0 4SSS0 4S SS0 4S SS0 4S!S"S#0 4S!SS0 4S$S"S#0 4S$SS0 4S%S"S#0 4S%SS0 4S&S"S#0 4S&SS0 4S'S"S0 4S'SS0 4S(S"S#0 4S(SS0 4S)S"S#0 4S)SS0 4S*S"S#0 4S*SS0 4S+S"S#0 4S+SS0 4/nS,U l        U R                  UR(                  U5        g s  snf )-Nr   r  r  r  r  r  r/  r  z!<music21.chord.Chord E3 F3 G3 A3>)r  r  r  r  mfr  r  r  ppr  r  rW   r  rs  Fr  r  rX   r  r  r  r  r.  r  r  r  r  r  rY   r  r  r  r  g     R@g      S@g     @S@g     S@i   )r  r  r  r   r  r@   r   r  r  r  r7   r  psr   r!   r7  r=   r   rT   maxDiffr(   )r-   r  r  r8   r   r   rG  r  s           r2   testChordsB2Test.testChordsB2  s   !d#MMO	!!#&'KKd#K6a"EFa0a''**a02JK		!!$'(	T4s;<	!!$'(	T4q9:	T4q9:	4q1221F#	1b!D!Q#3dAq"5EaQRTVGW1b!D!Q#3dAq"5EaQRTVGW1b!D!Q#3dAq"5EaQRTVGW1b!D!Q#31b!D!Q#31b!D!Q#3dAq"5EaQRTVGW1b!D!Q#3dAq"5EaQRTVGW1b!D!Q#3dAq"5EaQRTVGW1b!D!Q#35 '3 1s   I<c                (   SSK Jn  UR                  S5      n[        R                  " 5       nUR                  [        R                  " S5      5        UR                  [        R                  " S5      5        UR                  UR                  SSSS	95        UR                  [        R                  " S
5      5        UR                  UR                  SSSS	95        UR                  [        R                  " S5      5        UR                  UR                  SSSS	95        UR                  [        R                  " SSS	95        [        US S9nSUR                  l        UR                  5         U R                  UR                   S   SSS0 45        g )Nr   r  r  r  r  r  r  r/  r  r  r  r  r  r   r  r  rW   r  rs  Fr  rX   )r  r  r  r   r  r@   r   r  r   r!   r  r  r=   r   rT   r  r(   r  s        r2   testChordsB3Test.testChordsB36  s#   !d#MMO	!!#&'	4!	T4s;<	!!$'(	T4s;<	!!$'(	T4q9:	4q12-aDA#	S$2$67r5   c                f    [         R                  " S5      n[        USS S9nUR                  5         g )NrB  Bach)r   ri  )r   r  r  rT   rE  s      r2   
testDolanATest.testDolanAK  s'    LL(!6d3	r5   )r  r   )r   r   r   r   r  r  rV  r[  r_  r  r  r  r  r  r  r  r  r  r  r  r  r
  r   r   r5   r2   r  r    sc    %


:2Tj(*(&(,J,[[|"(J8*r5   r  __main__)Nr   
__future__r   r2  numbersru  r  typingrI   unittestmusic21.analysisr   r   r   r   r  r   r	   r
   r   r   r   r   r   r   r   r   music21.graphr   r   music21.graph.utilitiesr   r   EnvironmentrX  ProtoM21Objectr   rH   r   r   r   r   r   r   r   r   r   r  r  r  r'  r"  r+  r2  r7  rN  r@  r  r  r  r  r  r  r  r  r  r
  r  r  r  r  r!  TestCaser@  r  
_DOC_ORDERr   mainTestr   r5   r2   <module>r     s   #   	    & % & %             $ I &&|4Lg,, L`
0!!? 0>j%% >;W ;>A%C A4g @/W /hB
))? BJ+) +<1) 184Y 4@*j55 *&_ >_ B1_ 1p~)z00/ ~)B9" 9<-& -*|J11? |~IM I>8M 822JAA? 2jt$! t$t*'' *"9
 9D0*44o 0fW${ W$xY** Yxz8 zD """!!	***%+
2 zT r5   