d3blocks 2.3.2__tar.gz → 2.3.3__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 (172) hide show
  1. {d3blocks-2.3.2/d3blocks.egg-info → d3blocks-2.3.3}/PKG-INFO +5 -3
  2. {d3blocks-2.3.2 → d3blocks-2.3.3}/README.md +4 -2
  3. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/__init__.py +1 -1
  4. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/d3blocks.py +6 -4
  5. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/Flowgraph.py +26 -5
  6. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/d3js/d3.flowgraph.js +141 -5
  7. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/d3js/flowgraph.css +34 -0
  8. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/movingbubbles/d3js/movingbubbles.html.j2 +33 -28
  9. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_flowgraph.py +6 -1
  10. {d3blocks-2.3.2 → d3blocks-2.3.3/d3blocks.egg-info}/PKG-INFO +5 -3
  11. {d3blocks-2.3.2 → d3blocks-2.3.3}/LICENSE +0 -0
  12. {d3blocks-2.3.2 → d3blocks-2.3.3}/MANIFEST.in +0 -0
  13. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/_shared/__init__.py +0 -0
  14. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/_shared/d3js/__init__.py +0 -0
  15. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/_shared/d3js/d3.v7.min.js +0 -0
  16. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/_shared/d3js/theme.js +0 -0
  17. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/_shared/d3js/walkthrough.css +0 -0
  18. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/_shared/d3js/walkthrough.js +0 -0
  19. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/chord/Chord.py +0 -0
  20. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/chord/__init__.py +0 -0
  21. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/chord/d3js/__init__.py +0 -0
  22. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/chord/d3js/chord.css +0 -0
  23. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/chord/d3js/chord.html.j2 +0 -0
  24. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/chord/d3js/chord.js +0 -0
  25. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/circlepacking/Circlepacking.py +0 -0
  26. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/circlepacking/__init__.py +0 -0
  27. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/circlepacking/d3js/__init__.py +0 -0
  28. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/circlepacking/d3js/circlepacking.css +0 -0
  29. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/circlepacking/d3js/circlepacking.html.j2 +0 -0
  30. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/circlepacking/d3js/d3.v6.min.js +0 -0
  31. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/circlepacking/d3js/lodash.min.js +0 -0
  32. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/elasticgraph/__init__.py +0 -0
  33. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/elasticgraph/d3js/.gitkeep +0 -0
  34. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/elasticgraph/d3js/__init__.py +0 -0
  35. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/elasticgraph/d3js/d3.v2.js +0 -0
  36. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/elasticgraph/d3js/elasticgraph.css +0 -0
  37. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/elasticgraph/d3js/elasticgraph.html.j2 +0 -0
  38. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/elasticgraph/d3js/elasticgraph.js +0 -0
  39. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/elasticgraph/elasticgraph.py +0 -0
  40. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/erd/Erd.py +0 -0
  41. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/erd/__init__.py +0 -0
  42. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/erd/d3js/__init__.py +0 -0
  43. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/erd/d3js/d3.erd.js +0 -0
  44. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/erd/d3js/dagre.LICENSE +0 -0
  45. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/erd/d3js/dagre.min.js +0 -0
  46. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/erd/d3js/erd.css +0 -0
  47. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/erd/d3js/erd.html.j2 +0 -0
  48. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/examples.py +0 -0
  49. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/examples_docs.py +0 -0
  50. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/__init__.py +0 -0
  51. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/d3js/__init__.py +0 -0
  52. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/d3js/d3.v7.min.js +0 -0
  53. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/d3js/dagre.LICENSE +0 -0
  54. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/d3js/dagre.min.js +0 -0
  55. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/d3js/elk.LICENSE.md +0 -0
  56. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/d3js/elk.bundled.js +0 -0
  57. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/flowgraph/d3js/flowgraph.html.j2 +0 -0
  58. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/heatmap/Heatmap.py +0 -0
  59. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/heatmap/__init__.py +0 -0
  60. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/heatmap/d3js/__init__.py +0 -0
  61. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/heatmap/d3js/d3.scale.chromatic.v1.min.js +0 -0
  62. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/heatmap/d3js/d3.v4.js +0 -0
  63. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/heatmap/d3js/heatmap.css +0 -0
  64. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/heatmap/d3js/heatmap.html.j2 +0 -0
  65. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/heatmap/d3js/matrix.html.j2 +0 -0
  66. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/Imageslider.py +0 -0
  67. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/__init__.py +0 -0
  68. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/d3js/.keep +0 -0
  69. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/d3js/__init__.py +0 -0
  70. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/d3js/imageslider.css +0 -0
  71. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/d3js/imageslider.html.j2 +0 -0
  72. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/d3js/imageslider.js +0 -0
  73. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/d3js/jquery-2.1.1.js +0 -0
  74. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/d3js/modernizr.js +0 -0
  75. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/imageslider/d3js/reset.css +0 -0
  76. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/logo.txt +0 -0
  77. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/maps/Maps.py +0 -0
  78. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/maps/__init__.py +0 -0
  79. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/maps/d3js/__init__.py +0 -0
  80. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/maps/d3js/d3.v6.min.js +0 -0
  81. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/maps/d3js/geojson.zip +0 -0
  82. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/maps/d3js/maps.css +0 -0
  83. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/maps/d3js/maps.html.j2 +0 -0
  84. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/maps/d3js/world.geojson +0 -0
  85. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/matrix/Matrix.py +0 -0
  86. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/matrix/__init__.py +0 -0
  87. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/matrix/d3js/__init__.py +0 -0
  88. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/matrix/d3js/d3.scale.chromatic.v1.min.js +0 -0
  89. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/matrix/d3js/d3.v4.js +0 -0
  90. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/matrix/d3js/matrix.html.j2 +0 -0
  91. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/movingbubbles/Movingbubbles.py +0 -0
  92. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/movingbubbles/__init__.py +0 -0
  93. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/movingbubbles/d3js/__init__.py +0 -0
  94. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/movingbubbles/d3js/d3-3-5-5.min.js +0 -0
  95. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/movingbubbles/d3js/movingbubbles.css +0 -0
  96. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/particles/Particles.py +0 -0
  97. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/particles/__init__.py +0 -0
  98. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/particles/d3js/__init__.py +0 -0
  99. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/particles/d3js/d3-scale-chromatic.v1.min.js +0 -0
  100. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/particles/d3js/d3.v4.min.js +0 -0
  101. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/particles/d3js/particles.html.j2 +0 -0
  102. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/radialgraph/Radialgraph.py +0 -0
  103. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/radialgraph/__init__.py +0 -0
  104. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/radialgraph/d3js/__init__ .py +0 -0
  105. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/radialgraph/d3js/d3.radialgraph.js +0 -0
  106. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/radialgraph/d3js/d3.v7.min.js +0 -0
  107. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/radialgraph/d3js/radialgraph.css +0 -0
  108. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/radialgraph/d3js/radialgraph.html.j2 +0 -0
  109. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sankey/Sankey.py +0 -0
  110. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sankey/__init__.py +0 -0
  111. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sankey/d3js/__init__.py +0 -0
  112. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sankey/d3js/sankey.css +0 -0
  113. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sankey/d3js/sankey.html.j2 +0 -0
  114. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sankey/d3js/sankey.js +0 -0
  115. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/scatter/Scatter.py +0 -0
  116. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/scatter/__init__.py +0 -0
  117. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/scatter/d3js/__init__.py +0 -0
  118. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/scatter/d3js/associations.js +0 -0
  119. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/scatter/d3js/d3.v4.min.js +0 -0
  120. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/scatter/d3js/scatter.css +0 -0
  121. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/scatter/d3js/scatter.html.j2 +0 -0
  122. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sequence/Sequence.py +0 -0
  123. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sequence/__init__.py +0 -0
  124. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sequence/d3js/__init__.py +0 -0
  125. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sequence/d3js/d3.sequence.js +0 -0
  126. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sequence/d3js/sequence.css +0 -0
  127. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/sequence/d3js/sequence.html.j2 +0 -0
  128. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/__init__.py +0 -0
  129. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_all_examples.py +0 -0
  130. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_chord_margins.py +0 -0
  131. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_d3blocks.py +0 -0
  132. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_erd.py +0 -0
  133. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_medium_charts.py +0 -0
  134. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_movingbubbles_color.py +0 -0
  135. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_movingbubbles_timedelta.py +0 -0
  136. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_radialgraph.py +0 -0
  137. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tests/test_sequence.py +0 -0
  138. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/timeseries/Timeseries.py +0 -0
  139. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/timeseries/__init__.py +0 -0
  140. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/timeseries/d3js/__init__.py +0 -0
  141. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/timeseries/d3js/d3.v3.js +0 -0
  142. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/timeseries/d3js/timeseries.css +0 -0
  143. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/timeseries/d3js/timeseries.html.j2 +0 -0
  144. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/timeseries/d3js/timeseries.js +0 -0
  145. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tree/Tree.py +0 -0
  146. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tree/__init__.py +0 -0
  147. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tree/d3js/__init__.py +0 -0
  148. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tree/d3js/collapsibleTree.js +0 -0
  149. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tree/d3js/d3.tree.js +0 -0
  150. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tree/d3js/d3.v4.min.js +0 -0
  151. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tree/d3js/tree.css +0 -0
  152. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/tree/d3js/tree.html.j2 +0 -0
  153. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/treemap/Treemap.py +0 -0
  154. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/treemap/__init__.py +0 -0
  155. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/treemap/d3js/__init__.py +0 -0
  156. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/treemap/d3js/d3.v4.min.js +0 -0
  157. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/treemap/d3js/treemap.css +0 -0
  158. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/treemap/d3js/treemap.html.j2 +0 -0
  159. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/utils.py +0 -0
  160. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/violin/Violin.py +0 -0
  161. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/violin/__init__.py +0 -0
  162. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/violin/d3js/__init__.py +0 -0
  163. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/violin/d3js/d3-scale-chromatic.v1.min.js +0 -0
  164. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/violin/d3js/d3.v4.min.js +0 -0
  165. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/violin/d3js/violin.css +0 -0
  166. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks/violin/d3js/violin.html.j2 +0 -0
  167. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks.egg-info/SOURCES.txt +0 -0
  168. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks.egg-info/dependency_links.txt +0 -0
  169. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks.egg-info/requires.txt +0 -0
  170. {d3blocks-2.3.2 → d3blocks-2.3.3}/d3blocks.egg-info/top_level.txt +0 -0
  171. {d3blocks-2.3.2 → d3blocks-2.3.3}/pyproject.toml +0 -0
  172. {d3blocks-2.3.2 → d3blocks-2.3.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: d3blocks
3
- Version: 2.3.2
3
+ Version: 2.3.3
4
4
  Summary: Python package d3blocks.
5
5
  Author-email: Erdogan Taskesen <erdogant@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -156,12 +156,14 @@ A few practical rules of thumb: prefer `st.iframe` over the older `components.ht
156
156
 
157
157
  ### [MovingBubbles: Daily Life of a European](https://d3blocks.github.io/d3blocks/MovingBubbles.html#daily-life-of-european)
158
158
 
159
- <p align="center">
159
+
160
+ <p align="left">
160
161
  <a href="https://d3blocks.github.io/d3blocks/MovingBubbles.html#daily-life-of-european">
161
- <img src="https://erdogant.github.io/docs/d3blocks/daily_life_of_european.gif" width="600" alt="MovingBubbles: Daily Life of a European" />
162
+ <img src="https://erdogant.github.io/docs/d3blocks/daily_life_of_european.gif" width="1000"/>
162
163
  </a>
163
164
  </p>
164
165
 
166
+
165
167
  ---
166
168
 
167
169
 
@@ -125,12 +125,14 @@ A few practical rules of thumb: prefer `st.iframe` over the older `components.ht
125
125
 
126
126
  ### [MovingBubbles: Daily Life of a European](https://d3blocks.github.io/d3blocks/MovingBubbles.html#daily-life-of-european)
127
127
 
128
- <p align="center">
128
+
129
+ <p align="left">
129
130
  <a href="https://d3blocks.github.io/d3blocks/MovingBubbles.html#daily-life-of-european">
130
- <img src="https://erdogant.github.io/docs/d3blocks/daily_life_of_european.gif" width="600" alt="MovingBubbles: Daily Life of a European" />
131
+ <img src="https://erdogant.github.io/docs/d3blocks/daily_life_of_european.gif" width="1000"/>
131
132
  </a>
132
133
  </p>
133
134
 
135
+
134
136
  ---
135
137
 
136
138
 
@@ -10,7 +10,7 @@ from d3blocks.utils import (
10
10
 
11
11
  __author__ = 'Erdogan Taskesen'
12
12
  __email__ = 'erdogant@gmail.com'
13
- __version__ = '2.3.2'
13
+ __version__ = '2.3.3'
14
14
 
15
15
  # Setup root logger
16
16
  import logging
@@ -1482,12 +1482,14 @@ class D3Blocks():
1482
1482
  Movement of samples. A smaller number is slower/smoother movement.
1483
1483
  * 0.1: min
1484
1484
  * 10: max
1485
+
1485
1486
  Sets the initial value of the "Damper" slider in the Physics panel.
1486
1487
  collision : float, (default: 0.15)
1487
1488
  Strength of the push-apart between overlapping bubbles [0-1].
1488
1489
  * 0: no collision (bubbles may overlap freely; cheapest for large datasets).
1489
1490
  * 0.15: default. Calm, settles quickly also with hundreds of bubbles.
1490
1491
  * 0.5 and higher: bubbles are pushed apart strongly; dense clusters can start to pulse.
1492
+
1491
1493
  Sets the initial value of the "Collision strength" slider in the Physics panel.
1492
1494
 
1493
1495
  fontsize : int, (default: 14)
@@ -1550,16 +1552,16 @@ class D3Blocks():
1550
1552
  shape : str, (default: None)
1551
1553
  Name of a categorical column in ``df`` that is mapped to bubble shapes (circle, square, triangle, diamond).
1552
1554
  Sets the initial value of Layout -> Shape in the left side panel.
1553
- * None: all bubbles are circles.
1554
- * 'country': one shape per unique value in the column 'country'.
1555
+ Default (None): all bubbles are circles. Use e.g. ``'country'`` for one shape
1556
+ per unique value in the ``country`` column.
1555
1557
  tooltip : str, (default: None)
1556
1558
  Name of a column in ``df`` (or the ``state`` column) of which the value is shown when hovering a bubble.
1557
1559
  Sets the initial value of Layout -> Tooltip in the left side panel.
1558
- * None: no tooltip.
1560
+ Default (None): no tooltip.
1559
1561
  label : str, (default: None)
1560
1562
  Name of a column in ``df`` (or the ``state`` column) that is written on each bubble.
1561
1563
  Sets the initial value of Layout -> Label in the left side panel.
1562
- * None: no label.
1564
+ Default (None): no label.
1563
1565
 
1564
1566
  cmap : String, (default: 'Set1')
1565
1567
  All colors can be reversed with '_r', e.g. 'binary' to 'binary_r'
@@ -304,6 +304,12 @@ def set_edge_properties(df, edge_color='#8c8c8c', logger=None, **kwargs):
304
304
  _warn_unknown(anims.dropna(), ANIMATIONS, 'edge animation', 'chart default', logger)
305
305
  out['animation'] = anims.where(anims.isin(ANIMATIONS), None).values
306
306
 
307
+ # Mermaid <--> (and explicit DataFrame column) draws arrowheads on both ends.
308
+ if 'bidirectional' in df.columns:
309
+ out['bidirectional'] = df['bidirectional'].fillna(False).astype(bool).values
310
+ else:
311
+ out['bidirectional'] = False
312
+
307
313
  # Line width follows weight when weights differ, otherwise a constant width.
308
314
  w = out['weight'].values
309
315
  if len(w) and np.ptp(w) > 0:
@@ -741,6 +747,7 @@ def from_mermaid(text, logger=None):
741
747
  node(name, label, shape).update(extra)
742
748
  if label is not None or shape is not None or "class" in extra:
743
749
  define(name, lineno)
750
+ # chain edge: (source, target, label, style, weight, bidirectional)
744
751
  edges.extend([list(e) + [None, lineno] for e in chain_edges])
745
752
  if stack:
746
753
  raise ValueError(
@@ -783,9 +790,11 @@ def from_mermaid(text, logger=None):
783
790
  '"flowchart LR; A[Start] --> B{Valid?}", Markdown with a ```mermaid block, '
784
791
  'or a path to a %s file.' % '/'.join(MERMAID_FILE_SUFFIXES))
785
792
  # Invisible links (~~~) only count for linkStyle numbering.
786
- rows = [e[:6] for e in edges if e[3] != "invisible"]
793
+ # Edge row: source, target, label, style, weight, bidirectional, color [, lineno]
794
+ rows = [e[:7] for e in edges if e[3] != "invisible"]
787
795
  df = pd.DataFrame(
788
- rows, columns=["source", "target", "label", "style", "weight", "color"]
796
+ rows,
797
+ columns=["source", "target", "label", "style", "weight", "bidirectional", "color"],
789
798
  )
790
799
  if df["color"].isna().all():
791
800
  df = df.drop(columns='color')
@@ -903,8 +912,9 @@ def _apply_link_styles(edges, link_styles):
903
912
  )
904
913
  props = _mermaid_props(parts[2])
905
914
  for i in idx:
915
+ # Edge: [source, target, label, style, weight, bidirectional, color, lineno]
906
916
  if props.get("stroke"):
907
- edges[i][5] = props["stroke"]
917
+ edges[i][6] = props["stroke"]
908
918
  if props.get("stroke-dasharray"):
909
919
  edges[i][3] = "dashed"
910
920
 
@@ -1155,7 +1165,12 @@ def _mermaid_group(stmt, i, node):
1155
1165
 
1156
1166
 
1157
1167
  def _mermaid_chain(stmt, node, edges):
1158
- """Parse 'A --> B -->|x| C & D' and append edges."""
1168
+ """Parse 'A --> B -->|x| C & D' and append edges.
1169
+
1170
+ Arrow forms: --> (forward), <-- (reverse), <--> (bidirectional), --- (undirected).
1171
+ Bidirectional edges are one row with bidirectional=True so the renderer draws
1172
+ arrowheads on both ends; reverse arrows swap source and target.
1173
+ """
1159
1174
  left, i = _mermaid_group(stmt, 0, node)
1160
1175
  while True:
1161
1176
  while i < len(stmt) and stmt[i].isspace():
@@ -1176,9 +1191,15 @@ def _mermaid_chain(stmt, node, edges):
1176
1191
  right, i = _mermaid_group(stmt, i, node)
1177
1192
  style = "invisible" if "~" in arrow else "dotted" if "." in arrow else "solid"
1178
1193
  weight = 3 if "=" in arrow else 1
1194
+ # <--> both ways; <-- reverse (swap ends); --> / --- forward.
1195
+ starts_left = arrow.startswith('<')
1196
+ ends_right = arrow.endswith('>') or arrow.endswith('o') or arrow.endswith('x')
1197
+ bidirectional = starts_left and ends_right
1198
+ reverse = starts_left and not ends_right
1179
1199
  for s in left:
1180
1200
  for t in right:
1181
- edges.append((s, t, _mermaid_label(label), style, weight))
1201
+ src, tgt = (t, s) if reverse else (s, t)
1202
+ edges.append((src, tgt, _mermaid_label(label), style, weight, bidirectional))
1182
1203
  left = right
1183
1204
 
1184
1205
 
@@ -22,7 +22,8 @@
22
22
  showEdgeLabels: OPTS.showEdgeLabels,
23
23
  showGroups: OPTS.showGroups,
24
24
  fontsize: OPTS.fontsize,
25
- pinned: null // { type: 'node' | 'group' | 'edge', id }
25
+ pinned: null, // { type: 'node' | 'group' | 'edge', id }
26
+ liveControl: false // true once setStatus / setEdgeActive is used
26
27
  };
