- Para explorar, em uma única tela, os dados de mais de 100 milhões de livros tratados pelo Anna’s Archive, foi necessário adotar uma abordagem que transformasse o espaço limitado de identificadores do ISBN em um mapa
- O ISBN13, excluindo os prefixos
978-/979-e o dígito verificador final, forma um espaço unidimensional de cerca de 2 bilhões de slots, e faixas de países e editoras são atribuídas por unidade de prefixo - Como um layout simples por linhas ou uma Hilbert curve pode dificultar a visualização da estrutura do ISBN, foi usada a Bookshelf-Curve, que transfere os dígitos decimais para coordenadas 2D
- Os tiles do mapa são fornecidos como arquivos estáticos PNG e JSON, e shaders WebGL/GLSL processam instantaneamente renderização e filtragem como ano de publicação, taxa de acervo, comparação entre datasets e destaque de editoras
- A implementação foi feita como um frontend estático baseado em ThreeJS, React, MobX e react-threejs-fiber, e a otimização de desempenho para renderização de muito texto e navegação com zoom é o que determina a usabilidade real
Por que usar o espaço ISBN como alvo de visualização
- Bibliotecas vêm reunindo o conhecimento da humanidade há muito tempo, e na era digital pode se tornar possível coletar de forma abrangente obras que atendam a certos critérios
- O Anna’s Archive, uma das shadow libraries, precisava de uma visualização que permitisse explorar mais de 100 milhões de livros de uma vez
- Os dados incluem título, autor, país, editora, período de publicação, número de bibliotecas que possuem o livro e disponibilidade digital
- A visualização interativa oferece seleção de dataset, busca de livros individuais, filtro por ano de publicação e visualizações compostas baseadas em shaders personalizados
- No nível máximo de zoom, a representação muda para algo que faz cada livro parecer encaixado em uma estante
A estrutura do ISBN
- ISBN13 é um número de 13 dígitos atribuído a quase todos os livros publicados
- Atualmente, os três primeiros dígitos do ISBN13 são fixos como
978-ou979-, e o último dígito é um checksum - Portanto, o espaço real do ISBN13 pode ser visto como cerca de 2 bilhões de slots
- Os prefixos
978-e979-existem porque o ISBN13 é um subconjunto do European Article Number, e esse prefixo fixo é chamado de Bookland - Grandes blocos de ISBN são atribuídos pela International ISBN Agency a organizações internacionais, e cada país subdivide seu bloco por editora
- Blocos de ISBN são sempre atribuídos por unidade de prefixo
978-4é atribuído ao Japão- O Japão atribui
978-4-312a uma editora - Essa editora pode atribuir itens na faixa
000000-99999, criando ISBNs como978-4-312-99999-X
- Quanto mais longo o prefixo do país, menor o número de livros que pode ser atribuído dentro dele
- O Japão tem um espaço de 100 milhões de ISBNs
- Singapura começa com o prefixo
978-9971-e só pode ter 100 mil ISBNs
Como expandir um ISBN unidimensional em 2D
- Removendo os prefixos
978-/979-e o checksum, o ISBN se torna um valor unidimensional decimal entre 0 e 2 bilhões - A forma mais simples seria preencher pixels em linhas de cima para baixo, mas isso faz pequenas regiões se alongarem horizontalmente e dificulta enxergar a estrutura do ISBN
- A Hilbert curve deixa pequenas regiões mais próximas de quadrados, mas pode introduzir artefatos de estrutura espacial que não existem nos dados
- Para evitar estruturas inexistentes nos dados, esta visualização usa a Bookshelf-Curve, aproveitando a natureza decimal do ISBN
Bookshelf-Curve
- A Bookshelf-Curve coloca
0-9do primeiro dígito decimal lado a lado, e distribui0-9do próximo dígito para cima e para baixo, repetindo isso recursivamente - Para manter a proporção dos retângulos em dois níveis, a razão de aspecto de cada bloco é
√10, ou cerca de 3,16:1 - Essa estrutura é semelhante ao conceito de proporção recursiva de uma folha A4, mas em vez de dividir em dois, divide em 10 segmentos
- A conversão de coordenadas é simples, pois usa alternadamente os dígitos do ISBN como coordenadas
- O código de implementação ficou com 50 linhas por causa de uma tentativa de generalização, mas o princípio é fácil de entender a ponto de ser possível localizar manualmente a posição de um ISBN específico
Tiles do mapa e codificação dos dados
- São geradas imagens de tile para cada prefixo ISBN
- O tamanho-alvo de cada tile era cerca de
100kB, e o resultado foi um tile de2000 × 633pixels - As informações armazenadas em cada pixel variam conforme o dataset
- No dataset de ano de publicação, é armazenado em 8 bits o valor com
1800subtraído - O canal vermelho guarda o ano médio de publicação dos livros naquele pixel
- O canal azul guarda a proporção de livros existentes
- Por exemplo, se 50% dos livros existem, o valor do canal azul será
127/255
- No dataset de ano de publicação, é armazenado em 8 bits o valor com
- No nível máximo de zoom, para precisão, 1 livro é mapeado para 1 pixel
Renderização baseada em shaders GLSL
- No início, os dados RGB eram armazenados diretamente nos tiles, mas para ganhar flexibilidade passaram a armazenar dados mais abstratos, enquanto a renderização real é feita no fragment shader GLSL da GPU
- Essa abordagem permite escolher a paleta de cores depois, aplicar transformações e filtros arbitrários instantaneamente ou combinar vários datasets em tempo real
- Os dados de ano de publicação armazenam a faixa
1800-2055, mas como 95% dos dados estão entre1985-2024, o shader pode comprimir a visualização para esse intervalo - A função
heatmapColor(float)converte um valor0-1para a escala de cores escolhida pelo usuário - A sintaxe
$dataset_xnão é sintaxe nativa do GLSL, mas uma sintaxe simples de template baseada em regex para carregar apenas as imagens que o shader realmente lê - Na opção ⚙️ Advanced da visualização, é possível editar diretamente o shader, e o resultado das mudanças aparece em tempo real
- O significado de cada pixel de dataset está documentado no README
Fazer o zoom parecer uma estante de livros
- Na visualização totalmente ampliada, cada pixel recebe um estilo que o faz parecer um livro
- Cada livro recebe largura, altura e padrão aleatórios
- Não corresponde exatamente ao formato real de um livro, mas faz a cena no zoom máximo parecer mais viva
- Todo esse estilo é implementado no shader
- Como era necessário obter o mesmo resultado de geração aleatória em GLSL e JavaScript, a parte de calcular a altura do livro e alinhar os limites do texto foi complicada
- Passando o valor atual de zoom como uniform e aplicando um fade entre dois níveis de zoom, é possível introduzir suavemente o estilo de estante
Texto, estrutura em árvore e desempenho
- Assim como os tiles de imagem, o texto também é renderizado em estrutura hierárquica de acordo com o nível de zoom e o view frustum culling
- A implementação usa react-threejs-fiber
- O React adiciona elementos da cena recursivamente enquanto a visualização se move, compondo Plane, texto HTML e nós filhos de prefixo para cada prefixo
- No início, houve grandes problemas de desempenho ao renderizar muito texto
- A melhor abordagem foi colocar HTML dentro de
<foreignObject />em SVG, renderizar isso em canvas comdrawImagee então carregar como textura - Essa abordagem funcionou, mas criava uma latência de 20ms de forma síncrona em cada renderização
- Como não era possível desenhar SVG em um WebWorker, foi difícil mover isso para um WebWorker
- A maior parte dos problemas reais de desempenho foi resolvida reduzindo o número de elementos HTML, limitando o conteúdo DOM adicionado por frame e, principalmente, removendo a pilha de filtros CSS
text-shadow
Códigos de barras e faixas de editoras
- No zoom máximo, cada livro exibe um código de barras
- O código de barras foi adicionado para reforçar a ideia de que os livros estão ordenados por ISBN
- Em vez de usar uma biblioteca de renderização de código de barras, foi usada a fonte TTF Libre Barcode, que renderiza números de 13 dígitos como código de barras e até calcula o dígito verificador
- Graças às otimizações de renderização de texto do sistema operacional, essa abordagem foi prática e teve bom desempenho
- Cada grupo normalmente representa uma grande faixa por país, e as editoras ocupam faixas menores dentro dela
- Cada grupo e cada editora recebem uma cor aleatória única
- Mesmo quando uma editora possui várias faixas, a mesma cor é usada
- Para destacar simultaneamente todas as faixas, foi atribuído um ID único a cada editora e ele foi armazenado como componentes RGB
- Ainda há pontos insatisfatórios nas cores das editoras
- As cores das editoras entram em conflito com a escala de cores do heatmap
- As faixas de países são difíceis de visualizar
Navegação de busca e trajetória de voo
- Ao buscar um livro ou clicar no minimapa, a interface faz um voo até aquela posição
- Calcular uma trajetória de voo visualmente agradável foi mais difícil do que parecia
- Com ajuste parabólico, o resultado foi apenas mediano, e depois foi tentada uma abordagem usando um espaço de transformação separado
- O resultado final não é perfeito e parece um tanto excessivamente projetado, com cerca de 500 linhas de código, mas funciona melhor do que a abordagem original
Arquitetura e pipeline de processamento
- Não é necessário backend
- Os tiles de imagem são salvos como PNG
- A árvore de dados é salva como JSON
- Basta publicar HTML, JS, CSS, PNG e JSON em um host de arquivos estáticos como o GitHub Pages
- O frontend usa ThreeJS, React e MobX
- Essa combinação foi conveniente para criar cenas 2D/3D reativas, declarativas e aceleradas por GPU com componentes reutilizáveis
- Os scripts de processamento foram escritos majoritariamente em JS e geram JSON e PNG diretamente
- Alguns scripts precisaram ler arquivos-fonte de 250GB e exportar para SQLite, então foram escritos em Rust
Resultado e código
- O resultado é uma forma flexível de visualizar livros publicados aos quais foi atribuído ISBN
- Este projeto só foi possível porque o ISBN foi projetado com um espaço de identificadores pequeno, mas ainda suficiente
- Se o mesmo trabalho fosse feito com UUID, a maior parte seria um enorme espaço vazio
- O código-fonte está disponível em isbn-visualization
1 comentários
Opiniões no Hacker News
Quando começamos a Amazon, eu queria fazer exatamente algo assim, mas usando a classificação tripla da Library of Congress em vez de ISBN
No fim, os fornecedores de dados, Baker & Taylor e Books In Print, achatavam a classificação tripla em uma única string, então não era possível encontrar os limites de forma estável, e tivemos de desistir antes mesmo de começar direito
Implementar esse tipo de navegação em “voo” na web de 1994–1995 certamente também não teria sido fácil, então é um trabalho incrível
Já examinei bastante a LoC Classification e os LoC Subject Headings, e é uma pena que nenhum dos dois seja oferecido livremente em um formato útil para leitura por máquina. Com PDFs dá para fazer alguns malabarismos
Em especial, a seção de direito estadual da Classification tinha uma densidade de classificação muito desigual entre os estados; pelo que me lembro, NY e CA eram de longe os mais complexos, PA vinha em um terceiro lugar um pouco atrás, e muitos estados “flyover” eram quase ridiculamente simples e parecidos entre si. Isso parece refletir a complexidade das leis codificadas, regulações e jurisprudência de cada estado
Outro fato histórico interessante é que o sistema de classificação e as divisões de nível superior em ordem alfabética parecem vir diretamente da biblioteca pessoal de Thomas Jefferson, que deu origem à LoC
Se tiver interesse, nos relatórios anuais enviados ao Congresso pelo Librarian of Congress disponíveis no Hathi Trust dá para ver bastante sobre a história do desenvolvimento e da expansão da Classification
Classification: <https://www.loc.gov/catdir/cpso/lcco/>
Subject headings: <https://id.loc.gov/authorities/subjects.html>
Annual reports — Recentes: <https://www.loc.gov/about/reports-and-budgets/annual-reports...> / Arquivo histórico até cerca de 1866: <https://catalog.hathitrust.org/Record/000072049>
Foi uma das empresas mais atrasadas tecnologicamente com que já negociei, e até o início de 2020, quando encerramos a conta, eles ainda processavam pedidos de compra e conciliações em papel, PDF e e-mail. Acho que em algum momento até nos fizeram enviar documentos por fax
Como não é raro ISBNs serem atribuídos em duplicidade a livros diferentes [0], a expressão “todos os livros no espaço de ISBN” pode ser um exagero
Também há livros com ISBNs inválidos, cujo dígito verificador não bate com o restante do ISBN. Se, ao corrigir o dígito verificador, ele passar a coincidir com outro livro, então esse livro fica fora do espaço de ISBN assumido pelo post do blog
[0] https://scis.edublogs.org/2017/09/28/the-dreaded-case-of-dup...
Eu estava olhando os menores ISBNs conhecidos de editoras tchecas e apareceu uma cor diferente; https://books.google.cz/books?vid=ISBN9788000000015&redir_es... não parece ser um ISBN válido :-) Mas não sei se esse livro contém um ISBN falso tão descarado ou se é um erro nos dados do Google Books
É uma apresentação impressionante
Mas esta tela não reflete o catálogo completo de ISBNs, e sim apenas o acervo do Anna's Archive. Por causa do viés da coleta da Anna, há um viés visível para certas faixas de idioma, e as áreas em preto são itens que não estão no arquivo
O banco de metadados vem de várias fontes e, até onde sei, é bastante completo. O preto provavelmente representa, em sua maior parte, áreas sem livros atribuídos
É realmente muito legal, um projeto de paixão surpreendente e um excelente recurso
Ao dar zoom, dá para ver títulos e códigos de barras; ao passar o mouse, aparecem capas e detalhes. Tem quase tudo que se poderia desejar
Como ideia de melhoria, seria bom ter uma caixa de seleção para ocultar o painel branco flutuante no canto superior esquerdo e os elementos no canto superior direito. Gosto de “mergulhar” nesse tipo de visualização, e esses elementos flutuantes me tiram um pouco dessa experiência, reduzindo um pouco a diversão e a funcionalidade
Este é um caso perfeito para o Microsoft Silverlight PivotViewer, uma excelente interface web usada em neuroimagem antes de a Microsoft descontinuá-la
Há uma apresentação TED impressionante em que Gary W. Flake mostra como usá-la
https://m.youtube.com/watch?v=LT_x9s67yWA
Também há um artigo da IEEE de 2011. É uma pena que isso não seja um padrão da web
https://www.dropbox.com/scl/fi/bl8zkjs3y47q3377hh3ya/Yan_Wil...
Uma visualização muito legal
Há outras submissões ainda mais interessantes aqui: https://software.annas-archive.li/AnnaArchivist/annas-archiv...
Meu trabalho está em https://isbnviz.pages.dev
Ao ampliar, parece uma estante. Muito legal mesmo
Excelente. Parece uma Library of Babel da vida real: https://libraryofbabel.info/
Entre todo tipo de besteira em VR, acho que eu até pagaria por uma biblioteca infinita ou um museu infinito do mundo real
Teria sido muito mais interessante se fosse um projeto que desse acesso a todos os textos para download disponibilizados legalmente. Por exemplo, como uma interface para um lugar assim:
https://onlinebooks.library.upenn.edu/
A apresentação no formato atual pareceu um pouco esmagadora
Levei um tempo para entender que a área de presets no canto superior esquerdo na verdade leva a eixos adicionais de visualização de dados, como incluir ou não AA, raridade e incluir ou não Google Books. Ainda assim, a visualização e a profundidade dos dados são ricas
Também gostei de https://archive.anarchy.cool/blog/all-isbns.html#visualizing, que mostra a aparência dos clusters regionais
O preset por ano, por si só, também foi interessante para ver a atividade editorial por região. A Poland está muito ativa recentemente, enquanto a Norway parece relativamente tranquila. A China parece ter começado a crescer por volta de 2005 e ficado enorme nos últimos 10 anos
Há algo estranho também nos United States. Nunca ouvi falar delas, mas Blackstone Audio, Blurb Inc. e Draft2Digital emitiram uma quantidade enorme de ISBNs
Uma visualização um pouco mais minimalista (menos cores e apenas um nível de texto exibido ao mesmo tempo) está aqui:
https://phiresky.github.io/isbn-visualization/?dataset=all&g...
Acho que também daria para ajustar mais, por exemplo ocultando alguns textos, como a parte de N publishers, ou reduzindo as informações no mouseover
A trajetória de voo pode ser pensada de forma bastante razoável se modelada como movimento no semiplano superior hiperbólico. Basta tomar x como a posição no caminho linear entre os pontos finais, e y como o comprimento de um lado do viewport
Pensei em duas métricas que acabam ficando iguais. Primeiro, supondo um mapa hierárquico de tiles e minimizando o número de tiles carregados. Usando y como o comprimento de um lado do viewport, o custo de se mover horizontalmente em x é x/y tiles, e ao dar zoom de y_0 para y_1 você carrega abs(log_2(y_1/y_0)) tiles, o que coincide com ds = dy/y. Combinando, temos ds^2 = (dx^2 + dy^2)/y^2, exatamente a métrica do semiplano superior
Outra forma é ver isso como a minimização, em algum sentido, do “fluxo óptico” do viewport. Isso também leva à mesma métrica, mudando apenas a escala. Se você faz pan em x sem zoom, tudo se move x/y, isto é, uma fração relativa ao viewport. Se amplia por um fator k, um pixel em (u,v) vai para (ku,kv), então o deslocamento é (u,v)(k-1). Quando o comprimento de um lado passa de y para y+dy, isso vira (u,v)dy/y, portanto, dependendo de como se calcula a média dos deslocamentos, resulta em algum múltiplo constante de dy/y
Então a geodésica desejada é um horociclo, um círculo centrado em y=0, mas é preciso um pouco de trabalho para calcular o movimento ao longo da curva. Se pegarmos um arco de θ_0 a θ_1, o tempo total vem da integral de dtheta/y = dθ/sin(θ), então, para ser exato, seria preciso inverter t = ln(csc(θ)-cot(θ)). Achei que seria melhor aproximar, mas o Mathematica informou que θ = atan2(1-2e^(2t), 2e^t), então não é tão ruim
Comparando com a lógica de “blub space”, a métrica efetiva ali parece ser ds^2 = dz^2 + (z+1)^2 dx^2. É uma coordenada polar com z=1/y como nível de zoom, e usando dz=dy/y^2 temos ds^2 = dy^2/y^4 + dx^2*(1/y^2 + ...). Ou seja, a implementação existente parece gastar muito mais tempo fazendo pan em níveis altos de zoom do que o modelo hiperbólico. Isso porque o custo de reduzir de 4x para 2x é o dobro do de reduzir de 2x para 1x, embora visualmente seja o mesmo
O zoom deles não é um fator de escala, mas corresponde ao meu “y”, então a métrica é ds^2 = dy^2 + (C-y)^2 dx^2. Aqui, C é um pouco maior que o nível máximo de zoom. Também há tratamento especial para quando essa curva tenta dar ainda mais zoom out
Normalizando para que o custo de fazer pan até o fim no estado totalmente afastado (zoom=1) seja igual, em um nível de zoom muito profundo o custo de pan fica quase plano, enquanto em um nível relativamente menos ampliado o custo é maior que no modelo hiperbólico. Por isso, em distâncias curtas, o viewport parece se mover muito rápido, e em distâncias longas ele parece dar zoom out quase até o fim. Como o nível intermediário de zoom é desfavorável, acaba sendo melhor ir quase até o final