3

I really like the html annotation tool in QGIS. My plan is to show a photo (web based image// jpg) on each point of my point shapefile. Unfortunately labels don't work as they do not parse HTML and the tooltips won't last for long (only on hoover, right?) and can't show external images like from a website. Images need to be local.

So is there a way to create a HTMLAnnotation using pyqgis? I mean, I can see the HTMLAnnotation block in the qgs file:

 <HtmlAnnotationItem hasFeature="0" feature="0" htmlfile="/home/ricckli/Desktop/test.html" vectorLayer="Accessibility20160219224444279">
<AnnotationItem frameHeight="360" canvasPosX="281" mapPosX="1514906.43412938853725791" canvasPosY="195" mapPositionFixed="1" mapPosY="6873695.00431403797119856" frameColorAlpha="255" frameBackgroundColorAlpha="255" frameBorderWidth="1" visible="1" offsetX="50" offsetY="-50" frameWidth="527" frameBackgroundColor="#ffffff" frameColor="#000000">
 <symbol alpha="1" clip_to_extent="1" type="marker" name="marker symbol">
 <layer pass="0" class="SimpleMarker" locked="0">
 <prop k="angle" v="0"/>
 <prop k="color" v="255,0,0,255"/>
 <prop k="horizontal_anchor_point" v="1"/>
 <prop k="name" v="circle"/>
 <prop k="offset" v="0,0"/>
 <prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
 <prop k="offset_unit" v="MM"/>
 <prop k="outline_color" v="0,0,0,255"/>
 <prop k="outline_style" v="solid"/>
 <prop k="outline_width" v="0"/>
 <prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
 <prop k="outline_width_unit" v="MM"/>
 <prop k="scale_method" v="diameter"/>
 <prop k="size" v="2"/>
 <prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
 <prop k="size_unit" v="MM"/>
 <prop k="vertical_anchor_point" v="1"/>
 </layer>
 </symbol>
</AnnotationItem>

But I don't want to write it for my own for all the points. especially the canavasPosX and canvasPosy parameter...

PolyGeo
65.5k29 gold badges115 silver badges350 bronze badges
asked Feb 20, 2016 at 6:25
3
  • 2
    Here is one way not using html annotations nathanw.net/2016/02/04/live-svgs Commented Feb 20, 2016 at 6:58
  • that's exactly what I was searching for! Thanks @NathanW Commented Feb 20, 2016 at 8:32
  • unfortunately this works for an enduser. I would love to embed it all in my plugin. My knowledge and my skillset is limited. So the main question is: how to do the script definition @NathanW mentioned in a programmatic way out of a plugin,.... Commented Feb 20, 2016 at 13:43

1 Answer 1

2

The current workaround is to style the data as "categorized" layer and create a single svg for every point:

layer = QgsVectorLayer('Point?crs=EPSG:4326', 'Flickr', "memory")
pr = layer.dataProvider()
pr.addAttributes([QgsField("thumbnail", QVariant.String)])
pr.addAttributes([QgsField("photoid", QVariant.String)])
layer.updateFields()
categories = []
renderer = QgsCategorizedSymbolRendererV2("photoid", categories)
layer.setRendererV2(renderer)
QgsMapLayerRegistry.instance().addMapLayer(layer)
for photo in json:
 fet = QgsFeature()
 #now read additional information:
 details = flickr.photos.getInfo(photo_id=photo['id'])
 thumb = 'https://farm' + str(photo['farm']) + '.staticflickr.com/' + str(photo['server']) + '/' + str(photo['id'])+ '_' + str(photo['secret'])+ '_t.jpg'
 photoid = str(photo['id'])
 fet.setGeometry(QgsGeometry.fromPoint(QgsPoint(float(details['photo']['location']['longitude']),float(details['photo']['location']['latitude']))))
 geom = fet.geometry()
 fet.setAttributes([thumb,photoid])
 pr.addFeatures([fet])
 svg = """
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg>
 <g>
 <image xlink:href="data:image/jpeg;base64,{0}" height="256" width="320" />
 </g>
</svg>
"""
 data2 = requests.get(thumb, stream=True).content
 nameim = str(photo['id'])+'_t.jpg'
 b64response = base64.b64encode(data2)
 newsvg = svg.format(b64response).replace('\n','')
 path = tempfile.gettempdir() + os.sep + photo['id'] + '_t.jpg.svg'
 with open(path, 'w') as f:
 f.write(newsvg)
 svgStyle = {}
 svgStyle['fill'] = '#0000ff'
 svgStyle['name'] = tempfile.gettempdir() + os.sep + photo['id'] + '_t.jpg.svg'
 svgStyle['outline'] = '#000000'
 svgStyle['size'] = '30'
 symLyr1 = QgsSvgMarkerSymbolLayerV2.create(svgStyle)
 sym = QgsSymbolV2.defaultSymbol(layer.geometryType())
 sym.changeSymbolLayer(0, symLyr1)
 category = QgsRendererCategoryV2(str(photo['id']), sym, str(photo['id']))
 categories.append(category)
 renderer = QgsCategorizedSymbolRendererV2("photoid", categories)
 layer.setRendererV2(renderer)
 layer.updateExtents()
 layer.triggerRepaint()

This is cartographic nonsense but otherwise I'll need to inject a python script into the QGIS style control of a layer...

answered Feb 26, 2016 at 15:15

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.