microsegments 0.2.3__tar.gz → 0.2.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. {microsegments-0.2.3 → microsegments-0.2.5}/PKG-INFO +1 -1
  2. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/_version.py +2 -2
  3. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/html/export.py +2 -2
  4. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/html/template.html +28 -9
  5. {microsegments-0.2.3 → microsegments-0.2.5}/.github/workflows/publish.yml +0 -0
  6. {microsegments-0.2.3 → microsegments-0.2.5}/.github/workflows/test.yml +0 -0
  7. {microsegments-0.2.3 → microsegments-0.2.5}/.gitignore +0 -0
  8. {microsegments-0.2.3 → microsegments-0.2.5}/LICENSE +0 -0
  9. {microsegments-0.2.3 → microsegments-0.2.5}/README.md +0 -0
  10. {microsegments-0.2.3 → microsegments-0.2.5}/docs/report.jpg +0 -0
  11. {microsegments-0.2.3 → microsegments-0.2.5}/examples/gtfsrt_csv.toml +0 -0
  12. {microsegments-0.2.3 → microsegments-0.2.5}/examples/make_synth.py +0 -0
  13. {microsegments-0.2.3 → microsegments-0.2.5}/examples/stib1_platform.toml +0 -0
  14. {microsegments-0.2.3 → microsegments-0.2.5}/examples/stib55.toml +0 -0
  15. {microsegments-0.2.3 → microsegments-0.2.5}/examples/stib55_full.toml +0 -0
  16. {microsegments-0.2.3 → microsegments-0.2.5}/examples/stib71_platform.toml +0 -0
  17. {microsegments-0.2.3 → microsegments-0.2.5}/examples/synth.toml +0 -0
  18. {microsegments-0.2.3 → microsegments-0.2.5}/pyproject.toml +0 -0
  19. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/__init__.py +0 -0
  20. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/aggregate.py +0 -0
  21. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/cli.py +0 -0
  22. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/compare.py +0 -0
  23. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/config.py +0 -0
  24. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/contract.py +0 -0
  25. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/hotspots.py +0 -0
  26. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/html/__init__.py +0 -0
  27. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/html/leaflet.min.css +0 -0
  28. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/io/__init__.py +0 -0
  29. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/io/coverage.py +0 -0
  30. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/io/events.py +0 -0
  31. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/io/gtfsrt.py +0 -0
  32. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/io/ids.py +0 -0
  33. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/io/stib.py +0 -0
  34. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/io/tabular.py +0 -0
  35. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/io/timeutil.py +0 -0
  36. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/locate/__init__.py +0 -0
  37. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/locate/common.py +0 -0
  38. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/locate/linear.py +0 -0
  39. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/locate/mapmatch.py +0 -0
  40. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/locate/resample.py +0 -0
  41. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/metrics.py +0 -0
  42. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/network/__init__.py +0 -0
  43. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/network/calendar.py +0 -0
  44. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/network/geometry.py +0 -0
  45. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/network/keys.py +0 -0
  46. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/network/patterns.py +0 -0
  47. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/pipeline.py +0 -0
  48. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/plot.py +0 -0
  49. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/py.typed +0 -0
  50. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/report.py +0 -0
  51. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/scale.py +0 -0
  52. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/schema.py +0 -0
  53. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/segments.py +0 -0
  54. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/simulate.py +0 -0
  55. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/tracks.py +0 -0
  56. {microsegments-0.2.3 → microsegments-0.2.5}/src/microsegments/tune.py +0 -0
  57. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/golden/buckets.parquet +0 -0
  58. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/golden/drops.parquet +0 -0
  59. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/golden/flen.parquet +0 -0
  60. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/golden/obs_day.parquet +0 -0
  61. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/golden/obs_dow.parquet +0 -0
  62. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/golden/passages.parquet +0 -0
  63. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/golden/summary.json +0 -0
  64. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/golden/validation.parquet +0 -0
  65. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/gtfs/agency.parquet +0 -0
  66. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/gtfs/calendar.parquet +0 -0
  67. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/gtfs/calendar_dates.parquet +0 -0
  68. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/gtfs/routes.parquet +0 -0
  69. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/gtfs/shapes.parquet +0 -0
  70. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/gtfs/stop_times.parquet +0 -0
  71. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/gtfs/stops.parquet +0 -0
  72. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/gtfs/trips.parquet +0 -0
  73. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/punctuality/route55.parquet +0 -0
  74. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/speed55_ref.json +0 -0
  75. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/vd55/20250318.parquet +0 -0
  76. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/vd55/20250318.snaps.parquet +0 -0
  77. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/vd55/20250319.parquet +0 -0
  78. {microsegments-0.2.3 → microsegments-0.2.5}/tests/fixtures/stib55/vd55/20250319.snaps.parquet +0 -0
  79. {microsegments-0.2.3 → microsegments-0.2.5}/tests/gtfs_fixtures.py +0 -0
  80. {microsegments-0.2.3 → microsegments-0.2.5}/tests/regression/make_golden.py +0 -0
  81. {microsegments-0.2.3 → microsegments-0.2.5}/tests/t4_fixtures.py +0 -0
  82. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_aggregate.py +0 -0
  83. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_compare.py +0 -0
  84. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_coverage.py +0 -0
  85. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_hotspots.py +0 -0
  86. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_hotspots_criteria.py +0 -0
  87. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_io_events.py +0 -0
  88. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_io_gtfsrt.py +0 -0
  89. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_io_stib.py +0 -0
  90. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_io_tabular.py +0 -0
  91. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_locate_linear.py +0 -0
  92. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_locate_mapmatch.py +0 -0
  93. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_metrics.py +0 -0
  94. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_network_geometry.py +0 -0
  95. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_network_patterns.py +0 -0
  96. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_pipeline_cli.py +0 -0
  97. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_regression_stib55.py +0 -0
  98. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_report_html.py +0 -0
  99. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_scaffold.py +0 -0
  100. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_segments.py +0 -0
  101. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_simulate.py +0 -0
  102. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_tracks.py +0 -0
  103. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_tune.py +0 -0
  104. {microsegments-0.2.3 → microsegments-0.2.5}/tests/test_versions_merge.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: microsegments
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Where do transit vehicles linger? Count vehicle position observations per micro-segment of a line, from GTFS + AVL / GTFS-RT positions.
5
5
  Project-URL: Homepage, https://github.com/GaspardMerten/microsegments