27
28
 
28
29
  var FONT_FAMILY = '"Helvetica", Arial, sans-serif';
@@ -763,7 +764,8 @@
763
764
  .attr('id', function (d) { return 'fg-path-' + d.idx; })
764
765
  .style('stroke', function (d) { return paint(d.color); })
765
766
  .attr('stroke-width', function (d) { return d.width; })
766
- .attr('marker-end', function (d) { return markerFor(d.color); });
767
+ .attr('marker-end', function (d) { return markerFor(d.color); })
768
+ .attr('marker-start', function (d) { return d.bidirectional ? markerFor(d.color) : null; });
767
769
  eenter.append('path').attr('class', 'fg-edge-flow')
768
770
  .style('stroke', function (d) { return paint(d.color); })
769
771
  .attr('stroke-width', function (d) { return d.width + 1.5; });
@@ -803,13 +805,16 @@
803
805
  .attr('transform', function (d) { return 'translate(' + d.x + ',' + d.y + ')'; });
804
806
  nenter.append('path').attr('class', 'fg-shape');
805
807
  nenter.append('text').attr('class', 'fg-label').attr('text-anchor', 'middle');
808
+ var badge = nenter.append('g').attr('class', 'fg-badge').style('display', 'none');
809
+ badge.append('circle').attr('class', 'fg-badge-bg').attr('r', 9);
810
+ badge.append('text').attr('class', 'fg-badge-text').attr('text-anchor', 'middle').attr('dominant-baseline', 'central');
806
811
  nenter
