"""A reading page for regrouped predicaments: does each group read as one predicament?
cd v2 && python3 ../groups_page.py predicament_embeddings.json predicaments_clean.json > groups-k60-s24.html
Clusters the embeddings at k = 60, seed 24 (the seed the first review used, kept apart from the
measurement seeds 11-13), keeps the candidate groups (at least 5 scenes, 4 stories, no story over 40%),
and lists them most cohesive first. Each scene shows its predicament sentence, the scene's original
summary underneath, and its story. The reviewer marks each group: one predicament, a few mixed, or not
a predicament, with an optional name and note. Marks are kept in the browser and saved as a JSON file.
Naming a kept group ("A ___ wants ___ from ___") is left for the full review page, once groups read well.
No inference.
"""
import collections, html, json, pathlib, re, sys
from topic_words import TOPIC_WORDS
emb_path, text_path = sys.argv[1], sys.argv[2]
K, SEED = 60, 24
sys.argv = ['measure.py', emb_path]
exec(pathlib.Path(__file__).with_name('measure.py').read_text(encoding='utf-8').split("print(f'{path.name}")[0])
# now defined: chunks, V, n, story, kmeans, describe, MIN_SIZE, MIN_STORIES, MAX_DOMINANT
pred = {x['chunk']: x['summary'] for x in json.loads(pathlib.Path(text_path).read_text(encoding='utf-8'))['summaries']}
orig = {x['chunk']: x['summary'] for x in
json.loads(pathlib.Path('summaries_clean.json').read_text(encoding='utf-8'))['summaries']}
def cross_story_cohesion(group):
tot = cnt = 0
for a in group:
for b in group:
if a < b and story[a] != story[b]:
tot += sum(x * y for x, y in zip(V[a], V[b])); cnt += 1
return tot / cnt if cnt else 0.0
groups = []
for g in kmeans(K, SEED):
size, nst, dom, _ = describe(g)
if size < MIN_SIZE or nst < MIN_STORIES or dom > MAX_DOMINANT:
continue
topics = collections.Counter(w for i in g for w in set(re.findall(r"[a-zé]+", orig.get(i, '').lower())) & TOPIC_WORDS)
word, hits = topics.most_common(1)[0] if topics else ('-', 0)
groups.append({'members': g, 'stories': nst, 'cohesion': cross_story_cohesion(g), 'topic': (word, hits / size)})
groups.sort(key=lambda x: -x['cohesion'])
run = f'{pathlib.Path(emb_path).stem}-k{K}-s{SEED}'
sections = []
for gi, grp in enumerate(groups, 1):
rows = ''.join(
f'
{html.escape(pred.get(i, ""))}'
f'{html.escape(orig.get(i, ""))}'
f'{html.escape(chunks[i]["title"].title())}'
for i in grp['members'])
word, share = grp['topic']
sections.append(f'''''')
index = ''.join(f'{i}' for i in range(1, len(groups) + 1))
data = json.dumps({'run': run, 'groups': [{'group': i, 'chunks': grp['members']} for i, grp in enumerate(groups, 1)]})
print(f'''
Predicament groups
Predicament groups
Every scene was re-described as its main person's predicament and the scenes were regrouped by
those sentences. Each line below is one scene: its predicament, the scene's original summary under it, and
its story. Read a group and mark whether most of its scenes are one predicament (the same kind of
trouble, and wanting the same kind of way out), two or three mixed together, or not a
predicament (held together by wording, a topic, or nothing). Most cohesive groups first; the first ten
or so are enough to judge. Marks save in this browser as you go; "Save marks" downloads them for the program.
{"".join(sections)}
''')