6
6
  Project-URL: Repository, https://github.com/GaspardMerten/microsegments
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.2.3'
22
- __version_tuple__ = version_tuple = (0, 2, 3)
21
+ __version__ = version = '0.2.5'
22
+ __version_tuple__ = version_tuple = (0, 2, 5)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -52,8 +52,8 @@ def render(analysis_or_contract, *, title: str | None = None, lang: str = "fr",
52
52
  scales: dict | None = None, description: str | None = None, show_hotspots: bool = True, **contract_kw) -> str:
53
53
  """The full HTML document as a string. ``contract_kw`` go to ``to_contract`` when an Analysis /
54
54
  RunResult is given. The colour scale is fixed for every page (``microsegments.scale``); ``scales`` is
55
- deprecated and ignored. ``show_hotspots=False`` hides every hotspot element of the one-period view
56
- (list, map markers and outlines, tile, method paragraph); the page reads it from the contract key
55
+ deprecated and ignored. ``show_hotspots=False`` hides every hotspot element
56
+ (list, map markers and outlines, tile, method paragraph), and the retained changes of the two-period view; the page reads it from the contract key
57
57
  ``show_hotspots``, so a page fed with its data later can set that key instead."""
58
58
  c = dict(_contract(analysis_or_contract, **contract_kw))
59
59
  c["tiles"] = bool(tiles)
@@ -33,6 +33,7 @@ h2{font:700 24px/1.2 var(--serif);margin:0 0 6px}
33
33
  p.lede{font-size:clamp(17px,1.6vw,19px);color:var(--ink-2);max-width:68ch;margin:0}
34
34
  .tiles{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line);border:1px solid var(--line);border-radius:14px;overflow:hidden;margin-top:28px}
35
35
  .tiles.t3{grid-template-columns:repeat(3,1fr)}
36
+ .tiles.t2{grid-template-columns:repeat(2,1fr)}
36
37
  .tile{background:var(--surface);padding:18px 18px 16px;min-width:0}
