Created
December 15, 2014 18:04
-
-
Save cmc333333/e1c105da44dd03ea1591 to your computer and use it in GitHub Desktop.
Relevant diff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/peacecorps/peacecorps/fixtures/countries.yaml b/peacecorps/peacecorps/fixtures/countries.yaml | |
| index 23ee6d9..a8c3b0b 100644 | |
| --- a/peacecorps/peacecorps/fixtures/countries.yaml | |
| +++ b/peacecorps/peacecorps/fixtures/countries.yaml | |
| @@ -268,7 +268,7 @@ | |
| - fields: {code: KWT, name: Kuwait} | |
| model: peacecorps.country | |
| pk: 90 | |
| -- fields: {code: KGZ, name: Kyrgyzstan} | |
| +- fields: {code: KGZ, name: Kyrgyz Republic} | |
| model: peacecorps.country | |
| pk: 91 | |
| - fields: {code: LAO, name: Laos} | |
| @@ -568,6 +568,12 @@ | |
| - fields: {code: ZWE, name: Zimbabwe} | |
| model: peacecorps.country | |
| pk: 190 | |
| -- fields: {code: GAM, name: Gambia} | |
| +- fields: {code: GMB, name: Gambia} | |
| model: peacecorps.country | |
| pk: 191 | |
| +- fields: {code: KOS, name: Kosovo} | |
| + model: peacecorps.country | |
| + pk: 192 | |
| +- fields: {code: ESC, name: Eastern Caribbean} | |
| + model: peacecorps.country | |
| + pk: 193 | |
| diff --git a/peacecorps/peacecorps/scripts/README.md b/peacecorps/peacecorps/scripts/README.md | |
| index 0cca5f5..1c53585 100644 | |
| --- a/peacecorps/peacecorps/scripts/README.md | |
| +++ b/peacecorps/peacecorps/scripts/README.md | |
| @@ -11,12 +11,13 @@ quickly exceeds a reasonable amount of memory. This script, then, splits the | |
| world map into component countries, providing context in the form of | |
| surrounding countries and highlighting/zooming to the selected country. | |
| -To use the script, you must first install a python | |
| -[library](https://github.com/cjlano/svg) from source. Clone that repository | |
| +To use the script, you must first install two python libraries: `lxml` and | |
| +[svg](https://github.com/cjlano/svg) from source. Clone the latter repository | |
| within this `scripts` directory. Then run the script with the input SVG file | |
| and the output directory: | |
| ```bash | |
| +pip install lxml | |
| git clone https://github.com/cjlano/svg.git | |
| python cropmap.py ../static/peacecorps/img/BlankMap-World6.svg ../static/peacecorps/img/countries/ | |
| ``` | |
| @@ -26,3 +27,12 @@ takes around 5 minutes to run on a decent machine. | |
| TODO: It'd make sense to simplify the shapes/otherwise reduce the file size. | |
| The script removes unseen countries, but it could definitely be improved. | |
| + | |
| +## Crop To | |
| + | |
| +Similar to the above script, but zooms in to a particular area instead of a | |
| +single country. | |
| + | |
| +```bash | |
| +python croptoview.py ../static/peacecorps/img/BlankMap-World6.svg ../static/peacecorps/img/countries/esc.svg 700 560 125 125 | |
| +``` | |
| diff --git a/peacecorps/peacecorps/scripts/cropmap.py b/peacecorps/peacecorps/scripts/cropmap.py | |
| index cc6d9e7..4d3bb37 100644 | |
| --- a/peacecorps/peacecorps/scripts/cropmap.py | |
| +++ b/peacecorps/peacecorps/scripts/cropmap.py | |
| @@ -7,8 +7,8 @@ import itertools | |
| import logging | |
| import os | |
| import sys | |
| -import xml.etree.ElementTree as ET | |
| +from lxml import etree | |
| import svg | |
| @@ -40,13 +40,11 @@ def zoom_with_context(doc, el_id): | |
| factor = 1 + (2 * margin) | |
| zoomPercent = factor * bndWidth / svgWidth | |
| - if zoomPercent < 0.05: | |
| - root.set('class', root.get('class') + ' zoom4') | |
| - elif zoomPercent < 0.1: | |
| - root.set('class', root.get('class') + ' zoom3') | |
| - elif zoomPercent < 0.2: | |
| - root.set('class', root.get('class') + ' zoom2') | |
| - else: | |
| + thresholds = [0.2 / (2**i) for i in range(5)] | |
| + for idx, threshold in enumerate(reversed(thresholds)): | |
| + if zoomPercent < threshold: | |
| + root.set('class', root.get('class') + ' zoom%d' % (6-idx)) | |
| + if zoomPercent >= 0.2: | |
| root.set('class', root.get('class') + ' zoom1') | |
| root.set('viewBox', '%d %d %d %d' % ( | |
| @@ -72,16 +70,15 @@ def crop_to(doc, bboxes): | |
| for key, bbox in bboxes.items(): | |
| if not overlaps(left, top, right, bottom, | |
| bbox[0].x, bbox[0].y, bbox[1].x, bbox[1].y): | |
| - parent = root.find(".//*[@id='%s']/.." % key) | |
| - parent.remove(parent.find("./*[@id='%s']" % key)) | |
| + element = root.find(".//*[@id='%s']" % key) | |
| + element.getparent().remove(element) | |
| # Delete any groups which no longer have children. We run this five times | |
| # to account for nesting | |
| for _ in range(5): | |
| - for parent in root.iterfind(".//svg:g/..", namespaces): | |
| - for child in parent.iterfind("svg:g", namespaces): | |
| - if len(child) == 0 or (len(child) == 1 | |
| - and child[0].tag.endswith('title')): | |
| - parent.remove(child) | |
| + for group in root.iterfind(".//svg:g", namespaces): | |
| + if len(group) == 0 or (len(group) == 1 | |
| + and group[0].tag.endswith('title')): | |
| + group.getparent().remove(group) | |
| def ids_to_bboxes(root): | |
| @@ -89,24 +86,34 @@ def ids_to_bboxes(root): | |
| box""" | |
| namespaces = {"svg": "http://www.w3.org/2000/svg"} | |
| mapping = {} | |
| - for path in itertools.chain( | |
| - root.iterfind(".//svg:path[@id]", namespaces), | |
| - root.iterfind(".//svg:circle[@id]", namespaces)): | |
| + for path in root.iterfind(".//svg:path[@id]", namespaces): | |
| mapping[path.get('id')] = bbox(path) | |
| return mapping | |
| -def bbox(svg_el): | |
| +def bbox(xml_el): | |
| """Bounding box for this svg element. Accounts for transformations""" | |
| - if svg_el.tag.endswith("path"): | |
| - return svg.Path(svg_el).bbox() | |
| - elif svg_el.tag.endswith("circle"): | |
| - return svg.Circle(svg_el).bbox() | |
| + if xml_el.tag.endswith("path"): | |
| + svg_el = svg.Path(xml_el) | |
| else: | |
| - group = svg.Group(svg_el) | |
| - group.append(svg_el) | |
| - group.transform() | |
| - return group.bbox() | |
| + svg_el = svg.Group(xml_el) | |
| + svg_el.append(xml_el) | |
| + svg_el.transform() | |
| + return svg_el.bbox() | |
| + | |
| + top_el = svg_el | |
| + ancestor = xml_el.getparent() | |
| + while ancestor is not None: | |
| + if ancestor.tag.endswith("g"): | |
| + new_top = svg.Group(ancestor) | |
| + new_top.items.append(top_el) | |
| + top_el.matrix = new_top.matrix * top_el.matrix | |
| + top_el = new_top | |
| + ancestor = ancestor.getparent() | |
| + | |
| + if top_el != svg_el: | |
| + top_el.transform() | |
| + return top_el.bbox() | |
| def country_code(xml_el, namespaces): | |
| @@ -128,12 +135,15 @@ def cropmap(map_path, outputdir): | |
| """For each country in the map, create a new map file zoomed to that | |
| highlighted country""" | |
| namespaces = {"svg": "http://www.w3.org/2000/svg"} | |
| - doc = ET.parse(map_path) | |
| + doc = etree.parse(map_path) | |
| root = doc.getroot() | |
| + # Remove all circles | |
| + for xml_el in root.iterfind(".//svg:circle", namespaces): | |
| + xml_el.getparent().remove(xml_el) | |
| bboxes = ids_to_bboxes(root) | |
| for xml_el in itertools.chain(root.iterfind("svg:path", namespaces), | |
| root.iterfind("svg:g", namespaces)): | |
| - if "landxx" in xml_el.get('class', ''): # skip the ocean paths | |
| + if "oceanxx" not in xml_el.get('class', ''): # skip the ocean paths | |
| code = country_code(xml_el, namespaces) | |
| copy_doc = copy.deepcopy(doc) | |
| highlight(copy_doc, xml_el.get('id')) | |
| diff --git a/peacecorps/peacecorps/scripts/croptoview.py b/peacecorps/peacecorps/scripts/croptoview.py | |
| new file mode 100644 | |
| index 0000000..523336f | |
| --- /dev/null | |
| +++ b/peacecorps/peacecorps/scripts/croptoview.py | |
| @@ -0,0 +1,27 @@ | |
| +"""Given viewport coordinates, cuts out all elements not in view.""" | |
| +import sys | |
| + | |
| +from lxml import etree | |
| + | |
| +from cropmap import ids_to_bboxes, crop_to | |
| + | |
| + | |
| +def croptoview(map_path, out_path, coords): | |
| + """Crops the provided map to the given viewbox""" | |
| + namespaces = {"svg": "http://www.w3.org/2000/svg"} | |
| + doc = etree.parse(map_path) | |
| + root = doc.getroot() | |
| + # Remove all circles | |
| + for xml_el in root.iterfind(".//svg:circle", namespaces): | |
| + xml_el.getparent().remove(xml_el) | |
| + bboxes = ids_to_bboxes(root) | |
| + root.set('viewBox', ' '.join(coords)) | |
| + crop_to(doc, bboxes) | |
| + doc.write(out_path) | |
| + | |
| +if __name__ == "__main__": | |
| + if len(sys.argv) < 7: | |
| + print("Usage: python croptoview.py /path/to/insvg /path/to/outsvg" | |
| + + " [view coords]") | |
| + else: | |
| + croptoview(sys.argv[1], sys.argv[2], sys.argv[3:]) | |
| diff --git a/peacecorps/peacecorps/static/peacecorps/img/BlankMap-World6.svg b/peacecorps/peacecorps/static/peacecorps/img/BlankMap-World6.svg | |
| index b9bbb3b..c76518b 100644 | |
| --- a/peacecorps/peacecorps/static/peacecorps/img/BlankMap-World6.svg | |
| +++ b/peacecorps/peacecorps/static/peacecorps/img/BlankMap-World6.svg | |
| @@ -3,9 +3,6 @@ | |
| width="127"> | |
| <title>World Map</title> | |
| <defs id="defs2987"/> | |
| - <defs> | |
| - <link xmlns="http://www.w3.org/1999/xhtml" href="../css/svg.css" type="text/css" rel="stylesheet" /> | |
| - </defs> | |
| <style id="style_css_sheet" type="text/css"> | |
| /* | |
| * Below are Cascading Style Sheet (CSS) definitions in use in this file, | |
| @@ -21,6 +18,12 @@ | |
| stroke: #ffffff; | |
| fill-rule: evenodd; | |
| } | |
| +.world_map.zoom6 .landxx { | |
| + stroke-width: 0.1px; | |
| +} | |
| +.world_map.zoom5 .landxx { | |
| + stroke-width: 1px; | |
| +} | |
| .world_map.zoom4 .landxx { | |
| stroke-width: 2px; | |
| } | |
| @@ -433,6 +436,10 @@ | |
| <circle class="unxx xk srb" cx="1423.1255" cy="389.55505" id="xk_" r="4.2337999"/> | |
| </g> | |
| </g> | |
| + <g id="kosovo"> | |
| + <title>Kosovo</title> | |
| + <path class="landxx kos" d="M 1416.3623,389.94751 C 1416.7509,389.65989 1417.5637,389.13913 1417.9667,389.32013 1418.0687,388.63313 1418.1418,389.41593 1418.4127,388.95877 1418.8529,388.21601 1419.3863,388.31955 1419.8723,388.11055 1420.8673,387.68155 1420.8397,387.22655 1420.3697,386.13355 1420.8427,386.06955 1421.436,385.74223 1421.829,385.47023 1422.131,387.43223 1426.9617,386.74303 1426.6217,388.69403 1426.4497,389.68003 1428.362,390.03069 1428.57,390.84069 1428.875,392.02669 1426.6523,393.24027 1427.5263,394.19827 1426.7343,394.56435 1425.5126,394.61471 1425.8076,395.57733 1424.6058,395.42781 1424.8132,394.75663 1423.0556,395.46431 1421.6552,396.02813 1421.7462,397.66257 1421.025,397.88148 1420.5465,397.74941 1421.2253,395.48841 1420.2357,394.71861 1419.9956,393.85512 1419.1386,394.1619 1418.2791,393.5074 1417.7134,392.59298 1418.123,392.12743 1417.066,391.79403 1416.8527,391.30085 1415.8868,390.34349 1416.3623,389.94751" id="kos"/> | |
| + </g> | |
| <path class="landxx civ" d="M 1205.0463,703.22155 C 1205.4743,702.29655 1206.5863,702.09455 1206.9753,701.10055 1207.2323,700.44155 1207.4323,699.38955 1207.4763,698.68655 1207.5573,697.41155 1207.0503,695.09455 1206.1263,694.14955 1206.7173,693.52555 1207.5333,693.84655 1208.1363,694.22155 1208.2663,693.46555 1209.4793,692.64155 1209.0013,691.80955 1208.6143,691.13655 1209.2483,689.70355 1210.1563,690.18955 1209.4683,689.16755 1208.2673,688.53355 1207.9573,687.27255 1207.3733,684.89955 1211.8073,686.76555 1212.5263,687.09355 1212.0093,685.51755 1212.2033,683.75955 1210.1563,683.42155 1210.5293,682.36955 1210.5343,681.24855 1211.8863,681.04555 1210.7623,679.71455 1210.5503,680.00255 1210.9463,678.02155 1208.5033,679.59455 1208.607,674.18217 1208.9263,672.98155 1209.2336,671.82601 1210.0541,671.53216 1211.0739,671.23195 1211.6261,671.0694 1211.6653,670.03555 1212.0963,669.66955 1212.7313,669.13155 1213.4793,669.47955 1214.1863,669.16555 1214.0343,670.56955 1216.8723,671.97155 1218.0063,671.46955 1217.2413,670.20255 1218.5413,670.13055 1219.4673,670.14555 1220.7043,670.16455 1220.2673,668.11255 1220.3053,667.29355 1220.7923,667.56455 1221.2983,668.48255 1221.9653,668.30155 1222.6053,668.12655 1222.7323,666.92355 1223.4053,666.64555 1223.9563,667.64355 1223.1722,671.00242 1224.6113,671.35955 1225.912,671.68234 1224.8646,668.85207 1228.8023,668.97058 1229.1841,668.98208 1227.9675,670.10664 1231.1181,670.30557 1232.6007,670.39917 1232.9073,673.32892 1233.1083,673.56855 1234.1493,674.80953 1236.0825,676.11736 1238.0153,676.50955 1238.0333,674.76255 1240.6063,674.38555 1241.8353,673.91755 1242.9593,673.48955 1245.8643,674.77455 1246.5853,673.70155 1247.791,675.13272 1248.2783,676.69128 1249.8953,678.23655 1250.0783,678.00555 1250.2483,677.76555 1250.4053,677.51655 1250.8791,678.94563 1249.7717,680.31128 1249.9773,681.03255 1250.3197,682.23406 1251.0293,682.81355 1251.1913,684.20255 1251.3253,685.35255 1252.0373,687.29355 1251.6143,688.37655 1251.1373,689.59555 1250.5229,690.24855 1249.9269,691.35555 1249.1329,692.82955 1247.7838,693.68681 1247.8279,695.32062 1247.8849,697.44794 1246.8352,698.99807 1246.4023,700.57515 1245.9443,702.2437 1246.1578,704.93442 1247.1853,706.28755 1248.1975,707.62055 1248.6663,709.41955 1248.2783,710.85255 1250.8393,710.14355 1249.3393,714.03255 1249.7563,715.24555 1249.2413,715.23655 1248.7373,715.30855 1248.2463,715.46155 1248.3943,715.18655 1248.5613,714.92155 1248.7463,714.66955 1247.5423,716.47755 1246.5483,714.20255 1246.2963,713.30155 1245.6453,714.02155 1245.4003,715.01955 1244.2863,715.10155 1243.5653,715.15455 1242.6433,714.81355 1242.1263,714.30955 1241.7283,715.04255 1240.8153,714.34855 1240.4663,714.02155 1241.0933,713.88355 1241.7913,714.49655 1242.2663,713.80555 1242.0593,713.57155 1241.8203,713.37955 1241.5463,713.22955 1241.8443,714.66755 1241.2553,713.32855 1240.2563,713.58955 1240.4633,714.01655 1237.8873,713.77255 1237.2613,713.84155 1236.9413,713.87755 1233.7433,714.44855 1234.0013,714.58755 1235.6053,715.45455 1238.7493,712.68155 1240.0363,714.30955 1238.0423,714.41855 1236.1343,714.74655 1234.1813,715.09355 1233.7413,715.17155 1232.8283,715.35955 1232.5473,714.84055 1232.1493,714.10955 1230.2193,714.44255 1229.5273,715.10155 1230.6613,714.64755 1231.2893,714.76855 1232.4073,715.17355 1229.9553,715.45455 1227.3423,715.32055 1225.0313,716.31855 1223.0353,717.17955 1221.2433,718.79855 1219.0123,719.02555 1217.8763,719.14155 1215.4503,720.42555 1214.6153,721.22955 1212.7383,723.03655 1212.4093,719.69855 1212.7013,718.32355 1213.0483,716.68755 1213.6143,714.88155 1214.0673,713.52855 1214.6693,711.73455 1214.1553,709.77655 1212.7353,708.58455 1211.8733,707.86155 1210.6213,707.53655 1210.7623,706.02155 1210.9243,704.28355 1205.6223,705.79555 1206.6963,703.79755 1206.0613,703.94255 1205.4873,703.65955 1205.0463,703.22155" id="ci"> | |
| <title>Cote d'Ivoire</title> | |
| </path> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment