mapdata 3.19.0__tar.gz → 3.21.0__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 (207) hide show
  1. {mapdata-3.19.0/mapdata.egg-info → mapdata-3.21.0}/PKG-INFO +2 -17
  2. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/mapdata.py +362 -20
  3. {mapdata-3.19.0 → mapdata-3.21.0/mapdata.egg-info}/PKG-INFO +2 -17
  4. {mapdata-3.19.0 → mapdata-3.21.0}/setup.py +2 -2
  5. {mapdata-3.19.0 → mapdata-3.21.0}/LICENSE.txt +0 -0
  6. {mapdata-3.19.0 → mapdata-3.21.0}/MANIFEST.in +0 -0
  7. {mapdata-3.19.0 → mapdata-3.21.0}/README.md +0 -0
  8. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/configfile/mapdata.conf +0 -0
  9. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/0.xbm +0 -0
  10. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/1.xbm +0 -0
  11. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/2.xbm +0 -0
  12. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/3.xbm +0 -0
  13. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/4.xbm +0 -0
  14. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/5.xbm +0 -0
  15. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/6.xbm +0 -0
  16. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/7.xbm +0 -0
  17. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/8.xbm +0 -0
  18. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/9.xbm +0 -0
  19. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/A.xbm +0 -0
  20. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/B.xbm +0 -0
  21. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/C.xbm +0 -0
  22. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/D.xbm +0 -0
  23. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/E.xbm +0 -0
  24. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/F.xbm +0 -0
  25. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/G.xbm +0 -0
  26. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/H.xbm +0 -0
  27. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/I.xbm +0 -0
  28. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/J.xbm +0 -0
  29. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/K.xbm +0 -0
  30. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/L.xbm +0 -0
  31. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/M.xbm +0 -0
  32. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/N.xbm +0 -0
  33. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/O.xbm +0 -0
  34. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/P.xbm +0 -0
  35. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/Q.xbm +0 -0
  36. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/R.xbm +0 -0
  37. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/S.xbm +0 -0
  38. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/T.xbm +0 -0
  39. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/U.xbm +0 -0
  40. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/V.xbm +0 -0
  41. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/W.xbm +0 -0
  42. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/X.xbm +0 -0
  43. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/Y.xbm +0 -0
  44. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/Z.xbm +0 -0
  45. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/airplane.xbm +0 -0
  46. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/anchor.xbm +0 -0
  47. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/ball.xbm +0 -0
  48. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/ball_small.xbm +0 -0
  49. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/bar.xbm +0 -0
  50. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/bars.xbm +0 -0
  51. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/binoculars.xbm +0 -0
  52. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/bird.xbm +0 -0
  53. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/block.xbm +0 -0
  54. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/block_small.xbm +0 -0
  55. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/bookmark.xbm +0 -0
  56. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/box_stack.xbm +0 -0
  57. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/camera.xbm +0 -0
  58. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/cancel.xbm +0 -0
  59. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/car.xbm +0 -0
  60. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/car2.xbm +0 -0
  61. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/center8.xbm +0 -0
  62. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/check.xbm +0 -0
  63. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/check_circle.xbm +0 -0
  64. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/checkbox.xbm +0 -0
  65. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/checkerboard.xbm +0 -0
  66. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/chevrons.xbm +0 -0
  67. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/circle.xbm +0 -0
  68. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/circle_bar.xbm +0 -0
  69. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/circle_plus.xbm +0 -0
  70. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/circle_stipple.xbm +0 -0
  71. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/circle_triangle.xbm +0 -0
  72. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/circle_wedge.xbm +0 -0
  73. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/circle_x.xbm +0 -0
  74. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/clock.xbm +0 -0
  75. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/columns.xbm +0 -0
  76. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/contract.xbm +0 -0
  77. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/cross.xbm +0 -0
  78. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/darkeye.xbm +0 -0
  79. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/decrease.xbm +0 -0
  80. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/deposition.xbm +0 -0
  81. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/diag_ll.xbm +0 -0
  82. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/diag_lr.xbm +0 -0
  83. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/diag_ul.xbm +0 -0
  84. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/diag_ur.xbm +0 -0
  85. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/dialog.xbm +0 -0
  86. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/diamond.xbm +0 -0
  87. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/donkey.xbm +0 -0
  88. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/dot.xbm +0 -0
  89. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/down.xbm +0 -0
  90. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/drop.xbm +0 -0
  91. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/elephant.xbm +0 -0
  92. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/expand.xbm +0 -0
  93. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/eye.xbm +0 -0
  94. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/fire.xbm +0 -0
  95. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/fish.xbm +0 -0
  96. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/flag.xbm +0 -0
  97. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/flag2.xbm +0 -0
  98. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/four_arrows.xbm +0 -0
  99. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/graph.xbm +0 -0
  100. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/hand.xbm +0 -0
  101. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/hash.xbm +0 -0
  102. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/heart.xbm +0 -0
  103. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/hidden.xbm +0 -0
  104. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/hourglass.xbm +0 -0
  105. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/house.xbm +0 -0
  106. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/increase.xbm +0 -0
  107. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/info.xbm +0 -0
  108. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/leaf.xbm +0 -0
  109. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/left.xbm +0 -0
  110. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/lightbulb.xbm +0 -0
  111. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/lightning.xbm +0 -0
  112. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/lightning2.xbm +0 -0
  113. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/location_ptr.xbm +0 -0
  114. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/mine.xbm +0 -0
  115. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/nested_boxes.xbm +0 -0
  116. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/pennant.xbm +0 -0
  117. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/pennant2.xbm +0 -0
  118. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/people.xbm +0 -0
  119. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/person.xbm +0 -0
  120. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/person2.xbm +0 -0
  121. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/person3.xbm +0 -0
  122. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/phone.xbm +0 -0
  123. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/photo.xbm +0 -0
  124. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/picnic.xbm +0 -0
  125. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/plus.xbm +0 -0
  126. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/point_down.xbm +0 -0
  127. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/point_left.xbm +0 -0
  128. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/point_right.xbm +0 -0
  129. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/point_up.xbm +0 -0
  130. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/pointer_ne.xbm +0 -0
  131. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/pointer_nw.xbm +0 -0
  132. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/pointer_se.xbm +0 -0
  133. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/pointer_sw.xbm +0 -0
  134. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/puzzle.xbm +0 -0
  135. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/q1.xbm +0 -0
  136. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/q1_notch.xbm +0 -0
  137. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/q2.xbm +0 -0
  138. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/q2_notch.xbm +0 -0
  139. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/q3.xbm +0 -0
  140. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/q3_notch.xbm +0 -0
  141. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/q4.xbm +0 -0
  142. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/q4_notch.xbm +0 -0
  143. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/qmark_circle.xbm +0 -0
  144. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/qmark_circle2.xbm +0 -0
  145. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/raincloud.xbm +0 -0
  146. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/right.xbm +0 -0
  147. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/rocket.xbm +0 -0
  148. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/rocket2.xbm +0 -0
  149. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/rose.xbm +0 -0
  150. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/rows.xbm +0 -0
  151. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/scales.xbm +0 -0
  152. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/search.xbm +0 -0
  153. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/search2.xbm +0 -0
  154. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/skull.xbm +0 -0
  155. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/square.xbm +0 -0
  156. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/star.xbm +0 -0
  157. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/stipple.xbm +0 -0
  158. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/stop.xbm +0 -0
  159. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/surprise_circle.xbm +0 -0
  160. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/swamp.xbm +0 -0
  161. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/target.xbm +0 -0
  162. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/target2.xbm +0 -0
  163. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/ten.xbm +0 -0
  164. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/trash.xbm +0 -0
  165. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/tree.xbm +0 -0
  166. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/tree2.xbm +0 -0
  167. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/tree3.xbm +0 -0
  168. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/triangle.xbm +0 -0
  169. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/triangle_open.xbm +0 -0
  170. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/triangle_sm.xbm +0 -0
  171. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/up.xbm +0 -0
  172. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/vapor.xbm +0 -0
  173. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/warning.xbm +0 -0
  174. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/wave.xbm +0 -0
  175. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/wave2.xbm +0 -0
  176. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/wave3.xbm +0 -0
  177. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/weather.xbm +0 -0
  178. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/wedge.xbm +0 -0
  179. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/wedge_sm.xbm +0 -0
  180. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/wedges_3.xbm +0 -0
  181. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/well.xbm +0 -0
  182. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/whale.xbm +0 -0
  183. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/whale2.xbm +0 -0
  184. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/wheelchair.xbm +0 -0
  185. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/zigzags.xbm +0 -0
  186. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/16x16/zigzags2.xbm +0 -0
  187. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/20x20/ball20.xbm +0 -0
  188. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/20x20/block20.xbm +0 -0
  189. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/20x20/circle20.xbm +0 -0
  190. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/20x20/q1_20.xbm +0 -0
  191. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/20x20/q2_20.xbm +0 -0
  192. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/20x20/q3_20.xbm +0 -0
  193. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/20x20/q4_20.xbm +0 -0
  194. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/20x20/square20.xbm +0 -0
  195. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/24x24/ball24.xbm +0 -0
  196. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/24x24/block24.xbm +0 -0
  197. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/24x24/circle24.xbm +0 -0
  198. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/24x24/square24.xbm +0 -0
  199. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/28x28/ball28.xbm +0 -0
  200. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/28x28/block28.xbm +0 -0
  201. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/28x28/circle28.xbm +0 -0
  202. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata/symbols/28x28/square28.xbm +0 -0
  203. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata.egg-info/SOURCES.txt +0 -0
  204. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata.egg-info/dependency_links.txt +0 -0
  205. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata.egg-info/requires.txt +9 -9
  206. {mapdata-3.19.0 → mapdata-3.21.0}/mapdata.egg-info/top_level.txt +0 -0
  207. {mapdata-3.19.0 → mapdata-3.21.0}/setup.cfg +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mapdata
