musicbrainz-sparql

Alignment of MusicBrainz and Wikidata instruments

%run -i ../startup.py
ENTITY_TYPE = 'instrument'
Last notebook update: 2021-01-28
Importing libs
Defining database parameters
Defining *sql* helper function
Last database update: 2021-01-13

Defining *sparql* helper function

Instruments from Wikidata

Wikidata entities which are musical instruments or families of musical instruments:

# instance of musical instrument
wd_musical_instruments = sparql("""
SELECT ?instrument ?instrumentLabel ?HornbostelSachs
WHERE {
  { ?instrument wdt:P31* wd:Q34379 . }
  UNION
  { ?instrument wdt:P31 wd:Q1254773 . }
  OPTIONAL
  { ?instrument wdt:P1762 ?HornbostelSachs . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
""")
wd_musical_instruments.rename(columns={
    'instrument': 'wd', 'instrumentLabel': 'name'}, inplace=True)
wd_musical_instruments.head()
wd name HornbostelSachs
0 Q55724333 friction drums with free stick 231.13
1 Q55724337 rotating friction drums 232.2
2 Q55724342 friction drums with tied stick 231.2
3 Q55724561 stationary friction drums with friction cord 232.1
4 Q55724566 single-skin stationary drums with friction cord 232.11

Entities with “instrumental” links to MB:

# linked to MB instrument
links_from_wd = sparql("""
SELECT (?instrument AS ?wd) ?mbid ?instrumentLabel
WHERE {
  ?instrument wdt:P1330 ?mbid .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
ORDER BY ASC(?instrumentLabel)
""")
links_from_wd.rename(columns={'instrumentLabel': 'name'}, inplace=True)

display_df(links_from_wd.head())
wd mbid name
0 Q10751910 1c70cc38-deee-4a84-9b16-7a81c0f43aed Q10751910
1 Q13094251 f6b76abc-fdef-444c-97b1-27b12e3e3c0b Q13094251
2 Q13094253 176ce29f-bcf0-47f5-beda-c97ef6df6480 Q13094253
3 Q13094254 14acd267-2e1b-459d-b41e-058d2c106345 Q13094254
4 Q13094255 4ac4b541-116d-40c1-93c7-160153ca53ac Q13094255

Probably needs cleanup

set([wd for wd in links_from_wd.wd
     if links_from_wd.wd.to_list().count(wd) > 1])
{'Q1398629'}
set([mbid for mbid in links_from_wd.mbid
     if links_from_wd.mbid.to_list().count(mbid) > 1])
{'291e2d38-cdc9-4b9e-b592-5d653f32da6c',
 'd5b46baa-37fc-46cc-b99f-c455ce6e6a9c'}
links_from_mb = sql("""
SELECT
    url.url AS wd,
    instrument.gid AS mbid,
    instrument.name
FROM url
JOIN l_instrument_url AS llu ON llu.entity1 = url.id
JOIN instrument              ON llu.entity0 = instrument.id
WHERE
    url.url LIKE '%%wikidata.org%%'
ORDER BY instrument.name
;
""")
links_from_mb.wd = links_from_mb.wd.apply(lambda s: s.split('/')[-1])
links_from_mb.mbid = links_from_mb.mbid.apply(str)
display_df(links_from_mb.head())
wd mbid name
0 Q678090 d5cc3c69-218e-449a-b80d-8bd7a61311a1 12 string guitar
1 Q4118803 21468ce3-bad3-4f48-a2ff-01e6b0bc9ca2 17-string bass koto
2 Q1024685 33b6ba89-8265-4d8f-bbdc-ecff41e29e8c Afuche/Cabasa
3 Q18639099 26b4608d-acc3-46f3-b509-d83bd798e122 Anglo concertina
4 Q2145031 e618d02c-41c0-475c-be70-7ef0f92da7d0 Appalachian dulcimer

Probably needs cleanup

set([wd for wd in links_from_mb.wd
     if links_from_mb.wd.to_list().count(wd) > 1])
{'Q1398629', 'Q5266546'}
set([mbid for mbid in links_from_mb.mbid
     if links_from_mb.mbid.to_list().count(mbid) > 1])
{'291e2d38-cdc9-4b9e-b592-5d653f32da6c',
 'b0f83029-6d38-4f6f-bd30-db44e427f497',
 'd5b46baa-37fc-46cc-b99f-c455ce6e6a9c'}