807
812
  .on('mouseenter', function (ev, d) { highlight({ type: 'node', id: d.name }); showNodeTooltip(ev, d); })
808
813
  .on('mousemove', moveTooltip)
809
814
  .on('mouseleave', function () { hideTooltip(); restoreHighlight(); })
810
815
  .on('click', function (ev, d) { ev.stopPropagation(); togglePin({ type: 'node', id: d.name }); });
811
816
  if (state.draggable) nenter.call(drag).classed('fg-draggable', true);
812
- var nall = nenter.merge(nsel).style('--c', function (d) { return d.color; });
817
+ var nall = nenter.merge(nsel).style('--c', function (d) { return d._liveColor || d.color; });
813
818
  nall.select('path.fg-shape').attr('d', shapePath);
814
819
  nall.select('text.fg-label').each(function (d) {
815
820
  var text = d3.select(this).style('font-size', fs + 'px');
@@ -824,6 +829,7 @@
824
829
  maybe(nall, t).attr('transform', function (d) { return 'translate(' + d.x + ',' + d.y + ')'; });
825
830
 
826
831
  restoreHighlight();
832
+ applyLiveStyles();
827
833
  }
828
834
 
829
835
  // ---------------------------------------------------------------- animation
@@ -835,7 +841,13 @@
835
841
  var SVG_NS = 'http://www.w3.org/2000/svg';
836
842
 
837
843
  function effectiveAnimation(e) {
838
- if (!state.animate || reduceMotion) return 'none';
844
+ if (reduceMotion) return 'none';
845
+ // Live status mode: only edges explicitly marked active animate.
846
+ if (state.liveControl) {
847
+ if (!e._liveActive) return 'none';
848
+ return e.animation || state.animation || 'pulse';
849
+ }
850
+ if (!state.animate) return 'none';
839
851
  return e.animation || state.animation;
840
852
  }
841
853
 
@@ -1075,6 +1087,8 @@
1075
1087
  var meta = [d.shape];
1076
1088
  if (d.group && groupById.has(d.group)) meta.push(escapeHtml(groupById.get(d.group).label));
1077
1089
  meta.push((inEdges.get(d.name) || []).length + ' in · ' + (outEdges.get(d.name) || []).length + ' out');
1090
+ if (d._liveStatus) meta.push('status: ' + d._liveStatus);
1091
+ if (d._liveCount != null && d._liveCount > 0) meta.push('count: ' + d._liveCount);
1078
1092
  parts.push('<div class="fg-tt-meta">' + meta.join(' · ') + '</div>');
1079
1093
  tooltip.html(parts.join('')).classed('open', true);
1080
1094
  moveTooltip(ev);
@@ -1083,6 +1097,12 @@
1083
1097
  var html = '<div class="fg-tt-title">' + escapeHtml(endLabel(d.source).replace(/\n/g, ' ')) + ' → ' +
1084
1098
  escapeHtml(endLabel(d.target).replace(/\n/g, ' ')) + '</div>';
1085
1099
  if (d.label) html += '<div>' + escapeHtml(d.label) + '</div>';
1100
+ if (d._liveActive || (d._liveCount != null && d._liveCount > 0)) {
1101
+ var bits = [];
1102
+ if (d._liveActive) bits.push('active');
1103
+ if (d._liveCount != null) bits.push('count: ' + d._liveCount);
1104
+ html += '<div class="fg-tt-meta">' + bits.join(' · ') + '</div>';
1105
+ }
1086
1106
  tooltip.html(html).classed('open', true);
1087
1107
  moveTooltip(ev);
1088
1108
  }