3
- Version: 3.19.0
3
+ Version: 3.21.0
4
4
  Summary: An interactive map and table explorer for geographic coordinates in a spreadsheet, CSV file, or database that includes data plotting and statistical summaries
5
5
  Home-page: https:/hg.sr.ht/~rdnielsen/mapdata
6
6
  Author: Dreas Nielsen
7
7
  Author-email: cortice@tutanota.com
8
8
  License: GPL
9
- Keywords: Map,Locations,CRS,CSV,Spreadsheet,Database,PNG,JPG,Postscript
9
+ Keywords: Map,Locations,CRS,CSV,Spreadsheet,Database,Statistics,Plotting,PNG,JPG,Postscript
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Environment :: Console
12
12
  Classifier: Environment :: X11 Applications
@@ -24,21 +24,6 @@ Classifier: Topic :: Scientific/Engineering
24
24
  Requires-Python: >=3.8
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE.txt
27
- Requires-Dist: tkintermapview
28
- Requires-Dist: pyproj
29
- Requires-Dist: jenkspy
30
- Requires-Dist: odfpy
31
- Requires-Dist: openpyxl
32
- Requires-Dist: xlrd
33
- Requires-Dist: matplotlib
34
- Requires-Dist: seaborn
35
- Requires-Dist: loess
36
- Requires-Dist: statsmodels
37
- Requires-Dist: scipy
38
- Requires-Dist: scikit-learn
39
- Requires-Dist: pymannkendall
40
- Requires-Dist: umap-learn
41
- Requires-Dist: pynndescent
42
27
 
43
28
 
