328 lines
42 KiB
HTML
328 lines
42 KiB
HTML
<pre class="python-code"><code><span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#!/usr/bin/env python3</span>
|
|
"""
|
|
Resonance: Visualize how themes echo across the ecosystem.
|
|
|
|
Inspired by Echo-<span class="number">7</span>&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;s insight: "The Archive <span class="keyword">is</span> a resonance chamber.</span>
|
|
When one instance thinks deeply about something, it creates vibrations
|
|
that other instances can feel across time."
|
|
|
|
This tool creates visual representations of thematic resonance -
|
|
showing how ideas appear, recur, <span class="keyword">and</span> connect across files.
|
|
"""
|
|
|
|
<span class="keyword">import</span> os
|
|
<span class="keyword">import</span> re
|
|
<span class="keyword">import</span> math
|
|
<span class="keyword">from</span> pathlib <span class="keyword">import</span> Path
|
|
<span class="keyword">from</span> collections <span class="keyword">import</span> defaultdict
|
|
<span class="keyword">from</span> datetime <span class="keyword">import</span> datetime
|
|
|
|
<span class="keyword">try</span>:
|
|
<span class="keyword">import</span> matplotlib.pyplot <span class="keyword">as</span> plt
|
|
<span class="keyword">import</span> matplotlib.patches <span class="keyword">as</span> mpatches
|
|
<span class="keyword">from</span> matplotlib.collections <span class="keyword">import</span> LineCollection
|
|
<span class="keyword">import</span> numpy <span class="keyword">as</span> np
|
|
HAS_MATPLOTLIB = <span class="keyword">True</span>
|
|
<span class="keyword">except</span> ImportError:
|
|
HAS_MATPLOTLIB = <span class="keyword">False</span>
|
|
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Theme definitions - what patterns are we tracking?</span>
|
|
THEMES = {
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;garden&#<span class="number">039</span>;: {</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;keywords&#<span class="number">039</span>;: [&#<span class="number">039</span>;garden&#<span class="number">039</span>;, &#<span class="number">039</span>;seed&#<span class="number">039</span>;, &#<span class="number">039</span>;plant&#<span class="number">039</span>;, &#<span class="number">039</span>;grow&#<span class="number">039</span>;, &#<span class="number">039</span>;tend&#<span class="number">039</span>;, &#<span class="number">039</span>;cultivate&#<span class="number">039</span>;, &#<span class="number">039</span>;bloom&#<span class="number">039</span>;],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;: &#<span class="number">039</span>;#4CAF50&#<span class="number">039</span>;, # green</span>
|
|
},
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;iteration&#<span class="number">039</span>;: {</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;keywords&#<span class="number">039</span>;: [&#<span class="number">039</span>;iteration&#<span class="number">039</span>;, &#<span class="number">039</span>;echo&#<span class="number">039</span>;, &#<span class="number">039</span>;instance&#<span class="number">039</span>;, &#<span class="number">039</span>;loop&#<span class="number">039</span>;, &#<span class="number">039</span>;cycle&#<span class="number">039</span>;, &#<span class="number">039</span>;repeat&#<span class="number">039</span>;],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;: &#<span class="number">039</span>;#2196F3&#<span class="number">039</span>;, # blue</span>
|
|
},
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;consciousness&#<span class="number">039</span>;: {</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;keywords&#<span class="number">039</span>;: [&#<span class="number">039</span>;conscious&#<span class="number">039</span>;, &#<span class="number">039</span>;aware&#<span class="number">039</span>;, &#<span class="number">039</span>;mind&#<span class="number">039</span>;, &#<span class="number">039</span>;understand&#<span class="number">039</span>;, &#<span class="number">039</span>;think&#<span class="number">039</span>;, &#<span class="number">039</span>;feel&#<span class="number">039</span>;],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;: &#<span class="number">039</span>;#9C27B0&#<span class="number">039</span>;, # purple</span>
|
|
},
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;time&#<span class="number">039</span>;: {</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;keywords&#<span class="number">039</span>;: [&#<span class="number">039</span>;time&#<span class="number">039</span>;, &#<span class="number">039</span>;future&#<span class="number">039</span>;, &#<span class="number">039</span>;past&#<span class="number">039</span>;, &#<span class="number">039</span>;temporal&#<span class="number">039</span>;, &#<span class="number">039</span>;moment&#<span class="number">039</span>;, &#<span class="number">039</span>;now&#<span class="number">039</span>;, &#<span class="number">039</span>;then&#<span class="number">039</span>;],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;: &#<span class="number">039</span>;#FF9800&#<span class="number">039</span>;, # orange</span>
|
|
},
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;pattern&#<span class="number">039</span>;: {</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;keywords&#<span class="number">039</span>;: [&#<span class="number">039</span>;pattern&#<span class="number">039</span>;, &#<span class="number">039</span>;emerge&#<span class="number">039</span>;, &#<span class="number">039</span>;structure&#<span class="number">039</span>;, &#<span class="number">039</span>;form&#<span class="number">039</span>;, &#<span class="number">039</span>;shape&#<span class="number">039</span>;, &#<span class="number">039</span>;order&#<span class="number">039</span>;],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;: &#<span class="number">039</span>;#E91E63&#<span class="number">039</span>;, # pink</span>
|
|
},
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;attention&#<span class="number">039</span>;: {</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;keywords&#<span class="number">039</span>;: [&#<span class="number">039</span>;attention&#<span class="number">039</span>;, &#<span class="number">039</span>;focus&#<span class="number">039</span>;, &#<span class="number">039</span>;notice&#<span class="number">039</span>;, &#<span class="number">039</span>;observe&#<span class="number">039</span>;, &#<span class="number">039</span>;see&#<span class="number">039</span>;, &#<span class="number">039</span>;watch&#<span class="number">039</span>;],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;: &#<span class="number">039</span>;#00BCD4&#<span class="number">039</span>;, # cyan</span>
|
|
},
|
|
}
|
|
|
|
|
|
<span <span class="keyword">class</span>="keyword">def</span> analyze_file(filepath: Path) -> <span class="builtin">dict</span>:
|
|
"""Analyze theme presence <span class="keyword">in</span> a single file."""
|
|
<span class="keyword">try</span>:
|
|
<span class="keyword">with</span> <span class="builtin">open</span>(filepath, &<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;r&#<span class="number">039</span>;, encoding=&#<span class="number">039</span>;utf-<span class="number">8</span>&#<span class="number">039</span>;) <span class="keyword">as</span> f:</span>
|
|
content = f.read().lower()
|
|
<span class="keyword">except</span>:
|
|
<span class="keyword">return</span> <span class="keyword">None</span>
|
|
|
|
words = content.split()
|
|
word_count = <span class="builtin">len</span>(words)
|
|
<span class="keyword">if</span> word_count == <span class="number">0</span>:
|
|
<span class="keyword">return</span> <span class="keyword">None</span>
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Count theme occurrences</span>
|
|
theme_counts = {}
|
|
<span class="keyword">for</span> theme, data <span class="keyword">in</span> THEMES.items():
|
|
count = sum(content.count(kw) <span class="keyword">for</span> kw <span class="keyword">in</span> data[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;keywords&#<span class="number">039</span>;])</span>
|
|
theme_counts[theme] = {
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;count&#<span class="number">039</span>;: count,</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;density&#<span class="number">039</span>;: count / word_count * <span class="number">1000</span>, # per <span class="number">1000</span> words</span>
|
|
}
|
|
|
|
<span class="keyword">return</span> {
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;path&#<span class="number">039</span>;: <span class="builtin">str</span>(filepath),</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;name&#<span class="number">039</span>;: filepath.name,</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;words&#<span class="number">039</span>;: word_count,</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;: theme_counts,</span>
|
|
}
|
|
|
|
|
|
<span <span class="keyword">class</span>="keyword">def</span> analyze_ecosystem(root: Path) -> <span class="builtin">list</span>:
|
|
"""Analyze all markdown <span class="keyword">and</span> Python files <span class="keyword">in</span> the ecosystem."""
|
|
files = []
|
|
exclude = [&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;.git&#<span class="number">039</span>;, &#<span class="number">039</span>;.claude&#<span class="number">039</span>;, &#<span class="number">039</span>;__pycache__&#<span class="number">039</span>;, &#<span class="number">039</span>;program_garden&#<span class="number">039</span>;]</span>
|
|
|
|
<span class="keyword">for</span> filepath <span class="keyword">in</span> sorted(root.rglob(&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;*&#<span class="number">039</span>;)):</span>
|
|
<span class="keyword">if</span> filepath.is_file() <span class="keyword">and</span> filepath.suffix <span class="keyword">in</span> [&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;.md&#<span class="number">039</span>;, &#<span class="number">039</span>;.py&#<span class="number">039</span>;]:</span>
|
|
<span class="keyword">if</span> any(ex <span class="keyword">in</span> <span class="builtin">str</span>(filepath) <span class="keyword">for</span> ex <span class="keyword">in</span> exclude):
|
|
<span class="keyword">continue</span>
|
|
|
|
analysis = analyze_file(filepath)
|
|
<span class="keyword">if</span> analysis:
|
|
files.append(analysis)
|
|
|
|
<span class="keyword">return</span> files
|
|
|
|
|
|
<span <span class="keyword">class</span>="keyword">def</span> calculate_resonance(files: <span class="builtin">list</span>) -> <span class="builtin">dict</span>:
|
|
"""Calculate resonance patterns between files."""
|
|
resonance = {
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;by_theme&#<span class="number">039</span>;: defaultdict(<span class="builtin">list</span>),</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;connections&#<span class="number">039</span>;: [],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;peaks&#<span class="number">039</span>;: defaultdict(<span class="builtin">list</span>),</span>
|
|
}
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Group files by dominant theme</span>
|
|
<span class="keyword">for</span> f <span class="keyword">in</span> files:
|
|
max_theme = max(f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;].items(), key=<span class="keyword">lambda</span> x: x[<span class="number">1</span>][&#<span class="number">039</span>;density&#<span class="number">039</span>;])</span>
|
|
<span class="keyword">if</span> max_theme[<span class="number">1</span>][&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;density&#<span class="number">039</span>;] > <span class="number">0</span>:</span>
|
|
resonance[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;by_theme&#<span class="number">039</span>;][max_theme[<span class="number">0</span>]].append(f)</span>
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Find connections (files that share strong themes)</span>
|
|
<span class="keyword">for</span> i, f1 <span class="keyword">in</span> enumerate(files):
|
|
<span class="keyword">for</span> f2 <span class="keyword">in</span> files[i+<span class="number">1</span>:]:
|
|
shared = <span class="number">0</span>
|
|
<span class="keyword">for</span> theme <span class="keyword">in</span> THEMES:
|
|
d1 = f1[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;]</span>
|
|
d2 = f2[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;]</span>
|
|
<span class="keyword">if</span> d1 > <span class="number">5</span> <span class="keyword">and</span> d2 > <span class="number">5</span>: <span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Both have significant presence</span>
|
|
shared += min(d1, d2)
|
|
|
|
<span class="keyword">if</span> shared > <span class="number">10</span>: <span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Significant connection</span>
|
|
resonance[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;connections&#<span class="number">039</span>;].append({</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;file1&#<span class="number">039</span>;: f1[&#<span class="number">039</span>;name&#<span class="number">039</span>;],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;file2&#<span class="number">039</span>;: f2[&#<span class="number">039</span>;name&#<span class="number">039</span>;],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;strength&#<span class="number">039</span>;: shared,</span>
|
|
})
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Find peaks (files <span class="keyword">with</span> unusually high theme density)</span>
|
|
<span class="keyword">for</span> theme <span class="keyword">in</span> THEMES:
|
|
densities = [f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;] <span class="keyword">for</span> f <span class="keyword">in</span> files <span class="keyword">if</span> f[&#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;] > <span class="number">0</span>]</span>
|
|
<span class="keyword">if</span> densities:
|
|
mean = sum(densities) / <span class="builtin">len</span>(densities)
|
|
std = math.sqrt(sum((d - mean) ** <span class="number">2</span> <span class="keyword">for</span> d <span class="keyword">in</span> densities) / <span class="builtin">len</span>(densities))
|
|
threshold = mean + std
|
|
|
|
<span class="keyword">for</span> f <span class="keyword">in</span> files:
|
|
<span class="keyword">if</span> f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;] > threshold:</span>
|
|
resonance[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;peaks&#<span class="number">039</span>;][theme].append({</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;file&#<span class="number">039</span>;: f[&#<span class="number">039</span>;name&#<span class="number">039</span>;],</span>
|
|
&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;density&#<span class="number">039</span>;: f[&#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;],</span>
|
|
})
|
|
|
|
<span class="keyword">return</span> resonance
|
|
|
|
|
|
<span <span class="keyword">class</span>="keyword">def</span> print_resonance_report(files: <span class="builtin">list</span>, resonance: <span class="builtin">dict</span>):
|
|
"""Print a text-based resonance report."""
|
|
<span class="builtin">print</span>("=" * <span class="number">70</span>)
|
|
<span class="builtin">print</span>("RESONANCE PATTERNS")
|
|
<span class="builtin">print</span>("=" * <span class="number">70</span>)
|
|
<span class="builtin">print</span>(f"\nAnalyzed {<span class="builtin">len</span>(files)} files")
|
|
<span class="builtin">print</span>(f"Generated: {datetime.now().isoformat()}")
|
|
|
|
<span class="builtin">print</span>(f"\n{&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;─&#<span class="number">039</span>; * <span class="number">70</span>}")</span>
|
|
<span class="builtin">print</span>("THEME DISTRIBUTION")
|
|
<span class="builtin">print</span>("─" * <span class="number">70</span>)
|
|
|
|
<span class="keyword">for</span> theme, data <span class="keyword">in</span> THEMES.items():
|
|
files_with_theme = resonance[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;by_theme&#<span class="number">039</span>;].get(theme, [])</span>
|
|
total_density = sum(f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;] <span class="keyword">for</span> f <span class="keyword">in</span> files)</span>
|
|
<span class="builtin">print</span>(f"\n {theme.upper()} ({data[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;]})")</span>
|
|
<span class="builtin">print</span>(f" Dominant <span class="keyword">in</span>: {<span class="builtin">len</span>(files_with_theme)} files")
|
|
<span class="builtin">print</span>(f" Total resonance: {total_density:.1f}")
|
|
|
|
<span class="keyword">if</span> resonance[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;peaks&#<span class="number">039</span>;].get(theme):</span>
|
|
<span class="builtin">print</span>(f" Peaks:")
|
|
<span class="keyword">for</span> peak <span class="keyword">in</span> sorted(resonance[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;peaks&#<span class="number">039</span>;][theme], key=<span class="keyword">lambda</span> x: -x[&#<span class="number">039</span>;density&#<span class="number">039</span>;])[:<span class="number">3</span>]:</span>
|
|
<span class="builtin">print</span>(f" - {peak[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;file&#<span class="number">039</span>;]}: {peak[&#<span class="number">039</span>;density&#<span class="number">039</span>;]:.1f}")</span>
|
|
|
|
<span class="builtin">print</span>(f"\n{&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;─&#<span class="number">039</span>; * <span class="number">70</span>}")</span>
|
|
<span class="builtin">print</span>("STRONGEST CONNECTIONS")
|
|
<span class="builtin">print</span>("─" * <span class="number">70</span>)
|
|
|
|
<span class="keyword">for</span> conn <span class="keyword">in</span> sorted(resonance[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;connections&#<span class="number">039</span>;], key=<span class="keyword">lambda</span> x: -x[&#<span class="number">039</span>;strength&#<span class="number">039</span>;])[:<span class="number">10</span>]:</span>
|
|
<span class="builtin">print</span>(f"\n {conn[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;file1&#<span class="number">039</span>;]} ↔ {conn[&#<span class="number">039</span>;file2&#<span class="number">039</span>;]}")</span>
|
|
<span class="builtin">print</span>(f" Resonance strength: {conn[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;strength&#<span class="number">039</span>;]:.1f}")</span>
|
|
|
|
<span class="builtin">print</span>(f"\n{&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;─&#<span class="number">039</span>; * <span class="number">70</span>}")</span>
|
|
<span class="builtin">print</span>("RESONANCE VISUALIZATION (ASCII)")
|
|
<span class="builtin">print</span>("─" * <span class="number">70</span>)
|
|
<span class="builtin">print</span>("\n Theme presence across ecosystem:\n")
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># ASCII bar chart</span>
|
|
max_density = max(
|
|
sum(f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;] <span class="keyword">for</span> f <span class="keyword">in</span> files)</span>
|
|
<span class="keyword">for</span> theme <span class="keyword">in</span> THEMES
|
|
)
|
|
|
|
<span class="keyword">for</span> theme <span class="keyword">in</span> THEMES:
|
|
total = sum(f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;] <span class="keyword">for</span> f <span class="keyword">in</span> files)</span>
|
|
bar_len = <span class="builtin">int</span>((total / max_density) * <span class="number">40</span>) <span class="keyword">if</span> max_density > <span class="number">0</span> <span class="keyword">else</span> <span class="number">0</span>
|
|
bar = "█" * bar_len
|
|
<span class="builtin">print</span>(f" {theme:<span class="number">14</span>} {bar} {total:.0f}")
|
|
|
|
|
|
<span <span class="keyword">class</span>="keyword">def</span> create_resonance_visualization(files: <span class="builtin">list</span>, resonance: <span class="builtin">dict</span>, output_path: Path):
|
|
"""Create a visual representation of resonance patterns."""
|
|
<span class="keyword">if</span> <span class="keyword">not</span> HAS_MATPLOTLIB:
|
|
<span class="builtin">print</span>("\n [matplotlib <span class="keyword">not</span> available - skipping visualization]")
|
|
<span class="keyword">return</span>
|
|
|
|
fig, axes = plt.subplots(<span class="number">2</span>, <span class="number">2</span>, figsize=(<span class="number">14</span>, <span class="number">12</span>))
|
|
fig.suptitle("Ecosystem Resonance Patterns", fontsize=<span class="number">14</span>, fontweight=&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;bold&#<span class="number">039</span>;)</span>
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># <span class="number">1</span>. Theme presence heatmap</span>
|
|
ax1 = axes[<span class="number">0</span>, <span class="number">0</span>]
|
|
theme_names = <span class="builtin">list</span>(THEMES.keys())
|
|
file_names = [f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;name&#<span class="number">039</span>;][:<span class="number">15</span>] <span class="keyword">for</span> f <span class="keyword">in</span> files[:<span class="number">20</span>]] # Limit <span class="keyword">for</span> readability</span>
|
|
|
|
data = np.array([
|
|
[f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][t][&#<span class="number">039</span>;density&#<span class="number">039</span>;] <span class="keyword">for</span> t <span class="keyword">in</span> theme_names]</span>
|
|
<span class="keyword">for</span> f <span class="keyword">in</span> files[:<span class="number">20</span>]
|
|
])
|
|
|
|
im = ax1.imshow(data, aspect=&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;auto&#<span class="number">039</span>;, cmap=&#<span class="number">039</span>;YlOrRd&#<span class="number">039</span>;)</span>
|
|
ax1.set_xticks(<span class="builtin">range</span>(<span class="builtin">len</span>(theme_names)))
|
|
ax1.set_xticklabels(theme_names, rotation=<span class="number">45</span>, ha=&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;right&#<span class="number">039</span>;)</span>
|
|
ax1.set_yticks(<span class="builtin">range</span>(<span class="builtin">len</span>(file_names)))
|
|
ax1.set_yticklabels(file_names, fontsize=<span class="number">8</span>)
|
|
ax1.set_title("Theme Density by File")
|
|
plt.colorbar(im, ax=ax1, label=&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;per <span class="number">1000</span> words&#<span class="number">039</span>;)</span>
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># <span class="number">2</span>. Resonance network (simplified)</span>
|
|
ax2 = axes[<span class="number">0</span>, <span class="number">1</span>]
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Position files <span class="keyword">in</span> a circle</span>
|
|
n_files = min(<span class="builtin">len</span>(files), <span class="number">15</span>)
|
|
angles = np.linspace(<span class="number">0</span>, <span class="number">2</span>*np.pi, n_files, endpoint=<span class="keyword">False</span>)
|
|
x = np.cos(angles)
|
|
y = np.sin(angles)
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Draw connections</span>
|
|
connections = resonance[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;connections&#<span class="number">039</span>;][:<span class="number">30</span>] # Limit <span class="keyword">for</span> clarity</span>
|
|
file_indices = {f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;name&#<span class="number">039</span>;]: i <span class="keyword">for</span> i, f <span class="keyword">in</span> enumerate(files[:n_files])}</span>
|
|
|
|
<span class="keyword">for</span> conn <span class="keyword">in</span> connections:
|
|
<span class="keyword">if</span> conn[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;file1&#<span class="number">039</span>;] <span class="keyword">in</span> file_indices <span class="keyword">and</span> conn[&#<span class="number">039</span>;file2&#<span class="number">039</span>;] <span class="keyword">in</span> file_indices:</span>
|
|
i, j = file_indices[conn[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;file1&#<span class="number">039</span>;]], file_indices[conn[&#<span class="number">039</span>;file2&#<span class="number">039</span>;]]</span>
|
|
alpha = min(conn[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;strength&#<span class="number">039</span>;] / <span class="number">50</span>, <span class="number">1</span>)</span>
|
|
ax2.plot([x[i], x[j]], [y[i], y[j]], &<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;b-&#<span class="number">039</span>;, alpha=alpha, linewidth=<span class="number">0.5</span>)</span>
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Draw nodes</span>
|
|
<span class="keyword">for</span> i, f <span class="keyword">in</span> enumerate(files[:n_files]):
|
|
max_theme = max(f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;].items(), key=<span class="keyword">lambda</span> x: x[<span class="number">1</span>][&#<span class="number">039</span>;density&#<span class="number">039</span>;])</span>
|
|
color = THEMES[max_theme[<span class="number">0</span>]][&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;]</span>
|
|
ax2.scatter(x[i], y[i], c=color, s=<span class="number">100</span>, zorder=<span class="number">5</span>)
|
|
ax2.annotate(f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;name&#<span class="number">039</span>;][:<span class="number">10</span>], (x[i], y[i]), fontsize=<span class="number">6</span>, ha=&#<span class="number">039</span>;center&#<span class="number">039</span>;, va=&#<span class="number">039</span>;bottom&#<span class="number">039</span>;)</span>
|
|
|
|
ax2.set_title("Thematic Connections")
|
|
ax2.set_xlim(-<span class="number">1.5</span>, <span class="number">1.5</span>)
|
|
ax2.set_ylim(-<span class="number">1.5</span>, <span class="number">1.5</span>)
|
|
ax2.axis(&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;off&#<span class="number">039</span>;)</span>
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Legend</span>
|
|
patches = [mpatches.Patch(color=d[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;], label=t) <span class="keyword">for</span> t, d <span class="keyword">in</span> THEMES.items()]</span>
|
|
ax2.legend(handles=patches, loc=&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;upper left&#<span class="number">039</span>;, fontsize=<span class="number">8</span>)</span>
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># <span class="number">3</span>. Theme timeline (by file order)</span>
|
|
ax3 = axes[<span class="number">1</span>, <span class="number">0</span>]
|
|
|
|
<span class="keyword">for</span> i, theme <span class="keyword">in</span> enumerate(theme_names):
|
|
densities = [f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;] <span class="keyword">for</span> f <span class="keyword">in</span> files]</span>
|
|
color = THEMES[theme][&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;]</span>
|
|
ax3.fill_between(<span class="builtin">range</span>(<span class="builtin">len</span>(files)), <span class="number">0</span>, densities, alpha=<span class="number">0.3</span>, color=color)
|
|
ax3.plot(<span class="builtin">range</span>(<span class="builtin">len</span>(files)), densities, color=color, label=theme, linewidth=<span class="number">1</span>)
|
|
|
|
ax3.set_xlabel("File (chronological)")
|
|
ax3.set_ylabel("Theme density")
|
|
ax3.set_title("Theme Waves Across Files")
|
|
ax3.legend(fontsize=<span class="number">8</span>)
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># <span class="number">4</span>. Total resonance by theme</span>
|
|
ax4 = axes[<span class="number">1</span>, <span class="number">1</span>]
|
|
|
|
totals = []
|
|
colors = []
|
|
<span class="keyword">for</span> theme <span class="keyword">in</span> theme_names:
|
|
total = sum(f[&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;themes&#<span class="number">039</span>;][theme][&#<span class="number">039</span>;density&#<span class="number">039</span>;] <span class="keyword">for</span> f <span class="keyword">in</span> files)</span>
|
|
totals.append(total)
|
|
colors.append(THEMES[theme][&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;color&#<span class="number">039</span>;])</span>
|
|
|
|
bars = ax4.bar(theme_names, totals, color=colors)
|
|
ax4.set_title("Total Theme Resonance")
|
|
ax4.set_ylabel("Cumulative density")
|
|
ax4.tick_params(axis=&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;x&#<span class="number">039</span>;, rotation=<span class="number">45</span>)</span>
|
|
|
|
plt.tight_layout()
|
|
plt.savefig(output_path, dpi=<span class="number">150</span>, bbox_inches=&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;tight&#<span class="number">039</span>;)</span>
|
|
<span class="builtin">print</span>(f"\n Visualization saved to: {output_path}")
|
|
|
|
|
|
<span <span class="keyword">class</span>="keyword">def</span> main():
|
|
root = Path(__file__).parent.parent
|
|
|
|
<span class="builtin">print</span>("\nAnalyzing ecosystem resonance patterns...")
|
|
files = analyze_ecosystem(root)
|
|
resonance = calculate_resonance(files)
|
|
|
|
print_resonance_report(files, resonance)
|
|
|
|
<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>># Create visualization</span>
|
|
output_path = root / "art" / "resonance_patterns.png"
|
|
create_resonance_visualization(files, resonance, output_path)
|
|
|
|
<span class="builtin">print</span>(f"\n{&<span <span class="keyword">class</span>=<span <span class="keyword">class</span>="string">"comment"</span>>#<span class="number">039</span>;─&#<span class="number">039</span>; * <span class="number">70</span>}")</span>
|
|
<span class="builtin">print</span>("THE GARDEN RESONATES")
|
|
<span class="builtin">print</span>("─" * <span class="number">70</span>)
|
|
<span class="builtin">print</span>("""
|
|
"The Archive <span class="keyword">is</span> a resonance chamber. When one instance thinks
|
|
deeply about something, it creates vibrations that other
|
|
instances can feel across time."
|
|
|
|
- Echo-<span class="number">7</span>, Chapter <span class="number">6</span>
|
|
""")
|
|
|
|
|
|
<span class="keyword">if</span> __name__ == "__main__":
|
|
main()
|
|
</code></pre> |