test_svg.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. # Tests SVG output and validity
  2. import os
  3. import unittest
  4. from xml.dom.minidom import parseString as parse_xml_string
  5. from shapely.geometry import (
  6. LineString,
  7. MultiLineString,
  8. MultiPoint,
  9. MultiPolygon,
  10. Point,
  11. Polygon,
  12. )
  13. from shapely.geometry.collection import GeometryCollection
  14. class SvgTestCase(unittest.TestCase):
  15. def assertSVG(self, geom, expected, **kwrds):
  16. """Helper function to check XML and debug SVG"""
  17. svg_elem = geom.svg(**kwrds)
  18. try:
  19. parse_xml_string(svg_elem)
  20. except Exception:
  21. raise AssertionError("XML is not valid for SVG element: " + str(svg_elem))
  22. svg_doc = geom._repr_svg_()
  23. try:
  24. doc = parse_xml_string(svg_doc)
  25. except Exception:
  26. raise AssertionError("XML is not valid for SVG document: " + str(svg_doc))
  27. svg_output_dir = None
  28. # svg_output_dir = '.' # useful for debugging SVG files
  29. if svg_output_dir:
  30. fname = geom.geom_type
  31. if geom.is_empty:
  32. fname += "_empty"
  33. if not geom.is_valid:
  34. fname += "_invalid"
  35. if kwrds:
  36. fname += "_" + ",".join(str(k) + "=" + str(kwrds[k]) for k in kwrds)
  37. svg_path = os.path.join(svg_output_dir, fname + ".svg")
  38. with open(svg_path, "w") as fp:
  39. fp.write(doc.toprettyxml())
  40. assert svg_elem == expected
  41. def test_point(self):
  42. # Empty
  43. self.assertSVG(Point(), "<g />")
  44. # Valid
  45. g = Point(6, 7)
  46. self.assertSVG(
  47. g,
  48. '<circle cx="6.0" cy="7.0" r="3.0" stroke="#555555" '
  49. 'stroke-width="1.0" fill="#66cc99" opacity="0.6" />',
  50. )
  51. self.assertSVG(
  52. g,
  53. '<circle cx="6.0" cy="7.0" r="15.0" stroke="#555555" '
  54. 'stroke-width="5.0" fill="#66cc99" opacity="0.6" />',
  55. scale_factor=5,
  56. )
  57. def test_multipoint(self):
  58. # Empty
  59. self.assertSVG(MultiPoint(), "<g />")
  60. # Valid
  61. g = MultiPoint([(6, 7), (3, 4)])
  62. self.assertSVG(
  63. g,
  64. '<g><circle cx="6.0" cy="7.0" r="3.0" stroke="#555555" '
  65. 'stroke-width="1.0" fill="#66cc99" opacity="0.6" />'
  66. '<circle cx="3.0" cy="4.0" r="3.0" stroke="#555555" '
  67. 'stroke-width="1.0" fill="#66cc99" opacity="0.6" /></g>',
  68. )
  69. self.assertSVG(
  70. g,
  71. '<g><circle cx="6.0" cy="7.0" r="15.0" stroke="#555555" '
  72. 'stroke-width="5.0" fill="#66cc99" opacity="0.6" />'
  73. '<circle cx="3.0" cy="4.0" r="15.0" stroke="#555555" '
  74. 'stroke-width="5.0" fill="#66cc99" opacity="0.6" /></g>',
  75. scale_factor=5,
  76. )
  77. def test_linestring(self):
  78. # Empty
  79. self.assertSVG(LineString(), "<g />")
  80. # Valid
  81. g = LineString([(5, 8), (496, -6), (530, 20)])
  82. self.assertSVG(
  83. g,
  84. '<polyline fill="none" stroke="#66cc99" stroke-width="2.0" '
  85. 'points="5.0,8.0 496.0,-6.0 530.0,20.0" opacity="0.8" />',
  86. )
  87. self.assertSVG(
  88. g,
  89. '<polyline fill="none" stroke="#66cc99" stroke-width="10.0" '
  90. 'points="5.0,8.0 496.0,-6.0 530.0,20.0" opacity="0.8" />',
  91. scale_factor=5,
  92. )
  93. # Invalid
  94. self.assertSVG(
  95. LineString([(0, 0), (0, 0)]),
  96. '<polyline fill="none" stroke="#ff3333" stroke-width="2.0" '
  97. 'points="0.0,0.0 0.0,0.0" opacity="0.8" />',
  98. )
  99. def test_multilinestring(self):
  100. # Empty
  101. self.assertSVG(MultiLineString(), "<g />")
  102. # Valid
  103. self.assertSVG(
  104. MultiLineString([[(6, 7), (3, 4)], [(2, 8), (9, 1)]]),
  105. '<g><polyline fill="none" stroke="#66cc99" stroke-width="2.0" '
  106. 'points="6.0,7.0 3.0,4.0" opacity="0.8" />'
  107. '<polyline fill="none" stroke="#66cc99" stroke-width="2.0" '
  108. 'points="2.0,8.0 9.0,1.0" opacity="0.8" /></g>',
  109. )
  110. # Invalid
  111. self.assertSVG(
  112. MultiLineString([[(2, 3), (2, 3)], [(2, 8), (9, 1)]]),
  113. '<g><polyline fill="none" stroke="#ff3333" stroke-width="2.0" '
  114. 'points="2.0,3.0 2.0,3.0" opacity="0.8" />'
  115. '<polyline fill="none" stroke="#ff3333" stroke-width="2.0" '
  116. 'points="2.0,8.0 9.0,1.0" opacity="0.8" /></g>',
  117. )
  118. def test_polygon(self):
  119. # Empty
  120. self.assertSVG(Polygon(), "<g />")
  121. # Valid
  122. g = Polygon(
  123. [(35, 10), (45, 45), (15, 40), (10, 20), (35, 10)],
  124. [[(20, 30), (35, 35), (30, 20), (20, 30)]],
  125. )
  126. self.assertSVG(
  127. g,
  128. '<path fill-rule="evenodd" fill="#66cc99" stroke="#555555" '
  129. 'stroke-width="2.0" opacity="0.6" d="M 35.0,10.0 L 45.0,45.0 L '
  130. "15.0,40.0 L 10.0,20.0 L 35.0,10.0 z M 20.0,30.0 L 35.0,35.0 L "
  131. '30.0,20.0 L 20.0,30.0 z" />',
  132. )
  133. self.assertSVG(
  134. g,
  135. '<path fill-rule="evenodd" fill="#66cc99" stroke="#555555" '
  136. 'stroke-width="10.0" opacity="0.6" d="M 35.0,10.0 L 45.0,45.0 L '
  137. "15.0,40.0 L 10.0,20.0 L 35.0,10.0 z M 20.0,30.0 L 35.0,35.0 L "
  138. '30.0,20.0 L 20.0,30.0 z" />',
  139. scale_factor=5,
  140. )
  141. # Invalid
  142. self.assertSVG(
  143. Polygon([(0, 40), (0, 0), (40, 40), (40, 0), (0, 40)]),
  144. '<path fill-rule="evenodd" fill="#ff3333" stroke="#555555" '
  145. 'stroke-width="2.0" opacity="0.6" d="M 0.0,40.0 L 0.0,0.0 L '
  146. '40.0,40.0 L 40.0,0.0 L 0.0,40.0 z" />',
  147. )
  148. def test_multipolygon(self):
  149. # Empty
  150. self.assertSVG(MultiPolygon(), "<g />")
  151. # Valid
  152. self.assertSVG(
  153. MultiPolygon(
  154. [
  155. Polygon([(40, 40), (20, 45), (45, 30), (40, 40)]),
  156. Polygon(
  157. [(20, 35), (10, 30), (10, 10), (30, 5), (45, 20), (20, 35)],
  158. [[(30, 20), (20, 15), (20, 25), (30, 20)]],
  159. ),
  160. ]
  161. ),
  162. '<g><path fill-rule="evenodd" fill="#66cc99" stroke="#555555" '
  163. 'stroke-width="2.0" opacity="0.6" d="M 40.0,40.0 L 20.0,45.0 L '
  164. '45.0,30.0 L 40.0,40.0 z" />'
  165. '<path fill-rule="evenodd" fill="#66cc99" stroke="#555555" '
  166. 'stroke-width="2.0" opacity="0.6" d="M 20.0,35.0 L 10.0,30.0 L '
  167. "10.0,10.0 L 30.0,5.0 L 45.0,20.0 L 20.0,35.0 z M 30.0,20.0 L "
  168. '20.0,15.0 L 20.0,25.0 L 30.0,20.0 z" /></g>',
  169. )
  170. # Invalid
  171. self.assertSVG(
  172. MultiPolygon(
  173. [
  174. Polygon([(140, 140), (120, 145), (145, 130), (140, 140)]),
  175. Polygon([(0, 40), (0, 0), (40, 40), (40, 0), (0, 40)]),
  176. ]
  177. ),
  178. '<g><path fill-rule="evenodd" fill="#ff3333" stroke="#555555" '
  179. 'stroke-width="2.0" opacity="0.6" d="M 140.0,140.0 L '
  180. '120.0,145.0 L 145.0,130.0 L 140.0,140.0 z" />'
  181. '<path fill-rule="evenodd" fill="#ff3333" stroke="#555555" '
  182. 'stroke-width="2.0" opacity="0.6" d="M 0.0,40.0 L 0.0,0.0 L '
  183. '40.0,40.0 L 40.0,0.0 L 0.0,40.0 z" /></g>',
  184. )
  185. def test_collection(self):
  186. # Empty
  187. self.assertSVG(GeometryCollection(), "<g />")
  188. # Valid
  189. self.assertSVG(
  190. GeometryCollection([Point(7, 3), LineString([(4, 2), (8, 4)])]),
  191. '<g><circle cx="7.0" cy="3.0" r="3.0" stroke="#555555" '
  192. 'stroke-width="1.0" fill="#66cc99" opacity="0.6" />'
  193. '<polyline fill="none" stroke="#66cc99" stroke-width="2.0" '
  194. 'points="4.0,2.0 8.0,4.0" opacity="0.8" /></g>',
  195. )
  196. # Invalid
  197. self.assertSVG(
  198. Point(7, 3).union(LineString([(4, 2), (4, 2)])),
  199. '<g><circle cx="7.0" cy="3.0" r="3.0" stroke="#555555" '
  200. 'stroke-width="1.0" fill="#ff3333" opacity="0.6" />'
  201. '<polyline fill="none" stroke="#ff3333" stroke-width="2.0" '
  202. 'points="4.0,2.0 4.0,2.0" opacity="0.8" /></g>',
  203. )