44
29
  *mapdata.py* is a data explorer for data sets containing geographic coordinates. Data can be read from a CSV file, spreadsheet, or database. Both a map and a data
@@ -24,8 +24,8 @@
24
24
  #
25
25
  # ==================================================================
26
26
 
27
- version = "3.19.0"
28
- vdate = "2026-02-13"
27
+ version = "3.21.0"
28
+ vdate = "2026-03-17"
29
29
 
30
30
  copyright = "2023-2026"
31
31
 
@@ -1332,12 +1332,14 @@ def enable_if(widget, tf_val):
1332
1332
  widget["state"] = tk.NORMAL if tf_val else tk.DISABLED
1333
1333
 
1334
1334
  def chosen_dataset(maingui, column_list, selected_only):
1335
+ # Returns the dataset as a column-oriented list of lists.
1335
1336
  if selected_only:
1336
1337
  return maingui.get_sel_data(column_list)
1337
1338
  else:
1338
1339
  return maingui.get_all_data(column_list)
1339
1340
 
1340
1341
  def chosen_dataset_and_ids(maingui, column_list, selected_only):
1342
+ # Returns the dataset as a column-oriented list of lists.
1341
1343
  if selected_only:
1342
1344
  return maingui.get_sel_data(column_list), maingui.get_sel_rowids()
1343
1345
  else:
@@ -3401,7 +3403,7 @@ class MapUI(object):
3401
3403
  def get_all_rowids(self):
3402
3404
  return self.tbl.get_children()
3403
3405
  def get_sel_data(self, column_list):
3404
- # Plotting and statistics support. Return data from selected rows for the specified columns, as a list of lists.
3406
+ # Plotting and statistics support. Return data from selected rows for the specified columns, as a list of column-oriented lists.
3405
3407
  res = [[] for _ in column_list]
3406
3408
  indices = [self.headers.index(c) for c in column_list]
3407
3409
  for sel_row in self.tbl.selection():
@@ -4015,6 +4017,14 @@ class MapUI(object):
4015
4017
  dlg = UniqueValuesDialog(self, self.data_types)
4016
4018
  dlg.show()
4017
4019
 
4020
+ def show_missing_byrow(self, args=None):
4021
+ dlg = MissingByRowDialog(self, self.data_types)
4022
+ dlg.show()
4023
+
4024
+ def show_missing_byvariable(self, args=None):
4025
+ dlg = MissingByVariableDialog(self, self.data_types)
4026
+ dlg.show()
4027
+
4018
4028
  def add_rowid(self, args=None):
4019
4029
  dlg = AddRowIDDialog(self, self.data_types)
4020
4030
  colname, prefix = dlg.show()
@@ -4523,6 +4533,8 @@ class MapUI(object):
4523
4533
  tbl_menu.add_command(label="Hide/show columns", command = self.hide_columns, underline=0)
4524
4534
  tbl_menu.add_command(label="Counts by location", command=self.counts_by_loc, underline=0)
4525
4535
  tbl_menu.add_command(label="Unique values", command=self.unique_data_values, underline=3)
4536
+ tbl_menu.add_command(label="Missing by row", command=self.show_missing_byrow, underline=0)
4537
+ tbl_menu.add_command(label="Missing by variable", command=self.show_missing_byvariable, underline=11)
4526
4538
  tbl_menu.add_command(label="Find candidate keys", command=self.find_candkeys, underline=0)
4527
4539
  tbl_menu.add_command(label="Find duplicate rows", command=self.find_duprows, underline=3)
4528
4540
  tbl_menu.add_command(label="Test cardinality", command=self.cardinality_test, underline=10)
@@ -6733,6 +6745,15 @@ class UniqueValuesDialog(Dialog):
6733
6745
  self.data_labels = None
6734
6746
  self.dlg.bind("<Control-s>")
6735
6747
 
6748
+ # Top controls
6749
+ self.sel_only_var, self.sel_only_ck = add_sel_only(self.ctrl_frame, 0, 0, self.q_recalc)
6750
+ self.indiv_var = tk.StringVar(self.ctrl_frame, "0")
6751
+ indiv_ck = ttk.Checkbutton(self.ctrl_frame, text="Individually", command=self.q_recalc, variable=self.indiv_var,
6752
+ onvalue="1", offvalue="0")
6753
+ indiv_ck.grid(row=0, column=1, sticky=tk.W, padx=(6,3), pady=(3,3), columnspan=None)
6754
+ self.ctrl_frame.columnconfigure(0, weight=0)
6755
+ self.ctrl_frame.columnconfigure(1, weight=1)
6756
+
6736
6757
  # The content_frame encompasses the two panes of the variable frame and the content frame
6737
6758
  frame_panes = ttk.PanedWindow(self.content_frame, orient=tk.HORIZONTAL, width=600)
6738
6759
  frame_panes.grid(row=0, column=0, sticky=tk.NSEW)
@@ -6741,7 +6762,7 @@ class UniqueValuesDialog(Dialog):
6741
6762
  var_frame = tk.Frame(frame_panes, width=250, borderwidth=2, relief=tk.RIDGE)
6742
6763
  var_frame.grid(row=0, column=0, sticky=tk.NSEW)
6743
6764
  var_frame.rowconfigure(0, weight=1)
6744
- var_frame.columnconfigure(0, weight=1)
6765
+ var_frame.columnconfigure(0, weight=1, minsize=200)
6745
6766
  frame_panes.add(var_frame, weight=1)
6746
6767
  # Add multi-select list of variables to the leftmost pane
6747
6768
  varvals = [[v] for v in self.variables]
@@ -6775,20 +6796,48 @@ class UniqueValuesDialog(Dialog):
6775
6796
 
6776
6797
  def q_recalc(self, *event, get_data=True):
6777
6798
  self.clear_output()
