pip install dimcat Jinja2 colorlover GitPython plotly
%load_ext autoreload
%autoreload 2
import os
from collections import defaultdict, Counter
from fractions import Fraction
from IPython.display import HTML
import ms3
import dimcat as dc
from git import Repo
import plotly.express as px
import colorlover
import pandas as pd
import numpy as np
pd.set_option("display.max_columns", 100)
pd.set_option("display.max_rows", 500)
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.pyplot as plt
plt.set_loglevel('error')
def value_count_df(S, thing=None, counts='counts'):
thing = S.name if thing is None else thing
df = S.value_counts().rename(counts).to_frame()
df.index.rename(thing, inplace=True)
return df
def color_background(x, color="#ffffb3"):
return np.where(x.notna().to_numpy(), f"background-color: {color};", None)
This javascript allows to add a "Toggle Code" button to every cell as per http://www.eointravers.com/post/jupyter-toggle/
HTML('''<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('Show Code')
} else {
$('div.input').show('500');
$('#toggleButton').val('Hide Code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide()
});
</script>
<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Show Code"></form>''')
dataset_path = "~/all_subcorpora"
repo = Repo(dataset_path)
print(f"{os.path.basename(dataset_path)} repository @ commit {repo.commit().hexsha[:7]}")
print(f"dimcat version {dc.__version__}")
print(f"ms3 version {ms3.__version__}")
all_subcorpora repository @ commit c303877 dimcat version 0.2.0.post1.dev35+g9830b67 ms3 version 1.0.1
STD_LAYOUT = {
'paper_bgcolor': '#FFFFFF',
'plot_bgcolor': '#FFFFFF',
'margin': {'l': 40, 'r': 0, 'b': 0, 't': 40, 'pad': 0},
'font': {'size': 15}
}
import colorlover
#for name, scales in colorlover.scales['6']['qual'].items():
# print(name)
# display(HTML(colorlover.to_html(scales)))
cadence_colors = dict(zip(('HC', 'PAC', 'PC', 'IAC', 'DC', 'EC'), colorlover.scales['6']['qual']['Set1']))
dataset = dc.Dataset()
for folder in ['bach_solo', 'beethoven_piano_sonatas', 'c_schumann_lieder', 'chopin_mazurkas', 'corelli', 'debussy_suite_bergamasque', 'dvorak_silhouettes', 'grieg_lyrical_pieces', 'handel_keyboard', 'jc_bach_sonatas', 'liszt_pelerinage', 'mahler_kindertotenlieder', 'medtner_tales', 'pleyel_quartets', 'scarlatti_sonatas', 'schubert_dances', 'schumann_kinderszenen', 'tchaikovsky_seasons', 'wf_bach_sonatas']:
print("Loading", folder)
path = os.path.join(dataset_path, folder)
dataset.load(directory=path)
Loading bach_solo Loading beethoven_piano_sonatas Loading c_schumann_lieder Loading chopin_mazurkas Loading corelli Loading debussy_suite_bergamasque Loading dvorak_silhouettes Loading grieg_lyrical_pieces Loading handel_keyboard Loading jc_bach_sonatas Loading liszt_pelerinage Loading mahler_kindertotenlieder Loading medtner_tales Loading pleyel_quartets Loading scarlatti_sonatas Loading schubert_dances Loading schumann_kinderszenen Loading tchaikovsky_seasons Loading wf_bach_sonatas
dataset.data
[default|all]
All corpora
-----------
View: This view is called 'default'. It
- excludes fnames that are not contained in the metadata,
- filters out file extensions requiring conversion (such as .xml), and
- excludes review files and folders.
has active scores measures notes expanded
metadata view detected detected parsed detected parsed detected parsed
corpus
bach_solo yes default 68 68 68 68 68 68 68
beethoven_piano_sonatas yes default 87 87 87 87 87 64 64
c_schumann_lieder yes default 12 12 12 12 12 12 12
chopin_mazurkas yes default 55 55 55 55 55 55 55
corelli yes default 149 149 149 149 149 149 149
debussy_suite_bergamasque yes default 4 4 4 4 4 4 4
dvorak_silhouettes yes default 12 12 12 12 12 12 12
grieg_lyrical_pieces yes default 66 66 66 66 66 66 66
handel_keyboard yes default 6 6 6 6 6 6 6
jc_bach_sonatas yes default 29 29 29 29 29 29 29
liszt_pelerinage yes default 19 19 19 19 19 19 19
mahler_kindertotenlieder yes default 5 5 5 5 5 2 2
medtner_tales yes default 19 19 19 19 19 19 19
pleyel_quartets yes default 6 6 6 6 6 6 6
scarlatti_sonatas yes default 69 69 69 69 69 69 69
schubert_dances yes default 443 443 443 443 443 14 14
schumann_kinderszenen yes default 13 13 13 13 13 13 13
tchaikovsky_seasons yes default 12 12 12 12 12 12 12
wf_bach_sonatas yes default 9 9 9 9 9 9 9
951/5911 files are excluded from this view.
951 files have been excluded based on their file name.
There are 1 orphans that could not be attributed to any of the respective corpus's fnames.
#dataset = Corpus(directory=dataset_path)
#dataset.data
hascadence = dc.HasCadenceAnnotationsFilter().process_data(dataset)
display(HTML(f"<h4>Before: {len(dataset.indices[()])} pieces; "
f"after removing those without cadence labels: {len(hascadence.indices[()])}</h4>"))
INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 96) ms3.Parse.beethoven_piano_sonatas.04-3 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 96 (timesig 3/4, act_dur 1/4) is completed by 1 incorrect duration (expected: 1/2): {97: Fraction(3, 4)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 112) ms3.Parse.beethoven_piano_sonatas.04-3 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 112 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {25: Fraction(3, 4), 113: Fraction(1, 4)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 39) ms3.Parse.beethoven_piano_sonatas.13-1 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 39 (timesig 3/4, act_dur 1/8) is completed by 1 incorrect duration (expected: 5/8): {40: Fraction(3, 4)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 47) ms3.Parse.beethoven_piano_sonatas.13-1 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 47 (timesig 3/4, act_dur 5/8) is completed by 1 incorrect duration (expected: 1/8): {14: Fraction(1, 1), 48: Fraction(1, 8)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 267) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 267 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {268: Fraction(1, 2)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 269) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 269 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {270: Fraction(1, 2)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 271) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 271 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {272: Fraction(1, 2)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 273) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 273 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {274: Fraction(1, 2)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 275) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 275 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {276: Fraction(1, 2)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 277) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 277 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {278: Fraction(1, 2)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 279) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 279 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {280: Fraction(1, 2)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 281) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 281 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {282: Fraction(1, 2)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 283) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 283 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {284: Fraction(1, 2)} INCOMPLETE_MC_WRONGLY_COMPLETED_WARNING (3, 285) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 753) make_offset_col(): The incomplete MC 285 (timesig 3/4, act_dur 1/2) is completed by 1 incorrect duration (expected: 1/4): {286: Fraction(1, 2)} MCS_NOT_EXCLUDED_FROM_BARCOUNT_WARNING (1, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286) ms3.Parse.beethoven_piano_sonatas.13-4 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 204) check_measure_numbers(): MCs 268, 270, 272, 274, 276, 278, 280, 282, 284, 286 seem to be offset from the MN's beginning but have not been excluded from barcount. Context: mc mn act_dur mc_offset dont_count numbering_offset 266 267 266 1/2 0 <NA> <NA> 267 268 267 1/2 1/4 <NA> <NA> 268 269 268 1/2 0 <NA> <NA> 269 270 269 1/2 1/4 <NA> <NA> 270 271 270 1/2 0 <NA> <NA> 271 272 271 1/2 1/4 <NA> <NA> 272 273 272 1/2 0 <NA> <NA> 273 274 273 1/2 1/4 <NA> <NA> 274 275 274 1/2 0 <NA> <NA> 275 276 275 1/2 1/4 <NA> <NA> 276 277 276 1/2 0 <NA> <NA> 277 278 277 1/2 1/4 <NA> <NA> 278 279 278 1/2 0 <NA> <NA> 279 280 279 1/2 1/4 <NA> <NA> 280 281 280 1/2 0 <NA> <NA> 281 282 281 1/2 1/4 <NA> <NA> 282 283 282 1/2 0 <NA> <NA> 283 284 283 1/2 1/4 <NA> <NA> 284 285 284 1/2 0 <NA> <NA> 285 286 285 1/2 1/4 <NA> <NA> WARNING ms3.Parse.mahler_kindertotenlieder.kindertotenlieder_02_nun_seh_ich_wohl -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 617) squash_staves(): mc 42: The missing value in 'vspacerFixed' was replaced by '5.78307', present in 'staff' [2]. WARNING ms3.Parse.mahler_kindertotenlieder.kindertotenlieder_02_nun_seh_ich_wohl -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 617) squash_staves(): mc 66: The missing value in 'vspacerFixed' was replaced by '8.18246', present in 'staff' [2]. WARNING ms3.Parse.schubert_dances.D139trio01b -- /home/hentsche/PycharmProjects/ms3/src/ms3/utils.py (line 3264) unfold_measures_table(): Error in the repeat structure: Did not reach the stopping value -1 in measures.next: mc 1 (2,) 2 (3,) 3 (4,) 4 (5,) 5 (6,) 6 (7,) 7 (8,) 8 (9,) 9 (2, 10) 10 (11,) 11 (12,) 12 (13,) 13 (14,) 14 (15,) 15 (16,) 16 (17,) 17 (18,) 18 (19,) 19 (20,) 20 (21,) 21 (22,) 22 (23,) 23 (24,) 24 (25, 26) 25 (10,) 26 (1,) Name: next, dtype: object WARNING ms3.Parse.schubert_dances.D299ecossaise08 -- /home/hentsche/PycharmProjects/ms3/src/ms3/utils.py (line 3264) unfold_measures_table(): Error in the repeat structure: Did not reach the stopping value -1 in measures.next: mc 1 (2,) 2 (3,) 3 (4,) 4 (5,) 5 (6,) 6 (7,) 7 (8,) 8 (1, 9) 9 (10,) 10 (11,) 11 (12,) 12 (13,) 13 (14,) 14 (15,) 15 (16,) 16 (9, 1) Name: next, dtype: object UNUSED_FINE_MARKER_WARNING (20, 17) ms3.Parse.schubert_dances.D299ecossaise09 -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 266) __init__(): Piece has a Fine but the last MC is missing a repeat sign or a D.C. (da capo) or D.S. (dal segno). Ignoring Fine. WARNING ms3.Parse.schubert_dances.D299ecossaise10 -- /home/hentsche/PycharmProjects/ms3/src/ms3/utils.py (line 3264) unfold_measures_table(): Error in the repeat structure: Did not reach the stopping value -1 in measures.next: mc 1 (2,) 2 (3,) 3 (4,) 4 (5,) 5 (6,) 6 (7,) 7 (8,) 8 (1, 9) 9 (10,) 10 (11,) 11 (12,) 12 (13,) 13 (14,) 14 (15,) 15 (16,) 16 (9, 1) Name: next, dtype: object WARNING ms3.Parse.schubert_dances.D299ecossaise12 -- /home/hentsche/PycharmProjects/ms3/src/ms3/utils.py (line 3264) unfold_measures_table(): Error in the repeat structure: Did not reach the stopping value -1 in measures.next: mc 1 (2,) 2 (3,) 3 (4,) 4 (5,) 5 (6,) 6 (7,) 7 (8,) 8 (1, 9) 9 (10,) 10 (11,) 11 (12,) 12 (13,) 13 (14,) 14 (15,) 15 (16,) 16 (9, 1) Name: next, dtype: object UNUSED_FINE_MARKER_WARNING (20, 19) ms3.Parse.schubert_dances.D735galopp01a -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 266) __init__(): Piece has a Fine but the last MC is missing a repeat sign or a D.C. (da capo) or D.S. (dal segno). Ignoring Fine. PLAY_UNTIL_IS_MISSING_LABEL_WARNING (21, 16) ms3.Parse.schubert_dances.D735trio01b -- /home/hentsche/PycharmProjects/ms3/src/ms3/bs4_measures.py (line 325) jump2marker(): After jumping from MC 16 to start, the music is supposed to play until label fine but there is no corresponding marker in the score. Ignoring. WARNING ms3.Parse.schubert_dances.D735trio01b -- /home/hentsche/PycharmProjects/ms3/src/ms3/utils.py (line 3264) unfold_measures_table(): Error in the repeat structure: Did not reach the stopping value -1 in measures.next: mc 1 (2,) 2 (3,) 3 (4,) 4 (5,) 5 (6,) 6 (7,) 7 (8,) 8 (1, 9) 9 (10,) 10 (11,) 11 (12,) 12 (13,) 13 (14,) 14 (15,) 15 (16,) 16 (9, 1) Name: next, dtype: object
grouped_by_dataset = dc.CorpusGrouper().process_data(hascadence)
corpora = {group[0]: f"{len(ixs)} pieces" for group, ixs in grouped_by_dataset.indices.items()}
print(f"{len(corpora)} corpora with {sum(map(len, grouped_by_dataset.indices.values()))} pieces containing cadence annotations:")
corpora
19 corpora with 532 pieces containing cadence annotations:
{'bach_solo': '32 pieces', 'beethoven_piano_sonatas': '64 pieces', 'c_schumann_lieder': '12 pieces', 'chopin_mazurkas': '50 pieces', 'corelli': '145 pieces', 'debussy_suite_bergamasque': '4 pieces', 'dvorak_silhouettes': '12 pieces', 'grieg_lyrical_pieces': '65 pieces', 'handel_keyboard': '6 pieces', 'jc_bach_sonatas': '29 pieces', 'liszt_pelerinage': '19 pieces', 'mahler_kindertotenlieder': '2 pieces', 'medtner_tales': '15 pieces', 'pleyel_quartets': '6 pieces', 'scarlatti_sonatas': '25 pieces', 'schubert_dances': '14 pieces', 'schumann_kinderszenen': '13 pieces', 'tchaikovsky_seasons': '12 pieces', 'wf_bach_sonatas': '7 pieces'}
all_labels = hascadence.get_facet('expanded')
print(f"{len(all_labels.index)} hand-annotated harmony labels:")
all_labels.iloc[:10, 14:].style.apply(color_background, subset="chord")
86492 hand-annotated harmony labels:
globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
corpus | fname | interval | |||||||||||||||||||||
bach_solo | BWV1009_01_Prelude | [0.0, 6.0) | C | I | nan | I | I | nan | nan | nan | nan | nan | { | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan |
[6.0, 8.0) | C | I | nan | V | V | nan | nan | nan | nan | nan | nan | M | False | False | (1, 5, 2) | () | 1 | 1 | nan | nan | nan | ||
[8.0, 9.0) | C | I | nan | V7 | V | nan | 7 | nan | nan | nan | nan | Mm7 | False | False | (1, 5, 2, -1) | () | 1 | 1 | nan | nan | nan | ||
[9.0, 12.0) | C | I | nan | I | I | nan | nan | nan | nan | nan | nan | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | ||
[12.0, 14.0) | C | I | nan | V | V | nan | nan | nan | nan | nan | nan | M | False | False | (1, 5, 2) | () | 1 | 1 | nan | nan | nan | ||
[14.0, 15.0) | C | I | nan | V7 | V | nan | 7 | nan | nan | nan | nan | Mm7 | False | False | (1, 5, 2, -1) | () | 1 | 1 | nan | nan | nan | ||
[15.0, 20.0) | C | I | nan | I | I | nan | nan | nan | nan | nan | } | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | ||
[18.25, 18.25) | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | ||||
[20.0, 21.0) | C | I | nan | ii/V | ii | nan | nan | nan | V | nan | nan | m | False | False | (3, 0, 4) | () | 3 | 3 | nan | nan | nan | ||
[21.0, 23.0) | C | I | nan | V6/V | V | nan | 6 | nan | V | nan | nan | M | False | False | (6, 3, 2) | () | 2 | 6 | nan | nan | nan |
HTML('''<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('Show Code')
} else {
$('div.input').show('500');
$('#toggleButton').val('Hide Code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide()
});
</script>
<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Show Code"></form>''')
dataset_metadata = hascadence.data.metadata()
hascadence_metadata = dataset_metadata.loc[hascadence.indices[()]]
hascadence_metadata.index.rename('dataset', level=0, inplace=True)
hascadence_metadata.head()
TimeSig | KeySig | last_mc | last_mn | label_count | harmony_version | annotated_key | annotators | composed_start | composed_end | composer | workTitle | movementNumber | movementTitle | workNumber | poet | lyricist | arranger | copyright | creationDate | mscVersion | platform | source | translator | musescore | ambitus | rel_paths | originalFormat | staff_1_ambitus | staff_1_instrument | length_qb | length_qb_unfolded | all_notes_qb | n_onsets | n_onset_positions | reviewers | Reviewers | staff_2_ambitus | staff_2_instrument | score_integrity | imslp | staff_3_ambitus | staff_3_instrument | key | mode | typesetter | annotator | electronic editor | electronic encoder | staff_4_ambitus | staff_4_instrument | score integrity | comments | extension | md5 | viaf | Deutsch | dance | goldenberg_id | ||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
dataset | fname | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bach_solo | BWV1009_01_Prelude | 1: 3/4 | 1: 0 | 88 | 88 | 113 | 2.3.0 | C | Adrian Nagel | 1717 | 1723 | Bach, J.S. | Cello Suite No.3 in C major | 1 | NaN | NaN | NaN | NaN | NaN | NaN | 2021-02-21 | NaN | Apple Macintosh | NaN | NaN | 3.6.2 | 36-67 (C2-G4) | MS3 | NaN | 36-67 (C2-G4) | Piano | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
BWV1009_02_Allemande | 1: 4/4 | 1: 0 | 25 | 24 | 106 | 2.3.0 | C | Adrian Nagel | 1717 | 1723 | Bach, J.S. | Cello Suite No.3 in C major | 2 | NaN | NaN | NaN | NaN | NaN | NaN | 2021-02-21 | NaN | Apple Macintosh | NaN | NaN | 3.6.0 | 36-67 (C2-G4) | MS3 | NaN | 36-67 (C2-G4) | Piano | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | |
BWV1009_03_Courante | 1: 6/8 | 1: 0 | 86 | 84 | 83 | 2.3.0 | C | Adrian Nagel | 1717 | 1723 | Bach, J.S. | Cello Suite No.3 in C major | 3 | NaN | NaN | NaN | NaN | NaN | NaN | 2021-02-21 | NaN | Apple Macintosh | NaN | NaN | 3.6.0 | 36-64 (C2-E4) | MS3 | NaN | 36-64 (C2-E4) | Piano | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | |
BWV1009_04_Sarabande | 1: 3/4 | 1: 0 | 24 | 24 | 55 | 2.3.0 | C | Adrian Nagel | 1717 | 1723 | Bach, J.S. | Cello Suite No.3 in C major | 4 | NaN | NaN | NaN | NaN | NaN | NaN | 2021-03-08 | NaN | Apple Macintosh | NaN | NaN | 3.6.0 | 36-67 (C2-G4) | MS3 | NaN | 36-67 (C2-G4) | Piano | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | |
BWV1009_05_BourréeI | 1: 2/2 | 1: 0 | 29 | 28 | 64 | 2.3.0 | C | Adrian Nagel | 1717 | 1723 | Bach, J.S. | Cello Suite No.3 in C major | 5 | NaN | NaN | NaN | NaN | NaN | NaN | 2021-02-21 | NaN | Apple Macintosh | NaN | NaN | 3.6.2 | 36-65 (C2-F4) | MS3 | NaN | 36-65 (C2-F4) | Piano | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
mean_composition_years = hascadence_metadata.groupby(level=0).composed_end.mean().astype(int).sort_values()
chronological_order = mean_composition_years.index.to_list()
bar_data = pd.concat([mean_composition_years.rename('year'),
hascadence_metadata.groupby(level='dataset').size().rename('pieces')],
axis=1
).reset_index()
fig = px.bar(bar_data, x='year', y='pieces', color='dataset', title='Pieces contained in the dataset')
fig.update_traces(width=5)
segmented_by_keys = dc.Pipeline([
dc.LocalKeySlicer(),
dc.ModeGrouper()])\
.process_data(hascadence)
key_segments = segmented_by_keys.get_slice_info()
No localkey known for ('scarlatti_sonatas', 'K099'). Skipping.
print(key_segments.duration_qb.dtype)
key_segments.duration_qb = pd.to_numeric(key_segments.duration_qb)
object
key_segments.iloc[:15, 11:].fillna('').style.apply(color_background, subset="localkey")
label | alt_label | regex_match | globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | ||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
localkey_is_minor | corpus | fname | localkey_slice | ||||||||||||||||||||||||
False | bach_solo | BWV1009_01_Prelude | [0.0, 264.0) | C.I{ | dcml | C | I | I | I | { | M | False | False | (0, 4, 1) | () | 0 | 0 | ||||||||||
BWV1009_02_Allemande | [0.0, 16.75) | C.V{ | dcml | C | I | V | V | { | M | False | False | (1, 5, 2) | () | 1 | 1 | ||||||||||||
[16.75, 52.75) | V.V6 | dcml | C | V | V6 | V | 6 | M | False | False | (5, 2, 1) | () | 1 | 5 | |||||||||||||
[68.75, 96.0) | I.V7/IV | dcml | C | I | V7/IV | V | 7 | IV | Mm7 | False | False | (0, 4, 1, -2) | () | 0 | 0 | ||||||||||||
BWV1009_03_Courante | [0.0, 24.5) | C.I{ | dcml | C | I | I | I | { | M | False | False | (0, 4, 1) | () | 0 | 0 | ||||||||||||
[24.5, 123.5) | V.I6 | dcml | C | V | I6 | I | 6 | M | False | False | (4, 1, 0) | () | 0 | 4 | |||||||||||||
[168.5, 252.0) | I.V7/IV | dcml | C | I | V7/IV | V | 7 | IV | Mm7 | False | False | (0, 4, 1, -2) | () | 0 | 0 | ||||||||||||
BWV1009_04_Sarabande | [0.0, 13.0) | C.I{ | dcml | C | I | I | I | { | M | False | False | (0, 4, 1) | () | 0 | 0 | ||||||||||||
[13.0, 27.0) | V.ii7 | dcml | C | V | ii7 | ii | 7 | mm7 | False | False | (2, -1, 3, 0) | () | 2 | 2 | |||||||||||||
[48.0, 60.0) | V.viio64{ | dcml | C | V | viio64 | vii | o | 64 | { | o | False | False | (-1, 5, 2) | () | 5 | -1 | |||||||||||
[60.0, 72.0) | I.viio64/IV | dcml | C | I | viio64/IV | vii | o | 64 | IV | o | False | False | (-2, 4, 1) | () | 4 | -2 | |||||||||||
BWV1009_05_BourréeI | [0.0, 17.0) | C.I6{ | dcml | C | I | I6 | I | 6 | { | M | False | False | (4, 1, 0) | () | 0 | 4 | |||||||||||
[17.0, 40.0) | V.ii | dcml | C | V | ii | ii | m | False | False | (2, -1, 3) | () | 2 | 2 | ||||||||||||||
[66.0, 112.0) | I.V/V | dcml | C | I | V/V | V | V | M | False | False | (2, 6, 3) | () | 2 | 2 | |||||||||||||
BWV1009_06_BourréeII | [17.0, 41.0) | III.I{ | dcml | c | III | I | I | { | M | True | False | (0, 4, 1) | () | 0 | 0 |
maj_min_ratio = key_segments.groupby(level="localkey_is_minor").duration_qb.sum().to_frame()
maj_min_ratio['fraction'] = (100.0 * maj_min_ratio.duration_qb / maj_min_ratio.duration_qb.sum()).round(1)
maj_min_ratio
duration_qb | fraction | |
---|---|---|
localkey_is_minor | ||
False | 82518.375 | 62.2 |
True | 50119.500 | 37.8 |
segment_duration_per_dataset = key_segments.groupby(level=["corpus", "localkey_is_minor"]).duration_qb.sum().round(2)
norm_segment_duration_per_dataset = 100 * segment_duration_per_dataset / segment_duration_per_dataset.groupby(level="corpus").sum()
maj_min_ratio_per_dataset = pd.concat([segment_duration_per_dataset,
norm_segment_duration_per_dataset.rename('fraction').round(1).astype(str)+" %"],
axis=1)
segment_duration_per_dataset = key_segments.groupby(level=["corpus", "localkey_is_minor"]).duration_qb.sum().reset_index()
maj_min_ratio_per_dataset.reset_index()
corpus | localkey_is_minor | duration_qb | fraction | |
---|---|---|---|---|
0 | bach_solo | False | 3340.00 | 59.5 % |
1 | bach_solo | True | 2277.25 | 40.5 % |
2 | beethoven_piano_sonatas | False | 23659.75 | 66.3 % |
3 | beethoven_piano_sonatas | True | 12003.38 | 33.7 % |
4 | c_schumann_lieder | False | 1296.00 | 88.9 % |
5 | c_schumann_lieder | True | 162.50 | 11.1 % |
6 | chopin_mazurkas | False | 7845.50 | 57.2 % |
7 | chopin_mazurkas | True | 5881.75 | 42.8 % |
8 | corelli | False | 9178.00 | 52.8 % |
9 | corelli | True | 8215.00 | 47.2 % |
10 | debussy_suite_bergamasque | False | 584.00 | 36.1 % |
11 | debussy_suite_bergamasque | True | 1032.00 | 63.9 % |
12 | dvorak_silhouettes | False | 1239.50 | 66.9 % |
13 | dvorak_silhouettes | True | 613.00 | 33.1 % |
14 | grieg_lyrical_pieces | False | 9900.17 | 60.4 % |
15 | grieg_lyrical_pieces | True | 6504.33 | 39.6 % |
16 | handel_keyboard | False | 218.00 | 100.0 % |
17 | jc_bach_sonatas | False | 6653.00 | 80.0 % |
18 | jc_bach_sonatas | True | 1659.50 | 20.0 % |
19 | liszt_pelerinage | False | 6833.42 | 70.4 % |
20 | liszt_pelerinage | True | 2868.46 | 29.6 % |
21 | mahler_kindertotenlieder | True | 685.00 | 100.0 % |
22 | medtner_tales | False | 1598.67 | 38.8 % |
23 | medtner_tales | True | 2523.33 | 61.2 % |
24 | pleyel_quartets | False | 1713.00 | 56.5 % |
25 | pleyel_quartets | True | 1321.50 | 43.5 % |
26 | scarlatti_sonatas | False | 3307.88 | 59.9 % |
27 | scarlatti_sonatas | True | 2211.50 | 40.1 % |
28 | schubert_dances | False | 882.00 | 95.6 % |
29 | schubert_dances | True | 41.00 | 4.4 % |
30 | schumann_kinderszenen | False | 700.00 | 74.9 % |
31 | schumann_kinderszenen | True | 234.00 | 25.1 % |
32 | tchaikovsky_seasons | False | 2387.00 | 60.9 % |
33 | tchaikovsky_seasons | True | 1532.00 | 39.1 % |
34 | wf_bach_sonatas | False | 1182.50 | 77.0 % |
35 | wf_bach_sonatas | True | 354.00 | 23.0 % |
chronological_order
['corelli', 'handel_keyboard', 'bach_solo', 'scarlatti_sonatas', 'wf_bach_sonatas', 'jc_bach_sonatas', 'pleyel_quartets', 'beethoven_piano_sonatas', 'schubert_dances', 'chopin_mazurkas', 'schumann_kinderszenen', 'c_schumann_lieder', 'liszt_pelerinage', 'tchaikovsky_seasons', 'dvorak_silhouettes', 'grieg_lyrical_pieces', 'mahler_kindertotenlieder', 'debussy_suite_bergamasque', 'medtner_tales']
fig = px.bar(maj_min_ratio_per_dataset.reset_index(),
x="corpus",
y="duration_qb",
color="localkey_is_minor",
text='fraction',
labels=dict(dataset='', duration_qb="aggregated duration in quarter notes"),
category_orders=dict(dataset=chronological_order)
)
fig.update_layout(**STD_LAYOUT)
annotations_by_keys = segmented_by_keys.get_facet("expanded")
annotations_by_keys
quarterbeats | duration_qb | mc | mn | mc_onset | mn_onset | timesig | staff | voice | volta | harmony_layer | label | alt_label | regex_match | globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | |||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
localkey_is_minor | corpus | fname | localkey_slice | interval | |||||||||||||||||||||||||||||||||||
False | bach_solo | BWV1009_01_Prelude | [0.0, 264.0) | [0.0, 6.0) | 0 | 6.0 | 1 | 1 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | C.I{ | NaN | dcml | C | I | NaN | I | I | NaN | NaN | NaN | NaN | NaN | { | M | False | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN |
[6.0, 8.0) | 6 | 2.0 | 3 | 3 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | V | NaN | dcml | C | I | NaN | V | V | NaN | NaN | NaN | NaN | NaN | NaN | M | False | False | (1, 5, 2) | () | 1 | 1 | NaN | NaN | NaN | ||||
[8.0, 9.0) | 8 | 1.0 | 3 | 3 | 1/2 | 1/2 | 3/4 | 1 | 1 | <NA> | 1 | V7 | NaN | dcml | C | I | NaN | V7 | V | NaN | 7 | NaN | NaN | NaN | NaN | Mm7 | False | False | (1, 5, 2, -1) | () | 1 | 1 | NaN | NaN | NaN | ||||
[9.0, 12.0) | 9 | 3.0 | 4 | 4 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | I | NaN | dcml | C | I | NaN | I | I | NaN | NaN | NaN | NaN | NaN | NaN | M | False | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN | ||||
[12.0, 14.0) | 12 | 2.0 | 5 | 5 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | V | NaN | dcml | C | I | NaN | V | V | NaN | NaN | NaN | NaN | NaN | NaN | M | False | False | (1, 5, 2) | () | 1 | 1 | NaN | NaN | NaN | ||||
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
True | wf_bach_sonatas | F003_n04c | [266.0, 335.0) | [327.0, 327.0) | 327 | 0.0 | 84 | 82 | 1/2 | 1/2 | 2/2 | 2 | 1 | <NA> | 1 | { | NaN | dcml | D | vi | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | { | NaN | False | True | () | () | <NA> | <NA> | NaN | NaN | NaN |
[330.0, 331.0) | 330 | 1.0 | 85 | 83 | 1/4 | 1/4 | 2/2 | 2 | 1 | <NA> | 1 | i6 | NaN | dcml | D | vi | NaN | i6 | i | NaN | 6 | NaN | NaN | NaN | NaN | m | False | True | (-3, 1, 0) | () | 0 | -3 | NaN | NaN | NaN | ||||
[331.0, 332.0) | 331 | 1.0 | 85 | 83 | 1/2 | 1/2 | 2/2 | 2 | 1 | <NA> | 1 | iv | NaN | dcml | D | vi | NaN | iv | iv | NaN | NaN | NaN | NaN | NaN | NaN | m | False | True | (-1, -4, 0) | () | -1 | -1 | NaN | NaN | NaN | ||||
[332.0, 333.0) | 332 | 1.0 | 85 | 83 | 3/4 | 3/4 | 2/2 | 2 | 1 | <NA> | 1 | V | NaN | dcml | D | vi | NaN | V | V | NaN | NaN | NaN | NaN | NaN | NaN | M | False | True | (1, 5, 2) | () | 1 | 1 | NaN | NaN | NaN | ||||
[333.0, 335.0) | 333 | 2.0 | 86 | 84 | 0 | 0 | 2/2 | 2 | 1 | <NA> | 1 | i|IAC}{ | NaN | dcml | D | vi | NaN | i | i | NaN | NaN | NaN | NaN | IAC | }{ | m | False | True | (0, -3, 1) | () | 0 | 0 | NaN | NaN | NaN |
86305 rows × 35 columns
HTML('''<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('Show Code')
} else {
$('div.input').show('500');
$('#toggleButton').val('Hide Code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide()
});
</script>
<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Show Code"></form>''')
all_labels.groupby(["corpus"]).phraseend.value_counts()
corpus phraseend bach_solo } 172 { 170 }{ 24 beethoven_piano_sonatas } 925 { 918 }{ 424 c_schumann_lieder { 55 } 55 }{ 34 chopin_mazurkas } 505 { 498 }{ 49 corelli } 691 { 686 }{ 353 debussy_suite_bergamasque } 15 { 13 }{ 10 dvorak_silhouettes { 93 } 92 }{ 77 grieg_lyrical_pieces } 517 { 514 }{ 33 handel_keyboard { 25 } 25 }{ 1 jc_bach_sonatas } 297 { 293 }{ 144 \\ 5 liszt_pelerinage } 208 { 205 }{ 68 mahler_kindertotenlieder } 8 { 7 }{ 2 medtner_tales { 146 } 146 }{ 51 pleyel_quartets } 86 { 85 }{ 40 scarlatti_sonatas } 285 { 282 }{ 85 schubert_dances { 60 } 60 schumann_kinderszenen } 83 { 79 }{ 2 tchaikovsky_seasons { 291 } 287 }{ 10 wf_bach_sonatas { 73 } 73 }{ 51 Name: phraseend, dtype: int64
all_labels[all_labels.phraseend == r'\\'].style.apply(color_background, subset="label")
quarterbeats | duration_qb | mc | mn | mc_onset | mn_onset | timesig | staff | voice | volta | harmony_layer | label | alt_label | regex_match | globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
corpus | fname | interval | |||||||||||||||||||||||||||||||||||
jc_bach_sonatas | wa01op05no1a_Allegretto | [124.0, 124.0) | 124 | 0.000000 | 64 | 62 | 0 | 0 | 2/4 | 2 | 1 | 1 | \\ | nan | dcml | Bb | I | nan | nan | nan | nan | nan | nan | nan | nan | \\ | nan | False | False | () | () | nan | nan | nan | |||
wa04op05no4a_Allegro | [168.0, 172.0) | 168 | 4.000000 | 43 | 43 | 0 | 0 | 4/4 | 2 | 1 | 1 | I]\\ | nan | dcml | Eb | V | I | I | I | nan | nan | nan | nan | nan | \\ | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | ||
[464.0, 468.0) | 464 | 4.000000 | 117 | 117 | 0 | 0 | 4/4 | 2 | 1 | 1 | I]\\ | nan | dcml | Eb | I | I | I | I | nan | nan | nan | nan | nan | \\ | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | |||
wa05op05no5b_Adagio | [10.0, 11.0) | 10 | 1.000000 | 4 | 4 | 1/4 | 1/4 | 3/4 | 2 | 1 | 1 | I\\ | nan | dcml | A | I | nan | I | I | nan | nan | nan | nan | nan | \\ | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | ||
[118.0, 119.0) | 118 | 1.000000 | 40 | 40 | 1/4 | 1/4 | 3/4 | 2 | 1 | 1 | I\\ | nan | dcml | A | I | nan | I | I | nan | nan | nan | nan | nan | \\ | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan |
Relevant columns:
quarterbeats
: start position for each phraseduration_qb
: duration of each phrase, measured in quarter notesphrase_slice
: time interval of each annotated phrases (for segmenting chord progressions and notes)# segmented = PhraseSlicer().process_data(hascadence)
segmented = dc.PhraseSlicer().process_data(grouped_by_dataset)
phrases = segmented.get_slice_info()
print(f"Overall number of phrases is {len(phrases.index)}")
phrases.head(10).style.apply(color_background, subset=["quarterbeats", "duration_qb"])
WARNING:scarlatti_sonatas_K099:Error while creating durations from quarterbeats column. Error: list index out of range
Overall number of phrases is 5951
mc | mn | quarterbeats | duration_qb | mc_onset | mn_onset | timesig | staff | voice | volta | harmony_layer | label | alt_label | regex_match | globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
corpus | fname | phrase_slice | |||||||||||||||||||||||||||||||||||
bach_solo | BWV1009_01_Prelude | [0.0, 18.25) | 1 | 1 | 0 | 18.250000 | 0 | 0 | 3/4 | 1 | 1 | 1 | C.I{ | nan | dcml | C | I | nan | I | I | nan | nan | nan | nan | nan | { | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | |
[18.25, 36.25) | 7 | 7 | 73/4 | 18.000000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[36.25, 78.0) | 13 | 13 | 145/4 | 41.750000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[78.0, 108.0) | 27 | 27 | 78 | 30.000000 | 0 | 0 | 3/4 | 1 | 1 | 1 | vi}{ | nan | dcml | C | I | nan | vi | vi | nan | nan | nan | nan | nan | }{ | m | False | False | (3, 0, 4) | () | 3 | 3 | nan | nan | nan | |||
[108.0, 180.25) | 37 | 37 | 108 | 72.250000 | 0 | 0 | 3/4 | 1 | 1 | 1 | I}{ | nan | dcml | C | I | nan | I | I | nan | nan | nan | nan | nan | }{ | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | |||
[180.25, 210.25) | 61 | 61 | 721/4 | 30.000000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[210.25, 244.25) | 71 | 71 | 841/4 | 34.000000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[244.25, 264.0) | 82 | 82 | 977/4 | 19.750000 | 5/16 | 5/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | I | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
BWV1009_02_Allemande | [0.0, 15.75) | 1 | 0 | 0 | 15.750000 | 0 | 13/16 | 4/4 | 1 | 1 | 1 | C.V{ | nan | dcml | C | I | nan | V | V | nan | nan | nan | nan | nan | { | M | False | False | (1, 5, 2) | () | 1 | 1 | nan | nan | nan | ||
[15.75, 48.0) | 5 | 4 | 63/4 | 32.250000 | 3/4 | 3/4 | 4/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan |
print(phrases.duration_qb.dtype)
phrases.duration_qb = pd.to_numeric(phrases.duration_qb)
object
ToDo: Example for overlap / phrase beginning without new chord
phrase_segments = segmented.get_facet("expanded")
phrase_segments.head(10)
quarterbeats | duration_qb | mc | mn | mc_onset | mn_onset | timesig | staff | voice | volta | harmony_layer | label | alt_label | regex_match | globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | ||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
corpus | fname | phrase_slice | interval | |||||||||||||||||||||||||||||||||||
bach_solo | BWV1009_01_Prelude | [0.0, 18.25) | [0.0, 0.0) | 0.0 | 0.00 | 1 | 1 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | C.I{ | <NA> | dcml | C | I | NaN | <NA> | <NA> | <NA> | <NA> | <NA> | <NA> | NaN | { | <NA> | False | False | <NA> | <NA> | <NA> | <NA> | NaN | NaN | NaN |
[0.0, 6.0) | 0.0 | 6.00 | 1 | 1 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | C.I{ | NaN | dcml | C | I | NaN | I | I | NaN | NaN | NaN | NaN | <NA> | <NA> | M | False | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN | |||
[6.0, 8.0) | 6.0 | 2.00 | 3 | 3 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | V | NaN | dcml | C | I | NaN | V | V | NaN | NaN | NaN | NaN | NaN | NaN | M | False | False | (1, 5, 2) | () | 1 | 1 | NaN | NaN | NaN | |||
[8.0, 9.0) | 8.0 | 1.00 | 3 | 3 | 1/2 | 1/2 | 3/4 | 1 | 1 | <NA> | 1 | V7 | NaN | dcml | C | I | NaN | V7 | V | NaN | 7 | NaN | NaN | NaN | NaN | Mm7 | False | False | (1, 5, 2, -1) | () | 1 | 1 | NaN | NaN | NaN | |||
[9.0, 12.0) | 9.0 | 3.00 | 4 | 4 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | I | NaN | dcml | C | I | NaN | I | I | NaN | NaN | NaN | NaN | NaN | NaN | M | False | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN | |||
[12.0, 14.0) | 12.0 | 2.00 | 5 | 5 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | V | NaN | dcml | C | I | NaN | V | V | NaN | NaN | NaN | NaN | NaN | NaN | M | False | False | (1, 5, 2) | () | 1 | 1 | NaN | NaN | NaN | |||
[14.0, 15.0) | 14.0 | 1.00 | 5 | 5 | 1/2 | 1/2 | 3/4 | 1 | 1 | <NA> | 1 | V7 | NaN | dcml | C | I | NaN | V7 | V | NaN | 7 | NaN | NaN | NaN | NaN | Mm7 | False | False | (1, 5, 2, -1) | () | 1 | 1 | NaN | NaN | NaN | |||
[15.0, 15.0) | 15.0 | 0.00 | 6 | 6 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | I} | <NA> | dcml | C | I | NaN | <NA> | <NA> | <NA> | <NA> | <NA> | <NA> | NaN | } | <NA> | False | False | <NA> | <NA> | <NA> | <NA> | NaN | NaN | NaN | |||
[15.0, 18.25) | 15.0 | 3.25 | 6 | 6 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | I} | NaN | dcml | C | I | NaN | I | I | NaN | NaN | NaN | NaN | <NA> | <NA> | M | False | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN | |||
[18.25, 36.25) | [18.25, 18.25) | 18.25 | 0.00 | 7 | 7 | 1/16 | 1/16 | 3/4 | 1 | 1 | <NA> | 1 | { | NaN | dcml | C | I | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | { | NaN | False | False | () | () | <NA> | <NA> | NaN | NaN | NaN |
print(phrase_segments.duration_qb.dtype)
phrase_segments.duration_qb = pd.to_numeric(phrase_segments.duration_qb)
float64
phrase_durations = phrases.duration_qb.value_counts()
histogram = px.histogram(x=phrase_durations.index, y=phrase_durations, labels=dict(x='phrase lengths binned to a quarter note', y='#phrases within length bin'))
histogram.update_traces(xbins=dict( # bins used for histogram
#start=0.0,
end=100.0,
size=1
))
histogram.update_xaxes(dtick=4)
histogram.show()
Simply by subtracting for the span of every phrase the first measure measure number from the last.
phrase_gpb = phrase_segments.groupby(level=[0,1,2])
phrase_length_in_measures = phrase_gpb.mn.max() - phrase_gpb.mn.min()
measure_length_counts = phrase_length_in_measures.value_counts()
fig = px.bar(x=measure_length_counts.index, y=measure_length_counts, labels=dict(x="approximative size of all phrases (difference between end and start measure number)",
y="#phrases"))
fig.update_xaxes(dtick=4)
In order to divide the phrase length by the length of a measure, the phrases containing more than one time signature are filtered out.
Durations computed by dividing the duration by the measure length
phrase2timesigs = phrase_gpb.timesig.unique()
n_timesignatures_per_phrase = phrase2timesigs.map(len)
uniform_timesigs = phrase2timesigs[n_timesignatures_per_phrase == 1].map(lambda l: l[0])
more_than_one = n_timesignatures_per_phrase > 1
print(f"Filtered out the {more_than_one.sum()} phrases incorporating more than one time signature.")
n_timesigs = n_timesignatures_per_phrase.value_counts()
display(n_timesigs.reset_index().rename(columns=dict(index='#time signatures', timesig='#phrases')))
uniform_timesig_phrases = phrases.loc[uniform_timesigs.index]
timesig_in_quarterbeats = uniform_timesigs.map(Fraction) * 4
exact_measure_lengths = uniform_timesig_phrases.duration_qb / timesig_in_quarterbeats
uniform_timesigs = pd.concat([exact_measure_lengths.rename('duration_measures'), uniform_timesig_phrases], axis=1)
fig = px.histogram(uniform_timesigs, x='duration_measures',
labels=dict(duration_measures='phrase length in measures, factoring in time signatures'))
fig.update_traces(xbins=dict( # bins used for histogram
#start=0.0,
#end=100.0,
size=1
))
fig.update_xaxes(dtick=4)
Filtered out the 59 phrases incorporating more than one time signature.
#time signatures | #phrases | |
---|---|---|
0 | 1 | 5892 |
1 | 2 | 58 |
2 | 3 | 1 |
uniform_timesigs.head(10).style.apply(color_background, subset='duration_measures')
duration_measures | mc | mn | quarterbeats | duration_qb | mc_onset | mn_onset | timesig | staff | voice | volta | harmony_layer | label | alt_label | regex_match | globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
corpus | fname | phrase_slice | ||||||||||||||||||||||||||||||||||||
bach_solo | BWV1009_01_Prelude | [0.0, 18.25) | 6.083333 | 1 | 1 | 0 | 18.250000 | 0 | 0 | 3/4 | 1 | 1 | 1 | C.I{ | nan | dcml | C | I | nan | I | I | nan | nan | nan | nan | nan | { | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | |
[18.25, 36.25) | 6.000000 | 7 | 7 | 73/4 | 18.000000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[36.25, 78.0) | 13.916667 | 13 | 13 | 145/4 | 41.750000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[78.0, 108.0) | 10.000000 | 27 | 27 | 78 | 30.000000 | 0 | 0 | 3/4 | 1 | 1 | 1 | vi}{ | nan | dcml | C | I | nan | vi | vi | nan | nan | nan | nan | nan | }{ | m | False | False | (3, 0, 4) | () | 3 | 3 | nan | nan | nan | |||
[108.0, 180.25) | 24.083333 | 37 | 37 | 108 | 72.250000 | 0 | 0 | 3/4 | 1 | 1 | 1 | I}{ | nan | dcml | C | I | nan | I | I | nan | nan | nan | nan | nan | }{ | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | |||
[180.25, 210.25) | 10.000000 | 61 | 61 | 721/4 | 30.000000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[210.25, 244.25) | 11.333333 | 71 | 71 | 841/4 | 34.000000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[244.25, 264.0) | 6.583333 | 82 | 82 | 977/4 | 19.750000 | 5/16 | 5/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | I | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
BWV1009_02_Allemande | [0.0, 15.75) | 3.937500 | 1 | 0 | 0 | 15.750000 | 0 | 13/16 | 4/4 | 1 | 1 | 1 | C.V{ | nan | dcml | C | I | nan | V | V | nan | nan | nan | nan | nan | { | M | False | False | (1, 5, 2) | () | 1 | 1 | nan | nan | nan | ||
[15.75, 48.0) | 8.062500 | 5 | 4 | 63/4 | 32.250000 | 3/4 | 3/4 | 4/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan |
timsig_counts = uniform_timesigs.timesig.value_counts()
fig = px.bar(timsig_counts, labels=dict(index="time signature", value="#phrases"))
fig.update_layout(**STD_LAYOUT)
fig.update_yaxes(gridcolor='lightgrey')
filter_counts_smaller_than = 5
filtered_timesigs = timsig_counts[timsig_counts < filter_counts_smaller_than].index.to_list()
fig = px.histogram(uniform_timesigs[~uniform_timesigs.timesig.isin(filtered_timesigs)],
x='duration_measures', facet_col='timesig', facet_col_wrap=2, height=1500)
fig.update_xaxes(matches=None, showticklabels=True, visible=True, dtick=4)
fig.update_yaxes(matches=None, showticklabels=True, visible=True)
fig.update_traces(xbins=dict( # bins used for histogram
#start=0.0,
end=50.0,
size=1
))
see_greater_equal = 33
longest_measure_length = uniform_timesigs.loc[uniform_timesigs.duration_measures >= see_greater_equal, ["duration_measures", "timesig"]]
for timesig, long_phrases in longest_measure_length.groupby('timesig'):
L = len(long_phrases)
plural = 's' if L > 1 else ''
display(HTML(f"<h3>{L} long phrase{plural} in {timesig} meter:</h3>"))
display(long_phrases.sort_values('duration_measures'))
duration_measures | timesig | |||
---|---|---|---|---|
corpus | fname | phrase_slice | ||
bach_solo | BWV1012_01_Prelude | [306.0, 594.0) | 48.0 | 12/8 |
duration_measures | timesig | |||
---|---|---|---|---|
corpus | fname | phrase_slice | ||
grieg_lyrical_pieces | op57n02 | [64.0, 196.0) | 33.0 | 2/2 |
[260.0, 392.0) | 33.0 | 2/2 | ||
beethoven_piano_sonatas | 26-1 | [800.0, 936.0) | 34.0 | 2/2 |
pleyel_quartets | b309op2n3b | [500.0, 640.0) | 35.0 | 2/2 |
beethoven_piano_sonatas | 09-3 | [186.0, 332.0) | 36.5 | 2/2 |
08-1 | [200.0, 352.0) | 38.0 | 2/2 | |
21-3 | [804.0, 956.0) | 38.0 | 2/2 | |
26-1 | [244.0, 404.0) | 40.0 | 2/2 | |
21-3 | [956.0, 1132.0) | 44.0 | 2/2 | |
08-1 | [576.0, 776.0) | 50.0 | 2/2 |
duration_measures | timesig | |||
---|---|---|---|---|
corpus | fname | phrase_slice | ||
liszt_pelerinage | 160.09_Les_Cloches_de_Geneve_(Nocturne) | [202.5, 270.0) | 33.75 | 2/4 |
grieg_lyrical_pieces | op68n03 | [0.0, 68.0) | 34.0 | 2/4 |
op38n01 | [100.0, 172.0) | 36.0 | 2/4 | |
op68n04 | [16.0, 92.0) | 38.0 | 2/4 | |
[92.0, 168.0) | 38.0 | 2/4 | ||
beethoven_piano_sonatas | 06-1 | [152.5, 234.0) | 40.75 | 2/4 |
grieg_lyrical_pieces | op54n06 | [36.0, 120.0) | 42.0 | 2/4 |
liszt_pelerinage | 162.03_Tarantella_da_Guillaume_Louis_Cottrau._Presto_e_canzone_napolitana | [1025.5416666666667, 1109.875) | 42.166667 | 2/4 |
[885.875, 970.875) | 42.5 | 2/4 | ||
beethoven_piano_sonatas | 02-1 | [360.0, 448.0) | 44.0 | 2/4 |
21-3 | [476.0, 572.0) | 48.0 | 2/4 | |
liszt_pelerinage | 160.09_Les_Cloches_de_Geneve_(Nocturne) | [302.0, 401.25) | 49.625 | 2/4 |
beethoven_piano_sonatas | 23-3 | [314.0, 422.0) | 54.0 | 2/4 |
duration_measures | timesig | |||
---|---|---|---|---|
corpus | fname | phrase_slice | ||
chopin_mazurkas | BI153-1op56-1 | [306.0, 426.0) | 40.0 | 3/4 |
debussy_suite_bergamasque | l075-02_suite_menuet | [51.0, 312.0) | 87.0 | 3/4 |
duration_measures | timesig | |||
---|---|---|---|---|
corpus | fname | phrase_slice | ||
beethoven_piano_sonatas | 17-3 | [258.75, 321.0) | 41.5 | 3/8 |
[140.75, 225.75) | 56.666667 | 3/8 |
duration_measures | timesig | |||
---|---|---|---|---|
corpus | fname | phrase_slice | ||
liszt_pelerinage | 160.06_Vallee_dObermann | [165.0, 297.0) | 33.0 | 4/4 |
mahler_kindertotenlieder | kindertotenlieder_01_nun_will_die_sonn | [144.0, 308.0) | 41.0 | 4/4 |
beethoven_piano_sonatas | 32-1 | [364.125, 536.125) | 43.0 | 4/4 |
21-1 | [444.0, 620.0) | 44.0 | 4/4 | |
debussy_suite_bergamasque | l075-04_suite_passepied | [152.0, 332.0) | 45.0 | 4/4 |
liszt_pelerinage | 161.07_Apres_une_lecture_du_Dante | [909.0, 1101.0) | 48.0 | 4/4 |
160.06_Vallee_dObermann | [515.5, 711.25) | 48.9375 | 4/4 |
duration_measures | timesig | |||
---|---|---|---|---|
corpus | fname | phrase_slice | ||
beethoven_piano_sonatas | 18-4 | [83.5, 190.0) | 35.5 | 6/8 |
[272.5, 380.5) | 36.0 | 6/8 | ||
liszt_pelerinage | 162.03_Tarantella_da_Guillaume_Louis_Cottrau._Presto_e_canzone_napolitana | [0.0, 111.0) | 37.0 | 6/8 |
grieg_lyrical_pieces | op62n05 | [74.5, 186.0) | 37.166667 | 6/8 |
beethoven_piano_sonatas | 03-4 | [774.5, 891.5) | 39.0 | 6/8 |
18-4 | [596.5, 715.0) | 39.5 | 6/8 | |
liszt_pelerinage | 160.09_Les_Cloches_de_Geneve_(Nocturne) | [0.0, 123.0) | 41.0 | 6/8 |
beethoven_piano_sonatas | 31-3 | [229.5, 354.0) | 41.5 | 6/8 |
18-4 | [380.5, 512.5) | 44.0 | 6/8 | |
liszt_pelerinage | 162.01_Gondoliera | [243.5, 385.625) | 47.375 | 6/8 |
local_keys_per_phrase = phrase_gpb.localkey.unique().map(tuple)
n_local_keys_per_phrase = local_keys_per_phrase.map(len)
phrases_with_keys = pd.concat([n_local_keys_per_phrase.rename('n_local_keys'),
local_keys_per_phrase.rename('local_keys'),
phrases], axis=1)
phrases_with_keys.head(10).style.apply(color_background, subset=['n_local_keys', 'local_keys'])
n_local_keys | local_keys | mc | mn | quarterbeats | duration_qb | mc_onset | mn_onset | timesig | staff | voice | volta | harmony_layer | label | alt_label | regex_match | globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
corpus | fname | phrase_slice | |||||||||||||||||||||||||||||||||||||
bach_solo | BWV1009_01_Prelude | [0.0, 18.25) | 1 | ('I',) | 1 | 1 | 0 | 18.250000 | 0 | 0 | 3/4 | 1 | 1 | 1 | C.I{ | nan | dcml | C | I | nan | I | I | nan | nan | nan | nan | nan | { | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | |
[18.25, 36.25) | 1 | ('I',) | 7 | 7 | 73/4 | 18.000000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[36.25, 78.0) | 1 | ('I',) | 13 | 13 | 145/4 | 41.750000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[78.0, 108.0) | 1 | ('I',) | 27 | 27 | 78 | 30.000000 | 0 | 0 | 3/4 | 1 | 1 | 1 | vi}{ | nan | dcml | C | I | nan | vi | vi | nan | nan | nan | nan | nan | }{ | m | False | False | (3, 0, 4) | () | 3 | 3 | nan | nan | nan | |||
[108.0, 180.25) | 1 | ('I',) | 37 | 37 | 108 | 72.250000 | 0 | 0 | 3/4 | 1 | 1 | 1 | I}{ | nan | dcml | C | I | nan | I | I | nan | nan | nan | nan | nan | }{ | M | False | False | (0, 4, 1) | () | 0 | 0 | nan | nan | nan | |||
[180.25, 210.25) | 1 | ('I',) | 61 | 61 | 721/4 | 30.000000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[210.25, 244.25) | 1 | ('I',) | 71 | 71 | 841/4 | 34.000000 | 1/16 | 1/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
[244.25, 264.0) | 1 | ('I',) | 82 | 82 | 977/4 | 19.750000 | 5/16 | 5/16 | 3/4 | 1 | 1 | 1 | { | nan | dcml | C | I | I | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan | |||||
BWV1009_02_Allemande | [0.0, 15.75) | 1 | ('I',) | 1 | 0 | 0 | 15.750000 | 0 | 13/16 | 4/4 | 1 | 1 | 1 | C.V{ | nan | dcml | C | I | nan | V | V | nan | nan | nan | nan | nan | { | M | False | False | (1, 5, 2) | () | 1 | 1 | nan | nan | nan | ||
[15.75, 48.0) | 2 | ('I', 'V') | 5 | 4 | 63/4 | 32.250000 | 3/4 | 3/4 | 4/4 | 1 | 1 | 1 | { | nan | dcml | C | I | nan | nan | nan | nan | nan | nan | nan | nan | { | nan | False | False | () | () | nan | nan | nan |
count_n_keys = phrases_with_keys.n_local_keys.value_counts().rename("#phrases").to_frame()
count_n_keys.index.rename("unique keys", inplace=True)
count_n_keys
#phrases | |
---|---|
unique keys | |
1 | 4798 |
2 | 1035 |
3 | 92 |
4 | 17 |
6 | 7 |
5 | 1 |
8 | 1 |
unique_key_selector = phrases_with_keys.n_local_keys == 1
phrases_with_unique_key = phrases_with_keys[unique_key_selector].copy()
phrases_with_unique_key.local_keys = phrases_with_unique_key.local_keys.map(lambda t: t[0])
value_count_df(phrases_with_unique_key.local_keys, counts="#phrases")
#phrases | |
---|---|
local_keys | |
I | 2273 |
i | 1355 |
V | 343 |
III | 245 |
vi | 116 |
v | 115 |
IV | 60 |
iii | 54 |
VI | 52 |
iv | 27 |
VII | 25 |
bVI | 19 |
bIII | 16 |
#V | 13 |
ii | 11 |
vi/V | 10 |
#iii | 8 |
bII | 6 |
#II | 6 |
bvi | 5 |
bV | 4 |
iv/iv | 4 |
#VII | 4 |
#iv | 3 |
ii/VI | 3 |
iii/bVI | 2 |
bIV | 2 |
bI | 2 |
II | 2 |
bII/V | 2 |
vii | 2 |
#vii | 1 |
#I | 1 |
bVII | 1 |
V/VII | 1 |
#III | 1 |
bi | 1 |
bii | 1 |
V/V | 1 |
IV/IV | 1 |
two_keys_selector = phrases_with_keys.n_local_keys > 1
phrases_with_unique_key = phrases_with_keys[two_keys_selector].copy()
value_count_df(phrases_with_unique_key.local_keys, "modulations")
counts | |
---|---|
modulations | |
(I, V) | 121 |
(i, III) | 85 |
(V, I) | 80 |
(III, i) | 74 |
(I, vi) | 56 |
(vi, I) | 52 |
(i, v) | 47 |
(v, i) | 44 |
(iv, i) | 27 |
(i, I) | 24 |
(I, iii) | 19 |
(III, v) | 18 |
(V, vi) | 16 |
(VI, i) | 16 |
(I, i) | 14 |
(i, iv) | 13 |
(IV, I) | 13 |
(I, IV) | 13 |
(III, iv) | 12 |
(bIII, I) | 11 |
(iii, I) | 10 |
(v, III) | 10 |
(III, i, v) | 9 |
(I, ii) | 9 |
(I, bIII) | 8 |
(i, VI) | 7 |
(III, I) | 7 |
(I, III) | 7 |
(V, I, vi) | 6 |
(v, iv) | 6 |
(I, bVI) | 6 |
(i, V) | 5 |
(vi, ii) | 5 |
(iv, v) | 5 |
(i, ii) | 4 |
(ii, I) | 4 |
(III, bV, iii, i) | 4 |
(i, bIII) | 4 |
(vi, iii) | 4 |
(vi, V) | 4 |
(bIII, i) | 3 |
(i, iii) | 3 |
(ii, vi) | 3 |
(i, v, iv) | 3 |
(V, iii) | 3 |
(bVII, i, ii, iii, IV, I) | 3 |
(I, #II) | 3 |
(bV, bVI, bvii) | 3 |
(III, i, iv) | 3 |
(ii, iii) | 3 |
(v, V) | 3 |
(VII, i) | 3 |
(I, #vi) | 3 |
(bVI, I) | 3 |
(VI, bII) | 2 |
(i, bI) | 2 |
(I, bVII) | 2 |
(V, i) | 2 |
(bIII/bIII/V, I) | 2 |
(vi, V, iii) | 2 |
(VI, I) | 2 |
(bIII, iv) | 2 |
(III, V) | 2 |
(iv/iv, bII, iv, VI, i, III) | 2 |
(iv, iv/iv) | 2 |
(VII, bIII, II) | 2 |
(iii, vi) | 2 |
(IV, III, I) | 2 |
(iii, bv) | 2 |
(I, #V) | 2 |
(III, iv, v) | 2 |
(bIII/V, bIII/bIII/V) | 2 |
(V, bIII/V) | 2 |
(VII, I) | 2 |
(I, VII) | 2 |
(vii, i) | 2 |
(VI, iv) | 2 |
(#II, I) | 2 |
(i, #iii) | 2 |
(bVI, iii/bVI) | 2 |
(i, VII) | 2 |
(vii, I) | 2 |
(bIII, iv, i) | 2 |
(I, iv) | 2 |
(vi, IV) | 2 |
(bII, i) | 2 |
(iv, III) | 2 |
(v, IV) | 2 |
(iv, IV) | 2 |
(VII, v) | 2 |
(v, v/v) | 2 |
(v, I) | 2 |
(bV, bbVII, I) | 1 |
(V, biii, I) | 1 |
(bvi, v, bv, I) | 1 |
(bIII, bVII) | 1 |
(bIII, bvi, bV) | 1 |
(bVI, i) | 1 |
(I, bI, VI) | 1 |
(#VI, bV) | 1 |
(V, bI) | 1 |
(iv, i, I) | 1 |
(#VI, VI) | 1 |
(VI, ii/VI) | 1 |
(ii/VI, #VI) | 1 |
(#VI, I) | 1 |
(IV, ii, I) | 1 |
(bV, i) | 1 |
(I, vii) | 1 |
(I, bII, bIII) | 1 |
(ii, vi, i) | 1 |
(bII, iv, I, #III) | 1 |
(#III, VII) | 1 |
(VII, #VII, #IV) | 1 |
(#IV, #III) | 1 |
(#III, II) | 1 |
(II, i) | 1 |
(#VII, i) | 1 |
(bi, iv, i) | 1 |
(iii, I, i) | 1 |
(bv, i, bV, V, bii, VI) | 1 |
(VI, iv, I) | 1 |
(IV, #vi, VII, iv, vi) | 1 |
(VII, V, vi) | 1 |
(V, #III, VII, iii, iv, bi, bii, I) | 1 |
(I, III, V) | 1 |
(III, VII) | 1 |
(i, iv, VI) | 1 |
(III, bii) | 1 |
(v, VII/v) | 1 |
(V, VII) | 1 |
(I, III, i) | 1 |
(V, v) | 1 |
(I, V, v) | 1 |
(VII, biii) | 1 |
(v, iv, III, i) | 1 |
(ii, I, vi) | 1 |
(iii, I, vi) | 1 |
(V, ii) | 1 |
(v, i, iv) | 1 |
(III, V/III) | 1 |
(vi, #iv) | 1 |
(#iv, bvi) | 1 |
(bVII, I, II, III) | 1 |
(V, vi, ii) | 1 |
(iv, bIII, v, III/v) | 1 |
(iv, bIII, v, I) | 1 |
(ii, vi, I) | 1 |
(i, iv, III) | 1 |
(VII/v, v) | 1 |
(#iii, bii/#iii, i) | 1 |
(bVI, iv) | 1 |
(#V, V) | 1 |
(bii, i) | 1 |
(bII, bIII/bII) | 1 |
(bIII/bII, i) | 1 |
(VI, bIII/VI, V, i) | 1 |
(#iii, v/#iii) | 1 |
(VII, III) | 1 |
(V, bIII) | 1 |
(vi, ii, #iii/ii) | 1 |
(#iii/ii, ii, bii, iii, iv, I) | 1 |
(iii, bVII) | 1 |
(bVII, iii/iii, iii) | 1 |
(iv, VI) | 1 |
(VI, bIII/VI) | 1 |
(bIII/VI, VII, i) | 1 |
(#II, II, V) | 1 |
(iv, i, III) | 1 |
(#II, II, I) | 1 |
(bII, I) | 1 |
(vii, iii) | 1 |
(iii, vii, I) | 1 |
(bIV, i) | 1 |
(bIV, I) | 1 |
(I, bIV) | 1 |
(VI, VII) | 1 |
(IV, bII, I) | 1 |
(IV, V) | 1 |
(bII, vii, VI) | 1 |
(vi, I, v) | 1 |
(v, vi, I) | 1 |
(v, i, III) | 1 |
(ii, v) | 1 |
(iv, bII) | 1 |
(bII/V, iv) | 1 |
(v, III, i) | 1 |
(vii, II) | 1 |
(iii, III) | 1 |
(III, v, i) | 1 |
(bIII, I, VI) | 1 |
(IV/IV/IV, iv) | 1 |
(iv, I) | 1 |
(bIII, i, bVI) | 1 |
(#iii, i) | 1 |
(V, I, VI) | 1 |
(VI, II) | 1 |
(II, I) | 1 |
(III, VI) | 1 |
(bVI, III) | 1 |
(iv, bVI) | 1 |
(III, iii) | 1 |
(#VII, v) | 1 |
(v, VI) | 1 |
(#iii, v) | 1 |
(bVII, i) | 1 |
(v, #iii) | 1 |
(vi/V, I) | 1 |
(V, V/V, I) | 1 |
(v/v, v/v/v) | 1 |
(V, i, iv, V/V) | 1 |
(VI, vi) | 1 |
(I, bVII, bVI) | 1 |
(iii/i, i) | 1 |
(iii, vi, IV) | 1 |
(v/v, i) | 1 |
(I, v) | 1 |
(V/V, v, i) | 1 |
(v/v/v, v, V) | 1 |
(vii, bII) | 1 |
(i, #VI, III/#VI) | 1 |
(iv, bIII) | 1 |
(biii, bII, I) | 1 |
(V, V/V) | 1 |
(iii/V/VII, I) | 1 |
(III, iv, VI) | 1 |
(iv, IV/IV, IV/IV/IV) | 1 |
(bVII, IV) | 1 |
(I, VI) | 1 |
(vi, I, ii) | 1 |
(i, vi) | 1 |
(ii, V, I) | 1 |
(I, vi/V) | 1 |
(V, III) | 1 |
(v, iv, i) | 1 |
(ii, IV) | 1 |
(V, I, IV, vi) | 1 |
(III, v, iv, i) | 1 |
(i, bII) | 1 |
(bII, iv, i) | 1 |
(i, III, v) | 1 |
(v, iv, VI, i) | 1 |
(v, iv, III) | 1 |
(i, VII, III) | 1 |
(III, iv, v, i) | 1 |
(iii, I, IV, III) | 1 |
(IV, i) | 1 |
(i, v, III) | 1 |
HTML('''<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('Show Code')
} else {
$('div.input').show('500');
$('#toggleButton').val('Hide Code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide()
});
</script>
<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Show Code"></form>''')
print(f"{all_labels.cadence.notna().sum()} cadence labels.")
value_count_df(all_labels.cadence)
5245 cadence labels.
counts | |
---|---|
cadence | |
PAC | 2589 |
HC | 1439 |
IAC | 955 |
EC | 115 |
DC | 78 |
PC | 69 |
px.pie(all_labels[all_labels.cadence.notna()], names="cadence", color="cadence", color_discrete_map=cadence_colors)
cadence_count_per_dataset = all_labels.groupby("corpus").cadence.value_counts()
cadence_fraction_per_dataset = cadence_count_per_dataset / cadence_count_per_dataset.groupby(level=0).sum()
px.bar(cadence_fraction_per_dataset.rename('count').reset_index(), x='corpus', y='count', color='cadence',
color_discrete_map=cadence_colors, category_orders=dict(dataset=chronological_order))
fig = px.pie(cadence_count_per_dataset.rename('count').reset_index(), names='cadence', color='cadence', values='count',
facet_col='corpus', facet_col_wrap=4, height=2000, color_discrete_map=cadence_colors)
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
fig.update_layout(**STD_LAYOUT)
phrases_with_cadences = pd.concat([
phrase_gpb.cadence.nunique().rename('n_cadences'),
phrase_gpb.cadence.unique().rename('cadences').map(lambda l: tuple(e for e in l if not pd.isnull(e))),
phrases_with_keys
], axis=1)
value_count_df(phrases_with_cadences.n_cadences, counts="#phrases")
#phrases | |
---|---|
n_cadences | |
1 | 4838 |
0 | 966 |
2 | 144 |
3 | 3 |
n_cad = phrases_with_cadences.groupby(level='corpus').n_cadences.value_counts().rename('counts').reset_index().sort_values('n_cadences')
n_cad.n_cadences = n_cad.n_cadences.astype(str)
fig = px.bar(n_cad, x='corpus', y='counts', color='n_cadences', height=800, barmode='group',
labels=dict(n_cadences="#cadences in a phrase"),
category_orders=dict(dataset=chronological_order)
)
fig.show()
value_count_df(phrases_with_cadences[phrases_with_cadences.n_cadences > 1].cadences)
counts | |
---|---|
cadences | |
(HC, PAC) | 38 |
(EC, PAC) | 31 |
(DC, PAC) | 28 |
(IAC, PAC) | 12 |
(EC, HC) | 7 |
(PAC, HC) | 6 |
(DC, HC) | 4 |
(PC, PAC) | 3 |
(PAC, IAC) | 3 |
(EC, IAC) | 3 |
(PAC, DC) | 2 |
(HC, DC) | 1 |
(HC, IAC) | 1 |
(IAC, EC) | 1 |
(PAC, EC, DC) | 1 |
(DC, IAC) | 1 |
(IAC, HC) | 1 |
(HC, PC) | 1 |
(HC, DC, PAC) | 1 |
(IAC, HC, PAC) | 1 |
(PAC, PC) | 1 |
df_rows = []
y_position = 0
for ix in phrases_with_cadences[phrases_with_cadences.n_cadences > 0].sort_values('duration_qb').index:
df = phrase_segments.loc[ix]
description = str(ix)
if df.cadence.notna().any():
interval = ix[2]
df_rows.append((y_position, interval.length, "end of phrase", description))
start_pos = interval.left
cadences = df.loc[df.cadence.notna(), ['quarterbeats', 'cadence']]
cadences.quarterbeats -= start_pos
for cadence_x, cadence_type in cadences.itertuples(index=False, name=None):
df_rows.append((y_position, cadence_x, cadence_type, description))
y_position += 1
#else:
# df_rows.append((y_position, pd.NA, pd.NA, description))
data = pd.DataFrame(df_rows, columns=["phrase_ix", "x", "marker", "description"])
fig = px.scatter(data[data.x.notna()], x='x', y="phrase_ix", color="marker", hover_name="description", height=3000,
labels=dict(marker='legend'), color_discrete_map=cadence_colors)
fig.update_traces(marker_size=5)
fig.update_yaxes(autorange="reversed")
fig.show()
HTML('''<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('Show Code')
} else {
$('div.input').show('500');
$('#toggleButton').val('Hide Code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide()
});
</script>
<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Show Code"></form>''')
phrase_segments = segmented.get_facet("expanded")
cadence_selector = phrase_segments.cadence.notna()
missing_chord_selector = phrase_segments.chord.isna()
cadence_with_missing_chord_selector = cadence_selector & missing_chord_selector
#print(f"Ultima missing for {cadence_with_missing_chord_selector.sum()} cadences.")
missing = phrase_segments[cadence_with_missing_chord_selector]
expanded = ms3.expand_dcml.expand_labels(phrase_segments[cadence_with_missing_chord_selector], propagate=False, chord_tones=True, skip_checks=True)
phrase_segments.loc[cadence_with_missing_chord_selector] = expanded
print(f"Ultima harmony missing for {(phrase_segments.cadence.notna() & phrase_segments.bass_note.isna()).sum()} cadence labels.")
MC 49: #vii in major context corrected to vii.
Ultima harmony missing for 20 cadence labels.
def highlight(row, color="#ffffb3"):
if row.counts < 10:
return [None, None, None, None]
else:
return ["background-color: #ffffb3;"] * 4
cadence_counts = all_labels.cadence.value_counts()
ultima_root = phrase_segments.groupby(['localkey_is_minor', 'cadence']).numeral.value_counts().rename('counts').to_frame().reset_index()
ultima_root.localkey_is_minor = ultima_root.localkey_is_minor.map({False: 'in major', True: 'in minor'})
#ultima_root.style.apply(highlight, axis=1)
fig = px.pie(ultima_root, names='numeral', values='counts',
facet_row='cadence', facet_col='localkey_is_minor',
height=1500,
category_orders={'cadence': cadence_counts.index},
)
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
fig.update_traces(textposition='inside', textinfo='percent+label')
fig.update_layout(**STD_LAYOUT)
fig.show()
#phrase_segments.groupby(level=[0,1,2], group_keys=False).apply(lambda df: df if ((df.cadence == 'PAC') & (df.numeral == 'V')).any() else None)
ultima_bass = phrase_segments.groupby(['localkey_is_minor','cadence']).bass_note.value_counts().rename('counts').reset_index()
ultima_bass.bass_note = ms3.transform(ultima_bass, ms3.fifths2sd, dict(fifths='bass_note', minor='localkey_is_minor'))
ultima_bass.localkey_is_minor = ultima_bass.localkey_is_minor.map({False: 'in major', True: 'in minor'})
#ultima_bass.style.apply(highlight, axis=1)
fig = px.pie(ultima_bass, names='bass_note', values='counts',
facet_row='cadence', facet_col='localkey_is_minor',
height=1500,
category_orders={'cadence': cadence_counts.index},
)
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
fig.update_traces(textposition='inside', textinfo='percent+label')
fig.update_layout(**STD_LAYOUT)
fig.show()
#pac_on_i = phrase_segments.groupby(level=[0,1,2], group_keys=False).apply(lambda df: df if ((df.cadence == 'PAC') & (df.numeral.isin(('I', 'i')))).any() else None)
#pac_on_i.cadence.value_counts()
#pac_on_i.droplevel(-1).index.nunique()
def get_progressions(selected='PAC', last_row={}, feature='chord', dataset=None, as_series=True):
"""Uses the nonlocal variable phrase_segments."""
last_row = {k: v if isinstance(v, tuple) else (v,) for k, v in last_row.items()}
progressions = []
for (corp, fname, *_), df in phrase_segments[phrase_segments[feature].notna()].groupby(level=[0,1,2]):
if dataset is not None and dataset not in corp:
continue
if (df.cadence == selected).fillna(False).any():
# remove chords after the last cadence label
df = df[df.cadence.fillna(method='bfill').notna()]
# group segments leading up to a cadence label
cadence_groups = df.cadence.notna().shift().fillna(False).cumsum()
for i, cadence in df.groupby(cadence_groups):
last_r = cadence.iloc[-1]
typ = last_r.cadence
if typ != selected:
continue
if any(last_r[feat] not in values for feat, values in last_row.items()):
continue
progressions.append(tuple(cadence[feature]))
if as_series:
return pd.Series(progressions)
return progressions
chord_progressions = get_progressions('PAC', dict(numeral=('I', 'i')), 'chord')
print(f"Progressions for {len(chord_progressions)} cadences:")
value_count_df(chord_progressions, "chord progressions")
Progressions for 2553 cadences:
counts | |
---|---|
chord progressions | |
(I, V7, I) | 12 |
(V, V7, I, ii6(2), ii6, V7, I) | 12 |
(I, I6, IV, V(64), V, I) | 10 |
(i, VM7, i, V7, V7(#2), V7, i) | 8 |
(I, IV, V(64), V, I) | 6 |
... | ... |
(i, iv6, #viio6/iv, iv, iio6, VI6, i, I6, ii65, V, IM65, i6, i, ii%65, V, i) | 1 |
(i, VI6, V65/III, III(4), i6, iv, V(4), V, iv6(2), iv6, iv, iii65, I6, I, V7/V, VI, i6, ii65, V, i) | 1 |
(V, IV6(2), IV6, #viio, i(4), i, i6, bII6(2), bII6, viio/VI, VI(b4), VI, i6, iv7, V(4), V, i) | 1 |
(I, vi6, V6(2), V6, IV6(2), IV6, iii6(2), iii, ii6(2), ii6, I6(2), I6, viio6(2), viio6, I) | 1 |
(i, iv, V/III, III, VI, iv7, V, V2, i6, ii%65, V(4), V, i) | 1 |
2123 rows × 1 columns
numeral_progressions = get_progressions('PAC', dict(numeral=('I', 'i')), 'numeral')
value_count_df(numeral_progressions, "numeral progressions")
counts | |
---|---|
numeral progressions | |
(I, V, V, I) | 19 |
(I, V, I) | 16 |
(I, I, IV, V, V, I) | 13 |
(I, IV, V, V, I) | 13 |
(V, V, I, ii, ii, V, I) | 12 |
... | ... |
(i, iv, i, V, V, V, i, i, iv, V, V, III, i, ii, ii, i, i, ii, V, i) | 1 |
(V, i, V, V, iv, V, V, i, V, iv, i, V, V, i) | 1 |
(i, iv, iv, iv, V, V, i) | 1 |
(V, i, V, i, #vii, iv, V, V, V, I, IV, I, V, V, I) | 1 |
(I, vi, V, V, IV, IV, V, V, V, V, I) | 1 |
1962 rows × 1 columns
def remove_immediate_duplicates(l):
return tuple(a for a, b in zip(l, (None, ) + l) if a != b)
numeral_prog_no_dups = numeral_progressions.map(remove_immediate_duplicates)
value_count_df(numeral_prog_no_dups)
counts | |
---|---|
(I, V, I) | 54 |
(I, IV, V, I) | 44 |
(I, V, I, V, I) | 31 |
(i, V, i, V, i) | 22 |
(I, V, I, ii, V, I) | 22 |
... | ... |
(i, V, I, vi, ii, vii, I, V, I, ii, V, I) | 1 |
(i, V, i, ii, #vii, i) | 1 |
(V, i, V, VII, v, ii, V, VI, ii, V, i) | 1 |
(I, i, V, i, I, v, VI, i, V, i) | 1 |
(I, ii, V, I, ii, V, vi, I, ii, V, I) | 1 |
1705 rows × 1 columns
Scale degrees expressed w.r.t. major scale, regardless of actual key.
bass_progressions = get_progressions('PAC', dict(bass_note=0), 'bass_note')
bass_prog = bass_progressions.map(ms3.fifths2sd)
print(f"Progressions for {len(bass_progressions)} cadences:")
value_count_df(bass_prog, "bass progressions")
Progressions for 2372 cadences:
counts | |
---|---|
bass progressions | |
(1, 5, 1) | 23 |
(1, 4, 5, 5, 1) | 18 |
(1, 3, 4, 5, 5, 1) | 17 |
(1, 5, 5, 1) | 13 |
(5, 5, 1, 4, 4, 5, 1) | 12 |
... | ... |
(1, 5, 3, 4, 4, 1, 1, 5, 5, 1) | 1 |
(1, 5, 6, 5, 1) | 1 |
(1, 6, 5, 5, 4, 4, 3, 3, 4, 6, 3, 4, 5, 1) | 1 |
(1, 1, #7, 1, 4, b6, 5, 5, 5, 5, 1) | 1 |
(1, 1, #7, #7, 6, 6, 5, 5, 5, 5, 1) | 1 |
1824 rows × 1 columns
bass_prog_no_dups = bass_prog.map(remove_immediate_duplicates)
value_count_df(bass_prog_no_dups)
counts | |
---|---|
(1, 5, 1) | 48 |
(1, 5, 1, 5, 1) | 37 |
(1, 4, 5, 1) | 30 |
(1, 3, 4, 5, 1) | 25 |
(5, 1, 4, 5, 1) | 18 |
... | ... |
(1, b6, 4, b6, 4, 1, 5, 1) | 1 |
(1, 4, 1, 5, 4, b3, 1, 4, 2, 7, b3, 1, 4, b3, 2, 5, 1) | 1 |
(#7, 1, 4, 5, 4, b3, 3, 4, 1, 5, 1) | 1 |
(b3, 4, b6, 4, 5, 1) | 1 |
(1, 3, 1, 4, 1, 5, 6, 5, 1, #7, 1, 7, b6, 5, 1, 4, 5, b6, 4, 5, 1) | 1 |
1638 rows × 1 columns
def make_sankey(data, labels, node_pos=None, margin={'l': 10, 'r': 10, 'b': 10, 't': 10}, pad=20, color='auto', **kwargs):
if color=='auto':
unique_labels = set(labels)
color_step = 100 / len(unique_labels)
unique_colors = {label: f'hsv({round(i*color_step)}%,100%,100%)' for i, label in enumerate(unique_labels)}
color = list(map(lambda l: unique_colors[l], labels))
fig = go.Figure(go.Sankey(
arrangement = 'snap',
node = dict(
pad = pad,
#thickness = 20,
#line = dict(color = "black", width = 0.5),
label = labels,
x = [node_pos[i][0] if i in node_pos else 0 for i in range(len(labels))] if node_pos is not None else None,
y = [node_pos[i][1] if i in node_pos else 0 for i in range(len(labels))] if node_pos is not None else None,
color = color,
),
link = dict(
source = data.source,
target = data.target,
value = data.value
),
),
)
fig.update_layout(margin=margin, **kwargs)
return fig
def progressions2graph_data(progressions, cut_at_stage=None):
stage_nodes = defaultdict(dict)
edge_weights = Counter()
node_counter = 0
for progression in progressions:
previous_node = None
for stage, current in enumerate(reversed(progression)):
if cut_at_stage and stage > cut_at_stage:
break
if current in stage_nodes[stage]:
current_node = stage_nodes[stage][current]
else:
stage_nodes[stage][current] = node_counter
current_node = node_counter
node_counter += 1
if previous_node is not None:
edge_weights.update([(current_node, previous_node)])
previous_node = current_node
return stage_nodes, edge_weights
def graph_data2sankey(stage_nodes, edge_weights):
data = pd.DataFrame([(u, v, w) for (u, v), w in edge_weights.items()], columns = ['source', 'target', 'value'])
node2label = {node: label for stage, nodes in stage_nodes.items() for label, node in nodes.items()}
labels = [node2label[i] for i in range(len(node2label))]
return make_sankey(data, labels)
def plot_progressions(progressions, cut_at_stage=None):
stage_nodes, edge_weights = progressions2graph_data(progressions, cut_at_stage=cut_at_stage)
return graph_data2sankey(stage_nodes, edge_weights)
plot_progressions(numeral_prog_no_dups, cut_at_stage=3)
chord_progressions_minor = get_progressions('PAC', dict(numeral='i', localkey_is_minor=True), 'root')
chord_progressions_minor
0 (1, 0, 0, 0, 0, 2, 1, 0, -4, -1, 1, 0, -1, 5, ... 1 (0, -2, -3, -1, 5, 1, 1, 0, -2, -4, 1, -1, -3,... 2 (0, 5, 5, 0, 0, 2, -1, 1, 1, 1, 5, 0, 2, 1, 0) 3 (1, 0, 1, 1, 1, 1, -1, 0, 1, 0) 4 (0, 1, 0, 5, 0) ... 906 (-1, 0, 2, 0, 0, 0) 907 (0, 1, 1, 0, 0, 0, 0) 908 (1, 1, 1, 0, 5, 0, 2, 2, -1, -1, 5, 1, 0, 2, 1... 909 (-4, 6, 1, 1, 0) 910 (1, 1, 5, 0, 2, 1, 1, 4, -1, -1, 2, 5, 0, -1, ... Length: 911, dtype: object
pac_major = get_progressions('PAC', dict(numeral='I', localkey_is_minor=False), 'chord')
plot_progressions(pac_major, cut_at_stage=4)
deceptive = get_progressions('DC', dict(localkey_is_minor=False), 'chord')
deceptive.value_counts()
(I, V43(4), I6, IV, V7, vi) 3 (I, V, ii7(9), V, V, ii7(9), V, V7, ii7(9), V, ii7, V, ii7(13), ii7, V7(#2), V7(6), vi) 2 (i, iv/i, V(64)/i, V/i, I/i) 2 (I, IV, V(64), V, i) 2 (IV6, V6, I(4), I, I6, IV, ii6, V7(4), V7, vi(^2), vi) 2 (I, V, I, V7, I, V6, I, viio/V, V, vi) 2 (V43, I(4), V65, I, V2(6), V2, I6, #viio7/ii, iv64/ii, #viio65/ii, i6(6)/ii, #viio43/ii, i6/ii, vi, vii%2, vi, ii%43, I64, I6, V7/V, V7, V6/vi, vi) 2 (i, viio43/V, V6, i, viio43/V, V6, I, IV6, I6, IV, viio6, I6, IV6, viio, I, ii65, V, vi) 2 (I, IV, V/vi, vi, V, I, IV, V(64), V7, vi) 2 (V, V7, IV(+2), V7, vi) 1 (I, I6, ii6, V, vi) 1 (I, V6(4), V43/vi, vi, I6, ii6, V, V6/vi, vi, I6, ii6, V, V6/vi, vi) 1 (ii, V(64)/vi, It6/vi, V/vi, V7/V, V, V7/IV, IV, ii, V7(^9), V7, vi) 1 (V7, vi) 1 (V65, I, V7, I6, V65, I, V7, bVI) 1 (V65, I, V7, I, V65, I, V7, bVI) 1 (I6, IV, V7, vi) 1 (I, I6, IV, V(64), V, vi) 1 (#viio43/ii, ii, IV, V(64), V7, I) 1 (V(974), V, I, IV, V/vi, vi, I, IV, V(64), V7, vi) 1 (I, V6, vi, I6, ii6, V7, vi) 1 (vi, I6, ii6, V, vi) 1 (V(4), V, V7, V64, V7, vi, I6, IV, ii6, V7, vi) 1 (i6/iv, iv/iv, iio6/iv, V(64)/iv, V7/iv, bII) 1 (I, V7, I, V7, I, #viio7/ii, ii, V(64), V7, iv6) 1 (vi, V65/IV, IV, V7, vi, ii6, V(64), V7, vi(64), vi) 1 (I, V7, I, I6, viio6, vi6, V6, V7, I, IV64, I, V, V65, I, V, V65, I, ii6, V(64), V7, vi(64), vi) 1 (V2/V, V6, V2/IV, IV6, vi, ii, V7(^9), V7, I/bVI) 1 (I64, IV6, #viio2/vi, vi, vii%2, I, IV, V(64), V7, vi) 1 (I, viio6, I6, IV, I, viio6, I6, IV, I, viio6, I6, IV, I, viio6, I6, viio/V, V, V(64), V7, V(64), V7, I, I6, ii6, V6/V, V(64), V(4), V7, I, I6, ii6, V6/V, V(64), V(4), V, bVI) 1 (I, V2, I6, IV, V6/V, V, V6/vi, i/vi, V(64)/vi, V/vi, VI/vi) 1 (I, I, V, I, vi, V/vi, vi, IV, V/IV, IV, ii, V/ii, ii, V, vi7) 1 (I, ii2, I, I6, ii65, V(64), V, vi) 1 (V, V2(9), iii, V43, I, #viio65/vii, V43, #viio2/iii, V7/IV, V+7/IV, IV, vii%43, V7/vi, V7(4+2)/vi, V7/vi, vi, IV(94), IV, I6, V43, I, IV(94), IV, I64, V(4), V, v, ii) 1 (V(64)/vi, viio65/V/vi, V/vi, iii, V43, I, V6, V7, #viio43/ii, V7, bVI) 1 (I, V2, I, V2, I, V2, I, V2, I, V2, I6, I, viio6, viio, vi6, vi, V6, V, IV6, IV, iii6, iii, ii6, ii, I6, I, V6, IV6, iii6, ii6, I6, viio6, I, V, ii, vi, IV, I, V(4), V, I, V, ii, vi, I/IV, V2/IV, I/IV, V2/IV, I/IV, V7, V(64), V, V7, I, V6, IV6, iii6, ii6, I6, viio6, I, V6, IV6, iii6, ii6, I6, V7, bVI) 1 (I, V, I, IV6, ii, V7, bVI) 1 dtype: int64
plot_progressions(deceptive, cut_at_stage=4)
plot_progressions(bass_prog_no_dups, cut_at_stage=7)
def remove_sd_accidentals(t):
return tuple(map(lambda sd: sd[-1], t))
bass_prog_no_acc_no_dup = bass_prog.map(remove_sd_accidentals).map(remove_immediate_duplicates)
plot_progressions(bass_prog_no_acc_no_dup, cut_at_stage=7)
half = get_progressions('HC', dict(numeral='V'), 'bass_note').map(ms3.fifths2sd)
print(f"Progressions for {len(half)} cadences:")
plot_progressions(half.map(remove_immediate_duplicates), cut_at_stage=5)
Progressions for 1382 cadences:
HTML('''<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('Show Code')
} else {
$('div.input').show('500');
$('#toggleButton').val('Hide Code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide()
});
</script>
<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Show Code"></form>''')
HTML('''<script>
function code_toggle() {
if (code_shown){
$('div.input').hide('500');
$('#toggleButton').val('Show Code')
} else {
$('div.input').show('500');
$('#toggleButton').val('Hide Code')
}
code_shown = !code_shown
}
$( document ).ready(function(){
code_shown=false;
$('div.input').hide()
});
</script>
<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Show Code"></form>''')
chord_progressions = dict(
PAC = [],
IAC = [],
HC = [],
EC = [],
DC = [],
PC = [],
)
import plotly.graph_objects as go
import networkx as nx
G = nx.random_geometric_graph(200, 0.125)
edge_x = []
edge_y = []
for edge in G.edges():
x0, y0 = G.nodes[edge[0]]['pos']
x1, y1 = G.nodes[edge[1]]['pos']
edge_x.append(x0)
edge_x.append(x1)
edge_x.append(None)
edge_y.append(y0)
edge_y.append(y1)
edge_y.append(None)
edge_trace = go.Scatter(
x=edge_x, y=edge_y,
line=dict(width=0.5, color='#888'),
hoverinfo='none',
mode='lines')
node_x = []
node_y = []
for node in G.nodes():
x, y = G.nodes[node]['pos']
node_x.append(x)
node_y.append(y)
node_trace = go.Scatter(
x=node_x, y=node_y,
mode='markers',
hoverinfo='text',
marker=dict(
showscale=True,
# colorscale options
#'Greys' | 'YlGnBu' | 'Greens' | 'YlOrRd' | 'Bluered' | 'RdBu' |
#'Reds' | 'Blues' | 'Picnic' | 'Rainbow' | 'Portland' | 'Jet' |
#'Hot' | 'Blackbody' | 'Earth' | 'Electric' | 'Viridis' |
colorscale='YlGnBu',
reversescale=True,
color=[],
size=10,
colorbar=dict(
thickness=15,
title='Node Connections',
xanchor='left',
titleside='right'
),
line_width=2))
node_adjacencies = []
node_text = []
for node, adjacencies in enumerate(G.adjacency()):
node_adjacencies.append(len(adjacencies[1]))
node_text.append('# of connections: '+str(len(adjacencies[1])))
node_trace.marker.color = node_adjacencies
node_trace.text = node_text
fig = go.Figure(data=[edge_trace, node_trace],
layout=go.Layout(
title='<br>Network graph made with Python',
titlefont_size=16,
showlegend=False,
hovermode='closest',
margin=dict(b=20,l=5,r=5,t=40),
annotations=[ dict(
text="Python code: <a href='https://plotly.com/ipython-notebooks/network-graphs/'> https://plotly.com/ipython-notebooks/network-graphs/</a>",
showarrow=False,
xref="paper", yref="paper",
x=0.005, y=-0.002 ) ],
xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
yaxis=dict(showgrid=False, zeroline=False, showticklabels=False))
)
fig.show()
from ms3 import make_gantt_data
from gantt import create_gantt, create_modulation_plan, get_phraseends
df = all_labels.loc[('beethoven_piano_sonatas', '01-3')]
data = make_gantt_data(df)
data
Start | Finish | Duration | Resource | abs_numeral | fifths | semitones | localkey | globalkey | relativeroot | Description | |
---|---|---|---|---|---|---|---|---|---|---|---|
[0.0, 12.0) | 0.0 | 12.0 | 12.0 | local | i | 0 | 0 | i | f | NaN | Duration: 12.0<br>Tonicized global scale degre... |
[12.0, 49.0) | 12.0 | 49.0 | 37.0 | local | III | -3 | 3 | III | f | NaN | Duration: 37.0<br>Tonicized global scale degre... |
[49.0, 76.0) | 49.0 | 76.0 | 27.0 | local | iv | -1 | 5 | iv | f | NaN | Duration: 27.0<br>Tonicized global scale degre... |
[76.0, 120.0) | 76.0 | 120.0 | 44.0 | local | i | 0 | 0 | i | f | NaN | Duration: 44.0<br>Tonicized global scale degre... |
[120.0, 138.0) | 120.0 | 138.0 | 18.0 | local | I | 0 | 0 | I | f | NaN | Duration: 18.0<br>Tonicized global scale degre... |
[138.0, 157.0) | 138.0 | 157.0 | 19.0 | local | V | 1 | 7 | V | f | NaN | Duration: 19.0<br>Tonicized global scale degre... |
[157.0, 219.0) | 157.0 | 219.0 | 62.0 | local | I | 0 | 0 | I | f | NaN | Duration: 62.0<br>Tonicized global scale degre... |
[81.0, 82.0) | 81.0 | 82.0 | 1.0 | applied | V | 1 | 7 | i | f | V | Duration: 1.0<br>Tonicized global scale degree... |
[82.0, 84.0) | 82.0 | 84.0 | 2.0 | tonic of adjacent applied chord(s) | V | 1 | 7 | i | f | V | Duration: 2.0<br>Tonicized global scale degree... |
[100.0, 103.0) | 100.0 | 103.0 | 3.0 | applied | V | 1 | 7 | i | f | V | Duration: 3.0<br>Tonicized global scale degree... |
[103.0, 106.0) | 103.0 | 106.0 | 3.0 | tonic of adjacent applied chord(s) | V | 1 | 7 | i | f | V | Duration: 3.0<br>Tonicized global scale degree... |
[141.0, 142.0) | 141.0 | 142.0 | 1.0 | applied | #vi | 3 | 9 | V | f | ii | Duration: 1.0<br>Tonicized global scale degree... |
[142.0, 143.0) | 142.0 | 143.0 | 1.0 | tonic of adjacent applied chord(s) | #vi | 3 | 9 | V | f | ii | Duration: 1.0<br>Tonicized global scale degree... |
[143.0, 144.0) | 143.0 | 144.0 | 1.0 | tonic of adjacent applied chord(s) | II | 2 | 2 | V | f | V | Duration: 1.0<br>Tonicized global scale degree... |
[144.0, 145.0) | 144.0 | 145.0 | 1.0 | applied | II | 2 | 2 | V | f | V | Duration: 1.0<br>Tonicized global scale degree... |
[145.0, 148.0) | 145.0 | 148.0 | 3.0 | tonic of adjacent applied chord(s) | II | 2 | 2 | V | f | V | Duration: 3.0<br>Tonicized global scale degree... |
[163.0, 166.0) | 163.0 | 166.0 | 3.0 | tonic of adjacent applied chord(s) | V | 1 | 7 | I | f | V | Duration: 3.0<br>Tonicized global scale degree... |
[166.0, 169.0) | 166.0 | 169.0 | 3.0 | applied | V | 1 | 7 | I | f | V | Duration: 3.0<br>Tonicized global scale degree... |
[187.0, 190.0) | 187.0 | 190.0 | 3.0 | tonic of adjacent applied chord(s) | V | 1 | 7 | I | f | V | Duration: 3.0<br>Tonicized global scale degree... |
[190.0, 193.0) | 190.0 | 193.0 | 3.0 | applied | V | 1 | 7 | I | f | V | Duration: 3.0<br>Tonicized global scale degree... |
[193.0, 196.0) | 193.0 | 196.0 | 3.0 | tonic of adjacent applied chord(s) | V | 1 | 7 | I | f | V | Duration: 3.0<br>Tonicized global scale degree... |
[201.0, 202.0) | 201.0 | 202.0 | 1.0 | applied | V | 1 | 7 | I | f | V | Duration: 1.0<br>Tonicized global scale degree... |
[202.0, 205.0) | 202.0 | 205.0 | 3.0 | tonic of adjacent applied chord(s) | V | 1 | 7 | I | f | V | Duration: 3.0<br>Tonicized global scale degree... |
[213.0, 214.0) | 213.0 | 214.0 | 1.0 | applied | V | 1 | 7 | I | f | V | Duration: 1.0<br>Tonicized global scale degree... |
[214.0, 217.0) | 214.0 | 217.0 | 3.0 | tonic of adjacent applied chord(s) | V | 1 | 7 | I | f | V | Duration: 3.0<br>Tonicized global scale degree... |
create_gantt(data, task_column='fifths')
df[df.phraseend.notna()]
quarterbeats | duration_qb | mc | mn | mc_onset | mn_onset | timesig | staff | voice | volta | harmony_layer | label | alt_label | regex_match | globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
interval | |||||||||||||||||||||||||||||||||||
[0.0, 1.0) | 0 | 1.0 | 1 | 0 | 0 | 1/2 | 3/4 | 2 | 1 | <NA> | 1 | f.i[i{ | NaN | dcml | f | i | i | i | i | NaN | NaN | NaN | NaN | NaN | { | m | True | True | (0, -3, 1) | () | 0 | 0 | NaN | NaN | NaN |
[11.0, 12.0) | 11 | 1.0 | 5 | 4 | 1/4 | 1/4 | 3/4 | 2 | 1 | <NA> | 1 | i} | NaN | dcml | f | i | NaN | i | i | NaN | NaN | NaN | NaN | NaN | } | m | True | True | (0, -3, 1) | () | 0 | 0 | NaN | NaN | NaN |
[12.0, 13.0) | 12 | 1.0 | 5 | 4 | 1/2 | 1/2 | 3/4 | 2 | 1 | <NA> | 1 | III.I[I{ | NaN | dcml | f | III | I | I | I | NaN | NaN | NaN | NaN | NaN | { | M | True | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN |
[23.0, 24.0) | 23 | 1.0 | 9 | 8 | 1/4 | 1/4 | 3/4 | 2 | 1 | <NA> | 1 | I} | NaN | dcml | f | III | NaN | I | I | NaN | NaN | NaN | NaN | NaN | } | M | True | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN |
[24.0, 25.0) | 24 | 1.0 | 9 | 8 | 1/2 | 1/2 | 3/4 | 2 | 1 | <NA> | 1 | I6{ | NaN | dcml | f | III | NaN | I6 | I | NaN | 6 | NaN | NaN | NaN | { | M | True | False | (4, 1, 0) | () | 0 | 4 | NaN | NaN | NaN |
[34.0, 37.0) | 34 | 3.0 | 13 | 12 | 0 | 0 | 3/4 | 2 | 1 | <NA> | 1 | I|PAC} | NaN | dcml | f | III | NaN | I | I | NaN | NaN | NaN | NaN | PAC | } | M | True | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN |
[42.0, 42.0) | 42 | 0.0 | 16 | 14 | 0 | 1/2 | 3/4 | 2 | 1 | <NA> | 1 | { | NaN | dcml | f | III | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | { | NaN | True | False | () | () | <NA> | <NA> | NaN | NaN | NaN |
[58.0, 61.0) | 58 | 3.0 | 22 | 20 | 0 | 0 | 3/4 | 2 | 1 | <NA> | 1 | i|PAC} | NaN | dcml | f | iv | NaN | i | i | NaN | NaN | NaN | NaN | PAC | } | m | True | True | (0, -3, 1) | () | 0 | 0 | NaN | NaN | NaN |
[72.0, 72.0) | 72 | 0.0 | 26 | 24 | 1/2 | 1/2 | 3/4 | 2 | 1 | <NA> | 1 | { | NaN | dcml | f | iv | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | { | NaN | True | True | () | () | <NA> | <NA> | NaN | NaN | NaN |
[82.0, 84.0) | 82 | 2.0 | 30 | 28 | 0 | 0 | 3/4 | 2 | 1 | <NA> | 1 | V|HC} | NaN | dcml | f | i | NaN | V | V | NaN | NaN | NaN | NaN | HC | } | M | True | True | (1, 5, 2) | () | 1 | 1 | NaN | NaN | NaN |
[84.0, 85.0) | 84 | 1.0 | 30 | 28 | 1/2 | 1/2 | 3/4 | 2 | 1 | <NA> | 1 | i64{ | NaN | dcml | f | i | NaN | i64 | i | NaN | 64 | NaN | NaN | NaN | { | m | True | True | (1, 0, -3) | () | 0 | 1 | NaN | NaN | NaN |
[106.0, 109.0) | 106 | 3.0 | 38 | 36 | 0 | 0 | 3/4 | 2 | 1 | <NA> | 1 | i|PAC} | NaN | dcml | f | i | NaN | i | i | NaN | NaN | NaN | NaN | PAC | } | m | True | True | (0, -3, 1) | () | 0 | 0 | NaN | NaN | NaN |
[120.0, 124.0) | 120 | 4.0 | 43 | 40 | 0 | 1/2 | 3/4 | 2 | 1 | <NA> | 1 | I.I{ | NaN | dcml | f | I | NaN | I | I | NaN | NaN | NaN | NaN | NaN | { | M | True | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN |
[148.0, 154.0) | 148 | 6.0 | 53 | 50 | 0 | 0 | 3/4 | 2 | 1 | <NA> | 1 | I[I|PAC} | NaN | dcml | f | V | I | I | I | NaN | NaN | NaN | NaN | PAC | } | M | True | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN |
[150.0, 150.0) | 150 | 0.0 | 54 | 50 | 0 | 1/2 | 3/4 | 2 | 1 | <NA> | 1 | { | NaN | dcml | f | V | I | NaN | NaN | NaN | NaN | NaN | NaN | NaN | { | NaN | True | False | () | () | <NA> | <NA> | NaN | NaN | NaN |
[193.0, 196.0) | 193 | 3.0 | 69 | 65 | 0 | 0 | 3/4 | 2 | 1 | <NA> | 1 | V7} | NaN | dcml | f | I | NaN | V7 | V | NaN | 7 | NaN | NaN | NaN | } | Mm7 | True | False | (1, 5, 2, -1) | () | 1 | 1 | NaN | NaN | NaN |
[196.0, 199.0) | 196 | 3.0 | 70 | 66 | 0 | 0 | 3/4 | 2 | 1 | <NA> | 1 | I{ | NaN | dcml | f | I | NaN | I | I | NaN | NaN | NaN | NaN | NaN | { | M | True | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN |
[217.0, 219.0) | 217 | 2.0 | 77 | 73 | 0 | 0 | 3/4 | 2 | 1 | <NA> | 1 | I|PAC} | NaN | dcml | f | I | NaN | I | I | NaN | NaN | NaN | NaN | PAC | } | M | True | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN |
create_modulation_plan(data, title="Beethoven 01-3", globalkey='f', task_column='semitones', phraseends=get_phraseends(df))
for ix, df in phrase_segments.groupby(level=["corpus", "fname", "phrase_slice"]):
display(df)
break
quarterbeats | duration_qb | mc | mn | mc_onset | mn_onset | timesig | staff | voice | volta | harmony_layer | label | alt_label | regex_match | globalkey | localkey | pedal | chord | numeral | form | figbass | changes | relativeroot | cadence | phraseend | chord_type | globalkey_is_minor | localkey_is_minor | chord_tones | added_tones | root | bass_note | special | pedalend | placement | ||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
corpus | fname | phrase_slice | interval | |||||||||||||||||||||||||||||||||||
bach_solo | BWV1009_01_Prelude | [0.0, 18.25) | [0.0, 0.0) | 0.0 | 0.00 | 1 | 1 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | C.I{ | <NA> | dcml | C | I | NaN | <NA> | <NA> | <NA> | <NA> | <NA> | <NA> | NaN | { | <NA> | False | False | <NA> | <NA> | <NA> | <NA> | NaN | NaN | NaN |
[0.0, 6.0) | 0.0 | 6.00 | 1 | 1 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | C.I{ | NaN | dcml | C | I | NaN | I | I | NaN | NaN | NaN | NaN | <NA> | <NA> | M | False | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN | |||
[6.0, 8.0) | 6.0 | 2.00 | 3 | 3 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | V | NaN | dcml | C | I | NaN | V | V | NaN | NaN | NaN | NaN | NaN | NaN | M | False | False | (1, 5, 2) | () | 1 | 1 | NaN | NaN | NaN | |||
[8.0, 9.0) | 8.0 | 1.00 | 3 | 3 | 1/2 | 1/2 | 3/4 | 1 | 1 | <NA> | 1 | V7 | NaN | dcml | C | I | NaN | V7 | V | NaN | 7 | NaN | NaN | NaN | NaN | Mm7 | False | False | (1, 5, 2, -1) | () | 1 | 1 | NaN | NaN | NaN | |||
[9.0, 12.0) | 9.0 | 3.00 | 4 | 4 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | I | NaN | dcml | C | I | NaN | I | I | NaN | NaN | NaN | NaN | NaN | NaN | M | False | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN | |||
[12.0, 14.0) | 12.0 | 2.00 | 5 | 5 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | V | NaN | dcml | C | I | NaN | V | V | NaN | NaN | NaN | NaN | NaN | NaN | M | False | False | (1, 5, 2) | () | 1 | 1 | NaN | NaN | NaN | |||
[14.0, 15.0) | 14.0 | 1.00 | 5 | 5 | 1/2 | 1/2 | 3/4 | 1 | 1 | <NA> | 1 | V7 | NaN | dcml | C | I | NaN | V7 | V | NaN | 7 | NaN | NaN | NaN | NaN | Mm7 | False | False | (1, 5, 2, -1) | () | 1 | 1 | NaN | NaN | NaN | |||
[15.0, 15.0) | 15.0 | 0.00 | 6 | 6 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | I} | <NA> | dcml | C | I | NaN | <NA> | <NA> | <NA> | <NA> | <NA> | <NA> | NaN | } | <NA> | False | False | <NA> | <NA> | <NA> | <NA> | NaN | NaN | NaN | |||
[15.0, 18.25) | 15.0 | 3.25 | 6 | 6 | 0 | 0 | 3/4 | 1 | 1 | <NA> | 1 | I} | NaN | dcml | C | I | NaN | I | I | NaN | NaN | NaN | NaN | <NA> | <NA> | M | False | False | (0, 4, 1) | () | 0 | 0 | NaN | NaN | NaN |
make_gantt_data(df)
Start | Finish | Duration | Resource | abs_numeral | fifths | semitones | localkey | globalkey | Description | |
---|---|---|---|---|---|---|---|---|---|---|
interval | ||||||||||
[0.0, 18.25) | 0.0 | 18.25 | 18.25 | local | I | 0 | 0 | I | C | Duration: 18.25<br>Tonicized global scale degr... |