Data alignment

merge = pd.merge(links_from_wd, links_from_mb, 
                 on=['wd', 'mbid'], suffixes=('_wd', '_mb'),
                 how='outer', indicator=True)
display_df(merge.head())
wd mbid name_wd name_mb _merge
0 Q10751910 1c70cc38-deee-4a84-9b16-7a81c0f43aed Q10751910 cò ke both
1 Q13094251 f6b76abc-fdef-444c-97b1-27b12e3e3c0b Q13094251 kendhang batangan both
2 Q13094253 176ce29f-bcf0-47f5-beda-c97ef6df6480 Q13094253 kendhang ketipung both
3 Q13094254 14acd267-2e1b-459d-b41e-058d2c106345 Q13094254 kendhang gendhing both
4 Q13094255 4ac4b541-116d-40c1-93c7-160153ca53ac Q13094255 kendhang wayangan both
# link in mb but missing in wd
links_to_add_to_wd = merge.loc[lambda x : x['_merge']=='right_only'][['name_mb', 'mbid', 'wd']]
display_df(links_to_add_to_wd)
name_mb mbid wd
0 Pierrot ensemble 51e92fd2-e56e-4576-8547-acb63e8b8446 Q7192570
1 baglamas d4d5309f-166e-4e14-9887-06692f2c1027 Q528239
2 bağlama 2dd967cd-104e-4696-8a70-0f6fd37779e7 Q717773
3 bedug 9063d25e-87e4-4adc-81d4-8fdee23bd26f Q3624317
4 bīn efa5b047-95e7-4ebb-9987-b07208a1ac27 Q5266546
5 diatonic button accordion 842d3d24-f638-47e6-a239-8578723db09c Q379269
6 dilruba 57deb1b0-b7fe-4616-b9cb-bbd59bc0acd8 Q17190172
7 gendèr barung 60cd46dd-45d5-47ff-8d7e-a501e9c7938c Q74581228
8 kempul e0350378-0d4b-49d5-ad81-8f74e1b54efc Q6387169
9 lira da braccio 6060f9c4-10ee-48b7-a2d8-e97f944afa70 Q584967
10 piano duo 0a49e297-8430-44cd-be7b-1fd22560b6e1 Q43136500
11 piano four hands c3f3aacc-d9c0-4b6e-92e8-05df9af50e17 Q227484
12 piano quartet ffa61786-07ed-48ed-b7bb-a17d248fba8c Q1746025
13 pluriarc d43c2380-efe5-4488-b08f-777296d0c95c Q3392660
14 rammana 551e553a-cadd-4363-8723-f72aab5431d0 Q16033036
15 saron barung 5b159ed5-2c58-4200-accb-c2ac5c9ace7f Q13096799
16 saron demung 81da5ec5-4a2f-4481-b01d-fb8ab9ea116d Q4262704
17 saron panerus 2656be9c-b531-4cbb-a5b5-30454054343c Q20585538
18 saron peking b3fe02dc-f412-464e-b216-8c3fe45de456 Q13095883
19 scraped idiophone dbd1ec09-34fd-412e-b73b-124e46cf7cdf Q50825269
20 string trio 6efec29d-013a-4687-b710-fe25800eb358 Q29787068
21 tape 672c19ec-0ca3-4ece-9f6b-7f1c0018a0e6 Q193663
22 viol consort e46bffd3-15a3-426a-923f-705839128609 Q1492889
23 voice synthesizer b0f83029-6d38-4f6f-bd30-db44e427f497 Q16346

24 links in MB that are not in WD

# link in wd but missing in mb
links_to_add_to_mb = merge.loc[lambda x : x['_merge']=='left_only'][['name_wd', 'wd', 'mbid']]
display_df(links_to_add_to_mb)
name_wd wd mbid
0 Rebana Q3181140 551e553a-cadd-4363-8723-f72aab5431d0
1 akkordolia Q4701390 bd5fa79a-ea6f-4e11-9463-f6f43cca363c
2 bell Q101401 c95c7129-d180-4218-afea-4b74ef70e2be
3 bellows-blown bagpipe Q63619194 d4cbc6fd-5e68-4cf4-afeb-dd2fb4df3c2d
4 dilrupa Q5277044 57deb1b0-b7fe-4616-b9cb-bbd59bc0acd8
5 fretless bass Q932855 12f20f43-c71d-4476-8ada-b968aab50900
6 lap slide guitar Q6488060 c0ea0405-ae3f-4851-bf85-277fadff80e2
7 scraped idiophone Q1644824 dbd1ec09-34fd-412e-b73b-124e46cf7cdf
8 tromboon Q840638 ee499c78-26df-4698-ab97-c4120276eb1a