6778
- if len(self.column_table.selection()) > 0 and get_data:
6779
- self.recalc()
6799
+ if len(self.column_table.selection()) > 0:
6800
+ self.get_data()
6801
+ if self.rawdataset is not None and len(self.rawdataset[0]) > 0:
6802
+ self.recalc()
6780
6803
 
6781
- def recalc(self):
6782
- column_list = []
6804
+ def get_data(self):
6805
+ # Get the selected data into 'dataset'
6806
+ self.rawdataset = None
6807
+ self.colnames = []
6783
6808
  for sel_row in self.column_table.selection():
6784
6809
  datarow = self.column_table.item(sel_row)["values"]
6785
- column_list.append(datarow[0])
6786
- dbcols = db_colnames(column_list)
6787
- colstr = ",".join(dbcols)
6788
- sqlcmd = f"select distinct {colstr}, count(*) as nrows from mapdata group by {colstr} order by {colstr};"
6789
- cur = data_db.cursor()
6790
- self.dataset = cur.execute(sqlcmd).fetchall()
6791
- self.data_labels = column_list + ["Count"]
6810
+ self.colnames.append(datarow[0])
6811
+ if len(self.colnames) > 0:
6812
+ # Get either only the selected data or all data.
6813
+ dataset = chosen_dataset(self.parent, self.colnames, self.sel_only_var.get()=='1')
6814
+ if dataset is None or len(dataset[0]) == 0:
6815
+ self.rawdataset = None
6816
+ self.colnames = None
6817
+ else:
6818
+ self.rawdataset = dataset
6819
+
6820
+ def recalc(self):
6821
+ if self.indiv_var.get()=='1':
6822
+ counts = dict(zip(self.colnames, [0 for _ in range(len(self.colnames))]))
6823
+ for i,col in enumerate(self.colnames):
6824
+ counts[col] = len(set([x for x in self.rawdataset[i] if x is not None and str(x) != '']))
6825
+ self.dataset = list(counts.items())
6826
+ self.data_labels = ["Variable", "Count"]
6827
+ else:
6828
+ counts = {}
6829
+ ds = columns_to_rows(self.rawdataset)
6830
+ for row in ds:
6831
+ trow = tuple(row)
6832
+ if trow not in counts.keys():
6833
+ counts[trow] = 1
6834
+ else:
6835
+ counts[trow] += 1
6836
+ self.dataset = [list(k) for k in counts.keys()]
6837
+ vals = list(counts.values())
6838
+ for i in range(len(counts)):
6839
+ self.dataset[i].append(vals[i])
6840
+ self.data_labels = self.colnames + ["Count"]
6792
6841
  tframe, tdata = treeview_table(self.values_frame, self.dataset, self.data_labels)
6793
6842
  tframe.grid(row=0, column=0, sticky=tk.NSEW)
6794
6843
  self.dlg.bind("<Control-s>", self.save_data)
@@ -6798,6 +6847,277 @@ class UniqueValuesDialog(Dialog):
6798
6847
  self.dlg.wait_window(self.dlg)
6799
6848
 
6800
6849
 
