Re: [Qgis-user] Serial map from template composer. Working with QGIS 2.2, problems with QGIS 2.4
On Wed, Oct 1, 2014 at 10:12 PM, Nyall Dawson nyall.daw...@gmail.com wrote: On 02/10/2014 2:55 am, Andrea Amparore andrea.ampar...@gmail.com wrote: Thanks Andreas! Actually I need to do it with a script, because the serial printing is a part of a much more complex script. It works on QGIS 2.2, but on QGIS 2.4 it drives me crazy… Two things: - QgsMapRenderer is deprecated in 2.4 and above. You should update your code to use the new replacement QgsMapSettings object. - Why don't you try saving the XML templates from your script to qpt files and then try loading them manually into QGIS? That might give you a better idea where your script is breaking. Nyall Thanks to Nyall's suggestions now the script is adapted for QGIS 2.4. In fact, the problem was generated by the object QgsMapRenderer, that is deprecated in 2.4 and above. To make the script work it’s necessary to replace it by the object QgsMapSettings. Consequently, also some function names need to be slightly changed (e.g. from setProjectionsEnabled() to setCrsTransformEnabled(), from setLayerSet() to setLayers()) But there's still a minor problem: the two shapefiles on the map have different CRS (UTM zone 15N and WGS84), and I would like to assign to the map one of the two. It works only if I choose WGS84 (srid = 4326), but if I assign the UTM projection to the map no layer is displayed. The attribute “on the fly CRS transformations” is enabled, so I don’t see the reason. This is the new corrected script, now working also with QGIS 2.4 import os from qgis.core import * from qgis.gui import * from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4.QtXml import * import lxml.etree as etree print setting prefix QgsApplication.setPrefixPath(/usr, True) print initiating qgis QgsApplication.initQgis() print 'creating new app' app = QgsApplication([], True) #removing old layers QgsMapLayerRegistry.instance().removeAllMapLayers() script_folder = os.path.dirname(__file__) project_folder = os.path.dirname(script_folder) output_folder = os.path.join(project_folder, 'map_outputs') xml_folder = os.path.join(project_folder, 'project_outputs') shapefile_folder = os.path.join(project_folder, 'shapefile_folder') template_composer = os.path.join(project_folder, 'basic_composer_template.qpt') polyg_shapefile = os.path.join(shapefile_folder, 'polygon.shp') # crs EPSG:4326 - WGS 84 point_shapefile = os.path.join(shapefile_folder, 'point.shp') # crs EPSG:32615 - WGS 84 / UTM zone 15N mapname = Test Map srid = 4326 provider_name = 'ogr' layerset = [] #add layer 1 vlayer_name= 'polygon layer' vdata_source = polyg_shapefile print Loading EQ buffers layer = QgsVectorLayer(vdata_source, vlayer_name, provider_name) print Buffers loaded QgsMapLayerRegistry.instance().addMapLayer(layer) layerset.append(layer.id()) #add layer 2 point_layer_name= 'point layer' point_data_source = point_shapefile point_layer = QgsVectorLayer(point_data_source, point_layer_name, provider_name) QgsMapLayerRegistry.instance().addMapLayer(point_layer) layerset.append(point_layer.id()) # Set up the MapSetting object that will be assigned to the composition ms = QgsMapSettings() #preparing the map the extent - 3 times wider than the polygon layer's extent rect = layer.extent() rect.scale(3) # Enable on the fly CRS transformations ms.setCrsTransformEnabled(True) composition = QgsComposition(ms) #set WGS84 as destination crs map_projection = QgsCoordinateReferenceSystem(srid, QgsCoordinateReferenceSystem.PostgisCrsId) map_projection_descr = map_projection.description() ms.setDestinationCrs(map_projection) #open the composer template and edit it with open(template_composer, 'r') as f: tree = etree.parse(f) #setting extent for elem in tree.iter(tag = 'Extent'): elem.attrib['xmax'] = str(rect.xMaximum()) elem.attrib['xmin'] = str(rect.xMinimum()) elem.attrib['ymax'] = str(rect.yMaximum()) elem.attrib['ymin'] = str(rect.yMinimum()) #editing the title for elem in tree.iter(tag = 'ComposerLabel'): for child in elem: if child.tag == 'ComposerItem': if child.attrib['id'] == __maintitle__: elem.attrib['labelText'] = mapname #save the edited composer as a new file new_composer = os.path.join(xml_folder, mapname + _composer.qpt) tree.write(new_composer) #open the newly created composer new_composerfile = file(new_composer, 'rt') new_composer_content = new_composerfile.read() new_composerfile.close() document = QDomDocument() document.setContent(new_composer_content) result =composition.loadFromTemplate(document) # Get the main map canvas on the composition and set the layers composerMap = composition.getComposerMapById(0) composerMap.renderModeUpdateCachedImage() ms.setLayers(layerset) #legend legend
[Qgis-user] Serial map from template composer. Working with QGIS 2.2, problems with QGIS 2.4
Dear QGIS users community, I'm a new member and I am stuck on a problem since few days, maybe someone can help me with this. I have developed a stand-alone python script for making serial maps using PyQGIS library. The maps should follow a specific format that is indicated by a template .qpt file. This template file is opened and edited with lxml library in order to add information about the map (title, date, source, etc). The modified .qpt is then loaded into a new composition, the layers are added and the map exported. Everything was working perfectly since I’ve been using QGIS 2.2. Few days ago I have updated QGIS to the latest version 2.4 and now the output is sadly empty: map elements are displayed (frame, legend, title..), but no layer appears on the map. The script is correct, because it still run correctly on another machine having QGIS 2.2. Is there anything that I have to modify for running it with QGIS 2.4? This is a very basic version of the script. import os from qgis.core import * from qgis.gui import * from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4.QtXml import * import lxml.etree as etree print setting prefix QgsApplication.setPrefixPath(/usr, True) print initiating qgis QgsApplication.initQgis() print 'creating new app' app = QgsApplication([], True) #removing old layers QgsMapLayerRegistry.instance().removeAllMapLayers() script_folder = os.path.dirname(__file__) project_folder = os.path.dirname(script_folder) output_folder = os.path.join(project_folder, 'map_outputs') xml_folder = os.path.join(project_folder, 'project_outputs') shapefile_folder = os.path.join(project_folder, 'shapefile_folder') template_composer = os.path.join(project_folder, 'basic_composer_template_QGIS24.qpt') polyg_shapefile = os.path.join(shapefile_folder, 'polygon.shp') # crs EPSG:4326 - WGS 84 point_shapefile = os.path.join(shapefile_folder, 'point.shp') # crs EPSG:32615 - WGS 84 / UTM zone 15N mapname = Test Map srid = 4326 provider_name = 'ogr' layerset = [] #add layer 1 vlayer_name= 'polygon layer' vdata_source = polyg_shapefile print Loading EQ buffers layer = QgsVectorLayer(vdata_source, vlayer_name, provider_name) print Buffers loaded QgsMapLayerRegistry.instance().addMapLayer(layer) layerset.append(layer.id()) #add layer 2 point_layer_name= 'point layer' point_data_source = point_shapefile point_layer = QgsVectorLayer(point_data_source, point_layer_name, provider_name) QgsMapLayerRegistry.instance().addMapLayer(point_layer) layerset.append(point_layer.id()) # Set up the map renderer that will be assigned to the composition map_renderer = QgsMapRenderer() #preparing the map the extent - 3 times wider than the polygon layer's extent rect = layer.extent() rect.scale(3) # Set the labelling engine for the canvas labelling_engine = QgsPalLabeling() map_renderer.setLabelingEngine(labelling_engine) # Enable on the fly CRS transformations map_renderer.setProjectionsEnabled(True) # Now set up the composition composition = QgsComposition(map_renderer) #set WGS84 as destination crs map_projection = QgsCoordinateReferenceSystem(srid, QgsCoordinateReferenceSystem.PostgisCrsId) map_projection_descr = map_projection.description() map_renderer.setDestinationCrs(map_projection) #open the composer template and edit it with open(template_composer, 'r') as f: tree = etree.parse(f) #setting extent for elem in tree.iter(tag = 'Extent'): elem.attrib['xmax'] = str(rect.xMaximum()) elem.attrib['xmin'] = str(rect.xMinimum()) elem.attrib['ymax'] = str(rect.yMaximum()) elem.attrib['ymin'] = str(rect.yMinimum()) #editing the title for elem in tree.iter(tag = 'ComposerLabel'): for child in elem: if child.tag == 'ComposerItem': if child.attrib['id'] == __maintitle__: elem.attrib['labelText'] = mapname #save the edited composer as a new file new_composer = os.path.join(xml_folder, mapname + _composer.qpt) tree.write(new_composer) #open the newly created composer new_composerfile = file(new_composer, 'rt') new_composer_content = new_composerfile.read() new_composerfile.close() document = QDomDocument() document.setContent(new_composer_content) result = composition.loadFromTemplate(document) # Get the main map canvas on the composition and set the layers composerMap = composition.getComposerMapById(0) composerMap.renderModeUpdateCachedImage() map_renderer.setLayerSet(layerset) #legend legend = QgsComposerLegend(composition) legend.model().setLayerSet(map_renderer.layerSet()) legend.model().setLayerSet composition.addItem(legend) legend.setItemPosition (25,122) legend.setFrameEnabled(True) legend.setScale(.7) #save image print 'saving image' image = composition.printPageAsRaster(0) image.save(os.path.join(output_folder,mapname) + .png) In this link you can find the 2 shapefiles and the composer template that you need for running the script, and the example of failed
Re: [Qgis-user] Serial map from template composer. Working with QGIS 2.2, problems with QGIS 2.4
Hi Andrea, Are you aware that QGIS already supports serial printing out of the box without scripting? I would first test if that works fine for you before bothering with scripts. QGIS 2.2 had serial printing in core, 2.4 has it improved and 2.6 has a lot more improvements. I am pretty sure that many (most?) cases can now be handled out of the box. Andreas On 01.10.2014 10:54, Andrea Amparore wrote: Dear QGIS users community, I'm a new member and I am stuck on a problem since few days, maybe someone can help me with this. I have developed a stand-alone python script for making serial maps using PyQGIS library. The maps should follow a specific format that is indicated by a template .qpt file. This template file is opened and edited with lxml library in order to add information about the map (title, date, source, etc). The modified .qpt is then loaded into a new composition, the layers are added and the map exported. Everything was working perfectly since I’ve been using QGIS 2.2. Few days ago I have updated QGIS to the latest version 2.4 and now the output is sadly empty: map elements are displayed (frame, legend, title..), but no layer appears on the map. The script is correct, because it still run correctly on another machine having QGIS 2.2. Is there anything that I have to modify for running it with QGIS 2.4? This is a very basic version of the script. import os from qgis.core import * from qgis.gui import * from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4.QtXml import * import lxml.etree as etree print setting prefix QgsApplication.setPrefixPath(/usr, True) print initiating qgis QgsApplication.initQgis() print 'creating new app' app = QgsApplication([], True) #removing old layers QgsMapLayerRegistry.instance().removeAllMapLayers() script_folder = os.path.dirname(__file__) project_folder = os.path.dirname(script_folder) output_folder = os.path.join(project_folder, 'map_outputs') xml_folder = os.path.join(project_folder, 'project_outputs') shapefile_folder = os.path.join(project_folder, 'shapefile_folder') template_composer = os.path.join(project_folder, 'basic_composer_template_QGIS24.qpt') polyg_shapefile = os.path.join(shapefile_folder, 'polygon.shp') # crs EPSG:4326 - WGS 84 point_shapefile = os.path.join(shapefile_folder, 'point.shp') # crs EPSG:32615 - WGS 84 / UTM zone 15N mapname = Test Map srid = 4326 provider_name = 'ogr' layerset = [] #add layer 1 vlayer_name= 'polygon layer' vdata_source = polyg_shapefile print Loading EQ buffers layer = QgsVectorLayer(vdata_source, vlayer_name, provider_name) print Buffers loaded QgsMapLayerRegistry.instance().addMapLayer(layer) layerset.append(layer.id http://layer.id()) #add layer 2 point_layer_name= 'point layer' point_data_source = point_shapefile point_layer = QgsVectorLayer(point_data_source, point_layer_name, provider_name) QgsMapLayerRegistry.instance().addMapLayer(point_layer) layerset.append(point_layer.id http://point_layer.id()) # Set up the map renderer that will be assigned to the composition map_renderer = QgsMapRenderer() #preparing the map the extent - 3 times wider than the polygon layer's extent rect = layer.extent() rect.scale(3) # Set the labelling engine for the canvas labelling_engine = QgsPalLabeling() map_renderer.setLabelingEngine(labelling_engine) # Enable on the fly CRS transformations map_renderer.setProjectionsEnabled(True) # Now set up the composition composition = QgsComposition(map_renderer) #set WGS84 as destination crs map_projection = QgsCoordinateReferenceSystem(srid, QgsCoordinateReferenceSystem.PostgisCrsId) map_projection_descr = map_projection.description() map_renderer.setDestinationCrs(map_projection) #open the composer template and edit it with open(template_composer, 'r') as f: tree = etree.parse(f) #setting extent for elem in tree.iter(tag = 'Extent'): elem.attrib['xmax'] = str(rect.xMaximum()) elem.attrib['xmin'] = str(rect.xMinimum()) elem.attrib['ymax'] = str(rect.yMaximum()) elem.attrib['ymin'] = str(rect.yMinimum()) #editing the title for elem in tree.iter(tag = 'ComposerLabel'): for child in elem: if child.tag == 'ComposerItem': if child.attrib['id'] == __maintitle__: elem.attrib['labelText'] = mapname #save the edited composer as a new file new_composer = os.path.join(xml_folder, mapname + _composer.qpt) tree.write(new_composer) #open the newly created composer new_composerfile = file(new_composer, 'rt') new_composer_content = new_composerfile.read() new_composerfile.close() document = QDomDocument() document.setContent(new_composer_content) result = composition.loadFromTemplate(document) # Get the main map canvas on the composition and set the layers composerMap = composition.getComposerMapById(0) composerMap.renderModeUpdateCachedImage() map_renderer.setLayerSet(layerset) #legend legend =
Re: [Qgis-user] Serial map from template composer. Working with QGIS 2.2, problems with QGIS 2.4
Thanks Andreas! Actually I need to do it with a script, because the serial printing is a part of a much more complex script. It works on QGIS 2.2, but on QGIS 2.4 it drives me crazy… Should I go back to the previous version and forget about the new releases? Regards, Andrea On Wed, Oct 1, 2014 at 12:43 PM, Andreas Neumann a.neum...@carto.net wrote: Hi Andrea, Are you aware that QGIS already supports serial printing out of the box without scripting? I would first test if that works fine for you before bothering with scripts. QGIS 2.2 had serial printing in core, 2.4 has it improved and 2.6 has a lot more improvements. I am pretty sure that many (most?) cases can now be handled out of the box. Andreas On 01.10.2014 10:54, Andrea Amparore wrote: Dear QGIS users community, I'm a new member and I am stuck on a problem since few days, maybe someone can help me with this. I have developed a stand-alone python script for making serial maps using PyQGIS library. The maps should follow a specific format that is indicated by a template .qpt file. This template file is opened and edited with lxml library in order to add information about the map (title, date, source, etc). The modified .qpt is then loaded into a new composition, the layers are added and the map exported. Everything was working perfectly since I’ve been using QGIS 2.2. Few days ago I have updated QGIS to the latest version 2.4 and now the output is sadly empty: map elements are displayed (frame, legend, title..), but no layer appears on the map. The script is correct, because it still run correctly on another machine having QGIS 2.2. Is there anything that I have to modify for running it with QGIS 2.4? This is a very basic version of the script. import os from qgis.core import * from qgis.gui import * from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4.QtXml import * import lxml.etree as etree print setting prefix QgsApplication.setPrefixPath(/usr, True) print initiating qgis QgsApplication.initQgis() print 'creating new app' app = QgsApplication([], True) #removing old layers QgsMapLayerRegistry.instance().removeAllMapLayers() script_folder = os.path.dirname(__file__) project_folder = os.path.dirname(script_folder) output_folder = os.path.join(project_folder, 'map_outputs') xml_folder = os.path.join(project_folder, 'project_outputs') shapefile_folder = os.path.join(project_folder, 'shapefile_folder') template_composer = os.path.join(project_folder, 'basic_composer_template_QGIS24.qpt') polyg_shapefile = os.path.join(shapefile_folder, 'polygon.shp') # crs EPSG:4326 - WGS 84 point_shapefile = os.path.join(shapefile_folder, 'point.shp') # crs EPSG:32615 - WGS 84 / UTM zone 15N mapname = Test Map srid = 4326 provider_name = 'ogr' layerset = [] #add layer 1 vlayer_name= 'polygon layer' vdata_source = polyg_shapefile print Loading EQ buffers layer = QgsVectorLayer(vdata_source, vlayer_name, provider_name) print Buffers loaded QgsMapLayerRegistry.instance().addMapLayer(layer) layerset.append(layer.id()) #add layer 2 point_layer_name= 'point layer' point_data_source = point_shapefile point_layer = QgsVectorLayer(point_data_source, point_layer_name, provider_name) QgsMapLayerRegistry.instance().addMapLayer(point_layer) layerset.append(point_layer.id()) # Set up the map renderer that will be assigned to the composition map_renderer = QgsMapRenderer() #preparing the map the extent - 3 times wider than the polygon layer's extent rect = layer.extent() rect.scale(3) # Set the labelling engine for the canvas labelling_engine = QgsPalLabeling() map_renderer.setLabelingEngine(labelling_engine) # Enable on the fly CRS transformations map_renderer.setProjectionsEnabled(True) # Now set up the composition composition = QgsComposition(map_renderer) #set WGS84 as destination crs map_projection = QgsCoordinateReferenceSystem(srid, QgsCoordinateReferenceSystem.PostgisCrsId) map_projection_descr = map_projection.description() map_renderer.setDestinationCrs(map_projection) #open the composer template and edit it with open(template_composer, 'r') as f: tree = etree.parse(f) #setting extent for elem in tree.iter(tag = 'Extent'): elem.attrib['xmax'] = str(rect.xMaximum()) elem.attrib['xmin'] = str(rect.xMinimum()) elem.attrib['ymax'] = str(rect.yMaximum()) elem.attrib['ymin'] = str(rect.yMinimum()) #editing the title for elem in tree.iter(tag = 'ComposerLabel'): for child in elem: if child.tag == 'ComposerItem': if child.attrib['id'] == __maintitle__: elem.attrib['labelText'] = mapname #save the edited composer as a new file new_composer = os.path.join(xml_folder, mapname + _composer.qpt) tree.write(new_composer) #open the newly created composer new_composerfile =
Re: [Qgis-user] Serial map from template composer. Working with QGIS 2.2, problems with QGIS 2.4
On 02/10/2014 2:55 am, Andrea Amparore andrea.ampar...@gmail.com wrote: Thanks Andreas! Actually I need to do it with a script, because the serial printing is a part of a much more complex script. It works on QGIS 2.2, but on QGIS 2.4 it drives me crazy… Two things: - QgsMapRenderer is deprecated in 2.4 and above. You should update your code to use the new replacement QgsMapSettings object. - Why don't you try saving the XML templates from your script to qpt files and then try loading them manually into QGIS? That might give you a better idea where your script is breaking. Nyall ___ Qgis-user mailing list Qgis-user@lists.osgeo.org http://lists.osgeo.org/mailman/listinfo/qgis-user
Re: [Qgis-user] Serial map from template composer. Working with QGIS 2.2, problems with QGIS 2.4
Thanks Nyall! I did what you have suggested: in fact opening manually the new XML as a .qpt file into QGIS everything works perfectly, and I can manually export a map. But it doesn't work in the stand-alone script, which is what I need. I didn't know that QgsMapRenderer is deprecated in 2.4, this is probably causing the problem. I will try to use the QgsMapSettings object instead of it! Thanks for the hints! Andrea On Wed, Oct 1, 2014 at 10:12 PM, Nyall Dawson nyall.daw...@gmail.com wrote: On 02/10/2014 2:55 am, Andrea Amparore andrea.ampar...@gmail.com wrote: Thanks Andreas! Actually I need to do it with a script, because the serial printing is a part of a much more complex script. It works on QGIS 2.2, but on QGIS 2.4 it drives me crazy… Two things: - QgsMapRenderer is deprecated in 2.4 and above. You should update your code to use the new replacement QgsMapSettings object. - Why don't you try saving the XML templates from your script to qpt files and then try loading them manually into QGIS? That might give you a better idea where your script is breaking. Nyall ___ Qgis-user mailing list Qgis-user@lists.osgeo.org http://lists.osgeo.org/mailman/listinfo/qgis-user