9 links in WD that are not in MB

In those mismatches, some are not recognized because of redirects on WD side: Q54995817 to Q4138014, Q16033036 to Q3181140

no_links_from_mb = sql("""
SELECT
    gid AS mbid,
    name
FROM
    instrument
WHERE
    id NOT IN (
        SELECT
            instrument.id
        FROM url
        JOIN l_instrument_url AS llu ON llu.entity1 = url.id
        JOIN instrument              ON llu.entity0 = instrument.id
        WHERE
            url.url LIKE '%%wikidata.org%%'
    )
;
""")
no_links_from_mb.mbid = no_links_from_mb.mbid.apply(str)
display_df(no_links_from_mb)
mbid name
0 f711b03f-86c6-4e67-86eb-c6716ddbe1c1 kös
1 872b72a2-541c-4115-b7ce-2dfed3e84884 bin-sitar
2 a66b7f37-5aa2-43b8-85eb-0dea87aae930 gramorimba
3 c9fb1652-1a07-4f3d-b886-ec961efcc7c8 segunda
4 f0ddf0ec-e8ac-4765-acef-0687af2b2f32 fourth flute
5 bd5a399f-c18e-41ad-af23-a01353c51d7c ki pah
6 39b5634a-4802-4a66-a27a-58f37677c197 primero
7 44055718-26b6-4a25-9e76-5067ae5b9862 ding tac ta
8 1156c575-2165-4799-be3f-023ff1fc7655 daruan
9 ec478db3-c490-4fca-a688-0bdd9fb55806 heike biwa
10 7a5b3204-0200-426c-88d5-3f26a225b757 hmông flute
11 91eb1744-96d8-4c54-8aa2-f97ed7d88950 foot stomps
12 837c7244-ece8-47ff-b215-78f4aa4f227d treble violin
13 12f20f43-c71d-4476-8ada-b968aab50900 electric fretless guitar
14 e798a2bd-a578-4c28-8eea-6eca2d8b2c5d horn
15 b6aa8ec7-3ede-4f8b-92f1-45f4568e3261 khong wong
16 40243f27-1011-491b-8b06-28c48749b960 farfisa
17 ce8bf63e-ffb2-44e9-a886-16ca6522525f đing buốt
18 0e7c8402-0603-4aff-880b-bb7eedbf5c01 traditional basque ensemble
19 db36bd83-0606-42b9-91a0-d759ba52d0da trumpet family
20 3c5349ca-cf82-4537-851f-1957ac88bced electric lap steel guitar
21 809f4e7f-918f-4e7e-884a-dc7faa4e52c1 gendèr wayang
22 5888d65d-9d65-4d13-8454-3d68be9b3e55 acoustic fretless guitar
23 a3c58697-eae3-454c-90c5-5f911a24376a daire
24 f02ca577-d1ec-4c02-97c8-a15afff6bbfa daluo
25 3933adfe-f55b-47fd-b085-c9983d15cc9d five-string banjo
26 371dd55f-5251-4905-a8b2-2d2acf352376 keyed brass instruments
27 ac16043b-4727-40f9-bb2a-cb30ab4ce7a2 chikuzen biwa
28 ca17a349-e0e3-4b9b-b74d-898a2b54b43e syrinx
29 53174999-953d-482b-9240-23acf2452fc9 wavedrum
30 34c1af71-f7fc-4e34-a46a-5c29ee4c019b folk harp
31 e5781903-d6ef-4480-a158-60300265577c natural brass instruments
32 88f0d4fb-e7cc-4825-9d05-bcf974953790 disk drive
33 87d5bd6a-8d14-4ed0-befa-b90379536634 nylon guitar
34 bc542c3c-5cf6-4c31-b75f-a03d660cad75 German harp
35 4a5da835-0f0d-4010-b013-76d0a48f8578 slide brass instruments
36 7aed0189-ff99-4b43-8ff0-52ca5626d0b7 ankle rattlers
37 81b68590-5c82-47a3-9790-1570ca60f711 fundeh
38 ce9452ac-917f-4cab-ab13-75996816202b saz
39 fe2e16fc-81b7-44e7-a96a-c3afac308a04 valve trombone
40 65116580-10f5-4123-9d86-5e379cd9ab83 wire-strung harp
41 92ec69b8-c35c-4d44-9e99-953d229d6e87 pang gu ly hu hmông
42 d2f041b9-b6a6-4973-badd-1b07a37192c9 valved brass instruments
43 27a9b513-5218-404f-a285-02d89aa358df chacha
44 2561db4d-1018-4a40-9b15-93bcbd0887d4 pōrutu
45 ba6af31f-8b2f-4c5e-903e-882f88f6d3a6 soprano violin
46 de564c42-80db-4040-96c4-269ad9e063ac satsuma biwa
47 5f0a32fa-82b2-49da-a9ee-78cad9cf756d tanbou ka
48 ce0a1033-3e33-4d7f-8230-1fb53a57651d xiaoluo
49 44c74dce-8a26-4837-9c19-918b412c6a6a tràm plè
50 741715c4-1756-43f8-b56f-a4aca1dc2cfd żafżafa
51 9478e40f-bab3-4fcb-a52a-f3df65770bfa żummara
52 b0acbf59-ffba-4e2f-8104-31aed56fa364 tef
53 8045f4a3-7f12-4de4-957d-26908a2714eb trắng jâu
54 fd5caadd-efab-487a-8954-cd243396fbe2 trắng lu
55 2c27736b-e774-4f8e-8290-604d3c468870 đàn tứ dây
56 d4cbc6fd-5e68-4cf4-afeb-dd2fb4df3c2d bellow-blown bagpipes
57 023adf58-6aa2-4659-8760-3b36f81d0352 chamber organ
58 f1e042f5-2a09-47b1-9cdf-1018d239d330 rhythm sticks
59 63f030d8-f116-4f11-9dee-0cb1cfeb8445 pí thiu
60 e8e99279-0774-404a-9973-d4b06c759fc4 shudraga
61 76e5cc5f-aa37-4be3-a035-9e7518250ee5 ti bwa
62 0b9d87fa-93fa-4956-8b6a-a419566cc915 electric bass guitar
63 35e94803-4462-407a-8a01-3e474a45aaaf tenor trombone
64 ffe6c3f3-12a2-42e7-8cde-7ae24ff83fc5 trống bông
65 2fb619eb-c5b3-495a-967a-b747b976a7d9 bowed piano
66 8a4a2afb-609e-4316-b7fa-4a687aada9ee brushes
67 117dacfc-0ad0-4e90-81a4-a28b4c03929b Spanish acoustic guitar
68 c0ea0405-ae3f-4851-bf85-277fadff80e2 Hawaiian guitar
69 74e8088e-d5b0-44bc-853a-74aa8c8aa5aa finger cymbals
70 96bec768-bee7-4b67-816e-3b4743df98ec fretless bass
71 310cb712-c512-419f-9b61-ab77325b6636 Tibetan water drum
72 c95c7129-d180-4218-afea-4b74ef70e2be bell
73 a2d87653-559a-4c8e-9cb0-f72effb8df8f vacuum cleaner
74 f83c4b45-3584-401a-90bf-4ec80e7add78 bağlama (saz) family
75 e6571d23-5d79-4216-99d6-06e14e737da1 bass synthesizer
76 7631a763-6c36-4fc6-b04a-1021cd60e7e5 pūkaea
77 5c5cf664-4685-4089-bce0-b8c7e16ac698 rehu
78 98837460-d363-4af3-920c-cc016b48d98d pūmotomoto
79 68064791-4108-4c97-812f-990c45d1ba0d nguru
80 2e345a93-045e-403a-80a9-4c6835c3a49e pūrerehua
81 23af87b9-81a5-45ed-9d2e-cf4c64bfd932 piano spinet
82 b6649fb6-d4cc-477e-ae8d-39145fb46d06 poi āwhiowhio
83 b6c87b0e-5f2b-49a4-bc0e-457e0e4951b9 saduk
84 d0feefd4-147a-4ed9-a07c-c267b436f47f temür khuur
85 26ed69bd-3828-4c49-8e74-0fb4399a06d3 khulsan khuur
86 5ed5bf1f-ca26-4aeb-b4dd-88a52b1a17e7 pahū pounamu
87 f68936f2-194c-4bcd-94a9-81e1dd947b8d guitar family
88 925959ba-97d4-4e6f-b9dc-3ba8c4a773c4 pahū
89 3158f700-4e47-4cc5-b641-228b0c5e5a4a pākuru
90 37ebafcb-34d7-436e-ba6e-b8646086f665 chuurqin
91 30aeef52-3ebf-405e-9baa-ef6c6f3ef6d5 repeater
92 6bcb239b-e739-4d47-81e7-c2eec8e7b1ea chirimía and drum
93 90bd690b-f86d-4ea3-b87d-f945b1ab9e38 tōkere
94 908b5372-2a64-4248-8c27-3e9c76951aa1 porotiti
95 c2bfcf82-356c-4606-9dd7-51efd1b11bec gut guitar
96 bfa5b262-34cf-418b-a9c5-b629a24a96ee English flageolet
97 205acba3-c6aa-4e47-be4c-2be043cfd511 plucked idiophone
98 bac20474-624a-46ce-a517-871eea3486b1 bouzar / gouzouki
99 6dadb008-cb59-40cb-8b3a-a07942ffb818 viololyra
100 cc996d06-87dc-420e-9ed7-a52867ca6e1e vibrandoneon
101 68a64027-1bc3-4057-bd51-165697322aca kamalen ngɔni
102 a11e9091-1182-4d79-90a1-dcaa282e4a98 jeli ngɔni
103 f7e7dd09-eef7-4c66-a226-c8eb6ba378e1 pūpakapaka
104 a4f10af3-d440-4ee7-9093-c60a121df41a kōauau ponga ihu
105 fdc68c28-cc0c-4ae6-bd9e-dd0b68e3cf1a hue puruwai
106 fdcacb6d-7f3d-446d-aa65-fff4c9afb7f6 hue puruhau
107 0c5e5de9-605c-4487-b454-ef70ef8c1996 rōria
108 1b425878-18c7-4bcd-9129-bed989295e5f te kū
109 e5408785-e228-4919-9e79-6f997bcdfea5 tube zither
110 0a06dd9a-92d6-4891-a699-2b116a3d3f37 other instruments
111 3b7be43c-0b3b-42dd-8560-d61e41f6bd61 saron wayang
112 c588cc24-e139-44a9-8a48-7963eb693dd1 kendhang indung
113 ed1628bd-8541-4874-b8ca-2cec8b4c5140 baandu
114 292a95fd-9bc7-4052-aa6e-844c8f4f4905 kendhang kulanter