6850
+ class MissingByRowDialog(Dialog):
6851
+ def __init__(self, parent, column_specs):
6852
+ self.parent = parent
6853
+ self.column_specs = column_specs
6854
+ self.auto_update = True
6855
+ super().__init__("Rows with Missing Values",
6856
+ "Select one or more variables from the left to see how many rows have 0, 1, 2, or more missing values for these variables. A grouping variable may optionally be used. Use Ctrl-click or Shift-click to select multiple rows.",
6857
+ help_url="https://mapdata.readthedocs.io/en/latest/missing_by_row.html")
6858
+ # Data
6859
+ self.dataset = None
6860
+ self.data_labels = None
6861
+ self.all_columns = sorted([c[0] for c in self.column_specs])
6862
+ self.categ_columns = sorted([c[0] for c in self.column_specs if c[1] in ("string", "boolean", "date", "timestamp")])
6863
+ self.dnames = ["Group", "Missing values", "Number of rows"]
6864
+ self.dlg.bind("<Control-s>")
6865
+
6866
+ # Top controls
6867
+ self.sel_only_var, self.sel_only_ck = add_sel_only(self.ctrl_frame, 0, 0, self.q_recalc)
6868
+ self.autoupdate_var = add_autoupdate(self.ctrl_frame, 0, 1, self.set_autoupdate)
6869
+ self.ctrl_frame.columnconfigure(0, weight=0)
6870
+ self.ctrl_frame.columnconfigure(1, weight=1)
6871
+
6872
+ # Two panes for the variable frame and the content frame
6873
+ frame_panes = ttk.PanedWindow(self.content_frame, orient=tk.HORIZONTAL)
6874
+ frame_panes.grid(row=0, column=0, sticky=tk.NSEW, padx=3, pady=3)
6875
+
6876
+ # Variable frame for list of columns/variables
6877
+ var_frame = tk.Frame(frame_panes, borderwidth=2, relief=tk.RIDGE)
6878
+ var_frame.grid(row=0, column=0, sticky=tk.NSEW)
6879
+ var_frame.rowconfigure(0, weight=1)
6880
+ var_frame.columnconfigure(0, weight=1)
6881
+ frame_panes.add(var_frame, weight=1)
6882
+ # Add multi-select list of variables to the leftmost pane
6883
+ self.column_frame, self.column_table = treeview_table(var_frame, rowset=[[v] for v in self.all_columns], \
6884
+ column_headers=['Variable'], select_mode=tk.EXTENDED, nrows=min(10, len(self.all_columns)))
6885
+ self.column_frame.grid(row=0, column=0, sticky=tk.NSEW)
6886
+ self.column_table.bind('<ButtonRelease-1>', self.q_recalc)
6887
+
6888
+ # Add an optional 'group by' variable selection
6889
+ self.groupby_var = tk.StringVar(var_frame, "")
6890
+ groupby_lbl = ttk.Label(var_frame, text="Group by:")
6891
+ groupby_lbl.grid(row=1, column=0, sticky=tk.W, padx=(6,3), pady=(3,3))
6892
+ self.groupby_sel = ttk.Combobox(var_frame, state="readonly", textvariable=self.groupby_var,
6893
+ values= [''] + self.categ_columns, width=24)
6894
+ self.groupby_sel.grid(row=2, column=0, sticky=tk.W, padx=(12,3), pady=(3,3))
6895
+ self.groupby_sel.bind("<<ComboboxSelected>>", self.q_recalc)
6896
+
6897
+ # output frame. This contains a Treeview table with the counts of missing values.
6898
+ self.output_frame = tk.Frame(frame_panes, borderwidth=3, relief=tk.RIDGE)
6899
+ self.output_frame.grid(row=0, column=0, sticky=tk.NSEW)
6900
+ self.output_frame.rowconfigure(0, weight=1)
6901
+ self.output_frame.columnconfigure(0, weight=1)
6902
+ frame_panes.add(self.output_frame, weight=12)
6903
+
6904
+ # initialize content frame with headings, no data
6905
+ self.clear_output()
6906
+
6907
+ # Buttons
6908
+ add_help_close_buttons(self.dlg, self.btn_frame, self.do_help, self.do_close)
6909
+
6910
+ def clear_output(self):
6911
+ for ctl in self.output_frame.winfo_children():
6912
+ ctl.destroy()
6913
+ clear_dlg_hotkeys(self.dlg)
6914
+ self.dataset = None
6915
+ self.missingdata = None
6916
+ tframe, tdata = treeview_table(self.output_frame, [], self.dnames)
6917
+ tframe.grid(row=0, column=0, sticky=tk.NSEW)
6918
+
6919
+ def q_recalc(self, *args):
6920
+ if len(self.column_table.selection()) > 0:
6921
+ self.clear_output()
6922
+ self.get_data()
6923
+ if self.dataset is not None and len(self.dataset[0]) > 0:
6924
+ self.recalc()
6925
+
6926
+ def get_data(self):
6927
+ # Get the selected data into 'dataset'
6928
+ self.dataset = None
6929
+ self.n_dataset_columns = 0
6930
+ column_list = []
6931
+ for sel_row in self.column_table.selection():
6932
+ datarow = self.column_table.item(sel_row)["values"]
6933
+ column_list.append(datarow[0])
6934
+ if len(column_list) > 0:
6935
+ self.n_dataset_columns = len(column_list)
6936
+ if self.groupby_var.get() != "":
6937
+ column_list.append(self.groupby_var.get())
6938
+ # Get either only the selected data or all data.
6939
+ dataset = chosen_dataset(self.parent, column_list, self.sel_only_var.get() == "1")
6940
+ if dataset is None or len(dataset[0]) == 0:
6941
+ self.dataset = None
6942
+ self.data_labels = None
6943
+ else:
6944
+ self.dataset = dataset
6945
+ self.data_labels = column_list
6946
+
6947
+ def recalc(self):
6948
+ # Find the numbers of missing values of all selected rows. This is accumulated as a dictionary
6949
+ # with keys equal to numbers of missing values in a row and values of the number of rows with
6950
+ # that number of missing values.
6951
+ def incmissing(dic, n_missing):
6952
+ if n_missing not in dic.keys():
6953
+ dic[n_missing] = 0
6954
+ dic[n_missing] = dic[n_missing] + 1
6955
+
6956
+ if self.data_labels is not None:
6957
+ if self.groupby_var.get() == "":
6958
+ missings = {}
6959
+ for datarow in columns_to_rows(self.dataset):
6960
+ incmissing(missings, sum(val == '' for val in datarow))
6961
+ self.missingdata = sorted(list(zip(missings.keys(), missings.values())))
6962
+ self.dnames = ["Missing", "Rows"]
6963
+ else:
6964
+ datasetdict = subset_by_groups(self.dataset[0:self.n_dataset_columns], self.dataset[self.n_dataset_columns])
6965
+ self.missingdata = []
6966
+ for grp in datasetdict.keys():
6967
+ ds = columns_to_rows(datasetdict[grp])
6968
+ missings = {}
6969
+ for datarow in ds:
6970
+ incmissing(missings, sum(val == '' for val in datarow))
6971
+ self.missingdata.extend(sorted(list(zip([grp]*len(missings.keys()), missings.keys(), missings.values())), key=lambda x: x[1]))
6972
+ self.dnames = ["Group", "Missing", "Rows"]
6973
+ tframe, tdata = treeview_table(self.output_frame, self.missingdata, self.dnames)
6974
+ tframe.grid(row=0, column=0, sticky=tk.NSEW)
6975
+ self.dlg.bind("<Control-s>", self.save_data)
6976
+ def set_autoupdate(self):
6977
+ self.auto_update = self.autoupdate_var.get() == "1"
6978
+ if self.auto_update:
6979
+ self.q_recalc(None)
6980
+ def save_data(self, *args):
6981
+ export_data_table(self.dnames, self.missingdata, sheetname="Numbers of missing values")
6982
+ def do_close(self, *args):
6983
+ self.parent.remove_univar(self)
6984
+ super().do_cancel(args)
6985
+
6986
+
6987
+
6988
+ class MissingByVariableDialog(Dialog):
6989
+ def __init__(self, parent, column_specs):
6990
+ self.parent = parent
6991
+ self.column_specs = column_specs
6992
+ self.auto_update = True
6993
+ super().__init__("Variables with Missing Values",
6994
+ "Select one or more variables from the left to see how many missing values each has. A grouping variable may optionally be used. Use Ctrl-click or Shift-click to select multiple rows.",
6995
+ help_url="https://mapdata.readthedocs.io/en/latest/missing_by_variable.html")
6996
+ # Data
6997
+ self.dataset = None
6998
+ self.data_labels = None
6999
+ self.all_columns = sorted([c[0] for c in self.column_specs])
7000
+ self.categ_columns = sorted([c[0] for c in self.column_specs if c[1] in ("string", "boolean", "date", "timestamp")])
7001
+ self.dnames = ["Variable", "Missing"]
7002
+ self.dlg.bind("<Control-s>")
7003
+
7004
+ # Top controls
7005
+ self.sel_only_var, self.sel_only_ck = add_sel_only(self.ctrl_frame, 0, 0, self.q_recalc)
7006
+ self.autoupdate_var = add_autoupdate(self.ctrl_frame, 0, 1, self.set_autoupdate)
7007
+ self.ctrl_frame.columnconfigure(0, weight=0)
7008
+ self.ctrl_frame.columnconfigure(1, weight=1)
7009
+
7010
+ # Two panes for the variable frame and the content frame
7011
+ frame_panes = ttk.PanedWindow(self.content_frame, orient=tk.HORIZONTAL)
7012
+ frame_panes.grid(row=0, column=0, sticky=tk.NSEW, padx=3, pady=3)
7013
+
7014
+ # Variable frame for list of all columns/variables
7015
+ var_frame = tk.Frame(frame_panes, borderwidth=2, relief=tk.RIDGE)
7016
+ var_frame.grid(row=0, column=0, sticky=tk.NSEW)
7017
+ var_frame.rowconfigure(0, weight=1)
7018
+ var_frame.columnconfigure(0, weight=1)
7019
+ frame_panes.add(var_frame, weight=1)
7020
+ # Add multi-select list of variables to the leftmost pane
7021
+ self.column_frame, self.column_table = treeview_table(var_frame, rowset=[[v] for v in self.all_columns], \
7022
+ column_headers=['Variable'], select_mode=tk.EXTENDED, nrows=min(10, len(self.all_columns)))
7023
+ self.column_frame.grid(row=0, column=0, sticky=tk.NSEW)
7024
+ self.column_table.bind('<ButtonRelease-1>', self.q_recalc)
7025
+
7026
+ # Add an optional 'group by' variable selection
7027
+ self.groupby_var = tk.StringVar(var_frame, "")
7028
+ groupby_lbl = ttk.Label(var_frame, text="Group by:")
7029
+ groupby_lbl.grid(row=1, column=0, sticky=tk.W, padx=(6,3), pady=(3,3))
7030
+ self.groupby_sel = ttk.Combobox(var_frame, state="readonly", textvariable=self.groupby_var,
7031
+ values= [''] + self.categ_columns, width=24)
7032
+ self.groupby_sel.grid(row=2, column=0, sticky=tk.W, padx=(12,3), pady=(3,3))
7033
+ self.groupby_sel.bind("<<ComboboxSelected>>", self.q_recalc)
7034
+
7035
+ # Output frame. This contains a Treeview table with the counts of missing values.
7036
+ self.output_frame = tk.Frame(frame_panes, borderwidth=3, relief=tk.RIDGE)
7037
+ self.output_frame.grid(row=0, column=0, sticky=tk.NSEW)
7038
+ self.output_frame.rowconfigure(0, weight=1)
7039
+ self.output_frame.columnconfigure(0, weight=1)
7040
+ frame_panes.add(self.output_frame, weight=12)
7041
+
7042
+ # initialize content frame with headings, no data
7043
+ self.clear_output()
7044
+
7045
+ # Buttons
7046
+ add_help_close_buttons(self.dlg, self.btn_frame, self.do_help, self.do_close)
7047
+
7048
+ def clear_output(self):
7049
+ for ctl in self.output_frame.winfo_children():
7050
+ ctl.destroy()
7051
+ clear_dlg_hotkeys(self.dlg)
7052
+ self.dataset = None
7053
+ self.missingdata = None
7054
+ tframe, tdata = treeview_table(self.output_frame, [], self.dnames)
7055
+ tframe.grid(row=0, column=0, sticky=tk.NSEW)
7056
+
7057
+ def q_recalc(self, *args):
7058
+ if len(self.column_table.selection()) > 0:
7059
+ self.clear_output()
7060
+ self.get_data()
7061
+ if self.dataset is not None and len(self.dataset[0]) > 0:
7062
+ self.recalc()
7063
+
7064
+ def get_data(self):
7065
+ # Get the selected data into 'dataset'
7066
+ self.dataset = None
7067
+ self.n_dataset_columns = 0
7068
+ column_list = []
7069
+ for sel_row in self.column_table.selection():
7070
+ datarow = self.column_table.item(sel_row)["values"]
7071
+ column_list.append(datarow[0])
7072
+ if len(column_list) > 0:
7073
+ self.n_dataset_columns = len(column_list)
7074
+ if self.groupby_var.get() != "":
7075
+ column_list.append(self.groupby_var.get())
7076
+ # Get either only the selected data or all data.
7077
+ dataset = chosen_dataset(self.parent, column_list, self.sel_only_var.get() == "1")
7078
+ if dataset is None or len(dataset[0]) == 0:
7079
+ self.dataset = None
7080
+ self.data_labels = None
7081
+ else:
7082
+ self.dataset = dataset
7083
+ self.data_labels = column_list
7084
+
7085
+ def recalc(self):
7086
+ # Find the numbers of missing values of all selected variables.
7087
+ if self.data_labels is not None:
7088
+ if self.groupby_var.get() == "":
7089
+ # Output is two columns, one with the variable name and one with the number of missing values.
7090
+ n_missing = []
7091
+ for col in self.dataset:
7092
+ n_missing.append(sum(val == '' for val in col))
7093
+ self.missingdata = sorted(list(zip(self.data_labels, n_missing)))
7094
+ self.dnames = ["Variable", "Missing"]
7095
+ else:
7096
+ # Output is a table with groups in rows, variables in columns, missing values in cells
7097
+ datasetdict = subset_by_groups(self.dataset[0:self.n_dataset_columns], self.dataset[self.n_dataset_columns])
7098
+ self.missingdata = []
7099
+ for grp in datasetdict.keys():
7100
+ ds = datasetdict[grp]
7101
+ n_missing = [grp]
7102
+ for col in ds:
7103
+ n_missing.append(sum(val == '' for val in col))
7104
+ self.missingdata.append(n_missing)
7105
+ self.dnames = ["Group"] + self.data_labels[:-1]
7106
+ tframe, tdata = treeview_table(self.output_frame, self.missingdata, self.dnames)
7107
+ tframe.grid(row=0, column=0, sticky=tk.NSEW)
7108
+ self.dlg.bind("<Control-s>", self.save_data)
7109
+ def set_autoupdate(self):
7110
+ self.auto_update = self.autoupdate_var.get() == "1"
7111
+ if self.auto_update:
7112
+ self.q_recalc(None)
7113
+ def save_data(self, *args):
7114
+ export_data_table(self.dnames, self.missingdata, sheetname="Numbers of missing values")
7115
+ def do_close(self, *args):
7116
+ self.parent.remove_univar(self)
7117
+ super().do_cancel(args)
7118
+
7119
+
7120
+
6801
7121
  class SelNonMissingDialog(Dialog):
