User’s Guide, Chapter 22: Graphing and plotting¶
Music notation isn’t the only way to understand music visually.
Sometimes a plot of a musical score can reveal relationships across a
piece that are hard to understand otherwise. music21
includes a lot
of ways to visualize notes, scores, and measures, and in this chapter we
will see some of the most common ones.
Piano Rolls!¶
The easiest way to see how pitches evolve over the course of a piece is to create a virtual representation of a piano roll. Unlike a traditional piano roll, time is usually represented on the horizontal axis and pitch height along the vertical. The easiest way to see how this works is simply to create one of these graphs, so we can get started. Let’s load up some Verdi:
from music21 import *
verdi = corpus.parse('verdi/laDonnaEMobile')
verdi.id = 'verdi'
verdi.measures(1, 10).show()
First, let’s visualize the vocal part alone:
voice = verdi.parts[0]
voice.measures(1, 10).plot()
<music21.graph.plot.HorizontalBarPitchSpaceOffset for <music21.stream.PartStaff P1-Staff1>>
The default here is to plot pitch against time, calculated in measures.
If you are following along with these examples in a Jupyter or Google notebook, be sure to execute the magic command:
::
%matplotlib inline
To ensure that the graphs show up inside your notebook.
music21
takes care of some of the hard things that can make
visualizing music in most data visualization software (such as Microsoft
Excel) difficult. For instance, measure numbers are used directly as
they appear in the score; pitches are labeled with names only when they
appear (including the choosing most commonly appearing enharmonic
spelling, using proper sharp and flat signs instead of “b” and “#”). We
can make a fake piece to see how this works:
fakePiece = converter.parse("tinyNotation: 1/4 c#4 2/4 d-4 e#4 3/4 e#2 f4 4/4 c#4 d'--2")
fakePiece.id = 'fake'
fakePiece.show()
fakePiece.plot()
<music21.graph.plot.HorizontalBarPitchSpaceOffset for <music21.stream.Part fake>>
(This was hard to do! And we’re, I hope justifiably, proud of getting things like this right. Major shoutout to Christopher Ariza who wrote 90% of the graphing code).
We can make other types of graphs just as easily. For instance, plotting lengths of notes against their position in space. For this one, a little piece by Schoenberg (Opus 19, no. 2) is great, since the repetition of G4 + B4 as eighth notes becomes clear:
schoenberg = corpus.parse('schoenberg/opus19', 2)
schoenberg.id = 'schoenberg'
schoenberg.measures(1, 4).show()
Let’s do a scatter plot of quarterLength against pitch:
schoenberg.plot('scatter', 'quarterLength', 'pitch', title='See the G and B!')
<music21.graph.plot.ScatterPitchSpaceQuarterLength for <music21.stream.Score schoenberg>>
It’s a little small on this website (you can make it as big as you want
on your own with the keyword dpi=400
or so), so maybe just a
histogram of pitch would be better:
schoenberg.plot('histogram', 'octave', xHideUnused=False, yAxisLabel='Number of Pitches')
<music21.graph.plot.Histogram for <music21.stream.Score schoenberg>>
Or even just pitch classes:
schoenberg.plot('histogram', 'pitchClass')
<music21.graph.plot.HistogramPitchClass for <music21.stream.Score schoenberg>>
Okay, so we’ve gotten a taste for graphs, let’s look more closely at how to make them:
Installing graphing software¶
All plots require installing the matplotlib
and numpy
libraries.
On python3
install them by typing at the command line:
pip3 install matplotlib
and numpy
will come along free. Depending on your Python
installation you might need to instead type:
sudo pip3 install matplotlib
In recent versions of OS X/macOS, such as El Capitan and Sierra, there
are some major problems in installing matplotlib
on some Python
installations (including Anaconda
python). This is why music21
recommends using the Python 3 installation directly from the Python.org
website. To use matplotlib inside a Jupyter
notebook, add
%matplotlib inline
to the first notebook cell. However this step may not be necessary if the music21 extension is installed with:
%load_ext music21.ipython21
For more information on installing, see Extending music21 with Additional Software
Where are graphs located?¶
Graphing functions are located in the music21.graph modules, specifically: music21.graph.primitives, music21.graph.plot and music21.graph.axis. With some utility functions located in music21.graph.utilities and music21.graph.findPlot.
What sorts of graphs are there?¶
We can look in graph.findPlot.FORMATS
for the list of possible
graphs:
graph.findPlot.FORMATS
['horizontalbar',
'histogram',
'scatter',
'scatterweighted',
'3dbars',
'colorgrid',
'horizontalbarweighted']
We might as well start by trying them!
verdi.plot('horizontalbar')
<music21.graph.plot.HorizontalBarPitchSpaceOffset for <music21.stream.Score verdi>>
There are three types of horizontalbar
types defined, so we got all
of them. For the next we’ll be more picky…
This one we’ve already seen. Same with the next one:
verdi.plot('histogram', 'pitch')
<music21.graph.plot.HistogramPitchSpace for <music21.stream.Score verdi>>
schoenberg.plot('scatter', 'pitch', 'quarterLength')
<music21.graph.plot.ScatterPitchSpaceQuarterLength for <music21.stream.Score schoenberg>>
There were two kinds of scatter plots – one that plotted quarter length against pitch and one that plotted pitch against dynamics. We’ll figure out how to get the one we want later. Let’s keep going:
verdi.measures(1, 10).plot('scatterweighted', 'pitch', 'quarterLength')
<music21.graph.plot.ScatterWeightedPitchSpaceQuarterLength for <music21.stream.Score verdi>>
verdi.plot('colorgrid')
<music21.graph.plot.WindowedKey for <music21.stream.Score verdi>>
Here we can see each part plotted when it plays and with dynamics:
schoenberg.plot('horizontalbarweighted')
<music21.graph.plot.HorizontalBarWeighted for <music21.stream.Score schoenberg>>
and we’ve saved the silliest for last:
verdi.plot('3dbars')
<music21.graph.plot.Plot3DBarsPitchSpaceQuarterLength for <music21.stream.Score verdi>>
The 3D aspect looks pretty cool, but I have a hard time learning from it.
Each of these plots also has a bunch of synonyms in case you want to use other terms:
graph.findPlot.FORMAT_SYNONYMS
[('horizontalbar', 'bar', 'horizontal', 'pianoroll', 'piano'),
('histogram', 'histo', 'count'),
('scatter', 'point'),
('scatterweighted', 'weightedscatter', 'weighted'),
('3dbars', '3d'),
('colorgrid', 'grid', 'window', 'windowed'),
('horizontalbarweighted', 'barweighted', 'weightedbar')]
For completeness, there are a couple of shortcuts you can use also:
graph.findPlot.PLOTCLASS_SHORTCUTS
{'ambitus': music21.graph.plot.WindowedAmbitus,
'dolan': music21.graph.plot.Dolan,
'instruments': music21.graph.plot.Dolan,
'key': music21.graph.plot.WindowedKey,
'pianoroll': music21.graph.plot.HorizontalBarPitchSpaceOffset}
Okay, so now you know what types of graphs you can make. The next arguments determine what sorts of things you can put on the axes:
verdi.plot('scatter', 'pitchClass', 'quarterLength')
<music21.graph.plot.ScatterPitchClassQuarterLength for <music21.stream.Score verdi>>
verdi.plot('scatter', 'dynamics')
<music21.graph.plot.ScatterPitchSpaceDynamicSymbol for <music21.stream.Score verdi>>
We can see all the different things that we can put as an axis via
music21.graph.findPlot.getAxisQuantities()
:
graph.findPlot.getAxisQuantities()
['generic',
'count',
'dynamic',
'offset',
'offsetEnd',
'pitchGeneric',
'pitchClass',
'pitchSpace',
'octave',
'position',
'quarterLength']
Some of these have synonyms that you can use instead:
graph.findPlot.getAxisQuantities(synonyms=True)
['generic',
'one',
'nothing',
'blank',
'count',
'quantity',
'frequency',
'counting',
'dynamic',
'dynamics',
'volume',
'offset',
'measure',
'offsets',
'measures',
'time',
'offsetEnd',
'timespans',
'timespan',
'pitchGeneric',
'pitchClass',
'pitchclass',
'pc',
'pitchSpace',
'pitch',
'pitchspace',
'ps',
'octave',
'octaves',
'position',
'positions',
'quarterLength',
'ql',
'quarterlengths',
'durations',
'duration']
Application – pitchSpace counting¶
Both Robert Schumann and Frederic Chopin were composers living in the first half of the nineteenth century, both working in the tonal tradition. Their music sounds similar but strikingly different. Does their distribution of pitches have something to do with it? Let’s compare a Schumann piece in the corpus (String Quartet opus 41, no. 1, movement 3) with a Chopin piece in the corpus (Mazurka in C# minor, opus 6, no. 2):
schumann = corpus.parse('schumann/opus41no1', 3)
schumann.plot('histogram', 'pitch')
<music21.graph.plot.HistogramPitchSpace for <music21.stream.Score 0x7f8128494460>>
Schumann’s piece has a sort of bell-curve shaped distribution. Yes, some notes stand out, A2, E3, and E4–it is in a-minor after all…
schumann.analyze('key')
<music21.key.Key of a minor>
but for the most part, it’s pretty nicely shaped. Compare it to the work by Chopin:
chopin = corpus.parse('chopin/mazurka')
chopin.plot('histogram', 'pitch')
<music21.graph.plot.HistogramPitchSpace for <music21.stream.Score 0x7f810eea4520>>
Chopin’s piece has jagged points everywhere like a poorly planned city (Abu Dhabi?) with a few notes, especially G#4 sticking out. Does this say something different about Chopin as a composer? Or is it a function of the fact that the Chopin piece is for piano and the Schumann piece is for a group of four instruments, three of which have different ranges? We can’t compare Chopin’s string quartets–he didn’t write any–and unfortunately, we can’t compare Robert Schumann’s piano music, since I don’t know any pieces except for very short ones and excerpts that have been entered into musicxml. But we can compare Clara Schumann’s pitch usage, since a freely available transcription of her four Polonaises, op. 1 has been encoded by “Cypressdome”. Let’s check out the first of these:
cs = corpus.parse('schumann_clara/polonaise_op1n1')
cs.id = 'Chopin'
cs.measures(1, 7).show()
unused = cs.plot('histogram', 'pitchSpace')
It’s one piece, and we’d love to have much more (in fact, the other three Polonaises are in the corpus as well), but it looks promising!
(Oh, and in case you’re tired of seeing all that
<music21.graph.plot.Histohooyet for <music21.stream...
garbage when
plotting, just assign the result of the plot to an unused variable as we
did above)
There’s a lot more that can be done with graphing, but that’s a topic for later. If we’re going to do traditional analysis we’ve got to know where our Is and Vs are, and for that, we’ll need Chapter 23: Roman Numeral Analysis