Trực quan hóa mọi cuốn sách trên thế giới trong không gian ISBN
(phiresky.github.io)- Để khám phá dữ liệu của hơn 100 triệu cuốn sách mà Anna’s Archive xử lý trên một màn hình, cần một cách tiếp cận biến không gian định danh hữu hạn là ISBN thành bản đồ
- ISBN13, nếu bỏ tiền tố
978-/979-và chữ số kiểm tra cuối cùng, là một không gian 1 chiều khoảng 2 tỷ ô, trong đó các dải quốc gia và nhà xuất bản được cấp phát theo từng tiền tố - Cách bố trí theo hàng đơn giản hoặc Hilbert curve có thể làm khó quan sát cấu trúc ISBN, nên dự án dùng Bookshelf-Curve để chuyển các chữ số thập phân thành tọa độ 2D
- Các tile bản đồ được cung cấp dưới dạng tệp tĩnh PNG và JSON, còn shader WebGL/GLSL xử lý ngay lập tức rendering và filtering như năm xuất bản, tỷ lệ sở hữu, so sánh tập dữ liệu và nhấn mạnh nhà xuất bản
- Hệ thống được triển khai như một frontend tĩnh dựa trên ThreeJS, React, MobX và react-threejs-fiber, trong đó việc tối ưu hiệu năng render lượng lớn văn bản và thao tác zoom/pan quyết định tính hữu dụng thực tế
Vì sao chọn không gian ISBN làm đối tượng trực quan hóa
- Thư viện từ lâu đã thu thập tri thức của nhân loại, và trong thời đại số, việc thu thập toàn diện các tác phẩm đáp ứng những tiêu chí nhất định có thể trở nên khả thi
- Anna’s Archive, một shadow library, cần một dạng trực quan hóa cho phép khám phá hơn 100 triệu cuốn sách cùng lúc
- Dữ liệu mục tiêu bao gồm tiêu đề, tác giả, quốc gia, nhà xuất bản, thời điểm phát hành, số thư viện đang lưu giữ, và khả năng truy cập bản số
- Trực quan hóa tương tác hỗ trợ chọn tập dữ liệu, tìm kiếm từng cuốn sách, lọc theo năm xuất bản, và trực quan hóa kết hợp dựa trên shader tùy biến
- Khi phóng to tối đa, cách hiển thị chuyển sang dạng các cuốn sách được cắm trên giá sách
Cấu trúc của ISBN
- ISBN13 là mã số 13 chữ số được gán cho gần như mọi đầu sách xuất bản
- Hiện tại, ba chữ số đầu của ISBN13 được cố định là
978-hoặc979-, còn chữ số cuối là checksum - Vì vậy, không gian ISBN13 thực tế có thể xem như khoảng 2 tỷ ô
- Các tiền tố
978-và979-tồn tại vì ISBN13 là tập con của European Article Number, và các tiền tố cố định này được gọi là Bookland - Các khối ISBN lớn được International ISBN Agency cấp cho các tổ chức quốc tế, sau đó từng quốc gia chia tiếp khối của mình theo nhà xuất bản
- Các khối ISBN luôn được cấp theo đơn vị tiền tố (prefix)
978-4được cấp cho Nhật Bản- Nhật Bản cấp
978-4-312cho một nhà xuất bản - Nhà xuất bản đó có thể cấp các mục trong phạm vi
000000-99999để tạo ISBN như978-4-312-99999-X
- Tiền tố quốc gia càng dài thì số lượng sách có thể cấp trong đó càng ít
- Nhật Bản có không gian 100 triệu ISBN
- Singapore bắt đầu bằng tiền tố
978-9971-, nên chỉ có thể có 100 nghìn ISBN
Cách trải ISBN 1 chiều thành 2 chiều
- Khi bỏ tiền tố
978-/979-và checksum, ISBN trở thành một giá trị thập phân 1 chiều từ 0 đến 2 tỷ - Cách đơn giản nhất là điền pixel theo từng hàng từ trên xuống, nhưng các vùng nhỏ sẽ bị kéo dài theo chiều ngang, khiến cấu trúc ISBN khó quan sát
- Hilbert curve giúp các vùng nhỏ gần hình vuông hơn, nhưng có thể tạo ra artifact cấu trúc không gian không tồn tại trong dữ liệu
- Để tránh đưa vào những cấu trúc không có trong dữ liệu, trực quan hóa này dùng Bookshelf-Curve dựa trên tính chất thập phân của ISBN
Bookshelf-Curve
- Bookshelf-Curve đặt
0-9của chữ số thập phân đầu tiên theo chiều ngang, rồi đặt0-9của chữ số kế tiếp theo chiều dọc lên/xuống, và lặp lại đệ quy cách này - Để giữ tỷ lệ hình chữ nhật giữa hai tầng, tỷ lệ khung hình của mỗi khối là
√10, tức khoảng 3.16:1 - Cấu trúc này tương tự ý tưởng tỷ lệ khung hình đệ quy của giấy A4, nhưng thay vì chia đôi thì chia thành 10 đoạn
- Phép biến đổi tọa độ đơn giản vì chỉ cần dùng luân phiên từng chữ số của ISBN làm tọa độ
- Mã triển khai dài tới 50 dòng do từng thử tổng quát hóa, nhưng nguyên lý đủ dễ hiểu để có thể tự lần theo vị trí của một ISBN bằng tay
Tile bản đồ và mã hóa dữ liệu
- Một ảnh tile được tạo cho mỗi tiền tố ISBN
- Kích thước mục tiêu của mỗi tile là khoảng
100kB, và kết quả là kích thước tile2000 × 633pixel - Thông tin lưu trong pixel khác nhau tùy theo tập dữ liệu
- Với tập dữ liệu năm xuất bản, giá trị lưu là năm trừ
1800trong phạm vi 8 bit - Kênh đỏ chứa năm xuất bản trung bình của các cuốn sách trong pixel đó
- Kênh xanh dương chứa tỷ lệ sách tồn tại
- Ví dụ, nếu 50% sách tồn tại thì giá trị kênh xanh dương là
127/255
- Với tập dữ liệu năm xuất bản, giá trị lưu là năm trừ
- Ở mức zoom lớn nhất, để đảm bảo độ chính xác, 1 cuốn sách được ánh xạ thành 1 pixel
Rendering dựa trên shader GLSL
- Ban đầu dữ liệu RGB được lưu trực tiếp trong tile, nhưng để tăng tính linh hoạt, dự án lưu dữ liệu trừu tượng hơn và thực hiện render thực tế trong GLSL fragment shader của GPU
- Cách này cho phép chọn bảng màu về sau, áp dụng ngay các phép biến đổi và bộ lọc tùy ý, hoặc kết hợp nhiều tập dữ liệu tức thời
- Dữ liệu năm xuất bản lưu phạm vi
1800-2055, nhưng 95% dữ liệu nằm trong khoảng1985-2024, nên shader có thể nén để biểu diễn tập trung vào vùng này - Hàm
heatmapColor(float)chuyển giá trị0-1thành thang màu do người dùng chọn - Cú pháp
$dataset_xkhông phải cú pháp gốc của GLSL, mà là cú pháp mẫu đơn giản dựa trên regex để chỉ tải các ảnh mà shader thực sự đọc - Trong tùy chọn ⚙️ Advanced của trực quan hóa, có thể sửa shader trực tiếp và kết quả thay đổi được phản ánh theo thời gian thực
- Ý nghĩa của từng pixel trong mỗi tập dữ liệu được tổng hợp trong README
Làm cho giao diện trông như giá sách khi phóng to
- Ở chế độ xem phóng to hoàn toàn, mỗi pixel được tạo kiểu để trông giống một cuốn sách
- Mỗi cuốn sách được xử lý để có chiều rộng, chiều cao và hoa văn ngẫu nhiên
- Hình dạng này không hoàn toàn chính xác như sách thật, nhưng khiến màn hình ở mức zoom tối đa trông sống động hơn
- Toàn bộ phần tạo kiểu này được triển khai trong shader
- Vì cần cùng một kết quả sinh số ngẫu nhiên trong cả GLSL và JavaScript, phần tính chiều cao sách để khớp với biên văn bản khá phức tạp
- Có thể truyền giá trị zoom hiện tại dưới dạng uniform và fade giữa hai mức zoom để làm hiệu ứng giá sách xuất hiện mượt mà
Văn bản, cấu trúc cây và hiệu năng
- Tương tự tile ảnh, văn bản cũng được render theo cấu trúc phân cấp dựa trên mức zoom và view frustum culling
- Việc triển khai dùng react-threejs-fiber
- Khi khung nhìn di chuyển, React thêm đệ quy các phần tử cảnh, với mỗi tiền tố gồm Plane, văn bản HTML và các node tiền tố con
- Ban đầu có vấn đề hiệu năng lớn khi phải render nhiều văn bản
- Cách tốt nhất là đặt HTML vào trong SVG
<foreignObject />, render nó lên canvas bằngdrawImage, rồi nạp thành texture - Cách này hoạt động, nhưng trong quá trình render tạo ra độ trễ 20ms đồng bộ mỗi lần
- Vì không thể vẽ SVG trong WebWorker, rất khó chuyển phần này sang WebWorker
- Vấn đề hiệu năng thực tế chủ yếu được cải thiện bằng cách giảm số phần tử HTML, giới hạn lượng nội dung DOM được thêm vào mỗi frame, và đặc biệt là loại bỏ chuỗi bộ lọc CSS
text-shadow
Mã vạch và phạm vi nhà xuất bản
- Ở mức phóng to tối đa, mỗi cuốn sách hiển thị mã vạch
- Mã vạch được thêm vào để nhấn mạnh ý tưởng rằng các cuốn sách được sắp xếp theo thứ tự ISBN
- Thay vì dùng thư viện render mã vạch, dự án dùng phông TTF Libre Barcode có thể render số 13 chữ số thành mã vạch và tự tính cả check digit
- Nhờ tối ưu render văn bản của hệ điều hành, cách này vừa tiện vừa có hiệu năng tốt
- Mỗi nhóm thường có một phạm vi lớn ở cấp quốc gia, còn nhà xuất bản là các phạm vi nhỏ hơn bên trong
- Mỗi nhóm và mỗi nhà xuất bản được gán một màu ngẫu nhiên riêng
- Ngay cả khi một nhà xuất bản có nhiều phạm vi, chúng vẫn dùng cùng một màu
- Để nhấn mạnh tất cả các phạm vi cùng lúc, mỗi nhà xuất bản được gán một ID duy nhất rồi lưu dưới dạng các thành phần RGB
- Màu của nhà xuất bản hiện vẫn còn một số điểm chưa thật sự ưng ý
- Màu nhà xuất bản xung đột với thang màu heatmap
- Các phạm vi quốc gia khó nhìn
Di chuyển tìm kiếm và đường bay
- Khi tìm một cuốn sách hoặc nhấp vào minimap, giao diện sẽ bay đến vị trí đó
- Tính toán một đường bay đẹp hóa ra khó hơn dự kiến
- Việc fit parabol cho kết quả khá bình thường, sau đó tác giả thử một cách tiếp cận dùng không gian biến đổi riêng
- Kết quả cuối cùng chưa hoàn hảo và có cảm giác hơi thiết kế quá mức với khoảng 500 dòng mã, nhưng vẫn hoạt động tốt hơn cách ban đầu
Kiến trúc và pipeline xử lý
- Không cần backend
- Tile ảnh được lưu dưới dạng PNG
- Cây dữ liệu được lưu dưới dạng JSON
- Chỉ cần tải HTML, JS, CSS, PNG và JSON lên một nơi host tệp tĩnh như GitHub Pages
- Frontend dùng ThreeJS, React và MobX
- Tổ hợp này thuận tiện để xây dựng các cảnh 2D/3D tăng tốc GPU theo kiểu khai báo, phản ứng, với các component có thể tái sử dụng
- Các script xử lý phần lớn được viết bằng JS để xuất trực tiếp JSON và PNG
- Một số script phải đọc tệp nguồn 250GB và xuất sang SQLite nên được viết bằng Rust
Kết quả và mã nguồn
- Kết quả là một cách trực quan hóa linh hoạt cho các đầu sách xuất bản có gán ISBN
- Dự án này khả thi nhờ ISBN được thiết kế với không gian định danh vừa đủ nhỏ
- Nếu làm điều tương tự với UUID, phần lớn sẽ chỉ là khoảng trống khổng lồ
- Mã nguồn được công khai tại isbn-visualization
1 bình luận
Ý kiến trên Hacker News
Khi bắt đầu Amazon, tôi từng muốn làm đúng thứ như thế này, nhưng thay vì ISBN thì định dùng phân loại ba phần của Library of Congress
Cuối cùng, các nhà cung cấp dữ liệu là Baker & Taylor và Books In Print lại gộp phân loại ba phần thành một chuỗi duy nhất, khiến không thể xác định ranh giới một cách ổn định, nên chúng tôi phải bỏ cuộc trước khi kịp bắt đầu cho đàng hoàng
Việc triển khai kiểu khám phá “bay lượn” như thế này trên web phiên bản 1994–1995 chắc chắn cũng không dễ, nên đây là một công trình rất tuyệt
Tôi đã xem khá kỹ LoC Classification và LoC Subject Headings, nhưng tiếc là cả hai đều không được cung cấp tự do ở định dạng hữu ích cho máy đọc. Với PDF thì có thể lách được phần nào
Đặc biệt, phần luật tiểu bang (state law) trong Classification có mật độ phân loại theo từng tiểu bang rất không đồng đều; theo tôi nhớ thì NY và CA phức tạp áp đảo, PA đứng thứ ba nhưng kém hơn một chút, còn nhiều bang “flyover” thì đơn giản đến mức gần như buồn cười và khá giống nhau. Điều này có vẻ phản ánh mức độ phức tạp của luật thành văn, quy định và án lệ ở mỗi bang
Một sự thật lịch sử thú vị khác là hệ thống phân loại và các mục cấp cao nhất theo chữ cái dường như xuất phát trực tiếp từ thư viện cá nhân của Thomas Jefferson, vốn là nguồn gốc của LoC
Nếu quan tâm, bạn có thể tìm thấy rất nhiều lịch sử phát triển và mở rộng của Classification trong các báo cáo thường niên mà Librarian of Congress trình lên Quốc hội, có trên Hathi Trust
Classification: <https://www.loc.gov/catdir/cpso/lcco/>
Subject headings: <https://id.loc.gov/authorities/subjects.html>
Annual reports — Gần đây: <https://www.loc.gov/about/reports-and-budgets/annual-reports...> / Kho lưu trữ lịch sử đến khoảng năm 1866: <https://catalog.hathitrust.org/Record/000072049>
Đó là một trong những công ty lạc hậu nhất về mặt kỹ thuật mà tôi từng giao dịch; cho đến khi tôi đóng tài khoản vào đầu năm 2020, họ vẫn xử lý đơn mua hàng và đối soát bằng giấy, PDF và email. Tôi nhớ có thời điểm họ còn bắt gửi tài liệu qua fax
Việc ISBN bị gán trùng cho các cuốn sách khác nhau không phải hiếm [0], nên cách nói “mọi cuốn sách trong không gian ISBN” có thể hơi phóng đại
Cũng có những cuốn sách mang ISBN sai, trong đó chữ số kiểm tra không khớp với phần còn lại của ISBN. Nếu sửa chữ số kiểm tra thì lại trùng với một cuốn sách khác, nó sẽ nằm ngoài không gian ISBN mà bài blog giả định
[0] https://scis.edublogs.org/2017/09/28/the-dreaded-case-of-dup...
Khi xem các ISBN thấp nhất đã biết của một nhà xuất bản Séc, tôi thấy một màu khác nổi bật lên; https://books.google.cz/books?vid=ISBN9788000000015&redir_es... có vẻ không phải là ISBN hợp lệ :-) Tuy nhiên tôi không biết cuốn sách đó có chứa ISBN giả rõ ràng như vậy hay đây là lỗi dữ liệu của Google Books
Phần trình bày rất ấn tượng
Tuy nhiên, màn hình này không phản ánh toàn bộ catalog ISBN, mà chỉ phản ánh nội dung Anna's Archive đang có. Do thiên lệch trong bộ sưu tập của Anna, có thể thấy sự lệch về một số dải ngôn ngữ nhất định, và các vùng màu đen là những mục không có trong kho lưu trữ
Cơ sở dữ liệu metadata đến từ nhiều nguồn, và theo tôi biết thì khá đầy đủ. Màu đen nhiều khả năng chủ yếu là các vùng không có sách nào được gán
Thật sự rất hay, một dự án đam mê đáng kinh ngạc và là một tài nguyên tuyệt vời
Khi phóng to có thể thấy tiêu đề và mã vạch, còn khi rê chuột lên thì hiện cả bìa và thông tin chi tiết. Gần như có đủ mọi thứ người ta có thể mong muốn
Một ý tưởng cải thiện là có một checkbox để ẩn bảng trắng nổi ở góc trên bên trái và các thành phần ở góc trên bên phải. Tôi thích được “đắm mình” trong những visualization như thế này, nhưng các thành phần nổi đó hơi kéo tôi ra khỏi trải nghiệm, làm giảm đi một chút cả độ vui lẫn tính hữu dụng
Đây đúng là trường hợp rất hợp với Microsoft Silverlight PivotViewer, một giao diện web tuyệt vời từng được dùng trong lĩnh vực hình ảnh thần kinh trước khi Microsoft ngừng nó
Có một bài TED ấn tượng trong đó Gary W. Flake trình bày cách sử dụng
https://m.youtube.com/watch?v=LT_x9s67yWA
Cũng có một bài báo IEEE viết năm 2011. Thật đáng tiếc khi thứ này không phải là chuẩn web
https://www.dropbox.com/scl/fi/bl8zkjs3y47q3377hh3ya/Yan_Wil...
Một visualization rất tuyệt
Có thêm nhiều bài dự thi còn tuyệt hơn ở đây: https://software.annas-archive.li/AnnaArchivist/annas-archiv...
Phần tôi làm nằm ở https://isbnviz.pages.dev
Khi phóng to, trông như giá sách. Thật sự rất đẹp
Tuyệt vời. Giống như phiên bản đời thực của Library of Babel: https://libraryofbabel.info/
Trong số đủ thứ nhảm nhí về VR, nếu là một thư viện vô hạn hoặc bảo tàng vô hạn ngoài đời thật thì có lẽ tôi cũng sẵn sàng trả tiền
Nếu đây là một dự án cho phép truy cập mọi văn bản có thể tải xuống được cung cấp hợp pháp thì chắc hẳn sẽ thú vị hơn nhiều. Chẳng hạn như một giao diện cho những nơi như thế này:
https://onlinebooks.library.upenn.edu/
Phần trình bày ở định dạng hiện tại hơi gây choáng ngợp
Mất một lúc tôi mới hiểu phần preset ở góc trên bên trái thực ra dẫn tới các trục trực quan hóa dữ liệu bổ sung như có bao gồm AA hay không, độ hiếm, có bao gồm Google Books hay không. Dù vậy, phần trực quan hóa và độ sâu dữ liệu rất phong phú
Tôi cũng thích phần cho thấy các cụm theo khu vực ở https://archive.anarchy.cool/blog/all-isbns.html#visualizing
Preset theo năm tự thân nó cũng thú vị để xem mức độ hoạt động xuất bản theo khu vực. Poland gần đây rất sôi động, còn Norway có vẻ tương đối yên ắng. China dường như tăng từ khoảng năm 2005 và đã phình to khủng khiếp trong 10 năm qua
United States cũng có điểm kỳ lạ. Dù tôi chưa từng nghe nói đến, Blackstone Audio, Blurb Inc., Draft2Digital đã phát hành một số lượng ISBN khổng lồ
Một chế độ xem tối giản hơn một chút (giảm màu, chỉ hiển thị một cấp văn bản cùng lúc) nằm ở đây:
https://phiresky.github.io/isbn-visualization/?dataset=all&g...
Có lẽ còn có thể tinh chỉnh thêm bằng cách ẩn một số văn bản, chẳng hạn phần N publishers, hoặc giảm thông tin khi rê chuột qua
Có thể xem đường bay một cách khá hợp lý nếu mô hình hóa nó như chuyển động trên nửa mặt phẳng trên hyperbolic. Đặt x là vị trí trên đường tuyến tính giữa hai điểm đầu cuối, và y là độ dài một cạnh của viewport
Tôi đã nghĩ đến hai metric trở nên tương đương nhau. Trước hết là giả định một bản đồ tile phân cấp và tối thiểu hóa số tile được tải. Nếu dùng y làm độ dài một cạnh viewport, chi phí di chuyển ngang x là x/y tile, còn khi phóng to/thu nhỏ từ y_0 đến y_1 thì sẽ tải abs(log_2(y_1/y_0)) tile, nên khớp với ds = dy/y. Kết hợp lại là ds^2 = (dx^2 + dy^2)/y^2, đúng chính xác là metric của nửa mặt phẳng trên
Cách khác là có thể xem như tối thiểu hóa “optical flow” của viewport theo một nghĩa nào đó. Cách này cũng cho ra cùng metric, chỉ khác hệ số tỉ lệ. Nếu pan một đoạn x mà không phóng to, mọi thứ di chuyển x/y, tức theo tỉ lệ so với viewport. Nếu phóng to k lần, pixel tại (u,v) đi tới (ku,kv), nên độ dời là (u,v)(k-1). Khi độ dài cạnh đi từ y đến y+dy, nó trở thành (u,v)dy/y, nên tùy cách lấy trung bình độ dời mà sẽ là một hằng số nhân với dy/y
Khi đó đường trắc địa mong muốn là một horocycle, tức một cung tròn có tâm tại y=0, nhưng để tính chuyển động dọc theo đường cong thì cần làm thêm chút việc. Nếu lấy cung từ θ_0 đến θ_1, tổng thời gian thu được bằng cách tích phân dtheta/y = dθ/sin(θ), nên để chính xác thì phải đảo t = ln(csc(θ)-cot(θ)). Tôi nghĩ xấp xỉ có lẽ tốt hơn, nhưng Mathematica cho biết θ = atan2(1-2e^(2t), 2e^t), nên cũng không tệ lắm
So với logic “blub space”, metric hiệu dụng ở đó có vẻ là ds^2 = dz^2 + (z+1)^2 dx^2. Đây là tọa độ cực với z=1/y làm mức phóng đại, và dùng dz=dy/y^2 thì ds^2 = dy^2/y^4 + dx^2*(1/y^2 + ...)。Tức là triển khai hiện tại dường như dành nhiều thời gian hơn hẳn cho việc pan ở mức phóng đại cao so với mô hình hyperbolic. Chi phí giảm từ 4x xuống 2x gấp đôi chi phí giảm từ 2x xuống 1x, trong khi về mặt thị giác thì giống nhau
zoom của họ không phải là hệ số tỉ lệ mà tương ứng với “y” của tôi, nên metric là ds^2 = dy^2 + (C-y)^2 dx^2. Ở đây C lớn hơn mức phóng đại tối đa một chút. Cũng có xử lý đặc biệt cho trường hợp đường cong muốn zoom out xa hơn
Nếu chuẩn hóa sao cho chi phí pan tới cuối khi đang ở trạng thái zoom out hoàn toàn (zoom=1) là như nhau, thì ở trạng thái phóng rất sâu, chi phí pan gần như phẳng, còn ở trạng thái phóng tương đối ít hơn thì chi phí lớn hơn so với mô hình hyperbolic. Vì vậy với khoảng cách ngắn, nó góp phần khiến viewport có cảm giác di chuyển rất nhanh, còn với khoảng cách dài thì trông như gần như zoom out hết cỡ. Do mức phóng đại trung gian bất lợi, nên gần như đi tới cuối lại tốt hơn