6802
7122
  def __init__(self, column_specs):
6803
7123
  super().__init__("Select Non-Missing Values",
@@ -6948,7 +7268,7 @@ class PlotDialog(Dialog):
6948
7268
  plot_types.append("Date range by category")
6949
7269
  plot_types.extend(["Empirical CDF", "Histogram", "Kernel density (KD) plot", "Line plot", "Mean by category",
6950
7270
  "Min-max by bin", "Min-max by category", "Normal Q-Q plot", "Pareto chart", "Scatter plot", "Stripchart",
6951
- "Total by category", "Violin plot", "Y range plot"])
7271
+ "Total by category", "Violin plot", "Y range plot", "Zipf's Law"])
6952
7272
  self.type_sel = ttk.Combobox(self.ctrl_frame, state="readonly", textvariable=self.type_var, width=20, height=21, values=plot_types)
6953
7273
  self.type_sel.grid(row=0, column=1, columnspan=2, sticky=tk.W, padx=(3,6), pady=(3,3))
6954
7274
  self.type_sel["state"] = tk.NORMAL
@@ -7174,9 +7494,11 @@ class PlotDialog(Dialog):
7174
7494
  elif plot_type == "Min-max by category":
7175
7495
  self.x_sel["state"] = "readonly"
7176
7496
  self.x_sel["values"] = self.quant_columns