@@ -1579,5 +1599,121 @@
1579
1599
  throw err;
1580
1600
  });
1581
1601
 
1582
- window.__flowgraph = { state: state, nodes: nodes, edges: edges, groups: usedGroups, relayout: relayout, fit: fit, ready: ready, walkthrough: walkthrough };
1602
+ // ---------------------------------------------------------------- live status
1603
+ // External pipeline drives node/edge status via setStatus without relayout.
1604
+ // Status values: idle | active | done | error (others are accepted as class suffixes).
1605
+ function applyLiveStyles() {
1606
+ gNodes.selectAll('g.fg-node').each(function (d) {
1607
+ var el = d3.select(this);
1608
+ var st = d._liveStatus || 'idle';
1609
+ el.classed('fg-live', st === 'active');
1610
+ el.classed('fg-error', st === 'error');
1611
+ el.classed('fg-done', st === 'done');
1612
+ el.style('--c', d._liveColor || d.color);
1613
+ var count = d._liveCount;
1614
+ var show = count != null && count > 0;
1615
+ var badge = el.select('g.fg-badge');
1616
+ if (badge.empty()) return;
1617
+ badge.style('display', show ? null : 'none');
1618
+ if (show) {
1619
+ var label = count > 999 ? '999+' : String(count);
1620
+ var r = label.length > 2 ? 11 : 9;
1621
+ badge.select('circle').attr('r', r);
1622
+ badge.select('text').text(label).style('font-size', label.length > 2 ? '9px' : '10px');
1623
+ // Top-right of the node box (node is centered at 0,0).
1624
+ badge.attr('transform', 'translate(' + (d.width / 2 - 2) + ',' + (-d.height / 2 + 2) + ')');
1625
+ }
1626
+ });
1627
+ gEdges.selectAll('g.fg-edge-g').classed('fg-live-edge', function (d) { return !!d._liveActive; });
1628
+ if (state.liveControl) refreshAnimations();
1629
+ }
1630
+
1631
+ function setNodeStatus(name, opts) {
1632
+ opts = opts || {};
1633
+ var n = nodeById.get(name);
1634
+ if (!n) return false;
1635
+ if (opts.status !== undefined) n._liveStatus = opts.status || 'idle';
1636
+ if (opts.count !== undefined) n._liveCount = opts.count;
1637
+ if (opts.color !== undefined) n._liveColor = opts.color || null;
1638
+ applyLiveStyles();
1639
+ return true;
1640
+ }
1641
+
1642
+ function setEdgeActive(source, target, active, count) {
1643
+ state.liveControl = true;
1644
+ var found = false;
1645
+ edges.forEach(function (e) {
1646
+ if (e.source === source && e.target === target) {
1647
+ e._liveActive = !!active;
1648
+ if (count !== undefined) e._liveCount = count;
1649
+ found = true;
1650
+ }
1651
+ });
1652
+ if (found) applyLiveStyles();
1653
+ return found;
1654
+ }
1655
+
1656
+ function setStatus(snapshot) {
1657
+ snapshot = snapshot || {};
1658
+ state.liveControl = true;
1659
+ // Reset then apply so omitted nodes/edges go idle.
1660
+ nodes.forEach(function (n) {
1661
+ n._liveStatus = 'idle';
1662
+ n._liveCount = 0;
1663
+ n._liveColor = null;
1664
+ });
1665
+ edges.forEach(function (e) {
1666
+ e._liveActive = false;
1667
+ e._liveCount = 0;
1668
+ });
1669
+ var nodeMap = snapshot.nodes || {};
1670
+ Object.keys(nodeMap).forEach(function (name) {
1671
+ var n = nodeById.get(name), s = nodeMap[name] || {};
1672
+ if (!n) return;
1673
+ if (s.status !== undefined) n._liveStatus = s.status || 'idle';
1674
+ if (s.count !== undefined) n._liveCount = s.count;
1675
+ if (s.color !== undefined) n._liveColor = s.color || null;
1676
+ });
1677
+ (snapshot.edges || []).forEach(function (ed) {
1678
+ if (!ed || ed.source == null || ed.target == null) return;
1679
+ edges.forEach(function (e) {
1680
+ if (e.source === ed.source && e.target === ed.target) {
1681
+ e._liveActive = !!ed.active;
1682
+ if (ed.count !== undefined) e._liveCount = ed.count;
1683
+ }
1684
+ });
1685
+ });
1686
+ applyLiveStyles();
1687
+ }
1688
+
1689
+ function resetStatus() {
1690
+ nodes.forEach(function (n) {
1691
+ n._liveStatus = null;
1692
+ n._liveCount = null;
1693
+ n._liveColor = null;
1694
+ });
1695
+ edges.forEach(function (e) {
1696
+ e._liveActive = false;
1697
+ e._liveCount = null;
1698
+ });
1699
+ state.liveControl = false;
1700
+ applyLiveStyles();
1701
+ refreshAnimations();
1702
+ }
1703
+
1704
+ window.__flowgraph = {
1705
+ state: state,
1706
+ nodes: nodes,
1707
+ edges: edges,
1708
+ groups: usedGroups,
1709
+ relayout: relayout,
1710
+ fit: fit,
1711
+ ready: ready,
1712
+ walkthrough: walkthrough,
1713
+ setNodeStatus: setNodeStatus,
1714
+ setEdgeActive: setEdgeActive,
1715
+ setStatus: setStatus,
1716
+ resetStatus: resetStatus,
1717
+ applyLiveStyles: applyLiveStyles
1718
+ };
1583
1719
  })();