37
38
  .tile b{display:block;font:700 clamp(24px,3vw,32px)/1 var(--serif);font-variant-numeric:tabular-nums}
38
39
  .tile span{display:block;margin-top:8px;color:var(--ink-2);font-size:14px;line-height:1.4}
@@ -213,7 +214,7 @@ const MODE = {fr: {tram: 'Tram', bus: 'Bus', trolleybus: 'Trolleybus', metro: 'M
213
214
  const T = {
214
215
  fr: {
215
216
  title: (m, l) => `Où les ${m} s'attardent-ils\u00a0?`,
216
- lede: (L, tk, m1, m) => `La ligne est découpée en microsegments d'environ ${L} m. Toutes les ${tk} s environ, on relève la position de chaque ${m1} et on compte une observation dans le microsegment où il se trouve. Plus un microsegment cumule d'observations, plus les ${m} y restent longtemps : arrêts, feux, carrefours, files. Une observation correspond à peu près à ${tk} secondes de présence.`,
217
+ lede: (L, tk, m1, m) => `Toutes les ${tk} secondes, on note la position de chaque ${m1}. La ligne est découpée en tronçons d'environ ${L} m et on compte combien de fois un ${m1} y est vu : 1 observation ≈ ${tk} s passées là. Vert = ça roule, rouge = ça bloque. « Écart avec le soir » : le temps en plus par rapport à ${REFH[0]}–${REFH[1]} h, quand la circulation est fluide.`,
217
218
  days: 'Jours', dir: 'Sens', ver: 'Version du tracé', bands: 'Moyennes', metric: 'Mesure', unit: 'Par', stops: 'Arrêts',
218
219
  dow: ['Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa', 'Di'], dowl: ['lundis', 'mardis', 'mercredis', 'jeudis', 'vendredis', 'samedis', 'dimanches'],
219
220
  dowd: ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'],
@@ -300,7 +301,7 @@ const T = {
300
301
  },
301
302
  en: {
302
303
  title: (m, l) => `Where do ${m} linger?`,
303
- lede: (L, tk, m1, m) => `The line is cut into micro-segments of about ${L} m. Roughly every ${tk} s, each ${m1}'s position is recorded and counts as one observation in the micro-segment it is in. The more observations a micro-segment collects, the longer ${m} stay there: stops, traffic lights, junctions, queues. One observation is about ${tk} seconds of presence.`,
304
+ lede: (L, tk, m1, m) => `Every ${tk} seconds, we note where each ${m1} is. The line is cut into stretches of about ${L} m and we count how often a ${m1} is seen there: 1 observation ≈ ${tk} s spent there. Green = moving, red = stuck. "Excess over the evening": the extra time compared with ${REFH[0]}–${REFH[1]} h, when traffic flows.`,
304
305
  days: 'Days', dir: 'Direction', ver: 'Route version', bands: 'Averages', metric: 'Measure', unit: 'Per', stops: 'Stops',
305
306
  dow: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'], dowl: ['Mondays', 'Tuesdays', 'Wednesdays', 'Thursdays', 'Fridays', 'Saturdays', 'Sundays'],
306
307
  dowd: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
@@ -411,7 +412,7 @@ const CT = {
411
412
  tip: {a: (v, s) => `avant : ${v} obs. par passage (≈ ${s} s)`, b: (v, s) => `après : ${v} (≈ ${s} s)`,
412
413
  d: (v, m1) => `<b>${v} s par ${m1}</b>`, unsure: 'différence incertaine', absent: 'absent de la première période',
413
414
  freq: (a, b, m) => `${a} → ${b} ${m} par heure`},
414
- mxsub: (f, t, a, b, m1, stops) => [`De ${f} à ${t}.`, `Chaque case : la différence de temps par ${m1} entre ${a} et ${b}, à cette heure. Vert : plus rapide ; rouge : plus lent ; pâle : incertain${stops ? '' : ' ; hachures : zones d\'arrêt masquées'}. Contours jaunes : changements retenus. Cliquez une heure pour l'afficher sur la carte.`],
415
+ mxsub: (f, t, a, b, m1, stops, hs) => [`De ${f} à ${t}.`, `Chaque case : la différence de temps par ${m1} entre ${a} et ${b}, à cette heure. Vert : plus rapide ; rouge : plus lent ; pâle : incertain${stops ? '' : ' ; hachures : zones d\'arrêt masquées'}.${hs ? ' Contours jaunes : changements retenus.' : ''} Cliquez une heure pour l'afficher sur la carte.`],
415
416
  profsub: (f, t, w, m1, m) => [`De ${f} à ${t}, ${w}.`, `Au-dessus de zéro, chaque ${m1} met plus de temps qu'avant ; en dessous, moins. Pointillés jaunes : ${m} par heure après (échelle de droite).`],
416
417
  days: 'mêmes jours de semaine que chaque période',
417
418
  method: (m1, m, a, b) => `<b>Comparaison de deux périodes.</b> ${a} (avant) et ${b} (après), chacune sur ses propres jours et avec sa propre référence. Les microsegments sont appariés d'une période à l'autre ; ceux qui n'existent que dans une période sont écartés. La différence porte sur les observations par passage, donc le temps par ${m1}, ce qui la rend indépendante de la fréquence. L'incertitude vient d'un rééchantillonnage des jours de chaque période. Quand la fréquence change de plus de 20 %, le tronçon est signalé : un horaire différent (plus de ${m}, plus de files) peut expliquer une partie de l'écart.`,
@@ -438,7 +439,7 @@ const CT = {
438
439
  tip: {a: (v, s) => `before: ${v} obs. per passage (≈ ${s} s)`, b: (v, s) => `after: ${v} (≈ ${s} s)`,
439
440
  d: (v, m1) => `<b>${v} s per ${m1}</b>`, unsure: 'uncertain difference', absent: 'absent from the first period',
440
441
  freq: (a, b, m) => `${a} → ${b} ${m} per hour`},
441
- mxsub: (f, t, a, b, m1, stops) => [`From ${f} to ${t}.`, `Each cell: the difference in time per ${m1} between ${a} and ${b}, at that hour. Green: faster; red: slower; pale: uncertain${stops ? '' : '; hatching: stop zones hidden'}. Yellow outlines: retained changes. Click an hour to show it on the map.`],
442
+ mxsub: (f, t, a, b, m1, stops, hs) => [`From ${f} to ${t}.`, `Each cell: the difference in time per ${m1} between ${a} and ${b}, at that hour. Green: faster; red: slower; pale: uncertain${stops ? '' : '; hatching: stop zones hidden'}.${hs ? ' Yellow outlines: retained changes.' : ''} Click an hour to show it on the map.`],
442
443
  profsub: (f, t, w, m1, m) => [`From ${f} to ${t}, ${w}.`, `Above zero, each ${m1} takes longer than before; below, less. Yellow dots: ${m} per hour after (right scale).`],
443
444
  days: 'same weekdays as each period',
444
445
  method: (m1, m, a, b) => `<b>Comparing two periods.</b> ${a} (before) and ${b} (after), each on its own days and with its own reference. Micro-segments are matched from one period to the other; those that exist in one period only are left out. The difference is in observations per passage, so in time per ${m1}, which makes it independent of the frequency. The uncertainty comes from resampling the days of each period. When the frequency changes by more than 20 %, the stretch is flagged: a different timetable (more ${m}, more queues) may explain part of the difference.`,
@@ -516,7 +517,11 @@ const fmtShort = s => fmtDate(s, {day: '2-digit', month: '2-digit', year: '2-dig
516
517
  const DIRS = D.dirs || [];
517
518
  const PRESENT = [0,1,2,3,4,5,6].filter(w => (D.period.per_dow || [])[w] > 0);
518
519
  st.days = PRESENT.slice();
519
- st.dir = DIRS.length ? DIRS[0].dir : null;
520
+ // direction: ?dir= (or the embedding page's own control, see DIR_CONTROL), else the first one
521
+ st.dir = DIRS.some(d => String(d.dir) === qs.get('dir')) ? +qs.get('dir') : DIRS.length ? DIRS[0].dir : null;
522
+ // contract options for an embedding page: dir_control false hides the page's direction buttons (the
523
+ // host drives the direction with postMessage({ms: 'dir', dir})); method false drops the method section
524
+ const DIR_CONTROL = D.dir_control !== false, METHOD = D.method !== false;
520
525
  st.hour = D.hours.includes(8) ? 8 : D.hours[0];
521
526
  const dirOf = () => DIRS.find(x => x.dir === st.dir);
522
527
  // the entry shown: the display version of the direction, or one of its other versions
@@ -648,7 +653,7 @@ document.addEventListener('mouseout', e => { const b = e.target.closest && e.tar
648
653
  document.addEventListener('focusin', e => { const b = e.target.closest && e.target.closest('.qm'); if (b && !popPinned && b.matches(':focus-visible')) openPop(b, false); });
649
654
  window.addEventListener('scroll', () => { if (popBtn) { if (popBtn.isConnected) openPop(popBtn, popPinned); else closePop(); } }, {passive: true});
650
655
  // stop-zone hotspots are listed only when stop zones are shown
651
- const hsOn = () => isCmp() || D.show_hotspots !== false;
656
+ const hsOn = () => D.show_hotspots !== false;
652
657
  const hotDir = () => !hsOn() ? [] : (D.hotspots || []).filter(h => (h.dir ?? h.direction_id) === st.dir && (!h.pattern_uid || h.pattern_uid === (dirOf() || {}).pattern_uid)).sort((a, b) => a.rank - b.rank);
653
658
  const hotAll = () => hotDir().filter(h => st.stops || h.zone !== 'stop');
654
659
  // the list (and the map markers) show the top hotspots unless "show all" is on
@@ -717,7 +722,7 @@ function cTipHtml(E, v) {
717
722
  if (v.stop) h += `<br><i>${l.stop}</i>`;
718
723
  return h;
719
724
  }
720
- const chgAll = () => CMP ? (CMP.changes || []).filter(c => c.dir === st.dir && (!c.pattern_uid || c.pattern_uid === (dirOf() || {}).pattern_uid)).sort((a, b) => a.rank - b.rank) : [];
725
+ const chgAll = () => CMP && hsOn() ? (CMP.changes || []).filter(c => c.dir === st.dir && (!c.pattern_uid || c.pattern_uid === (dirOf() || {}).pattern_uid)).sort((a, b) => a.rank - b.rank) : [];
721
726
  const chgShown = () => chgAll().filter(c => st.stops || c.zone !== 'stop');
722
727
  const chgDir = () => st.hotAll ? chgShown() : chgShown().slice(0, HOT_TOP);
723
728
  const signCol = s => s < 0 ? FASTC : SLOWC;
@@ -853,12 +858,14 @@ function tiles() {
853
858
  if (isCmp()) {
854
859
  const c = ctx().tiles, ch = CMP.changes || [];
855
860
  document.getElementById('tiles').classList.remove('t3');
861
+ document.getElementById('tiles').classList.toggle('t2', !hsOn());
856
862
  document.getElementById('tiles').innerHTML = [[nf(CMP.a.days, 0), `${c.a} (${perLabel(CMP.a)})`], [nf(CMP.b.days, 0), `${c.b} (${perLabel(CMP.b)})`],
857
- [nf(ch.filter(x => x.sign > 0).length, 0), c.slower], [nf(ch.filter(x => x.sign < 0).length, 0), c.faster]]
863
+ ...(hsOn() ? [[nf(ch.filter(x => x.sign > 0).length, 0), c.slower], [nf(ch.filter(x => x.sign < 0).length, 0), c.faster]] : [])]
858
864
  .map(([b, s]) => `<div class="tile"><b>${b}</b><span>${esc(s)}</span></div>`).join('');
859
865
  return;
860
866
  }
861
867
  const big = v => v >= 1e6 ? nf(v / 1e6, 1) + (st.lang === 'fr' ? ' M' : 'M') : v >= 1e4 ? nf(v / 1e3, 0) + (st.lang === 'fr' ? ' k' : 'k') : nf(v, 0);
868
+ document.getElementById('tiles').classList.remove('t2');
862
869
  document.getElementById('tiles').classList.toggle('t3', !hsOn());
863
870
  document.getElementById('tiles').innerHTML = [
864
871
  [nf(D.period.days, 0), esc(l.tiles.days(D.period.days, exclSummary(D.period.excluded)))],
@@ -874,6 +881,7 @@ function buttons(el, items, onclick) {
874
881
  el.innerHTML = '';
875
882
  for (const [k, t, title] of items) { const b = document.createElement('button'); b.type = 'button'; b.textContent = t; b.dataset.k = k; if (title) b.title = title; b.onclick = () => onclick(k); el.append(b); }
876
883
  }
884
+ let SETDIR = null;
877
885
  function buildControls() {
878
886
  const l = tx();
879
887
  buttons($('langs'), [['fr', 'FR'], ['en', 'EN']], k => { st.lang = k; buildControls(); texts(); tiles(); drawAll(); });
@@ -889,6 +897,8 @@ function buildControls() {
889
897
  const setDir = k => { st.dir = +k; st.ver = null; st.hot = null; st.chg = null; drawAll(); };
890
898
  buttons($('dirs'), dirItems, setDir);
891
899
  buttons($('mxdirs'), dirItems, setDir);
900
+ $('dirs').closest('.grp').style.display = DIR_CONTROL ? '' : 'none'; $('mxdirs').style.display = DIR_CONTROL ? '' : 'none';
901
+ SETDIR = setDir;
892
902
  buttons($('bands'), Object.keys(BANDDEF).map(k => [k, l.bandl[k], `${BANDDEF[k][0]}–${BANDDEF[k][1]} h`]), k => { stop(); st.band = st.band === k ? null : k; render(); });
893
903
  $('g_mode').hidden = !CMP;
894
904
  if (CMP) buttons($('modes'), [['one', l.modes.one], ['cmp', l.modes.cmp]], k => { st.mode = k; st.ver = null; st.hot = null; st.chg = null; buildControls(); texts(); tiles(); drawAll(); });
@@ -1079,7 +1089,7 @@ function drawMatrix() {
1079
1089
  svg.innerHTML = s;
1080
1090
  MX = {E, rows, m, RH, W, Ltot, tip: cm ? cTipHtml : tipHtml};
1081
1091
  const what = l.metrics[st.metric].toLowerCase() + (st.per10 ? ' (10 m)' : ' (30 m)');
1082
- setSub($('mxsub'), cm ? ctx().mxsub(E.from, E.to, perLabel(CMP.a), perLabel(CMP.b), noun(false), st.stops) : l.mxsub(E.from, E.to, daysLabel(), what, st.stops, hsOn() && hotOfDir().length > 0));
1092
+ setSub($('mxsub'), cm ? ctx().mxsub(E.from, E.to, perLabel(CMP.a), perLabel(CMP.b), noun(false), st.stops, chgDir().length > 0) : l.mxsub(E.from, E.to, daysLabel(), what, st.stops, hsOn() && hotOfDir().length > 0));
1083
1093
  }
1084
1094
  $('mx').addEventListener('mousemove', e => {
1085
1095
  if (!MX) return;
@@ -1213,6 +1223,15 @@ document.addEventListener('fullscreenchange', () => { if (!document.fullscreenEl
1213
1223
  document.addEventListener('keydown', e => { if (e.key === 'Escape' && mxCard.classList.contains('full')) setFull(false); });
1214
1224
 
1215
1225
  buildControls(); texts(); tiles(); initMap(); drawAll();
1226
+ document.querySelector('section.method').hidden = !METHOD;
1227
+ // embedded: tell the host the directions, follow its direction control
1228
+ if (window.parent !== window) {
1229
+ try { parent.postMessage({ms: 'dirs', dir: st.dir, dirs: DIRS.map(d => ({dir: d.dir, from: d.from, to: d.to}))}, '*'); } catch (x) {}
1230
+ window.addEventListener('message', e => {
1231
+ const m = e.data || {};
1232
+ if (m.ms === 'dir' && SETDIR && DIRS.some(d => d.dir === +m.dir) && +m.dir !== st.dir) SETDIR(m.dir);
1233
+ });
1234
+ }
1216
1235
  </script>
1217
1236
  </body>
1218
1237
  </html>
File without changes
File without changes
File without changes