7177
- self.xlog_ck["state"] = tk.NORMAL
7178
7497
  self.y_sel["state"] = "readonly"
7179
7498
  self.y_sel["values"] = self.categ_columns2
7499
+ elif plot_type == "Zipf's Law":
7500
+ self.x_sel["state"] = "readonly"
7501
+ self.x_sel["values"] = sorted([c[0] for c in self.column_specs if c[1] == "string"])
7180
7502
  else:
7181
7503
  self.x_sel["state"] = "readonly"
7182
7504
  self.x_sel["values"] = self.quant_columns
@@ -7197,7 +7519,7 @@ class PlotDialog(Dialog):
7197
7519
  # Conditionally (re)draw the plot.
7198
7520
  plot_type = self.type_var.get()
7199
7521
  can_redraw = (plot_type in ("Count by category", "Empirical CDF", "Normal Q-Q plot", "Breaks groups", "Breaks optimum", \
7200
- "Histogram", "Pareto chart") and self.x_var.get() != '') \
7522
+ "Histogram", "Pareto chart", "Zipf's Law") and self.x_var.get() != '') \
7201
7523
  or (plot_type in ("Scatter plot", "Line plot", "Min-max by bin", "Min-max by category", "Y range plot") and \
7202
7524
  self.x_var.get() != '' and self.y_var.get() != '') \
7203
7525
  or (plot_type in ("Box plot", "Kernel density (KD) plot", "Stripchart", "Violin plot") and self.x_var.get() != '') \
@@ -7293,6 +7615,19 @@ class PlotDialog(Dialog):
7293
7615
  x_counts = [counter[k] for k in x_vals]
7294
7616
  self.plot_data = [x_vals, x_counts]
7295
7617
  self.plot_data_labels = [self.data_labels[0], "Count"]
7618
+ elif plot_type == "Zipf's Law":
7619
+ counter = collections.Counter(self.dataset[0])
7620
+ zcts = sorted(list(zip(counter.values(), counter.keys())), key=lambda x: x[0], reverse=True)
7621
+ zd = list(zip(*zcts))
7622
+ zdata = [list(zd[1]), list(zd[0])]
7623
+ zdata.append(list(range(1, len(zdata[0])+1)))
7624
+ tot = sum(zdata[1])
7625
+ zdata.append([x/tot for x in zdata[1]])
7626
+ zdata.append([math.log10(x) for x in zdata[2]])
7627
+ zdata.append([math.log10(x) for x in zdata[3]])
7628
+ self.plot_data = zdata
7629
+ self.plot_data_labels = [self.data_labels[0], "Count", "Rank", "Frequency", "Log10_Rank", "Log10_Frequency"]
7630
+ self.xlog_ck["state"] = tk.DISABLED
7296
7631
  elif plot_type in ("Box plot", "Histogram", "Kernel density (KD) plot", "Stripchart", "Violin plot"):