@@ -261,6 +261,40 @@ body.light .fg-node .fg-shape { fill-opacity: 0.12; }
261
261
  .fg-node:hover .fg-shape { stroke-width: 2.6px; }
262
262
  .fg-node.fg-focus .fg-shape { stroke-width: 3px; fill-opacity: 0.32; }
263
263
 
264
+ /* Live status (setStatus / setNodeStatus). */
265
+ .fg-node.fg-live .fg-shape {
266
+ stroke-width: 3px;
267
+ fill-opacity: 0.38;
268
+ filter: brightness(1.15);
269
+ }
270
+ .fg-node.fg-error .fg-shape {
271
+ stroke: #e74c3c;
272
+ stroke-width: 3px;
273
+ fill: #e74c3c;
274
+ fill-opacity: 0.28;
275
+ }
276
+ .fg-node.fg-done .fg-shape {
277
+ fill-opacity: 0.22;
278
+ stroke-opacity: 0.85;
279
+ }
280
+ .fg-badge { pointer-events: none; }
281
+ .fg-badge-bg {
282
+ fill: var(--accent, #4ea1ff);
283
+ stroke: var(--bg, #1a1a1a);
284
+ stroke-width: 1.5px;
285
+ }
286
+ .fg-node.fg-error .fg-badge-bg { fill: #e74c3c; }
287
+ .fg-badge-text {
288
+ fill: #fff;
289
+ font-weight: 700;
290
+ font-size: 10px;
291
+ font-family: "Helvetica", Arial, sans-serif;
292
+ }
293
+ .fg-edge-g.fg-live-edge .fg-edge {
294
+ filter: brightness(1.45);
295
+ stroke-width: inherit;
296
+ }
297
+
264
298
  /* Groups: dashed container with a header label. */
265
299
  .fg-group { cursor: pointer; transition: opacity 0.2s; }
266
300
  .fg-group-box {
@@ -1741,15 +1741,20 @@ function initLayoutPropertyControls() {
1741
1741
  var labelSelect = document.getElementById("layoutLabelSelect");
1742
1742
  var tooltipSelect = document.getElementById("layoutTooltipSelect");
1743
1743
 
1744
- var prevSize = sizeSelect ? sizeSelect.value : '';
1744
+ // When the side panel is hidden the selects are missing. Preserve the
1745
+ // current mode from in-memory state so re-runs do not wipe shape/label/
1746
+ // tooltip that were applied from the Python INIT_* arguments.
1747
+ var prevSize = sizeSelect ? sizeSelect.value : (layoutSizeKey || '');
1745
1748
  var prevColor = colorSelect ? colorSelect.value : '';
1746
1749
  if (!colorModeInitialized) {
1747
1750
  prevColor = (color_method === "STATE") ? COLOR_MODE_STATE : COLOR_MODE_CUSTOM;
1748
1751
  colorModeInitialized = true;
1752
+ } else if (!colorSelect && layoutColorKey) {
1753
+ prevColor = layoutColorKey;
1749
1754
  }
1750
- var prevShape = shapeSelect ? shapeSelect.value : 'circle';
1751
- var prevLabel = labelSelect ? labelSelect.value : '';
1752
- var prevTooltip = tooltipSelect ? tooltipSelect.value : '';
1755
+ var prevShape = shapeSelect ? shapeSelect.value : (categoricalShapeKey ? ("prop:" + categoricalShapeKey) : 'circle');
1756
+ var prevLabel = labelSelect ? labelSelect.value : (currentLabelKey || '');
1757
+ var prevTooltip = tooltipSelect ? tooltipSelect.value : (currentTooltipKey || '');
1753
1758
  if (!layoutDefaultsApplied) {
1754
1759
  // First run: start from the arguments given in Python.
1755
1760
  layoutDefaultsApplied = true;
@@ -1795,30 +1800,30 @@ function initLayoutPropertyControls() {
1795
1800
  if (!select) return false;
1796
1801
  return Array.prototype.some.call(select.options, function (o) { return o.value === value; });
1797
1802
  }
1798
- // Restore prior selection when still valid; otherwise fall back. Always
1799
- // re-apply so Color continuous↔discrete and Size/Shape membership update
1800
- // the chart immediately after a Variables dtype change.
1801
- if (sizeSelect) {
1802
- sizeSelect.value = hasOption(sizeSelect, prevSize) ? prevSize : '';
1803
- applySizeMode(sizeSelect.value);
1804
- }
1805
- if (colorSelect) {
1806
- var colorFallback = (color_method === "STATE") ? COLOR_MODE_STATE : COLOR_MODE_CUSTOM;
1807
- colorSelect.value = hasOption(colorSelect, prevColor) ? prevColor : colorFallback;
1808
- applyColorMode(colorSelect.value);
1809
- }
1810
- if (shapeSelect) {
1811
- shapeSelect.value = hasOption(shapeSelect, prevShape) ? prevShape : 'circle';
1812
- applyShapeMode(shapeSelect.value);
1813
- }
1814
- if (labelSelect) {
1815
- labelSelect.value = hasOption(labelSelect, prevLabel) ? prevLabel : '';
1816
- applyLabelMode(labelSelect.value);
1817
- }
1818
- if (tooltipSelect) {
1819
- tooltipSelect.value = hasOption(tooltipSelect, prevTooltip) ? prevTooltip : '';
1820
- applyTooltipMode(tooltipSelect.value);
1821
- }
1803
+ // Always re-apply modes so shape/label/tooltip/size/color still take effect
1804
+ // when show_side_panel=False (no Layout selects in the DOM). When the
1805
+ // selects exist, also restore their values.
1806
+ var sizeVal = (sizeSelect && hasOption(sizeSelect, prevSize)) ? prevSize : (sizeSelect ? '' : prevSize);
1807
+ if (sizeSelect) sizeSelect.value = sizeVal;
1808
+ applySizeMode(sizeVal);
1809
+
1810
+ var colorFallback = (color_method === "STATE") ? COLOR_MODE_STATE : COLOR_MODE_CUSTOM;
1811
+ var colorVal = (colorSelect && hasOption(colorSelect, prevColor)) ? prevColor : (colorSelect ? colorFallback : (prevColor || colorFallback));
1812
+ if (colorSelect) colorSelect.value = colorVal;
1813
+ applyColorMode(colorVal);
1814
+
1815
+ var shapeVal = (shapeSelect && hasOption(shapeSelect, prevShape)) ? prevShape : (shapeSelect ? 'circle' : prevShape);
1816
+ if (shapeSelect) shapeSelect.value = shapeVal;
1817
+ applyShapeMode(shapeVal);
1818
+
1819
+ var labelVal = (labelSelect && hasOption(labelSelect, prevLabel)) ? prevLabel : (labelSelect ? '' : prevLabel);
1820
+ if (labelSelect) labelSelect.value = labelVal;
1821
+ applyLabelMode(labelVal);
1822
+
1823
+ var tooltipVal = (tooltipSelect && hasOption(tooltipSelect, prevTooltip)) ? prevTooltip : (tooltipSelect ? '' : prevTooltip);
1824
+ if (tooltipSelect) tooltipSelect.value = tooltipVal;
1825
+ applyTooltipMode(tooltipVal);
1826
+
1822
1827
  // A Numeric <-> Category flip changes which variables can be filtered.
1823
1828
  if (typeof populateFilterVarDropdown === 'function') populateFilterVarDropdown();
1824
1829
  }
@@ -165,7 +165,12 @@ def test_flowgraph_mermaid_shapes_links_and_subgraphs():
165
165
  assert groups['qa']['parent'] == 'wh' and groups['wh']['label'] == 'Warehouse'
166
166
  assert nodes['done']['color'] == '#59a14f' and nodes['back']['color'] == '#e15759'
167
167
 
168
- edges = {(s, t): (lab, st, w) for s, t, lab, st, w in df.itertuples(index=False)}
168
+ edges = {
169
+ (s, t): (lab, st, w)
170
+ for s, t, lab, st, w in df[['source', 'target', 'label', 'style', 'weight']].itertuples(
171
+ index=False, name=None
172
+ )
173
+ }
169
174
  assert edges[('check', 'pick')][0] == 'yes'
170
175
  assert edges[('check', 'back')][0] == 'no'
171
176
  assert edges[('back', 'check')] == ('restocked', 'dotted', 1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: d3blocks
3
- Version: 2.3.2
3
+ Version: 2.3.3
4
4
  Summary: Python package d3blocks.
5
5
  Author-email: Erdogan Taskesen <erdogant@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -156,12 +156,14 @@ A few practical rules of thumb: prefer `st.iframe` over the older `components.ht
156
156
 
157
157
  ### [MovingBubbles: Daily Life of a European](https://d3blocks.github.io/d3blocks/MovingBubbles.html#daily-life-of-european)
158
158
 
159
- <p align="center">
159
+
160
+ <p align="left">
160
161
  <a href="https://d3blocks.github.io/d3blocks/MovingBubbles.html#daily-life-of-european">
161
- <img src="https://erdogant.github.io/docs/d3blocks/daily_life_of_european.gif" width="600" alt="MovingBubbles: Daily Life of a European" />
162
+ <img src="https://erdogant.github.io/docs/d3blocks/daily_life_of_european.gif" width="1000"/>
162
163
  </a>
163
164
  </p>
164
165
 
166
+
165
167
  ---
166
168
 
167
169
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes