{"$schema":"https://ejfox.com/schema/page-twin@1.json","kind":"project","url":"https://ejfox.com/projects/obsidian-analysis","json_url":"https://ejfox.com/projects/obsidian-analysis.json","generator":"ejfox.com/json-twin@1","data":{"cacheVersion":"2026-05-13-gear-cards","html":"<p class=\"\">I embedded my entire Obsidian vault — around 2,000 notes, chunked — using local Nomic embeddings running in LM Studio, so my private notes never leave my machine, and then I laid the whole thing out as a semantic map. Every note is a point, and points that sit close together are notes that are actually about the same thing. You search it in plain natural language, and you can recolor the map by semantics, recency, note size, or link density to see the vault from a different angle each time.</p>\n<figure role=\"figure\" aria-label=\"~2,000 notes embedded into a single semantic map — search and filter by SEMANTIC / TEMPORAL / SIZE / LINKS\" class=\"\">\n<img src=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/projects/obsidian-analysis/map.png\" alt=\"~2,000 notes embedded into a single semantic map — search and filter by SEMANTIC / TEMPORAL / SIZE / LINKS\" loading=\"lazy\" decoding=\"async\" srcset=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_640/projects/obsidian-analysis/map.png 640w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_960/projects/obsidian-analysis/map.png 960w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/projects/obsidian-analysis/map.png 1280w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1920/projects/obsidian-analysis/map.png 1920w\" sizes=\"(max-width: 430px) 92vw, (max-width: 768px) 85vw, 900px\" title=\"~2,000 notes embedded into a single semantic map — search and filter by SEMANTIC / TEMPORAL / SIZE / LINKS\" width=\"1440\" height=\"813\" style=\"--splay-rot:2.44deg;\" data-dimensions=\"1440×813\" class=\"img-full my-8 rounded-sm img-splay aspect-video w-full mx-auto py-4\" crossorigin=\"anonymous\">\n<figcaption class=\"\">~2,000 notes embedded into a single semantic map — search and filter by SEMANTIC / TEMPORAL / SIZE / LINKS</figcaption>\n</figure>\n<p class=\"\">The other half of this is the parameter grid. UMAP has a lot of knobs and the layout you get depends entirely on how you set them, so instead of guessing I ran 64 combinations of <code class=\"md-inline-code\">n_neighbors</code> and <code class=\"md-inline-code\">min_dist</code> at once and put them side by side. It turns \"which settings are right\" into something you can just look at — the same vault laid out 64 different ways, all on one screen.</p>\n<figure role=\"figure\" aria-label=\"A 64-combination UMAP parameter grid — the same vault laid out 64 different ways\" class=\"\">\n<img src=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/projects/obsidian-analysis/grid.png\" alt=\"A 64-combination UMAP parameter grid — the same vault laid out 64 different ways\" loading=\"lazy\" decoding=\"async\" srcset=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_640/projects/obsidian-analysis/grid.png 640w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_960/projects/obsidian-analysis/grid.png 960w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/projects/obsidian-analysis/grid.png 1280w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1920/projects/obsidian-analysis/grid.png 1920w\" sizes=\"(max-width: 430px) 92vw, (max-width: 768px) 85vw, 900px\" title=\"A 64-combination UMAP parameter grid — the same vault laid out 64 different ways\" width=\"1440\" height=\"813\" style=\"--splay-rot:1.59deg;\" data-dimensions=\"1440×813\" class=\"img-full my-8 rounded-sm img-splay aspect-video w-full mx-auto py-4\" crossorigin=\"anonymous\">\n<figcaption class=\"\">A 64-combination UMAP parameter grid — the same vault laid out 64 different ways</figcaption>\n</figure>\n<h2 class=\"\" id=\"more-semantic-maps\">More semantic maps</h2>\n<h3 class=\"\" id=\"criterion-embeddings\">Criterion Embeddings</h3>\n<figure role=\"figure\" aria-label=\"Criterion film embeddings explored as a 2D map\" class=\"\">\n<img src=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/v1780060622/projects/data-visualization-suite/gh-4.png\" alt=\"Criterion film embeddings explored as a 2D map\" loading=\"lazy\" decoding=\"async\" srcset=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_640/v1780060622/projects/data-visualization-suite/gh-4.png 640w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_960/v1780060622/projects/data-visualization-suite/gh-4.png 960w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/v1780060622/projects/data-visualization-suite/gh-4.png 1280w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1920/v1780060622/projects/data-visualization-suite/gh-4.png 1920w\" sizes=\"(max-width: 430px) 92vw, (max-width: 768px) 85vw, 900px\" title=\"Criterion film embeddings explored as a 2D map\" width=\"2024\" height=\"2474\" style=\"--splay-rot:-2.99deg;\" data-dimensions=\"2024×2474\" class=\"img-full my-8 rounded-sm img-splay aspect-[3/4] w-full mx-auto py-4\" crossorigin=\"anonymous\">\n<figcaption class=\"\">Criterion film embeddings explored as a 2D map</figcaption>\n</figure>\n<p class=\"\"><a href=\"https://github.com/ejfox/criterion-embedding-viz\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"external-link group inline-flex items-center text-blue-600 dark:text-blue-400\" data-preview-url=\"https://github.com/ejfox/criterion-embedding-viz\">Criterion Embeddings<svg class=\"inline-block w-4 h-4 ml-1 opacity-50 dark:opacity-75 group-hover:opacity-100 transition-opacity align-text-bottom\" xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\" class=\"\"></path></svg></a> computes vector embeddings for every Criterion Collection film and projects them into an explorable 2D map. You search by theme (\"films about existentialism\") instead of by keyword.</p>\n<h3 class=\"\" id=\"rdataisbeautiful-embedded\">r/dataisbeautiful, Embedded</h3>\n<figure role=\"figure\" aria-label=\"r/dataisbeautiful embedded — 1,000 posts clustered into 50 thematic bubbles, sized by count\" class=\"\">\n<img src=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/projects/reddit-embeddings/map.png\" alt=\"r/dataisbeautiful embedded — 1,000 posts clustered into 50 thematic bubbles, sized by count\" loading=\"lazy\" decoding=\"async\" srcset=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_640/projects/reddit-embeddings/map.png 640w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_960/projects/reddit-embeddings/map.png 960w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/projects/reddit-embeddings/map.png 1280w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1920/projects/reddit-embeddings/map.png 1920w\" sizes=\"(max-width: 430px) 92vw, (max-width: 768px) 85vw, 900px\" title=\"r/dataisbeautiful embedded — 1,000 posts clustered into 50 thematic bubbles, sized by count\" width=\"1440\" height=\"953\" style=\"--splay-rot:-2.1deg;\" data-dimensions=\"1440×953\" class=\"img-full my-8 rounded-sm img-splay w-full mx-auto py-4\" crossorigin=\"anonymous\">\n<figcaption class=\"\">r/dataisbeautiful embedded — 1,000 posts clustered into 50 thematic bubbles, sized by count</figcaption>\n</figure>\n<p class=\"\">The top 1,000 posts from r/dataisbeautiful, each embedded with OpenAI and clustered into 50 themes, laid out as a map. The biggest clusters: US politics dataviz, COVID and mortality, Google search trends, climate, creative visualizations, and personal-finance charts.</p>\n<h3 class=\"\" id=\"code-network-gen\">code-network-gen</h3>\n<figure role=\"figure\" aria-label=\"Real output — every script in this site&#x27;s content pipeline as a call-constellation (pink hub = file scope, teal = functions, edges = calls)\" class=\"\">\n<img src=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/projects/code-network-gen/graph.png\" alt=\"Real output — every script in this site&#x27;s content pipeline as a call-constellation (pink hub = file scope, teal = functions, edges = calls)\" loading=\"lazy\" decoding=\"async\" srcset=\"https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_640/projects/code-network-gen/graph.png 640w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_960/projects/code-network-gen/graph.png 960w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1280/projects/code-network-gen/graph.png 1280w, https://res.cloudinary.com/ejf/image/upload/c_scale,f_auto,q_auto:good,w_1920/projects/code-network-gen/graph.png 1920w\" sizes=\"(max-width: 430px) 92vw, (max-width: 768px) 85vw, 900px\" title=\"Real output — every script in this site&#x27;s content pipeline as a call-constellation (pink hub = file scope, teal = functions, edges = calls)\" width=\"1677\" height=\"1000\" style=\"--splay-rot:-0.94deg;\" data-dimensions=\"1677×1000\" class=\"img-full my-8 rounded-sm img-splay w-full mx-auto py-4\" crossorigin=\"anonymous\">\n<figcaption class=\"\">Real output — every script in this site's content pipeline as a call-constellation (pink hub = file scope, teal = functions, edges = calls)</figcaption>\n</figure>\n<p class=\"\"><a href=\"https://github.com/ejfox/code-network-gen\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"external-link group inline-flex items-center text-blue-600 dark:text-blue-400\" data-preview-url=\"https://github.com/ejfox/code-network-gen\">code-network-gen<svg class=\"inline-block w-4 h-4 ml-1 opacity-50 dark:opacity-75 group-hover:opacity-100 transition-opacity align-text-bottom\" xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\" class=\"\"></path></svg></a> generates a node/edge graph from a JavaScript codebase by walking the AST with acorn and babel. It shows software architecture as an explorable network instead of a file tree — above, the scripts behind this site's own content pipeline.</p>","title":"Obsidian Analysis","metadata":{"title":"Obsidian Analysis","date":"2024-06-01T04:00:00.000Z","category":"Dataviz","featured":false,"url":"https://github.com/ejfox/obsidian-analysis","tech":["Python","Embeddings","UMAP","LM Studio"],"state":"deployed","ai-involvement":"ai-collaborative","tags":["data","visualization","ai"],"words":362,"images":5,"imageDetails":{"total":5,"cloudinary":4,"withDimensions":0},"links":2,"codeBlocks":0,"headers":{"h2":1},"toc":[{"text":"More semantic maps","slug":"more-semantic-maps","level":"h2","children":[{"text":"Criterion Embeddings","slug":"criterion-embeddings","level":"h3","children":[]},{"text":"r/dataisbeautiful, Embedded","slug":"rdataisbeautiful-embedded","level":"h3","children":[]},{"text":"code-network-gen","slug":"code-network-gen","level":"h3","children":[]}]}],"type":"post"}},"_links":{"self":"https://ejfox.com/projects/obsidian-analysis.json","html":"https://ejfox.com/projects/obsidian-analysis","index":"/projects.json"}}