7297
7632
  if self.groupby_var.get() != '':
7298
7633
  self.plot_data_labels, self.plot_data = spread_by_groups(self.dataset[1], self.dataset[0])
@@ -7869,7 +8204,7 @@ class PlotDialog(Dialog):
7869
8204
  self.plot.axes.plot([pmin, pmax], [pmin, pmax])
7870
8205
  self.plot.set_axis_labels(self.xlabel or self.plot_data_labels[2], self.ylabel or self.plot_data_labels[1])
7871
8206
  elif plot_type == "Pareto chart":
7872
- groups = self.plot_data[0]
8207
+ groups = [str(g) for g in self.plot_data[0]]
7873
8208
  grp_lbls = []
7874
8209
  for g in groups:
7875
8210
  if wrap_at_underscores:
@@ -7983,6 +8318,13 @@ class PlotDialog(Dialog):
7983
8318
  else:
7984
8319
  sns.violinplot({self.x_var.get(): self.dataset[0]}, x=self.x_var.get(), alpha=self.alpha, ax=self.plot_axes)
7985
8320
  self.plot.set_axis_labels(self.ylabel or self.data_labels[0], self.xlabel or self.x_var.get())
8321
+ elif plot_type == "Zipf's Law":
8322
+ self.plot.axes.set_xscale('log')
8323
+ self.plot.axes.set_yscale('log')
8324
+ self.plot.axes.grid(visible=True, color="0.8", linestyle="dotted", which='both', axis='both')
8325
+ self.plot.axes.plot(self.plot_data[2], self.plot_data[3], alpha=self.alpha)
8326
+ self.plot.set_axis_labels(self.plot_data_labels[2], self.xlabel or self.plot_data_labels[3])
8327
+ self.plot_title = self.data_labels[0]
7986
8328
  if self.plot_title is not None:
7987
8329
  self.plot.axes.set_title(self.plot_title)
7988
8330
  self.plot.axes.title.set_visible(True)
@@ -13351,7 +13693,7 @@ class NMFUnmixingDialog(Dialog):
13351
13693
  frame_panes.grid(row=0, column=0, sticky=tk.NSEW)
13352
13694
 
13353
13695
  # Variable frame for list of quantitative columns/variables
13354
- var_frame = tk.Frame(frame_panes, borderwidth=2, relief=tk.RIDGE)
13696
+ var_frame = tk.Frame(frame_panes, width=250, borderwidth=2, relief=tk.RIDGE)
13355
13697
  var_frame.grid(row=0, column=0, sticky=tk.NSEW)
13356
13698
  var_frame.rowconfigure(0, weight=1)
13357
13699
  var_frame.columnconfigure(0, weight=1, minsize=200)
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mapdata
3
- Version: 3.19.0
3
+ Version: 3.21.0
4
4
  Summary: An interactive map and table explorer for geographic coordinates in a spreadsheet, CSV file, or database that includes data plotting and statistical summaries
5
5
  Home-page: https:/hg.sr.ht/~rdnielsen/mapdata
6
6
  Author: Dreas Nielsen
7
7
  Author-email: cortice@tutanota.com
8
8
  License: GPL
9
- Keywords: Map,Locations,CRS,CSV,Spreadsheet,Database,PNG,JPG,Postscript
9
+ Keywords: Map,Locations,CRS,CSV,Spreadsheet,Database,Statistics,Plotting,PNG,JPG,Postscript
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Environment :: Console
12
12
  Classifier: Environment :: X11 Applications
@@ -24,21 +24,6 @@ Classifier: Topic :: Scientific/Engineering
24
24
  Requires-Python: >=3.8
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE.txt
27
- Requires-Dist: tkintermapview
28
- Requires-Dist: pyproj
29
- Requires-Dist: jenkspy
30
- Requires-Dist: odfpy
31
- Requires-Dist: openpyxl
32
- Requires-Dist: xlrd
33
- Requires-Dist: matplotlib
34
- Requires-Dist: seaborn
35
- Requires-Dist: loess
36
- Requires-Dist: statsmodels
37
- Requires-Dist: scipy
38
- Requires-Dist: scikit-learn
39
- Requires-Dist: pymannkendall
40
- Requires-Dist: umap-learn
41
- Requires-Dist: pynndescent
42
27
 
43
28
 
44
29
  *mapdata.py* is a data explorer for data sets containing geographic coordinates. Data can be read from a CSV file, spreadsheet, or database. Both a map and a data
@@ -9,7 +9,7 @@ symbol_files = glob.glob("mapdata/symbols/16x16/*.xbm") + glob.glob("mapdata/sym
9
9
  glob.glob("mapdata/symbols/24x24/*.xbm") + glob.glob("mapdata/symbols/28x28/*.xbm")
10
10
 
11
11
  setuptools.setup(name='mapdata',
12
- version='3.19.0',
12
+ version='3.21.0',
13
13
  description="An interactive map and table explorer for geographic coordinates in a spreadsheet, CSV file, or database that includes data plotting and statistical summaries",
14
14
  author='Dreas Nielsen',
15
15
  author_email='cortice@tutanota.com',
@@ -36,7 +36,7 @@ setuptools.setup(name='mapdata',
36
36
  'Topic :: Office/Business',
37
37
  'Topic :: Scientific/Engineering'
38
38
  ],
39
- keywords=['Map', 'Locations', 'CRS', 'CSV', 'Spreadsheet', 'Database', 'PNG', 'JPG', 'Postscript'],
39
+ keywords=['Map', 'Locations', 'CRS', 'CSV', 'Spreadsheet', 'Database', 'Statistics', 'Plotting', 'PNG', 'JPG', 'Postscript'],
40
40
  long_description_content_type="text/markdown",
41
41
  long_description=long_description
42
42
  )
File without changes
File without changes
File without changes