Alignment suggestions

Exact match

Exact match between instrument names in WD and MB:

no_links_merge = pd.merge(no_links_from_mb, wd_musical_instruments, 
                 on='name', how='inner', indicator=False)
display_df(no_links_merge)
mbid name wd HornbostelSachs
0 ca17a349-e0e3-4b9b-b74d-898a2b54b43e syrinx Q10902606 NaN
1 c95c7129-d180-4218-afea-4b74ef70e2be bell Q101401 111.242
2 c95c7129-d180-4218-afea-4b74ef70e2be bell Q96309259 NaN
3 e5408785-e228-4919-9e79-6f997bcdfea5 tube zither Q30034781 312

With fuzzy-matching library

Using fuzzy-matching to find close instrument names:

import fuzzymatcher

match = fuzzymatcher.fuzzy_left_join(
    no_links_from_mb, wd_musical_instruments[['wd', 'name']], 
    left_on='name', right_on='name')[['best_match_score', 'mbid', 
                                      'name_left', 'name_right', 'wd']]
match = match[match['best_match_score'] > 0.09].sort_values(by='best_match_score', 
                                                            ascending=False)
display_df(match, index=False)
best_match_score mbid name_left name_right wd
0.459847 e5408785-e228-4919-9e79-6f997bcdfea5 tube zither tube zither Q30034781
0.282946 3c5349ca-cf82-4537-851f-1957ac88bced electric lap steel guitar Lap steel Q94994651
0.246483 ca17a349-e0e3-4b9b-b74d-898a2b54b43e syrinx syrinx Q10902606
0.206346 e798a2bd-a578-4c28-8eea-6eca2d8b2c5d horn Horn Q94994539
0.193824 c95c7129-d180-4218-afea-4b74ef70e2be bell bell Q101401
0.130599 872b72a2-541c-4115-b7ce-2dfed3e84884 bin-sitar Sitar Q79485179
0.130280 371dd55f-5251-4905-a8b2-2d2acf352376 keyed brass instruments brass instrument Q180744
0.125435 837c7244-ece8-47ff-b215-78f4aa4f227d treble violin Violin Q80002939
0.114376 e5781903-d6ef-4480-a158-60300265577c natural brass instruments brass instrument Q180744
0.104660 7a5b3204-0200-426c-88d5-3f26a225b757 hmông flute flute Q11405
0.104342 d2f041b9-b6a6-4973-badd-1b07a37192c9 valved brass instruments brass instrument Q180744
0.097538 205acba3-c6aa-4e47-be4c-2be043cfd511 plucked idiophone idiophone Q12639
0.094626 f0ddf0ec-e8ac-4765-acef-0687af2b2f32 fourth flute flute Q11405
0.094540 87d5bd6a-8d14-4ed0-befa-b90379536634 nylon guitar Guitar Q79485088
0.094540 c0ea0405-ae3f-4851-bf85-277fadff80e2 Hawaiian guitar Guitar Q79485088
0.094540 c2bfcf82-356c-4606-9dd7-51efd1b11bec gut guitar Guitar Q79485088
0.091077 db36bd83-0606-42b9-91a0-d759ba52d0da trumpet family trumpet Q8338
0.090461 2fb619eb-c5b3-495a-967a-b747b976a7d9 bowed piano piano Q5994

