Pytmx rendering animated tiles from Tiled map - python
So I have been working on a project for some time now and I realy wanted to get animated tiles in to the game. Im creating a 2d pixel art styled game with pygame and Im using the an editor called Tiled to create the map. Tiled generates a .tmx file as well as a .tsx file to be used to render the map. I have gotten the map to render without any problems. The problems comes with rendering animated tiles. They just dont get animated. I understand the basics of how the animation works. I just need to get the first image of the animation, wait the duration between frames and then render the next frame. But I just cant figure out how to get it working. There is minimal documentation of pytmx and how it reads animations from Tiled files.
This is the .tmx file:
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.2" tiledversion="1.3.4" orientation="orthogonal" renderorder="right-down" width="32" height="32" tilewidth="96" tileheight="96" infinite="0" nextlayerid="5" nextobjectid="5">
<tileset firstgid="1" source="Bigger-Textures(96x96).tsx"/>
<layer id="1" name="Tile Layer 1" width="32" height="32">
<data encoding="csv">
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,4,6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,13,15,1,1,1,1,1,1,12,12,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,13,15,1,1,1,1,1,1,11,12,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,13,25,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,22,23,23,23,23,23,23,23,9,7,23,23,23,23,23,23,24,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,13,15,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,13,15,1,1,1,1,12,3,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,12,12,1,4,5,5,27,25,5,5,6,1,1,12,12,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,11,12,1,13,7,8,9,7,8,9,15,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,12,1,1,13,16,17,18,16,11,18,15,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,13,25,26,27,25,26,27,15,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,13,7,23,23,23,23,23,24,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,13,15,1,1,1,1,1,10,12,12,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,13,15,1,1,1,1,1,12,1,12,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,13,25,5,5,5,5,5,5,5,5,5,6,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,22,23,23,23,23,23,23,23,23,23,23,24,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
</data>
</layer>
<objectgroup id="4" name="Obstacles">
<object id="1" name="wall" x="0" y="-96" width="3168" height="96"/>
<object id="2" name="wall" x="3072" y="0" width="96" height="3168"/>
<object id="3" name="wall" x="-96" y="3072" width="3168" height="96"/>
<object id="4" name="wall" x="-96" y="-96" width="96" height="3168"/>
</objectgroup>
</map>
And this is the .tsx file:
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.2" tiledversion="1.3.4" name="Bigger-Textures (96x96)" tilewidth="96" tileheight="96" tilecount="81" columns="9">
<image source="../gfx/tiles/tilesheets/Textures-sprite-sheet-4X.png" width="864" height="864"/>
<tile id="1">
<animation>
<frame tileid="1" duration="500"/>
<frame tileid="2" duration="500"/>
</animation>
</tile>
<tile id="2">
<animation>
<frame tileid="2" duration="500"/>
<frame tileid="1" duration="500"/>
</animation>
</tile>
<tile id="9">
<animation>
<frame tileid="9" duration="500"/>
<frame tileid="10" duration="500"/>
</animation>
</tile>
<tile id="10">
<animation>
<frame tileid="10" duration="500"/>
<frame tileid="9" duration="500"/>
</animation>
</tile>
</tileset>
And this is how I currently render the tiles:
def render(self):
self.ti = self.handler.currentMap.get_tile_image_by_gid
xStart = max(0, self.handler.camera.xOffset / self.handler.currentMap.tilewidth)
xEnd = min(self.handler.currentMap.width, (self.handler.camera.xOffset + self.handler.displayWidth) / self.handler.currentMap.tilewidth + 1)
yStart = max(0, self.handler.camera.yOffset / self.handler.currentMap.tileheight)
yEnd = min(self.handler.currentMap.height, (self.handler.camera.yOffset + self.handler.displayHeight) / self.handler.currentMap.tileheight + 1)
for i in range(len(self.handler.currentMap.layers) - 1):
for x in range(int(xStart), int(xEnd)):
for y in range(int(yStart), int(yEnd)):
tile = self.handler.currentMap.get_tile_image(x, y, i)
if (tile):
self.display.blit(tile, (x * self.handler.currentMap.tilewidth - self.handler.camera.xOffset,
y * self.handler.currentMap.tileheight - self.handler.camera.yOffset))
This is what it says on the Pytmx github :
# just iterate over animated tiles and demo them
# tmx_map is a TiledMap object
# tile_properties is a dictionary of all tile properties
# iterate over the tile properties
for gid, props in tmx_map.tile_properties.items():
# iterate over the frames of the animation
# if there is no animation, this list will be empty
for animation_frame in props['frames']:
# do something with the gid and duration of the frame
# this may change in the future, as it is a little awkward now
image = tmx_map.get_tile_image_by_gid(gid)
duration = animation_frame.duration
...
Any help is greatly appreciated!
Here is the project on GitHub if it is to any use :D
I had fun looking for this today. And it's not that complicated after all.
I made something like this in Tiled
Note the animated water tiles.
Now look at the code below:
def update(self, frame):
if frame in getFrequencyList(6):
self.current_anim_index += 1
if self.current_anim_index == 4:
self.current_anim_index = 0
def getSurface(self):
for layer in self.tmx_data.visible_layers:
for x, y, image in layer.tiles():
for gid, props in self.tmx_data.tile_properties.items():
if image == self.tmx_data.get_tile_image_by_gid(props['frames'][0].gid):
image = self.tmx_data.get_tile_image_by_gid(props['frames'][self.current_anim_index].gid)
self.surface.blit(image, (x * 16, y * 16))
else:
self.surface.blit(image, ((x * 16) + layer.offsetx, (y * 16) + layer.offsety))
return super().getSurface()
when you browse the list of tiles by layers, you recover the image by position (x and y).
The principle is that, before displaying the current image (the tile), we check that it is not in fact an animation.
For that you have to get all the animated tiles.
So we do
for gid, props in self.tmx_data.tile_properties.items():
All animated tiles are in props['frames'].
If you look at your tsx file, you could see something like this :
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.5" tiledversion="1.6.0" name="Overworld (Light)"
tilewidth="16" tileheight="16" tilecount="1664" columns="52">
<image source="Overworld (Light).png" trans="ff00ff" width="832" height="512"/>
<tile id="30">
<animation>
<frame tileid="30" duration="250"/>
<frame tileid="82" duration="250"/>
<frame tileid="134" duration="250"/>
<frame tileid="186" duration="250"/>
</animation>
</tile>
...
So each part of props['frame'] are tables represent each animation nodes.
So
if image == self.tmx_data.get_tile_image_by_gid(props['frames'][0].gid):
means that current image is an animated tile. In that case all you need to de is to blit one of the tile in your props['frame'] table. As you can see I created a current_anim_index attribute. I vary it in the update method.
I make sure that this is called in my game loop. The frame argument varies from 0 to 60 (Yes, 60 FPS). And getFrequencyList(6) return a table like [0, 10, 20, 30, 40, 50].
Related
sumo problem when using traci.person.getPosition3D(Persons[i]) the z axis value is zero
hello I'm using python to get the person traces in my parking scenario as I'm trying to get the person position in 3D but the Z value shows as z in all his stages here is my code and output Persons = traci.person.getIDList(); PersonsLists = [] for i in range(0,len(Persons)): [enter image description here][1]personid = Persons[i] perSpeedFactor = traci.person.getSpeedFactor(Persons[i]) perSpeed = traci.person.getSpeed(Persons[i]) perPos2D = traci.person.getPosition(Persons[i]) perPos3D = traci.person.getPosition3D(Persons[i]) perRemainStage = traci.person.getRemainingStages(Persons[i]) perVehid = traci.person.getVehicle(Persons[i]) perStage = traci.person.getStage(Persons[i],0) #Packing of all the data for export to CSV/XLSX PersonsLists = [getdatetime(), personid, perSpeedFactor, perSpeed, perPos2D, perPos3D, perRemainStage, perVehid, perStage] here is one of the examples of the route file <trip id="62472_377_0" depart="22284.00" from="133859192" to="154755102#0" type="pkw"> <stop duration="400" parkingArea="pa154755102#0_17" triggered="person" /> </trip> <person id="per11" depart="triggered" type="person" speedFactor= "1.7"> <ride from="133859192" to="154755102#0" lines="62472_377_0"/> <walk to= "154755102#0" duration= "400"/> <walk to= "154755102#0" parkingArea="pa154755102#0_17" arrivalPos="71.00"/> <ride to="154755102#0" lines="62472_377_0"/> </person> output
How to extract data from GML file
I have a text file and would like to extract the <gml:pos>73664.300 836542.700</gml:pos> from it. More precisely I would like to get the GPS coordinate system [73664.300 836542.700] from the pos tag. The file contains multiple <wfs:member> and each of them has a <gml:pos> (deepest layer). <?xml version='1.0' encoding='UTF-8'?> <wfs:FeatureCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd http://www.deegree.org/app https://web.de/feature_descr?SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&OUTPUTFORMAT=application%2Fgml%2Bxml%3B+version%3D3.2&TYPENAME=app:lsa_data&NAMESPACES=xmlns(app,http%3A%2F%2Fwww.deegree.org%2Fapp)" xmlns:wfs="http://www.opengis.net/wfs/2.0" timeStamp="2020-11-18T15:01:17Z" xmlns:gml="http://www.opengis.net/gml/3.2" numberMatched="unknown" numberReturned="0"> <!--NOTE: numberReturned attribute should be 'unknown' as well, but this would not validate against the current version of the WFS 2.0 schema (change upcoming). See change request (CR 144): https://portal.opengeospatial.org/files?fact_id=6798.--> <wfs:member> <app:dat_set xmlns:app="http://www.deegree.org/app" gml:id="app:dat_set_1"> <app:point>2</app:point> <app:art>K </app:art> <app:L_Name>westt / woustest </app:L_Name> <app:geom> <!--Inlined geometry 'data_1_APP_GEOM'--> <gml:MultiPoint gml:id="data_1_APP_GEOM" srsName="EPSG:25832"> <gml:pointMember> <gml:Point gml:id="GEOMETRY_ad608059-f297-4554-8464-cdde248cb531" srsName="EPSG:25832"> <gml:pos>73664.300 836542.700</gml:pos> </gml:Point> </gml:pointMember> </gml:MultiPoint> </app:geom> </app:lsa_pointdata> </wfs:member> <wfs:member> <app:dat_set xmlns:app="http://www.deegree.org/app" gml:id="app:dat_set_2"> <app:point>3</app:point> <app:art>K </app:art> <app:L_Name>route / riztr </app:L_Name> <app:geom> <!--Inlined geometry 'data_2_APP_GEOM'--> <gml:MultiPoint gml:id="data_2_APP_GEOM" srsName="EPSG:25832"> <gml:pointMember> <gml:Point gml:id="GEOMETRY_440d8630-b674-4768-a5b7-3fab46d9ac8c" srsName="EPSG:25832"> <gml:pos>74354.900 837456.300</gml:pos> </gml:Point> </gml:pointMember> </gml:MultiPoint> </app:geom> </app:lsa_pointdata> </wfs:member> <wfs:member> ... ... How could I get those gps coordinates ? Thank you in advance.
You can use lxml and XPATH. data = b'''\ <?xml version='1.0' encoding='UTF-8'?> <wfs:FeatureCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd http://www.deegree.org/app https://web.de/feature_descr?SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType&OUTPUTFORMAT=application%2Fgml%2Bxml%3B+version%3D3.2&TYPENAME=app:lsa_data&NAMESPACES=xmlns(app,http%3A%2F%2Fwww.deegree.org%2Fapp)" xmlns:wfs="http://www.opengis.net/wfs/2.0" timeStamp="2020-11-18T15:01:17Z" xmlns:gml="http://www.opengis.net/gml/3.2" numberMatched="unknown" numberReturned="0"> <!--NOTE: numberReturned attribute should be 'unknown' as well, but this would not validate against the current version of the WFS 2.0 schema (change upcoming). See change request (CR 144): https://portal.opengeospatial.org/files?fact_id=6798.--> <wfs:member> <app:dat_set xmlns:app="http://www.deegree.org/app" gml:id="app:dat_set_1"> <app:point>2</app:point> <app:art>K </app:art> <app:L_Name>westt / woustest </app:L_Name> <app:geom> <!--Inlined geometry 'data_1_APP_GEOM'--> <gml:MultiPoint gml:id="data_1_APP_GEOM" srsName="EPSG:25832"> <gml:pointMember> <gml:Point gml:id="GEOMETRY_ad608059-f297-4554-8464-cdde248cb531" srsName="EPSG:25832"> <gml:pos>73664.300 836542.700</gml:pos> </gml:Point> </gml:pointMember> </gml:MultiPoint> </app:geom> </app:dat_set> </wfs:member> <wfs:member> <app:dat_set xmlns:app="http://www.deegree.org/app" gml:id="app:dat_set_2"> <app:point>3</app:point> <app:art>K </app:art> <app:L_Name>route / riztr </app:L_Name> <app:geom> <!--Inlined geometry 'data_2_APP_GEOM'--> <gml:MultiPoint gml:id="data_2_APP_GEOM" srsName="EPSG:25832"> <gml:pointMember> <gml:Point gml:id="GEOMETRY_440d8630-b674-4768-a5b7-3fab46d9ac8c" srsName="EPSG:25832"> <gml:pos>74354.900 837456.300</gml:pos> </gml:Point> </gml:pointMember> </gml:MultiPoint> </app:geom> </app:dat_set> </wfs:member> </wfs:FeatureCollection> ''' from lxml import etree from io import BytesIO f = BytesIO(data) ns = {"gml": "http://www.opengis.net/gml/3.2"} tree = etree.parse(f) for e in tree.findall("//gml:pos", ns): print(e.text)
Moving and optimizing svg coordinates to a grid in python
I am working with .svg files exported from GIMP. I need the nodes on each path moved to the nearest vertex (on a 70px grid) and remove duplicates. A sample .svg looks like this: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg xmlns="http://www.w3.org/2000/svg" width="1283.95mm" height="1037.04mm" viewBox="0 0 3640 2940"> <path id="Selection" fill="none" stroke="black" stroke-width="1" d="M 1475.00,205.00 C 1475.00,225.21 1471.02,215.59 1471.00,231.00 1471.00,231.00 1471.00,329.00 1471.00,329.00 1471.00,331.56 1470.89,334.55 1471.65,337.00 1472.95,341.22 1476.88,346.28 1481.01,347.99 1484.25,349.34 1489.44,349.00 1493.00,349.00 1493.00,349.00 1515.00,349.00 1515.00,349.00 1515.00,349.00 1660.00,349.00 1660.00,349.00 1662.50,349.00 1665.62,349.11 1668.00,348.35 1682.12,343.87 1679.00,324.35 1679.00,313.00 1679.00,313.00 1679.00,231.00 1679.00,231.00 1678.98,215.59 1675.00,225.21 1675.00,205.25 1675.00,205.25 1685.00,205.25 1685.00,205.25 1685.00,205.25 1698.00,209.00 1698.00,209.00 1698.00,209.00 1731.00,209.00 1731.00,209.00 1731.00,209.00 1755.00,205.00 1755.00,205.00 1755.00,205.00 1755.00,209.00 1755.00,209.00 1754.97,222.24 1751.16,217.55 1751.00,229.00 1751.00,229.00 1751.00,314.00 1751.00,314.00 1751.00,314.00 1751.00,469.00 1751.00,469.00 1751.02,484.41 1755.00,474.79 1755.00,494.75 1755.00,494.75 1745.00,494.75 1745.00,494.75 1745.00,494.75 1732.00,491.00 1732.00,491.00 1732.00,491.00 1630.00,491.00 1630.00,491.00 1630.00,491.00 1605.00,495.00 1605.00,495.00 1605.00,474.79 1608.98,484.41 1609.00,469.00 1609.00,469.00 1609.00,441.00 1609.00,441.00 1608.99,433.51 1607.29,426.29 1599.96,422.45 1596.23,420.50 1590.22,421.00 1586.00,421.00 1586.00,421.00 1559.00,421.00 1559.00,421.00 1547.59,421.06 1541.16,427.47 1541.00,439.00 1541.00,439.00 1541.00,470.00 1541.00,470.00 1541.05,480.13 1542.88,477.97 1544.75,484.00 1545.21,486.62 1545.00,492.08 1544.75,494.75 1544.75,494.75 1535.00,494.75 1535.00,494.75 1535.00,494.75 1522.00,491.00 1522.00,491.00 1522.00,491.00 1420.00,491.00 1420.00,491.00 1420.00,491.00 1395.00,495.00 1395.00,495.00 1395.00,495.00 1395.00,491.00 1395.00,491.00 1395.03,477.76 1398.84,482.45 1399.00,471.00 1399.00,471.00 1399.00,386.00 1399.00,386.00 1399.00,386.00 1399.00,231.00 1399.00,231.00 1398.98,215.59 1395.00,225.21 1395.00,205.25 1395.00,205.25 1405.00,205.25 1405.00,205.25 1405.00,205.25 1418.00,209.00 1418.00,209.00 1418.00,209.00 1451.00,209.00 1451.00,209.00 1451.00,209.00 1475.00,205.00 1475.00,205.00 Z M 2035.00,1255.00 C 2035.00,1255.00 2035.00,1260.00 2035.00,1260.00 2034.92,1272.31 2031.02,1266.58 2031.00,1281.00 2031.00,1281.00 2031.00,1449.00 2031.00,1449.00 2031.02,1464.41 2035.00,1454.79 2035.00,1474.75 2035.00,1474.75 2025.00,1474.75 2025.00,1474.75 2025.00,1474.75 2012.00,1471.00 2012.00,1471.00 2012.00,1471.00 1910.00,1471.00 1910.00,1471.00 1910.00,1471.00 1885.00,1475.00 1885.00,1475.00 1885.00,1475.00 1885.00,1465.00 1885.00,1465.00 1903.68,1465.00 1894.73,1468.98 1910.00,1469.00 1910.00,1469.00 2010.00,1469.00 2010.00,1469.00 2012.98,1469.00 2016.18,1469.16 2018.99,1467.99 2023.12,1466.28 2027.05,1461.22 2028.35,1457.00 2028.35,1457.00 2029.00,1425.00 2029.00,1425.00 2029.00,1425.00 2029.00,1281.00 2029.00,1281.00 2028.98,1267.66 2023.60,1261.02 2010.00,1261.00 2010.00,1261.00 1916.00,1261.00 1916.00,1261.00 1916.00,1261.00 1770.00,1261.00 1770.00,1261.00 1767.02,1261.00 1763.82,1260.84 1761.01,1262.01 1756.88,1263.72 1752.95,1268.78 1751.65,1273.00 1751.65,1273.00 1751.00,1305.00 1751.00,1305.00 1751.00,1305.00 1751.00,1449.00 1751.00,1449.00 1751.01,1456.49 1752.71,1463.71 1760.04,1467.55 1763.77,1469.50 1769.78,1469.00 1774.00,1469.00 1774.00,1469.00 1800.00,1469.00 1800.00,1469.00 1815.27,1468.98 1806.32,1465.00 1825.00,1465.00 1825.00,1465.00 1825.00,1474.75 1825.00,1474.75 1825.00,1474.75 1815.00,1474.75 1815.00,1474.75 1815.00,1474.75 1802.00,1471.00 1802.00,1471.00 1802.00,1471.00 1769.00,1471.00 1769.00,1471.00 1769.00,1471.00 1745.00,1475.00 1745.00,1475.00 1745.00,1475.00 1745.00,1470.00 1745.00,1470.00 1745.08,1457.69 1748.98,1463.42 1749.00,1449.00 1749.00,1449.00 1749.00,1281.00 1749.00,1281.00 1748.98,1265.59 1745.00,1275.21 1745.00,1255.00 1745.00,1255.00 1749.00,1255.00 1749.00,1255.00 1749.00,1255.00 1770.00,1259.00 1770.00,1259.00 1770.00,1259.00 2010.00,1259.00 2010.00,1259.00 2010.00,1259.00 2035.00,1255.00 2035.00,1255.00 Z M 1054.75,2095.00 C 1055.00,2097.92 1055.21,2103.38 1054.75,2106.00 1053.06,2111.36 1051.12,2110.34 1051.00,2119.00 1051.00,2119.00 1051.00,2219.00 1051.00,2219.00 1051.02,2234.41 1055.00,2224.79 1055.00,2244.75 1055.00,2244.75 1045.00,2244.75 1045.00,2244.75 1045.00,2244.75 1032.00,2241.00 1032.00,2241.00 1032.00,2241.00 999.00,2241.00 999.00,2241.00 999.00,2241.00 975.25,2245.00 975.25,2245.00 975.00,2242.08 974.79,2236.62 975.25,2234.00 976.94,2228.64 978.88,2229.66 979.00,2221.00 979.00,2221.00 979.00,2121.00 979.00,2121.00 978.98,2105.59 975.00,2115.21 975.00,2095.25 975.00,2095.25 985.00,2095.25 985.00,2095.25 985.00,2095.25 998.00,2099.00 998.00,2099.00 998.00,2099.00 1031.00,2099.00 1031.00,2099.00 1031.00,2099.00 1054.75,2095.00 1054.75,2095.00 Z M 3447.00,2899.00 C 3440.66,2897.20 3422.63,2898.43 3415.00,2898.18 3415.00,2898.18 3379.00,2898.18 3379.00,2898.18 3379.00,2898.18 3366.99,2898.18 3366.99,2898.18 3366.99,2898.18 3361.42,2898.87 3361.42,2898.87 3361.42,2898.87 3355.00,2898.04 3355.00,2898.04 3344.76,2897.54 3340.14,2901.77 3340.00,2912.00 3339.93,2917.84 3339.11,2925.22 3345.10,2928.55 3349.34,2930.90 3353.58,2929.57 3358.00,2929.77 3358.00,2929.77 3366.00,2929.77 3366.00,2929.77 3366.00,2929.77 3413.00,2929.77 3413.00,2929.77 3421.78,2929.42 3439.43,2931.15 3447.00,2929.00 3447.01,2931.77 3446.67,2936.29 3448.74,2938.40 3451.05,2940.76 3464.95,2940.76 3467.26,2938.40 3469.33,2936.29 3468.99,2931.77 3469.00,2929.00 3474.26,2930.50 3487.74,2929.97 3494.00,2930.00 3504.82,2930.06 3502.45,2932.75 3511.00,2932.98 3523.14,2933.32 3518.81,2930.02 3532.00,2930.00 3532.00,2930.00 3619.00,2930.00 3619.00,2930.00 3630.80,2929.94 3632.98,2926.21 3633.00,2915.00 3633.01,2907.54 3633.86,2898.49 3624.00,2897.23 3618.29,2896.49 3615.45,2899.85 3611.00,2901.09 3611.00,2901.09 3599.00,2901.09 3599.00,2901.09 3599.00,2901.09 3576.00,2901.09 3576.00,2901.09 3569.17,2899.98 3573.24,2897.81 3559.00,2898.00 3550.73,2898.11 3551.68,2899.93 3545.00,2901.12 3545.00,2901.12 3530.00,2901.12 3530.00,2901.12 3530.00,2901.12 3502.00,2901.12 3502.00,2901.12 3502.00,2901.12 3492.00,2901.88 3492.00,2901.88 3484.85,2901.36 3481.54,2895.44 3469.00,2899.00 3468.97,2895.56 3469.08,2892.17 3466.99,2889.21 3463.30,2883.98 3453.87,2883.66 3449.65,2888.39 3446.93,2891.45 3447.04,2895.19 3447.00,2899.00 Z" /> </svg> I would need to replace each number inside the string to the closest number divisible by 70. Once that's done it's very likely that there will be duplicate paths so they should be removed until only one remains. Problem is I have absolutely no idea how to best achieve that in python. For the first part perhaps using regex to find all numbers and for each replace with something like: round(n / 70) * 70 For the second, I'm not sure yet if each line of 6 numbers would be equal to another full line, or only some of the numbers.
Python XML iterate over multiple blocks
I have an python XML parsing problem that I can't seem to figure out. I have the following XML: <data> <data_in base="base64"> </data_in> <log_sense_data> <ds base="bool">1</ds> <spf base="bool">0</spf> <page_code base="hex">15</page_code> <background_scan_results_log_page> <parameter> <parameter_code base="hex">0000</parameter_code> <du base="bool">0</du> <tsd base="bool">0</tsd> <etc base="bool">0</etc> <tmc base="hex">00</tmc> <format_linking base="hex">03</format_linking> <parameter_length base="dec">12</parameter_length> <description base="string">background scanning status parameter</description> <accumulated_power_on_minutes base="dec">579578</accumulated_power_on_minutes> <background_scanning_status base="hex">01</background_scanning_status> <number_of_background_scans_performed base="dec">112</number_of_background_scans_performed> <background_scan_progress base="hex">00000036</background_scan_progress> <number_of_background_medium_scans_performed base="dec">112</number_of_background_medium_scans_performed> </parameter> <parameter> <parameter_code base="hex">0001</parameter_code> <du base="bool">0</du> <tsd base="bool">0</tsd> <etc base="bool">0</etc> <tmc base="hex">00</tmc> <format_linking base="hex">03</format_linking> <parameter_length base="dec">20</parameter_length> <description base="string">background medium scan parameter</description> <accumulated_power_on_minutes base="dec">82932</accumulated_power_on_minutes> <reassign_status base="hex">05</reassign_status> <sense_key base="hex">01</sense_key> <additional_sense_code base="hex">17</additional_sense_code> <additional_sense_code_qualifier base="hex">01</additional_sense_code_qualifier> <vendor_specific base="hex">20e2570187</vendor_specific> <logical_block_address base="hex">00000000478994d8</logical_block_address> </parameter> <parameter> <parameter_code base="hex">0002</parameter_code> <du base="bool">0</du> <tsd base="bool">0</tsd> <etc base="bool">0</etc> <tmc base="hex">00</tmc> <format_linking base="hex">03</format_linking> <parameter_length base="dec">20</parameter_length> <description base="string">background medium scan parameter</description> <accumulated_power_on_minutes base="dec">104467</accumulated_power_on_minutes> <reassign_status base="hex">05</reassign_status> <sense_key base="hex">01</sense_key> <additional_sense_code base="hex">18</additional_sense_code> <additional_sense_code_qualifier base="hex">07</additional_sense_code_qualifier> <vendor_specific base="hex">203ab846ea</vendor_specific> <logical_block_address base="hex">00000000133d5046</logical_block_address> </parameter> </background_scan_results_log_page> </log_sense_data> </data> Where Parameter_code 0000 will always exist, and there could be any number of parameter_codes after that. Esentially I want to pull 2 values (power on minutes, background scans) from parameter_code 0000, as well as most values from parameter_code 0001 and greater, to be later put into a database. The code I have so far is this: import xml.etree.ElementTree as et log_page_tree = et.fromstring(results['Data']['RawData']) if log_page_tree.find('log_sense_data') == None: continue else: for element in log_page_tree.find('log_sense_data'): for pagecode in element.iter('page_code'): if pagecode.text == '15': for param in log_page_tree.find('log_sense_data').find('background_scan_results_log_page'): for derp in param.iter(): print derp.tag, derp.text #for totalpoweron in param.iter('accumulated_power_on_minutes'): #print totalpoweron.text I want to be able to keep the 2 values from parameter_code 0000, while iterating through the rest of the parameter_codes to be put into a database. Can anyone give me a push in the right direction here? If I specify param.iter('somevalue') to grab each value, the code doesn't seem to iterate.
OK, although there are ways you could simplify/improve your code, it sounds like you're happy up to here: for param in log_page_tree.find('log_sense_data').find('background_scan_results_log_page'): This will in fact iterate over each parameter. But now you want to switch on whether parameter_code is 0000, doing different things in each case. So: converters = { 'hex': lambda s: int(s, 16) 'dec': int, 'bool': bool } if param.find('parameter_code').text == '0000': accumulated_power_on_minutes = int(param.find('accumulated_power_on_minutes').text) number_of_background_scans_performed = int(param.find('number_of_background_scans_performed').text) else: obj = {} for elem in param.getchildren(): name = elem.tag base = elem.attrib['base'] converter = converters.get(base, lambda x: x) value = convert(elem.text) obj[name] = value # do something with obj
Setting default units in svg (Python svgwrite)
I'm generating SVG drawings using python's svgwrite. Every time I want to draw something, I find myself doing this ugly awkward thing: line = drawing.line(start = "%dmm" % start, end = "%dmm" % end) I wish I could just do: line = drawing.line(start = start, end = end) Is there a way to set the default units to 'mm' for the entire svg drawing?
A possible way is to set the viewBox attribute along with the document sizing, dwg = svgwrite.Drawing('myDrawing.svg', size=('170mm', '130mm'), viewBox=('0 0 170 130')) dwg.add(dwg.line(start=(30, 30), end=(50,50))) dwg.save() produces for me, <?xml version="1.0" encoding="utf-8" ?> <svg baseProfile="full" height="130mm" version="1.1" viewBox="0 0 170 130" width="170mm" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"><defs /><line x1="30" x2="50" y1="30" y2="50" /> </svg>
I just found that you can do this: from svgwrite import cm, mm dwg = svgwrite.Drawing('my_drawing.svg', height='10cm', width='10cm') dwg.add(dwg.line((0*cm, 0*cm), (10*cm, 10*cm)) dwg.save()