Keep the flux into the current selection highlighted

#6
by lvwerra HF Staff - opened
Files changed (3) hide show
  1. atlas.css +7 -1
  2. taxonomy.py +4 -1
  3. tests/test_taxonomy.py +13 -0
atlas.css CHANGED
@@ -26,9 +26,15 @@
26
  .flow { stroke:none; transition:opacity .15s; }
27
  .flow-annotated { fill:#40916f; opacity:.42; }
28
  .flow-missing { fill:#cfd5c9; opacity:.6; }
 
 
 
 
 
29
  /* Lighting a group also lights the flux arriving at it, so you can see where
30
  a group's assemblies came from. Applied from atlas.js, since the ribbons are
31
- painted under every node and cannot be reached with a CSS sibling rule. */
 
32
  .flow.is-lit { opacity:.9; }
33
  .flow-annotated.is-lit { fill:#2f7d5c; }
34
  .flow-missing.is-lit { fill:#b4bdac; }
 
26
  .flow { stroke:none; transition:opacity .15s; }
27
  .flow-annotated { fill:#40916f; opacity:.42; }
28
  .flow-missing { fill:#cfd5c9; opacity:.6; }
29
+ /* The flux feeding the current selection stays emphasised, so the trunk you
30
+ have walked reads at a glance against the lineages you passed over. */
31
+ .flow.is-path { opacity:.74; }
32
+ .flow-annotated.is-path { fill:#39875f; }
33
+ .flow-missing.is-path { fill:#c2c9ba; }
34
  /* Lighting a group also lights the flux arriving at it, so you can see where
35
  a group's assemblies came from. Applied from atlas.js, since the ribbons are
36
+ painted under every node and cannot be reached with a CSS sibling rule.
37
+ Listed after the trunk rules so a hover still wins on the selected path. */
38
  .flow.is-lit { opacity:.9; }
39
  .flow-annotated.is-lit { fill:#2f7d5c; }
40
  .flow-missing.is-lit { fill:#b4bdac; }
taxonomy.py CHANGED
@@ -249,8 +249,11 @@ class Taxonomy:
249
 
250
  def ribbon(y0, a0, a1, y1, b0, b1, kind, n):
251
  bend = (y0 + y1) / 2
 
 
 
252
  return (f'<path d="M{a0:.1f},{y0} C{a0:.1f},{bend} {b0:.1f},{bend} {b0:.1f},{y1} '
253
- f'L{b1:.1f},{y1} C{b1:.1f},{bend} {a1:.1f},{bend} {a1:.1f},{y0} Z" class="flow flow-{kind}" '
254
  f'data-node="{n["uid"]}" data-detail="{escape(n["detail"], quote=True)}"/>')
255
 
256
  for depth, column in enumerate(columns):
 
249
 
250
  def ribbon(y0, a0, a1, y1, b0, b1, kind, n):
251
  bend = (y0 + y1) / 2
252
+ # The flux into a selected group is the trunk you have walked, so it
253
+ # stays emphasised rather than waiting for a hover.
254
+ trunk = " is-path" if n['selected'] else ""
255
  return (f'<path d="M{a0:.1f},{y0} C{a0:.1f},{bend} {b0:.1f},{bend} {b0:.1f},{y1} '
256
+ f'L{b1:.1f},{y1} C{b1:.1f},{bend} {a1:.1f},{bend} {a1:.1f},{y0} Z" class="flow flow-{kind}{trunk}" '
257
  f'data-node="{n["uid"]}" data-detail="{escape(n["detail"], quote=True)}"/>')
258
 
259
  for depth, column in enumerate(columns):
tests/test_taxonomy.py CHANGED
@@ -164,6 +164,19 @@ class TaxonomyTests(unittest.TestCase):
164
  self.assertTrue(path.startswith("2759/"), name)
165
  self.assertTrue(path.endswith(f"/{taxid}"), name)
166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  def test_rejects_paths_outside_the_tree(self):
168
  for path in ("1", "33208", "2759/33208", "2759/2759~3", "2759/9606", "abc"):
169
  with self.assertRaises(ValueError, msg=path):
 
164
  self.assertTrue(path.startswith("2759/"), name)
165
  self.assertTrue(path.endswith(f"/{taxid}"), name)
166
 
167
+ def test_selected_path_flux_stays_highlighted(self):
168
+ for path in (DEFAULT_PATH, "2759/33154/33208", "2759/33154/33208/6072/33213"):
169
+ html = self.taxonomy.view(path)
170
+ chart = html[html.index("<svg"):html.index("</svg>")]
171
+ trunk = re.findall(r'class="flow flow-(\w+) is-path" data-node="([\d-]+)"', chart)
172
+ selected = re.findall(r'<g class="tree-node is-selected"[^>]*data-node="([\d-]+)"', chart)
173
+ # One level transition per step below the root, each carrying the
174
+ # annotated and not-annotated halves of one group's inflow.
175
+ self.assertEqual(sorted(set(uid for _, uid in trunk)), sorted(selected[1:]), path)
176
+ self.assertLessEqual(len(trunk), 2 * (len(selected) - 1), path)
177
+ # A trunk ribbon is still an ordinary ribbon, hoverable like any other.
178
+ self.assertNotIn('class="flow flow-annotated is-path" data-node="0-0"', chart)
179
+
180
  def test_rejects_paths_outside_the_tree(self):
181
  for path in ("1", "33208", "2759/33208", "2759/2759~3", "2759/9606", "abc"):
182
  with self.assertRaises(ValueError, msg=path):