With record linkage library

import recordlinkage

# Indexation step
indexer = recordlinkage.SortedNeighbourhoodIndex('name', window=9)
pairs = indexer.index(no_links_from_mb, wd_musical_instruments[['wd', 'name']])
print(len(pairs))

# Comparison step
compare_cl = recordlinkage.Compare()
compare_cl.string('name', 'name', method='jarowinkler', 
                  threshold=0.9, label='name')
features = compare_cl.compute(pairs, no_links_from_mb, wd_musical_instruments[['wd', 'name']])
print(features[features.sum(axis=1) > 0].shape)

# Classification step
linkage = []
for (idx0, idx1) in features[features.sum(axis=1) > 0].index:
    linkage.append([
        no_links_from_mb.loc[idx0]['mbid'],
        no_links_from_mb.loc[idx0]['name'],
        wd_musical_instruments.loc[idx1]['name'],
        wd_musical_instruments.loc[idx1]['wd'],
    ])
    
display_df(pd.DataFrame(linkage, columns=('mbid', 'name_left', 'name_right', 'wd')),
           index=False)
681
(5, 1)
mbid name_left name_right wd
ca17a349-e0e3-4b9b-b74d-898a2b54b43e syrinx syrinx Q10902606
c95c7129-d180-4218-afea-4b74ef70e2be bell bell Q101401
c95c7129-d180-4218-afea-4b74ef70e2be bell bell Q96309259
e5408785-e228-4919-9e79-6f997bcdfea5 tube zither tube zither Q30034781
db36bd83-0606-42b9-91a0-d759ba52d0da trumpet family trumpet Q8338

