Download hub-collocation.html from jimfhahn/bibframe-hub-collocation: direct link, hf CLI and curl.
- Browser
- Download file 36.4 kB
-
https://huggingface.co/spaces/jimfhahn/bibframe-hub-collocation/resolve/main/hub-collocation.html
- Command line
-
hf download hf://spaces/jimfhahn/bibframe-hub-collocation/hub-collocation.html
-
curl -L -o hub-collocation.html https://huggingface.co/spaces/jimfhahn/bibframe-hub-collocation/resolve/main/hub-collocation.html
36.4 kB
| <html lang="en"><head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <style type="text/css">:root{--serif:"Source Serif 4 Variable", ui-serif, serif;--sans-serif:"Inter Variable", ui-sans-serif, sans-serif;--monospace:"Spline Sans Mono Variable", Menlo, Consolas, monospace;--monospace-font:14px/1.5 var(--monospace);--max-width:calc(1024px - 4 * 16px)}html{font:17px/1.5 var(--serif);-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{background:var(--theme-background);color:var(--theme-foreground);margin:16px 0;padding:16px 24px}main{max-width:var(--max-width);margin:auto}h1,h2,h3,h4,h5,h6{color:var(--theme-foreground-alt);text-wrap:balance;margin-top:0;margin-bottom:.25rem;font-weight:700;line-height:1.15}h2+p,h3+p,h4+p,h2+table,h3+table,h4+table{margin-top:0}.observablehq:first-of-type h1+h2{color:var(--theme-foreground);margin-bottom:1rem;font-size:20px;font-style:italic;font-weight:400}a[href]{color:var(--theme-foreground-focus);text-decoration:none}a[href]:hover,a[href]:focus{text-decoration:underline}pre,code,tt{font-family:var(--monospace);font-size:82.3529%}pre code,figcaption code{font-size:inherit}pre[data-language]{position:relative}pre[data-language]:before{content:attr(data-language);text-align:right;pointer-events:none;height:0;color:var(--theme-foreground-muted);margin-right:-4px;font-size:12px;line-height:21px;display:block;position:sticky;top:0;left:0}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-size:88.2353%}h2[id] a[href],h3[id] a[href]{color:inherit}pre{line-height:1.5}img{max-width:100%}p,table,figure,figcaption,h1,h2,h3,h4,h5,h6,.katex-display{max-width:640px}blockquote,ol,ul{max-width:600px}blockquote{margin:1rem 1.5rem}ul,ol{padding-left:28px}hr{background:no-repeat center/100% 1px linear-gradient(to right, var(--theme-foreground-faintest), var(--theme-foreground-faintest));border:none;height:1px;margin:1rem 0;padding:1rem 0}pre{background-color:var(--theme-background-alt);overscroll-behavior-x:none;box-sizing:border-box;border-radius:4px;min-height:1.5em;margin:1rem -1rem;padding:4px 1rem;overflow-x:auto}pre>code:only-child{width:fit-content;display:block}input:not([type]),input[type=email],input[type=number],input[type=password],input[type=range],input[type=search],input[type=tel],input[type=text],input[type=url]{width:240px}input,canvas,button{vertical-align:middle}button,input,textarea{accent-color:var(--theme-foreground-focus)}table{border-collapse:collapse;width:100%;font:13px/1.2 var(--sans-serif)}table pre,table code,table tt{font-size:inherit;line-height:inherit}th>pre:only-child,td>pre:only-child{margin:0;padding:0}th{color:var(--theme-foreground);text-align:left;vertical-align:bottom}td{color:var(--theme-foreground-alt);vertical-align:top}th,td{padding:3px 6.5px 3px 0}th:last-child,td:last-child{padding-right:0}tr:not(:last-child){border-bottom:solid 1px var(--theme-foreground-faintest)}thead tr{border-bottom:solid 1px var(--theme-foreground-fainter)}figure,table{margin:1rem 0}figure img{max-width:100%}figure>h2,figure>h3{font-family:var(--sans-serif)}figure>h2{font-size:20px}figure>h3{font-size:16px;font-weight:400}figcaption{font:small var(--sans-serif);color:var(--theme-foreground-muted)}.observablehq--collapsed,.observablehq--expanded.observablehq--inspect a{cursor:pointer}.observablehq--caret{vertical-align:baseline;margin-right:4px}.observablehq--field{text-indent:-1rem;margin-left:1rem}.observablehq--inspect{font:var(--monospace-font);white-space:pre;padding:2px 0;display:block;overflow-x:auto}.observablehq--inspect.observablehq--import{white-space:normal}.observablehq--inspect::-webkit-scrollbar{display:none}.observablehq--error .observablehq--inspect{word-break:break-all;white-space:pre-wrap}.observablehq--string-expand{background:var(--theme-background-alt);cursor:pointer;vertical-align:middle;border-radius:2px;margin-left:6px;padding:2px 6px;font-size:80%}.observablehq--keyword{color:var(--syntax-keyword)}.observablehq--index,.observablehq--key{color:var(--syntax-definition)}.observablehq--symbol,.observablehq--regexp,.observablehq--string{color:var(--syntax-string)}.observablehq--undefined,.observablehq--null{color:var(--syntax-keyword)}.observablehq--prototype-key{color:var(--syntax-comment)}.observablehq--bigint,.observablehq--boolean,.observablehq--date,.observablehq--forbidden,.observablehq--number{color:var(--syntax-literal)}.observablehq--error{color:var(--theme-error)}.observablehq--cell{min-height:1px;margin:17px 0;position:relative}.tok-link{color:var(--syntax-link)}.tok-strong{font-weight:600}.tok-emphasis{font-style:italic}.tok-keyword{color:var(--syntax-keyword)}.tok-atom{color:var(--syntax-atom)}.tok-literal{color:var(--syntax-literal)}.tok-string{color:var(--syntax-string)}.tok-comment{color:var(--syntax-comment)}.tok-invalid{color:var(--syntax-invalid)}.tok-variable{color:var(--syntax-variable)}.tok-definition{color:var(--syntax-definition)}.tok-meta{color:var(--syntax-meta)}.plot-d6a7b5{--plot-background:var(--theme-background)}p .plot-d6a7b5{display:inline-block}.observablehq--cell:empty{min-height:0}.observablehq--cell:not(:empty)+pre{margin-top:-11px}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./assets/inter-cyrillic-wght-normal-DqGufNeO.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./assets/inter-greek-ext-wght-normal-DlzME5K_.woff2)format("woff2-variations");unicode-range:U+1F??}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./assets/inter-greek-wght-normal-CkhJZR-_.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./assets/inter-latin-wght-normal-Dx4kXJAl.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter Variable;font-style:italic;font-display:swap;font-weight:100 900;src:url(./assets/inter-cyrillic-ext-wght-italic-B5xAaiFk.woff2)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:italic;font-display:swap;font-weight:100 900;src:url(./assets/inter-cyrillic-wght-italic-DzZdc28x.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Inter Variable;font-style:italic;font-display:swap;font-weight:100 900;src:url(./assets/inter-greek-ext-wght-italic-DcOpz6Lw.woff2)format("woff2-variations");unicode-range:U+1F??}@font-face{font-family:Inter Variable;font-style:italic;font-display:swap;font-weight:100 900;src:url(./assets/inter-greek-wght-italic-CILZdfAp.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:Inter Variable;font-style:italic;font-display:swap;font-weight:100 900;src:url(./assets/inter-vietnamese-wght-italic-K3WlGtc8.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:italic;font-display:swap;font-weight:100 900;src:url(./assets/inter-latin-ext-wght-italic-0pjOp8NU.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:italic;font-display:swap;font-weight:100 900;src:url(./assets/inter-latin-wght-italic-DpCbqKDY.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:"Source Serif 4 Variable";font-style:normal;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-cyrillic-ext-wght-normal-cHuGMAiY.woff2)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:"Source Serif 4 Variable";font-style:normal;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-cyrillic-wght-normal-DwHjdM4S.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:"Source Serif 4 Variable";font-style:normal;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-greek-wght-normal-ece1310W.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:"Source Serif 4 Variable";font-style:normal;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-vietnamese-wght-normal-D-yuW59g.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:"Source Serif 4 Variable";font-style:normal;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-latin-ext-wght-normal-CxNHBx-q.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:"Source Serif 4 Variable";font-style:normal;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-latin-wght-normal-D9elroTD.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:"Source Serif 4 Variable";font-style:italic;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-cyrillic-ext-wght-italic-BXuSHrjR.woff2)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:"Source Serif 4 Variable";font-style:italic;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-cyrillic-wght-italic-RLIThRd4.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:"Source Serif 4 Variable";font-style:italic;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-greek-wght-italic-F2ziEGcb.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:"Source Serif 4 Variable";font-style:italic;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-vietnamese-wght-italic-C3q834ic.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:"Source Serif 4 Variable";font-style:italic;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-latin-ext-wght-italic-CpkvI5hy.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:"Source Serif 4 Variable";font-style:italic;font-display:swap;font-weight:200 900;src:url(./assets/source-serif-4-latin-wght-italic-D2yaqPoE.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Spline Sans Mono Variable;font-style:normal;font-display:swap;font-weight:300 700;src:url(./assets/spline-sans-mono-latin-ext-wght-normal-Dh0aNLWd.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Spline Sans Mono Variable;font-style:normal;font-display:swap;font-weight:300 700;src:url(./assets/spline-sans-mono-latin-wght-normal-DlaB5ohX.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Spline Sans Mono Variable;font-style:italic;font-display:swap;font-weight:300 700;src:url(./assets/spline-sans-mono-latin-ext-wght-italic-RJy045_w.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Spline Sans Mono Variable;font-style:italic;font-display:swap;font-weight:300 700;src:url(./assets/spline-sans-mono-latin-wght-italic-DPjO1keU.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}</style> | |
| <meta name="generator" content="Observable Notebook Kit v2.6.4"><title>BIBFRAME Hubs collocate records across classification</title> <script type="module" crossorigin src="./assets/hub-collocation-CI5CJGX0.js"></script> | |
| <link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-DK3Fl9T5.js"> | |
| <link rel="modulepreload" crossorigin href="./assets/preload-helper-uBIymjUX.js"> | |
| <link rel="modulepreload" crossorigin href="./assets/fileAttachment-e5diAeLP.js"> | |
| </head> | |
| <body> | |
| <main><div id="cell-1" class="observablehq observablehq--cell"><div><h1>Hubs collocate records across classification</h1> | |
| <p>A library shelves each book once, by class. Oliver Sacks’s case studies <em>The man who mistook | |
| his wife for a hat</em> sit in <strong>R</strong> (medicine); Michael Nyman’s chamber opera of the same name sits | |
| in <strong>M</strong> (music), so classification splits them. LC subject headings don’t rejoin them either. | |
| Subject headings group records by what they are <em>about</em>: the book has <em>Neurology — Anecdotes</em>, | |
| the opera <em>Operas — Scores</em> and <em>Visual agnosia — Drama</em>. The one existing link is inside the | |
| opera’s records: an added entry for <em>Sacks, Oliver. Man who mistook his wife for a hat…</em>. It | |
| points one way, appears only in the opera’s records, and doesn’t say how the two are related.</p> | |
| <p>Library of Congress <strong>BIBFRAME Hubs</strong> turn that into a link between the works themselves. A Hub | |
| is the authorized heading for a work (<em>Sacks, Oliver. Man who mistook his wife for a hat</em>) with | |
| a URI, and Hubs carry typed relationships to each other: <em>opera adaptation of</em>, <em>based on</em>, | |
| <em>libretto for</em>. Once bibliographic records are attached to their Hubs, every record of the book | |
| is one typed hop from every record of the opera, whatever shelf or subject headings each has. | |
| Section 2 checks how often subject headings or a record’s own added entries already connect | |
| such pairs.</p> | |
| <p>This page shows that, using <strong>437,836 LC bibliographic records matched to their Hub at high | |
| confidence</strong> (about 96% exactly right in a hand check). The match is the <code>bib_to_hub</code> table in | |
| <a href="https://huggingface.co/datasets/jimfhahn/lc-bibframe-hubs#hubs-collocate-records-across-classification">jimfhahn/lc-bibframe-hubs</a>; | |
| the records come from LC’s experimental embeddings release | |
| (<a href="https://huggingface.co/datasets/jimfhahn/lc-bib-embeddings">jimfhahn/lc-bib-embeddings</a>, 12.2M | |
| records). Everything runs in your browser. To browse any Hub’s whole family, use the | |
| <a href="https://jimfhahn-bibframe-hub-explorer.static.hf.space/">Hub family explorer</a>.</p> | |
| <p>One gap to keep in mind: the source has <strong>no class P (language and literature) and no T | |
| (technology)</strong> yet, because LC’s files for them are not downloadable. P is where most | |
| adaptations start, so every count here is a floor.</p> | |
| </div></div><div id="cell-2" class="observablehq observablehq--cell"></div><div id="cell-3" class="observablehq observablehq--cell"></div><pre data-language="js"><code class="language-js"><span class="tok-comment">// Four small Parquet files (~0.5 MB) written by tools/bib-hub-mapping/build_bib_to_hub.py</span> | |
| <span class="tok-comment">// --collocation. Same loader as the Hub family explorer: a same-origin copy in ./data/</span> | |
| <span class="tok-comment">// first (deploy-space.sh puts it there), then the dataset repo.</span> | |
| <span class="tok-keyword">const</span> <span class="tok-definition">DATASET</span> = <span class="tok-string">"https://huggingface.co/datasets/jimfhahn/lc-bibframe-hubs/resolve/main/collocation/"</span>; | |
| <span class="tok-keyword">const</span> <span class="tok-definition">SOURCES</span> = [<span class="tok-keyword">new</span> <span class="tok-definition">URL</span>(<span class="tok-string">"./data/"</span>, <span class="tok-variable">location</span>.<span class="tok-definition">href</span>).<span class="tok-definition">href</span>, <span class="tok-variable">DATASET</span>]; | |
| <span class="tok-keyword">const</span> <span class="tok-definition">db</span> = <span class="tok-keyword">await</span> <span class="tok-variable">DuckDBClient</span>.<span class="tok-definition">of</span>(); | |
| <span class="tok-keyword">const</span> <span class="tok-definition">isParquet</span> = (<span class="tok-definition">b</span>) => <span class="tok-variable">b</span>.<span class="tok-definition">length</span> > <span class="tok-literal">8</span> && <span class="tok-variable">b</span>[<span class="tok-literal">0</span>] === <span class="tok-literal">0x50</span> && <span class="tok-variable">b</span>[<span class="tok-literal">1</span>] === <span class="tok-literal">0x41</span> && <span class="tok-variable">b</span>[<span class="tok-literal">2</span>] === <span class="tok-literal">0x52</span> && <span class="tok-variable">b</span>[<span class="tok-literal">3</span>] === <span class="tok-literal">0x31</span>; <span class="tok-comment">// "PAR1"</span> | |
| <span class="tok-keyword">async</span> <span class="tok-keyword">function</span> <span class="tok-definition">attach</span>(<span class="tok-definition">name</span>) { | |
| <span class="tok-keyword">const</span> <span class="tok-definition">errors</span> = []; | |
| <span class="tok-keyword">for</span> (<span class="tok-keyword">const</span> <span class="tok-definition">base</span> <span class="tok-keyword">of</span> <span class="tok-variable">SOURCES</span>) { | |
| <span class="tok-keyword">try</span> { | |
| <span class="tok-keyword">const</span> <span class="tok-definition">res</span> = <span class="tok-keyword">await</span> <span class="tok-variable">fetch</span>(<span class="tok-variable">base</span> + <span class="tok-variable">name</span>); | |
| <span class="tok-keyword">if</span> (!<span class="tok-variable">res</span>.<span class="tok-definition">ok</span>) <span class="tok-keyword">throw</span> <span class="tok-keyword">new</span> <span class="tok-definition">Error</span>(<span class="tok-string">`HTTP </span>${<span class="tok-variable">res</span>.<span class="tok-definition">status</span>}<span class="tok-string">`</span>); | |
| <span class="tok-keyword">const</span> <span class="tok-definition">bytes</span> = <span class="tok-keyword">new</span> <span class="tok-definition">Uint8Array</span>(<span class="tok-keyword">await</span> <span class="tok-variable">res</span>.<span class="tok-definition">arrayBuffer</span>()); | |
| <span class="tok-keyword">if</span> (!<span class="tok-variable">isParquet</span>(<span class="tok-variable">bytes</span>)) <span class="tok-keyword">throw</span> <span class="tok-keyword">new</span> <span class="tok-definition">Error</span>(<span class="tok-string">"not a Parquet file"</span>); | |
| <span class="tok-keyword">return</span> <span class="tok-variable">db</span>.<span class="tok-definition">_db</span>.<span class="tok-definition">registerFileBuffer</span>(<span class="tok-variable">name</span>, <span class="tok-variable">bytes</span>); | |
| } <span class="tok-keyword">catch</span> (<span class="tok-definition">e</span>) { | |
| <span class="tok-variable">errors</span>.<span class="tok-definition">push</span>(<span class="tok-string">`</span>${<span class="tok-variable">base</span>}${<span class="tok-variable">name</span>}<span class="tok-string">: </span>${<span class="tok-variable">e</span>.<span class="tok-definition">message</span>}<span class="tok-string">`</span>); | |
| } | |
| } | |
| <span class="tok-keyword">throw</span> <span class="tok-keyword">new</span> <span class="tok-definition">Error</span>(<span class="tok-string">`Could not load </span>${<span class="tok-variable">name</span>}<span class="tok-string">:</span><span class="tok-literal">\n</span>${<span class="tok-variable">errors</span>.<span class="tok-definition">join</span>(<span class="tok-string">"</span><span class="tok-literal">\n</span><span class="tok-string">"</span>)}<span class="tok-string">`</span>); | |
| } | |
| <span class="tok-keyword">const</span> <span class="tok-definition">FILES</span> = {<span class="tok-definition">hub_class</span>: <span class="tok-string">"colloc_hub_class.parquet"</span>, <span class="tok-definition">edges</span>: <span class="tok-string">"colloc_edges.parquet"</span>, | |
| <span class="tok-definition">records</span>: <span class="tok-string">"colloc_records.parquet"</span>, <span class="tok-definition">coverage</span>: <span class="tok-string">"colloc_coverage.parquet"</span>}; | |
| <span class="tok-keyword">await</span> <span class="tok-variable">Promise</span>.<span class="tok-definition">all</span>(<span class="tok-variable">Object</span>.<span class="tok-definition">values</span>(<span class="tok-variable">FILES</span>).<span class="tok-definition">map</span>(<span class="tok-variable">attach</span>)); | |
| <span class="tok-keyword">for</span> (<span class="tok-keyword">const</span> [<span class="tok-definition">table</span>, <span class="tok-definition">file</span>] <span class="tok-keyword">of</span> <span class="tok-variable">Object</span>.<span class="tok-definition">entries</span>(<span class="tok-variable">FILES</span>)) { | |
| <span class="tok-keyword">await</span> <span class="tok-variable">db</span>.<span class="tok-definition">query</span>(<span class="tok-string">`CREATE TABLE </span>${<span class="tok-variable">table</span>}<span class="tok-string"> AS SELECT * FROM read_parquet('</span>${<span class="tok-variable">file</span>}<span class="tok-string">')`</span>); | |
| }</code></pre><div id="cell-4" class="observablehq observablehq--cell"></div><div id="cell-5" class="observablehq observablehq--cell"></div><div id="cell-6" class="observablehq observablehq--cell"><div><h2 id="-1-one-work-two-shelves" tabindex="-1"><a href="#-1-one-work-two-shelves">1. One work, two shelves</a></h2> | |
| <p>Pick a pair of works joined by a creative relationship. Each side lists the LC records matched | |
| to that work’s Hub, grouped by the class they are shelved in. Titles link to LC’s BIBFRAME | |
| description of the record; the work names open the Hub in the family explorer.</p> | |
| </div></div><div id="cell-7" class="observablehq observablehq--cell"></div><pre data-language="js"><code class="language-js"><span class="tok-keyword">const</span> <span class="tok-definition">SACKS</span> = <span class="tok-string">"a9402977-4b49-89c3-e703-6f4e0c969790"</span>; | |
| <span class="tok-keyword">const</span> <span class="tok-definition">pair</span> = <span class="tok-variable">view</span>(<span class="tok-variable">Inputs</span>.<span class="tok-definition">select</span>(<span class="tok-variable">crossPairs</span>, { | |
| <span class="tok-definition">label</span>: <span class="tok-string">"Pair"</span>, | |
| <span class="tok-definition">value</span>: <span class="tok-variable">crossPairs</span>.<span class="tok-definition">find</span>((<span class="tok-definition">p</span>) => <span class="tok-variable">p</span>.<span class="tok-definition">a</span> === <span class="tok-variable">SACKS</span> || <span class="tok-variable">p</span>.<span class="tok-definition">b</span> === <span class="tok-variable">SACKS</span>), | |
| <span class="tok-definition">format</span>: (<span class="tok-definition">p</span>) => <span class="tok-string">`</span>${<span class="tok-variable">trunc</span>(<span class="tok-variable">shortHub</span>(<span class="tok-variable">p</span>.<span class="tok-definition">from</span>), <span class="tok-literal">45</span>)}<span class="tok-string"> → </span>${<span class="tok-variable">p</span>.<span class="tok-definition">relText</span>}<span class="tok-string"> → </span>${<span class="tok-variable">trunc</span>(<span class="tok-variable">shortHub</span>(<span class="tok-variable">p</span>.<span class="tok-definition">to</span>), <span class="tok-literal">45</span>)}<span class="tok-string">`</span> | |
| }));</code></pre><div id="cell-8" class="observablehq observablehq--cell"></div><div id="cell-9" class="observablehq observablehq--cell"><div><h2 id="-2-every-creative-link-that-crosses-shelves" tabindex="-1"><a href="#-2-every-creative-link-that-crosses-shelves">2. Every creative link that crosses shelves</a></h2> | |
| <p>Each row is a pair of works joined by a creative relationship (adaptation, libretto, musical | |
| setting, based on…) where both works have matched LC records and the records sit in different | |
| classes. Dots show where each work’s records are shelved; the grey line is the distance the Hub | |
| relationship bridges. Columns P and T are empty because the source has no records there; the | |
| novels and plays that do appear sit in <strong>A</strong> because LC classes collected sets such as <em>Great | |
| Books of the Western World</em> (<code>AC1 .G72</code>) and some translation series there.</p> | |
| </div></div><div id="cell-10" class="observablehq observablehq--cell"></div><div id="cell-11" class="observablehq observablehq--cell"></div><div id="cell-21" class="observablehq observablehq--cell"><div><p><strong>Don’t subject headings already do this?</strong> Sometimes. We checked these 40 pairs against LC’s | |
| MARC records (up to five per side, October 2026). The two sides share an identical LCSH heading | |
| in only 3 pairs (<em>Faust, -approximately 1540 — Drama</em>; <em>Othello (Fictitious character from Shakespeare) — Drama</em>; <em>Operas — Librettos</em>). They share a main heading in 14, mostly a person or character both | |
| works are about (Alexander Hamilton, Benvenuto Cellini, Athaliah, Mongkut) or a broad form | |
| (<em>Operas</em>; <em>Hymns, English</em>). Subject headings collocate by topic, which complements Hubs, but | |
| they rarely record that one work adapts another.</p> | |
| <p>The closer equivalent is in the records themselves. In 28 pairs, a record on one side names the | |
| other work in a name/title entry (600/700/730), sometimes with a relationship designator | |
| (Ellington’s <em>Beautiful Indians</em>: <em>Inspired by (work): Longfellow, Henry Wadsworth. Song of | |
| Hiawatha</em>). That link is one-way and attached to that record only. The Hub relationship joins | |
| every record on both sides. In the other 12 pairs no record names the other work, so the Hub | |
| is the only link between them, apart from four that share a main heading (<em>Cellini, Benvenuto</em> twice; <em>Operas</em>; | |
| <em>Hymns, English</em>). Most are 19th-century stage works: Scribe and Boieldieu’s <em>La dame blanche</em> after | |
| Scott’s <em>Monastery</em> and <em>Abbot</em>, Gevaert’s <em>Quentin Durward</em>, Bishop’s <em>Heart of Mid-Lothian</em>, | |
| Solomon’s <em>Pickwick</em>, Lassen’s <em>Faust</em> music. Script: | |
| <a href="https://github.com/jimfhahn/vufind-bf-hubs-plugin/tree/main/tools/bib-hub-mapping"><code>tools/bib-hub-mapping/lcsh_overlap.py</code></a>.</p> | |
| </div></div><div id="cell-12" class="observablehq observablehq--cell"><div><h2 id="-3-one-work-many-shelves" tabindex="-1"><a href="#-3-one-work-many-shelves">3. One work, many shelves</a></h2> | |
| <p>Collocation also happens on a single Hub: one work whose editions LC classed under different | |
| subjects. The U.S. Constitution sits in general works, American history, political science and | |
| law; Machiavelli’s <em>Prince</em>, Franklin’s <em>Autobiography</em> and Hobbes’s <em>Leviathan</em> each span three | |
| classes. Collective titles (<em>Works. Selections</em>, <em>Essays</em>) gather different books by one author | |
| rather than one work, so they are hidden by default. Many of these Hubs (<em>Prince</em>, | |
| <em>Autobiography</em>) have no links to other Hubs, so their table link goes to <code>id.loc.gov</code> | |
| rather than the family explorer.</p> | |
| </div></div><div id="cell-13" class="observablehq observablehq--cell"></div><pre data-language="js"><code class="language-js"><span class="tok-keyword">const</span> <span class="tok-definition">hideCollective</span> = <span class="tok-variable">view</span>(<span class="tok-variable">Inputs</span>.<span class="tok-definition">toggle</span>({<span class="tok-definition">label</span>: <span class="tok-string">"Hide collective titles"</span>, <span class="tok-definition">value</span>: <span class="tok-literal">true</span>}));</code></pre><div id="cell-14" class="observablehq observablehq--cell"></div><pre data-language="js"><code class="language-js"><span class="tok-keyword">const</span> <span class="tok-definition">topN</span> = <span class="tok-variable">view</span>(<span class="tok-variable">Inputs</span>.<span class="tok-definition">range</span>([<span class="tok-literal">10</span>, <span class="tok-literal">60</span>], {<span class="tok-definition">label</span>: <span class="tok-string">"Works shown"</span>, <span class="tok-definition">step</span>: <span class="tok-literal">5</span>, <span class="tok-definition">value</span>: <span class="tok-literal">25</span>}));</code></pre><div id="cell-15" class="observablehq observablehq--cell"></div><div id="cell-16" class="observablehq observablehq--cell"></div><div id="cell-17" class="observablehq observablehq--cell"><div><h2 id="-4-how-much-of-the-catalogue-this-reaches" tabindex="-1"><a href="#-4-how-much-of-the-catalogue-this-reaches">4. How much of the catalogue this reaches</a></h2> | |
| <p>Share of each class’s records matched to a Hub. Music leads because composers’ works are | |
| almost always under uniform titles; most other classes sit at 2–5%. A record can only be | |
| matched where LC made a name/title authority for its work.</p> | |
| </div></div><div id="cell-18" class="observablehq observablehq--cell"></div><div id="cell-19" class="observablehq observablehq--cell"><div><h2 id="-5-how-far-to-trust-it" tabindex="-1"><a href="#-5-how-far-to-trust-it">5. How far to trust it</a></h2> | |
| <p>Records were matched offline: each record’s first creator and title (normalized, subtitle | |
| dropped) against each Hub’s authorized access point, then against the Hub’s variant titles, | |
| which catches translations (<em>Studies on the development of consciousness</em> → Chesni, | |
| <em>Recherches sur le développement de la conscience</em>). A stratified sample of 300 matches was | |
| checked against LC’s own BIBFRAME Work links and, where LC links none, by hand.</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>confidence</th> | |
| <th>records</th> | |
| <th>exactly the right Hub</th> | |
| <th>right work</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>high (used on this page)</td> | |
| <td>437,836</td> | |
| <td><strong>96.5%</strong> (95% CI 93–98%)</td> | |
| <td>99%</td> | |
| </tr> | |
| <tr> | |
| <td>medium: several Hubs tie</td> | |
| <td>30,425</td> | |
| <td>66%</td> | |
| <td>78%</td> | |
| </tr> | |
| <tr> | |
| <td>low: title-only or name-only matches</td> | |
| <td>25,070</td> | |
| <td>66%</td> | |
| <td>72%</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p>Two error patterns are labelled down rather than counted: titles that are just the creator’s | |
| name (exhibition catalogues called <em>Picasso</em> gathered on one <code>Picasso, Pablo. Picasso</code> Hub), | |
| and series whose volumes share a main title (<em>Chicken soup for the soul : …</em>), which show up | |
| as one Hub spread over many classes with a different subtitle on almost every record. Method, | |
| columns and every hand-checked row are on the | |
| <a href="https://huggingface.co/datasets/jimfhahn/lc-bibframe-hubs#bib_to_hubparquet-details">dataset card</a>.</p> | |
| </div></div><div id="cell-20" class="observablehq observablehq--cell"><div><hr> | |
| <h2 id="about" tabindex="-1"><a href="#about">About</a></h2> | |
| <p><strong>Data.</strong> Library of Congress BIBFRAME Hubs bulk dump (2026-05-05) and LC’s experimental | |
| bibliographic embeddings (2025), both in the public domain, repackaged as Parquet: | |
| <a href="https://huggingface.co/datasets/jimfhahn/lc-bibframe-hubs">lc-bibframe-hubs</a> (including | |
| <code>bib_to_hub</code> and the four small <code>collocation/</code> files this page loads) and | |
| <a href="https://huggingface.co/datasets/jimfhahn/lc-bib-embeddings">lc-bib-embeddings</a>. | |
| “Creative relationship” means the surprise tiers 1–3 used by the companion VuFind plugin: | |
| transformations and parodies, cross-medium adaptations, sequels and <em>based on</em>.</p> | |
| <p><strong>Code.</strong> <a href="https://github.com/jimfhahn/vufind-bf-hubs-plugin/tree/main/tools/bib-hub-mapping"><code>tools/bib-hub-mapping/</code></a> | |
| builds the match and these files; this page is | |
| <a href="https://github.com/jimfhahn/vufind-bf-hubs-plugin/tree/main/notebooks"><code>notebooks/hub-collocation.html</code></a> | |
| (<a href="https://observablehq.github.io/notebook-kit/">Observable Notebook Kit</a>). Tables loaded in | |
| the browser: <code>hub_class(hub_id, label, hub_name, hub_title, lcc_class, n, hub_total, hub_classes, hub_links)</code>, | |
| <code>edges(source_id, target_id, rel_type)</code>, <code>records(lc_001, hub_id, lcc_class, title, creator)</code>, | |
| <code>coverage(lcc_class, records, high, medium, low)</code>.</p> | |
| </div></div></main> | |
| <style type="text/css">:root{--syntax-link:var(--theme-foreground-focus);--syntax-keyword:#e36209;--syntax-atom:#032f62;--syntax-literal:#6f42c1;--syntax-string:#22863a;--syntax-comment:var(--theme-foreground-muted);--syntax-invalid:var(--theme-error);--syntax-definition:#005cc5;--syntax-variable:var(--theme-foreground-alt);--syntax-meta:#d73a49;--theme-background-b:color-mix(in srgb, var(--theme-foreground) 4%, var(--theme-background-a));--theme-background:var(--theme-background-a);--theme-background-alt:var(--theme-background-b);--theme-foreground-alt:color-mix(in srgb, var(--theme-foreground) 90%, var(--theme-background-a));--theme-foreground-muted:color-mix(in srgb, var(--theme-foreground) 60%, var(--theme-background-a));--theme-foreground-faint:color-mix(in srgb, var(--theme-foreground) 50%, var(--theme-background-a));--theme-foreground-fainter:color-mix(in srgb, var(--theme-foreground) 30%, var(--theme-background-a));--theme-foreground-faintest:color-mix(in srgb, var(--theme-foreground) 14%, var(--theme-background-a));--theme-error:#e7040f;--lightningcss-light:initial;--lightningcss-dark: ;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--theme-foreground:#1b1e23;--theme-foreground-focus:#3b5fc0;--theme-background-a:#fff}</style></body></html> |