Report

import jinja2

template = jinja2.Template("""
<!doctype html>

<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Alignment of MusicBrainz and Wikidata Instruments</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
  </head>

  <body style="margin: 20px;">
    <h1>Alignment of MusicBrainz and Wikidata Instruments</h1>

    <p>Latest MB database update: </p>
    <p>Latest update: </p>
    
    <ol>
      <li><a href="#wd2mb">Add missing Wikidata links to MusicBrainz</a></li>
      <li><a href="#mb2wd">Add missing MusicBrainz links to Wikidata</a></li>
      <li><a href="#alignment">Missing alignment suggestions</a>
    </ol>
    
    <h2 id="wd2mb">Add missing Wikidata links to MusicBrainz</h2>
    

    <h2 id="mb2wd">Add missing MusicBrainz links to Wikidata</h2>
    

    <h2 id="alignment">Missing alignment suggestions</h2>
    
    <h3>Alignment on exact names</h3>
    
    
    <h3>Alignment on fuzzy matching</h3>
        
  
  </body>
</html>
""")

with open('../docs/wd-instruments-report.html', 'w') as f:
    f.write(template.render(**globals())
            .replace('&lt;', '<').replace('&gt;', '>')
            .replace('class="dataframe"', 'class="table table-striped table-hover table-sm"')
            .replace('thead', 'thead class="thead-light"'))