def testExpressionInText(self): """Test expressions embedded in legend node text""" point_path = os.path.join(TEST_DATA_DIR, 'points.shp') point_layer = QgsVectorLayer(point_path, 'points', 'ogr') layout = QgsPrintLayout(QgsProject.instance()) layout.setName('LAYOUT') layout.initializeDefaults() map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(20, 20, 80, 80)) map.setFrameEnabled(True) map.setLayers([point_layer]) layout.addLayoutItem(map) map.setExtent(point_layer.extent()) legend = QgsLayoutItemLegend(layout) legend.setTitle("Legend") legend.attemptSetSceneRect(QRectF(120, 20, 100, 100)) legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) legend.setTitle('') legend.setLegendFilterByMapEnabled(False) legend.setStyleFont(QgsLegendStyle.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setAutoUpdateModel(False) QgsProject.instance().addMapLayers([point_layer]) s = QgsMapSettings() s.setLayers([point_layer]) group = legend.model().rootGroup().addGroup("Group [% 1 + 5 %] [% @layout_name %]") layer_tree_layer = group.addLayer(point_layer) layer_tree_layer.setCustomProperty("legend/title-label", 'bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]') QgsMapLayerLegendUtils.setLegendNodeUserLabel(layer_tree_layer, 0, 'xxxx') legend.model().refreshLayerLegend(layer_tree_layer) legend.model().layerLegendNodes(layer_tree_layer)[0].setUserLabel('bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]') layout.addLayoutItem(legend) legend.setLinkedMap(map) map.setExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30)) checker = QgsLayoutChecker( 'composer_legend_expressions', layout) checker.setControlPathPrefix("composer_legend") result, message = checker.testLayout() self.assertTrue(result, message) QgsProject.instance().removeMapLayers([point_layer.id()])
def testCase(self): TEST_DATA_DIR = unitTestDataPath() vectorFileInfo = QFileInfo(TEST_DATA_DIR + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsProject.instance().addMapLayers([mVectorLayer]) layout = QgsPrintLayout(QgsProject.instance()) layout.initializeDefaults() label = QgsLayoutItemLabel(layout) layout.addLayoutItem(label) self.evaluation_test(layout, label) self.feature_evaluation_test(layout, label, mVectorLayer) self.page_evaluation_test(layout, label, mVectorLayer)
def rotation_test(self): # We will create a polygon layer with a rotated rectangle. # Then we will make it the object layer for the atlas, # rotate the map and test that the bounding rectangle # is smaller than the bounds without rotation. polygonLayer = QgsVectorLayer('Polygon', 'test_polygon', 'memory') poly = QgsFeature(polygonLayer.fields()) points = [(10, 15), (15, 10), (45, 40), (40, 45)] poly.setGeometry(QgsGeometry.fromPolygonXY([[QgsPointXY(x[0], x[1]) for x in points]])) polygonLayer.dataProvider().addFeatures([poly]) QgsProject.instance().addMapLayer(polygonLayer) # Recreating the layout locally composition = QgsPrintLayout(QgsProject.instance()) composition.initializeDefaults() # the atlas map atlasMap = QgsLayoutItemMap(composition) atlasMap.attemptSetSceneRect(QRectF(20, 20, 130, 130)) atlasMap.setFrameEnabled(True) atlasMap.setLayers([polygonLayer]) atlasMap.setExtent(QgsRectangle(0, 0, 100, 50)) composition.addLayoutItem(atlasMap) # the atlas atlas = composition.atlas() atlas.setCoverageLayer(polygonLayer) atlas.setEnabled(True) atlasMap.setAtlasDriven(True) atlasMap.setAtlasScalingMode(QgsLayoutItemMap.Auto) atlasMap.setAtlasMargin(0.0) # Testing atlasMap.setMapRotation(0.0) atlas.beginRender() atlas.first() nonRotatedExtent = QgsRectangle(atlasMap.extent()) atlasMap.setMapRotation(45.0) atlas.first() rotatedExtent = QgsRectangle(atlasMap.extent()) self.assertLess(rotatedExtent.width(), nonRotatedExtent.width() * 0.9) self.assertLess(rotatedExtent.height(), nonRotatedExtent.height() * 0.9) QgsProject.instance().removeMapLayer(polygonLayer)
def prepareIteratorLayout(self): layer_path = os.path.join(TEST_DATA_DIR, 'france_parts.shp') layer = QgsVectorLayer(layer_path, 'test', "ogr") project = QgsProject() project.addMapLayers([layer]) # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) project.setCrs(crs) layout = QgsPrintLayout(project) layout.initializeDefaults() # fix the renderer, fill with green props = { "color": "0,127,0", "outline_width": "4", "outline_color": '255,255,255' } fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) layer.setRenderer(renderer) # the atlas map atlas_map = QgsLayoutItemMap(layout) atlas_map.attemptSetSceneRect(QRectF(20, 20, 130, 130)) atlas_map.setFrameEnabled(True) atlas_map.setLayers([layer]) layout.addLayoutItem(atlas_map) # the atlas atlas = layout.atlas() atlas.setCoverageLayer(layer) atlas.setEnabled(True) atlas_map.setExtent( QgsRectangle(332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338)) atlas_map.setAtlasDriven(True) atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Auto) atlas_map.setAtlasMargin(0.10) return project, layout
def testSymbolExpressions(self): "Test expressions embedded in legend node text" QgsProject.instance().clear() point_path = os.path.join(TEST_DATA_DIR, 'points.shp') point_layer = QgsVectorLayer(point_path, 'points', 'ogr') layout = QgsPrintLayout(QgsProject.instance()) layout.initializeDefaults() map = QgsLayoutItemMap(layout) map.setLayers([point_layer]) layout.addLayoutItem(map) map.setExtent(point_layer.extent()) legend = QgsLayoutItemLegend(layout) layer = QgsProject.instance().addMapLayer(point_layer) legendlayer = legend.model().rootGroup().addLayer(point_layer) counterTask = point_layer.countSymbolFeatures() counterTask.waitForFinished() legend.model().refreshLayerLegend(legendlayer) legendnodes = legend.model().layerLegendNodes(legendlayer) legendnodes[0].setUserLabel('[% @symbol_id %]') legendnodes[1].setUserLabel('[% @symbol_count %]') legendnodes[2].setUserLabel('[% sum("Pilots") %]') label1 = legendnodes[0].evaluateLabel() label2 = legendnodes[1].evaluateLabel() label3 = legendnodes[2].evaluateLabel() self.assertEqual(label1, '0') #self.assertEqual(label2, '5') #self.assertEqual(label3, '12') legendlayer.setLabelExpression("Concat(@symbol_label, @symbol_id)") label1 = legendnodes[0].evaluateLabel() label2 = legendnodes[1].evaluateLabel() label3 = legendnodes[2].evaluateLabel() self.assertEqual(label1, ' @symbol_id 0') #self.assertEqual(label2, '@symbol_count 1') #self.assertEqual(label3, 'sum("Pilots") 2') QgsProject.instance().clear()
def test_datadefined_margin(self): polygonLayer = QgsVectorLayer('Polygon?field=margin:int', 'test_polygon', 'memory') poly = QgsFeature(polygonLayer.fields()) poly.setAttributes([0]) poly.setGeometry(QgsGeometry.fromWkt('Polygon((30 30, 40 30, 40 40, 30 40, 30 30))')) polygonLayer.dataProvider().addFeatures([poly]) poly = QgsFeature(polygonLayer.fields()) poly.setAttributes([10]) poly.setGeometry(QgsGeometry.fromWkt('Polygon((10 10, 20 10, 20 20, 10 20, 10 10))')) polygonLayer.dataProvider().addFeatures([poly]) poly = QgsFeature(polygonLayer.fields()) poly.setAttributes([20]) poly.setGeometry(QgsGeometry.fromWkt('Polygon((50 50, 60 50, 60 60, 50 60, 50 50))')) polygonLayer.dataProvider().addFeatures([poly]) QgsProject.instance().addMapLayer(polygonLayer) layout = QgsPrintLayout(QgsProject.instance()) map = QgsLayoutItemMap(layout) map.setCrs(polygonLayer.crs()) map.attemptSetSceneRect(QRectF(20, 20, 130, 130)) map.setFrameEnabled(True) map.setLayers([polygonLayer]) map.setExtent(QgsRectangle(0, 0, 100, 50)) layout.addLayoutItem(map) atlas = layout.atlas() atlas.setCoverageLayer(polygonLayer) atlas.setEnabled(True) map.setAtlasDriven(True) map.setAtlasScalingMode(QgsLayoutItemMap.Auto) map.setAtlasMargin(77.0) map.dataDefinedProperties().setProperty(QgsLayoutObject.MapAtlasMargin, QgsProperty.fromExpression('margin/2')) atlas.beginRender() atlas.first() self.assertEqual(map.extent(), QgsRectangle(25, 30, 45, 40)) self.assertTrue(atlas.next()) self.assertEqual(map.extent(), QgsRectangle(4.5, 9.75, 25.5, 20.25)) self.assertTrue(atlas.next()) self.assertEqual(map.extent(), QgsRectangle(44, 49.5, 66, 60.5)) QgsProject.instance().removeMapLayer(polygonLayer)
def testClippedMapExtent(self): p = QgsProject() l = QgsPrintLayout(p) map = QgsLayoutItemMap(l) shape = QgsLayoutItemShape(l) l.addLayoutItem(map) map.attemptSetSceneRect(QRectF(10, 20, 100, 80)) map.zoomToExtent(QgsRectangle(100, 200, 50, 40)) l.addLayoutItem(shape) shape.setShapeType(QgsLayoutItemShape.Triangle) shape.attemptSetSceneRect(QRectF(20, 30, 70, 50)) settings = map.itemClippingSettings() settings.setEnabled(True) settings.setSourceItem(shape) geom = settings.clippedMapExtent() self.assertEqual(geom.asWkt(), 'Polygon ((-5 80, 135 80, 65 180, -5 80))')
def testSaveRestore(self): p = QgsProject() l = QgsPrintLayout(p) p.layoutManager().addLayout(l) map = QgsLayoutItemMap(l) shape = QgsLayoutItemShape(l) l.addLayoutItem(map) l.addLayoutItem(shape) settings = map.itemClippingSettings() settings.setEnabled(True) settings.setFeatureClippingType( QgsMapClippingRegion.FeatureClippingType.NoClipping) settings.setForceLabelsInsideClipPath(True) settings.setSourceItem(shape) # save map to xml doc = QDomDocument("testdoc") elem = doc.createElement("test") self.assertTrue(map.writeXml(elem, doc, QgsReadWriteContext())) elem_shape = doc.createElement("shape") self.assertTrue(shape.writeXml(elem_shape, doc, QgsReadWriteContext())) layout2 = QgsPrintLayout(p) layout2.setName('test2') p.layoutManager().addLayout(layout2) map2 = QgsLayoutItemMap(layout2) layout2.addLayoutItem(map2) shape2 = QgsLayoutItemShape(layout2) layout2.addLayoutItem(shape2) self.assertFalse(map2.itemClippingSettings().enabled()) # restore from xml self.assertTrue( map2.readXml(elem.firstChildElement(), doc, QgsReadWriteContext())) self.assertTrue( shape2.readXml(elem_shape.firstChildElement(), doc, QgsReadWriteContext())) self.assertTrue(map2.itemClippingSettings().enabled()) self.assertEqual(map2.itemClippingSettings().featureClippingType(), QgsMapClippingRegion.FeatureClippingType.NoClipping) self.assertTrue( map2.itemClippingSettings().forceLabelsInsideClipPath()) self.assertIsNone(map2.itemClippingSettings().sourceItem()) map2.finalizeRestoreFromXml() self.assertEqual(map2.itemClippingSettings().sourceItem(), shape2)
def prepareIteratorLayout(self): layer_path = os.path.join(TEST_DATA_DIR, 'france_parts.shp') layer = QgsVectorLayer(layer_path, 'test', "ogr") project = QgsProject() project.addMapLayers([layer]) # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) project.setCrs(crs) layout = QgsPrintLayout(project) layout.initializeDefaults() # fix the renderer, fill with green props = {"color": "0,127,0", "outline_width": "4", "outline_color": '255,255,255'} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) layer.setRenderer(renderer) # the atlas map atlas_map = QgsLayoutItemMap(layout) atlas_map.attemptSetSceneRect(QRectF(20, 20, 130, 130)) atlas_map.setFrameEnabled(True) atlas_map.setLayers([layer]) layout.addLayoutItem(atlas_map) # the atlas atlas = layout.atlas() atlas.setCoverageLayer(layer) atlas.setEnabled(True) atlas_map.setExtent( QgsRectangle(332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338)) atlas_map.setAtlasDriven(True) atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Auto) atlas_map.setAtlasMargin(0.10) return project, layout
def testToMapClippingRegion(self): p = QgsProject() l = QgsPrintLayout(p) p.layoutManager().addLayout(l) map = QgsLayoutItemMap(l) shape = QgsLayoutItemShape(l) l.addLayoutItem(map) map.attemptSetSceneRect(QRectF(10, 20, 100, 80)) map.zoomToExtent(QgsRectangle(100, 200, 50, 40)) l.addLayoutItem(shape) shape.setShapeType(QgsLayoutItemShape.Triangle) shape.attemptSetSceneRect(QRectF(20, 30, 70, 50)) settings = map.itemClippingSettings() settings.setEnabled(True) settings.setFeatureClippingType( QgsMapClippingRegion.FeatureClippingType.NoClipping) settings.setSourceItem(shape) region = settings.toMapClippingRegion() self.assertEqual(region.geometry().asWkt(), 'Polygon ((-5 80, 135 80, 65 180, -5 80))') self.assertEqual(region.featureClip(), QgsMapClippingRegion.FeatureClippingType.NoClipping)
def test_move_chart_in_layout(self): """ Test moving charts in layout plot up and down """ # print('moving charts in layout plot up and down') # create project and layout project = QgsProject.instance() layout = QgsPrintLayout(project) layout_name = "PrintLayoutMovingUpDown" layout.initializeDefaults() layout.setName(layout_name) manager = project.layoutManager() self.assertEqual(True, manager.addLayout(layout)) layout = manager.layoutByName(layout_name) layout_plot = PlotLayoutItem(layout) self.assertEqual(len(layout_plot.plot_settings), 1) # self.assertEqual(len(layout.items()), 0) layout.addLayoutItem(layout_plot) # self.assertEqual(len(layout.items()), 1) plot_dialog = PlotLayoutItemWidget(None, layout_plot) # add second plot plot_dialog.add_plot() self.assertEqual(len(layout_plot.plot_settings), 2) # edit first plot plot_dialog.setDockMode(True) plot_dialog.show_properties() plot_property_panel = plot_dialog.panel plot_property_panel.set_plot_type('violin') self.assertEqual(plot_property_panel.ptype, 'violin') plot_property_panel.acceptPanel() plot_property_panel.destroy() # edit second plot plot_dialog.plot_list.setCurrentRow(1) plot_dialog.show_properties() plot_property_panel = plot_dialog.panel plot_property_panel.set_plot_type('bar') self.assertEqual(plot_property_panel.ptype, 'bar') plot_property_panel.acceptPanel() plot_property_panel.destroy() # move up and down # cannot move up first item plot_dialog.plot_list.setCurrentRow(0) plot_dialog.move_up_plot() self.assertEqual(layout_plot.plot_settings[0].plot_type, 'violin') self.assertEqual(layout_plot.plot_settings[1].plot_type, 'bar') # move up second item plot_dialog.plot_list.setCurrentRow(1) plot_dialog.move_up_plot() self.assertEqual(layout_plot.plot_settings[0].plot_type, 'bar') self.assertEqual(layout_plot.plot_settings[1].plot_type, 'violin') # cannot move down second item plot_dialog.plot_list.setCurrentRow(1) plot_dialog.move_down_plot() self.assertEqual(layout_plot.plot_settings[0].plot_type, 'bar') self.assertEqual(layout_plot.plot_settings[1].plot_type, 'violin') # move down first item plot_dialog.plot_list.setCurrentRow(0) plot_dialog.move_down_plot() self.assertEqual(layout_plot.plot_settings[0].plot_type, 'violin') self.assertEqual(layout_plot.plot_settings[1].plot_type, 'bar') self.assertEqual(True, manager.removeLayout(layout))
def testExpressionInText(self): """Test expressions embedded in legend node text""" point_path = os.path.join(TEST_DATA_DIR, 'points.shp') point_layer = QgsVectorLayer(point_path, 'points', 'ogr') layout = QgsPrintLayout(QgsProject.instance()) layout.setName('LAYOUT') layout.initializeDefaults() map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(20, 20, 80, 80)) map.setFrameEnabled(True) map.setLayers([point_layer]) layout.addLayoutItem(map) map.setExtent(point_layer.extent()) legend = QgsLayoutItemLegend(layout) legend.setTitle("Legend") legend.attemptSetSceneRect(QRectF(120, 20, 100, 100)) legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) legend.setTitle('') legend.setLegendFilterByMapEnabled(False) legend.setStyleFont(QgsLegendStyle.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setAutoUpdateModel(False) QgsProject.instance().addMapLayers([point_layer]) s = QgsMapSettings() s.setLayers([point_layer]) group = legend.model().rootGroup().addGroup( "Group [% 1 + 5 %] [% @layout_name %]") layer_tree_layer = group.addLayer(point_layer) layer_tree_layer.setCustomProperty( "legend/title-label", 'bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]') QgsMapLayerLegendUtils.setLegendNodeUserLabel(layer_tree_layer, 0, 'xxxx') legend.model().refreshLayerLegend(layer_tree_layer) legend.model().layerLegendNodes(layer_tree_layer)[0].setUserLabel( 'bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]') layout.addLayoutItem(legend) legend.setLinkedMap(map) map.setExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30)) checker = QgsLayoutChecker('composer_legend_expressions', layout) checker.setControlPathPrefix("composer_legend") result, message = checker.testLayout() self.assertTrue(result, message) QgsProject.instance().removeMapLayers([point_layer.id()])
def testCombo(self): project = QgsProject() layout = QgsPrintLayout(project) combo = QgsLayoutItemComboBox(None) spy = QSignalSpy(combo.itemChanged) self.assertEqual(combo.count(), 0) self.assertIsNone(combo.currentLayout()) self.assertIsNone(combo.currentItem()) self.assertIsNone(combo.item(0)) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(combo.currentIndex(), -1) self.assertEqual(len(spy), 0) combo.setCurrentLayout(layout) self.assertEqual(combo.currentIndex(), -1) self.assertEqual(len(spy), 0) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.count(), 0) self.assertIsNone(combo.currentItem()) self.assertIsNone(combo.item(0)) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 0) combo.setAllowEmptyItem(True) self.assertEqual(combo.currentIndex(), 0) self.assertEqual(combo.count(), 1) self.assertEqual(len(spy), 2) self.assertEqual(combo.currentLayout(), layout) self.assertIsNone(combo.currentItem()) self.assertIsNone(combo.item(0)) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 2) self.assertEqual(combo.currentIndex(), 0) self.assertEqual(combo.itemText(0), '') combo.setAllowEmptyItem(False) self.assertEqual(combo.currentIndex(), -1) self.assertEqual(combo.count(), 0) self.assertEqual(len(spy), 4) self.assertEqual(combo.currentLayout(), layout) self.assertIsNone(combo.currentItem()) self.assertIsNone(combo.item(0)) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 4) self.assertEqual(combo.currentIndex(), -1) label1 = QgsLayoutItemLabel(layout) label1.setId('llll') # don't add to layout yet! combo.setItem(label1) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 4) self.assertEqual(combo.currentIndex(), -1) combo.setAllowEmptyItem(True) combo.setItem(label1) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 6) self.assertEqual(combo.currentIndex(), 0) combo.setAllowEmptyItem(False) layout.addLayoutItem(label1) self.assertEqual(combo.currentIndex(), 0) self.assertEqual(combo.count(), 1) self.assertEqual(combo.itemText(0), 'llll') self.assertEqual(len(spy), 10) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.currentItem(), label1) self.assertEqual(combo.item(0), label1) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 11) self.assertEqual(combo.currentIndex(), -1) combo.setItem(label1) self.assertEqual(combo.currentItem(), label1) self.assertEqual(len(spy), 12) self.assertEqual(combo.currentIndex(), 0) combo.setAllowEmptyItem(True) self.assertEqual(combo.currentIndex(), 1) self.assertEqual(combo.count(), 2) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'llll') self.assertEqual(len(spy), 13) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.currentItem(), label1) self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label1) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(2)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 14) self.assertEqual(combo.currentIndex(), 0) combo.setItem(label1) self.assertEqual(combo.currentItem(), label1) self.assertEqual(len(spy), 15) self.assertEqual(combo.currentIndex(), 1) label2 = QgsLayoutItemLabel(layout) label2.setId('mmmm') layout.addLayoutItem(label2) self.assertEqual(combo.currentIndex(), 1) self.assertEqual(combo.count(), 3) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'llll') self.assertEqual(combo.itemText(2), 'mmmm') self.assertEqual(len(spy), 15) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.currentItem(), label1) self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label1) self.assertEqual(combo.item(2), label2) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(3)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 16) self.assertEqual(combo.currentIndex(), 0) combo.setItem(label1) self.assertEqual(combo.currentItem(), label1) self.assertEqual(len(spy), 17) self.assertEqual(combo.currentIndex(), 1) label1.setId('nnnn') self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'mmmm') self.assertEqual(combo.itemText(2), 'nnnn') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.item(2), label1) self.assertEqual(combo.currentItem(), label1) combo.setAllowEmptyItem(False) self.assertEqual(combo.itemText(0), 'mmmm') self.assertEqual(combo.itemText(1), 'nnnn') self.assertEqual(combo.item(0), label2) self.assertEqual(combo.item(1), label1) self.assertEqual(combo.currentItem(), label1) combo.setItem(label2) label2.setId('oooo') self.assertEqual(combo.itemText(0), 'nnnn') self.assertEqual(combo.itemText(1), 'oooo') self.assertEqual(combo.item(0), label1) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.currentItem(), label2) combo.setAllowEmptyItem(True) layout.removeLayoutItem(label1) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'oooo') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.currentItem(), label2) map = QgsLayoutItemMap(layout) layout.addLayoutItem(map) map.setId('pppp') self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'oooo') self.assertEqual(combo.itemText(2), 'pppp') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.item(2), map) self.assertEqual(combo.currentItem(), label2) combo.setItemType(QgsLayoutItemRegistry.LayoutMap) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'pppp') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), map) self.assertIsNone(combo.currentItem()) combo.setItemType(QgsLayoutItemRegistry.LayoutLabel) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'oooo') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertIsNone(combo.currentItem()) combo.setItemType(QgsLayoutItemRegistry.LayoutAttributeTable) self.assertEqual(combo.itemText(0), '') self.assertIsNone(combo.item(0)) self.assertIsNone(combo.currentItem()) combo.setAllowEmptyItem(False) self.assertEqual(combo.count(), 0) self.assertIsNone(combo.currentItem()) self.assertEqual(combo.currentIndex(), -1)
class TestQgsLayoutAtlas(unittest.TestCase): def setUp(self): self.report = "<h1>Python QgsLayoutAtlas Tests</h1>\n" def tearDown(self): report_file_path = "%s/qgistest.html" % QDir.tempPath() with open(report_file_path, 'a') as report_file: report_file.write(self.report) def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() tmppath = tempfile.mkdtemp() for file in glob.glob(os.path.join(self.TEST_DATA_DIR, 'france_parts.*')): shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath) vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsProject.instance().addMapLayers([mVectorLayer]) self.layers = [mVectorLayer] # create layout with layout map # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) QgsProject.instance().setCrs(crs) self.layout = QgsPrintLayout(QgsProject.instance()) self.layout.initializeDefaults() # fix the renderer, fill with green props = {"color": "0,127,0", 'outline_color': 'black'} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) mVectorLayer.setRenderer(renderer) # the atlas map self.atlas_map = QgsLayoutItemMap(self.layout) self.atlas_map.attemptSetSceneRect(QRectF(20, 20, 130, 130)) self.atlas_map.setFrameEnabled(True) self.atlas_map.setLayers([mVectorLayer]) self.layout.addLayoutItem(self.atlas_map) # the atlas self.atlas = self.layout.atlas() self.atlas.setCoverageLayer(mVectorLayer) self.atlas.setEnabled(True) # an overview self.overview = QgsLayoutItemMap(self.layout) self.overview.attemptSetSceneRect(QRectF(180, 20, 50, 50)) self.overview.setFrameEnabled(True) self.overview.overview().setLinkedMap(self.atlas_map) self.overview.setLayers([mVectorLayer]) self.layout.addLayoutItem(self.overview) nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887) self.overview.setExtent(nextent) # set the fill symbol of the overview map props2 = {"color": "127,0,0,127", 'outline_color': 'black'} fillSymbol2 = QgsFillSymbol.createSimple(props2) self.overview.overview().setFrameSymbol(fillSymbol2) # header label self.mLabel1 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel1) self.mLabel1.setText("[% \"NAME_1\" %] area") self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.attemptSetSceneRect(QRectF(150, 5, 60, 15)) self.mLabel1.setMarginX(1) self.mLabel1.setMarginY(1) # feature number label self.mLabel2 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel2) self.mLabel2.setText("# [%@atlas_featurenumber || ' / ' || @atlas_totalfeatures%]") self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.attemptSetSceneRect(QRectF(150, 200, 60, 15)) self.mLabel2.setMarginX(1) self.mLabel2.setMarginY(1) self.filename_test() self.autoscale_render_test() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test() self.legend_test() self.rotation_test() shutil.rmtree(tmppath, True) def testReadWriteXml(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setHideCoverage(True) atlas.setFilenameExpression('filename exp') atlas.setCoverageLayer(vector_layer) atlas.setPageNameExpression('page name') atlas.setSortFeatures(True) atlas.setSortAscending(False) atlas.setSortExpression('sort exp') atlas.setFilterFeatures(True) atlas.setFilterExpression('filter exp') doc = QDomDocument("testdoc") elem = l.writeXml(doc, QgsReadWriteContext()) l2 = QgsPrintLayout(p) self.assertTrue(l2.readXml(elem, doc, QgsReadWriteContext())) atlas2 = l2.atlas() self.assertTrue(atlas2.enabled()) self.assertTrue(atlas2.hideCoverage()) self.assertEqual(atlas2.filenameExpression(), 'filename exp') self.assertEqual(atlas2.coverageLayer(), vector_layer) self.assertEqual(atlas2.pageNameExpression(), 'page name') self.assertTrue(atlas2.sortFeatures()) self.assertFalse(atlas2.sortAscending()) self.assertEqual(atlas2.sortExpression(), 'sort exp') self.assertTrue(atlas2.filterFeatures()) self.assertEqual(atlas2.filterExpression(), 'filter exp') def testIteration(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) atlas_feature_changed_spy = QSignalSpy(atlas.featureChanged) context_changed_spy = QSignalSpy(l.reportContext().changed) self.assertTrue(atlas.beginRender()) self.assertTrue(atlas.first()) self.assertEqual(len(atlas_feature_changed_spy), 1) self.assertEqual(len(context_changed_spy), 1) self.assertEqual(atlas.currentFeatureNumber(), 0) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') self.assertEqual(l.reportContext().layer(), vector_layer) f1 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 2) self.assertEqual(len(context_changed_spy), 2) self.assertEqual(atlas.currentFeatureNumber(), 1) self.assertEqual(l.reportContext().feature()[4], 'Bretagne') f2 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 3) self.assertEqual(len(context_changed_spy), 3) self.assertEqual(atlas.currentFeatureNumber(), 2) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') f3 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 4) self.assertEqual(len(context_changed_spy), 4) self.assertEqual(atlas.currentFeatureNumber(), 3) self.assertEqual(l.reportContext().feature()[4], 'Centre') f4 = l.reportContext().feature() self.assertFalse(atlas.next()) self.assertTrue(atlas.seekTo(2)) self.assertEqual(len(atlas_feature_changed_spy), 5) self.assertEqual(len(context_changed_spy), 5) self.assertEqual(atlas.currentFeatureNumber(), 2) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') self.assertTrue(atlas.last()) self.assertEqual(len(atlas_feature_changed_spy), 6) self.assertEqual(len(context_changed_spy), 6) self.assertEqual(atlas.currentFeatureNumber(), 3) self.assertEqual(l.reportContext().feature()[4], 'Centre') self.assertTrue(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 7) self.assertEqual(len(context_changed_spy), 7) self.assertEqual(atlas.currentFeatureNumber(), 2) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') self.assertTrue(atlas.previous()) self.assertTrue(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 9) self.assertFalse(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 9) self.assertTrue(atlas.endRender()) self.assertEqual(len(atlas_feature_changed_spy), 10) self.assertTrue(atlas.seekTo(f1)) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') self.assertTrue(atlas.seekTo(f4)) self.assertEqual(l.reportContext().feature()[4], 'Centre') self.assertTrue(atlas.seekTo(f3)) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') self.assertTrue(atlas.seekTo(f2)) self.assertEqual(l.reportContext().feature()[4], 'Bretagne') self.assertFalse(atlas.seekTo(QgsFeature(5))) def testUpdateFeature(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) self.assertTrue(atlas.beginRender()) self.assertTrue(atlas.first()) self.assertEqual(atlas.currentFeatureNumber(), 0) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') self.assertEqual(l.reportContext().layer(), vector_layer) vector_layer.startEditing() self.assertTrue(vector_layer.changeAttributeValue(l.reportContext().feature().id(), 4, 'Nah, Canberra mate!')) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') l.atlas().refreshCurrentFeature() self.assertEqual(l.reportContext().feature()[4], 'Nah, Canberra mate!') vector_layer.rollBack() def testFileName(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) atlas.setFilenameExpression("'output_' || \"NAME_1\"") self.assertTrue(atlas.beginRender()) self.assertEqual(atlas.count(), 4) atlas.first() self.assertEqual(atlas.currentFilename(), 'output_Basse-Normandie') self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Basse-Normandie.png') self.assertEqual(atlas.filePath('/tmp/output/', '.png'), '/tmp/output/output_Basse-Normandie.png') self.assertEqual(atlas.filePath('/tmp/output/', 'svg'), '/tmp/output/output_Basse-Normandie.svg') atlas.next() self.assertEqual(atlas.currentFilename(), 'output_Bretagne') self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Bretagne.png') atlas.next() self.assertEqual(atlas.currentFilename(), 'output_Pays de la Loire') self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Pays de la Loire.png') atlas.next() self.assertEqual(atlas.currentFilename(), 'output_Centre') self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Centre.png') # try changing expression, filename should be updated instantly atlas.setFilenameExpression("'export_' || \"NAME_1\"") self.assertEqual(atlas.currentFilename(), 'export_Centre') atlas.endRender() def testNameForPage(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) atlas.setPageNameExpression("\"NAME_1\"") self.assertTrue(atlas.beginRender()) self.assertEqual(atlas.nameForPage(0), 'Basse-Normandie') self.assertEqual(atlas.nameForPage(1), 'Bretagne') self.assertEqual(atlas.nameForPage(2), 'Pays de la Loire') self.assertEqual(atlas.nameForPage(3), 'Centre') def filename_test(self): self.atlas.setFilenameExpression("'output_' || @atlas_featurenumber") self.atlas.beginRender() for i in range(0, self.atlas.count()): self.atlas.seekTo(i) expected = "output_%d" % (i + 1) self.assertEqual(self.atlas.currentFilename(), expected) self.atlas.endRender() def autoscale_render_test(self): self.atlas_map.setExtent( QgsRectangle(332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338)) self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Auto) self.atlas_map.setAtlasMargin(0.10) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_autoscale%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() self.atlas_map.setAtlasDriven(False) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas_map.setAtlasMargin(0) def fixedscale_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_fixedscale%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() def predefinedscales_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Predefined) scales = [1800000, 5000000] self.layout.reportContext().setPredefinedScales(scales) for i, s in enumerate(self.layout.reportContext().predefinedScales()): self.assertEqual(s, scales[i]) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_predefinedscales%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() def hidden_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas.setHideCoverage(True) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_hiding%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() self.atlas.setHideCoverage(False) def sorting_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas.setHideCoverage(False) self.atlas.setSortFeatures(True) self.atlas.setSortKeyAttributeIndex(4) # departement name self.atlas.setSortAscending(False) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_sorting%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() def filtering_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas.setHideCoverage(False) self.atlas.setSortFeatures(False) self.atlas.setFilterFeatures(True) self.atlas.setFeatureFilter("substr(NAME_1,1,1)='P'") # select only 'Pays de la loire' self.atlas.beginRender() for i in range(0, 1): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_filtering%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() def legend_test(self): self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Auto) self.atlas_map.setAtlasMargin(0.10) # add a point layer ptLayer = QgsVectorLayer("Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)", "points", "memory") pr = ptLayer.dataProvider() f1 = QgsFeature(1) f1.initAttributes(2) f1.setAttribute(0, 1) f1.setAttribute(1, "Test label 1") f1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-0.638, 48.954))) f2 = QgsFeature(2) f2.initAttributes(2) f2.setAttribute(0, 2) f2.setAttribute(1, "Test label 2") f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-1.682, 48.550))) pr.addFeatures([f1, f2]) # categorized symbology r = QgsCategorizedSymbolRenderer("attr", [QgsRendererCategory(1, QgsMarkerSymbol.createSimple({"color": "255,0,0", 'outline_color': 'black'}), "red"), QgsRendererCategory(2, QgsMarkerSymbol.createSimple({"color": "0,0,255", 'outline_color': 'black'}), "blue")]) ptLayer.setRenderer(r) QgsProject.instance().addMapLayer(ptLayer) # add the point layer to the map settings layers = self.layers layers = [ptLayer] + layers self.atlas_map.setLayers(layers) self.overview.setLayers(layers) # add a legend legend = QgsLayoutItemLegend(self.layout) legend.attemptMove(QgsLayoutPoint(200, 100)) # sets the legend filter parameter legend.setLinkedMap(self.atlas_map) legend.setLegendFilterOutAtlas(True) self.layout.addLayoutItem(legend) self.atlas.beginRender() self.atlas.seekTo(0) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_legend', self.layout) myTestResult, myMessage = checker.testLayout() self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() # restore state self.atlas_map.setLayers([layers[1]]) self.layout.removeLayoutItem(legend) QgsProject.instance().removeMapLayer(ptLayer.id()) def rotation_test(self): # We will create a polygon layer with a rotated rectangle. # Then we will make it the object layer for the atlas, # rotate the map and test that the bounding rectangle # is smaller than the bounds without rotation. polygonLayer = QgsVectorLayer('Polygon', 'test_polygon', 'memory') poly = QgsFeature(polygonLayer.fields()) points = [(10, 15), (15, 10), (45, 40), (40, 45)] poly.setGeometry(QgsGeometry.fromPolygonXY([[QgsPointXY(x[0], x[1]) for x in points]])) polygonLayer.dataProvider().addFeatures([poly]) QgsProject.instance().addMapLayer(polygonLayer) # Recreating the layout locally composition = QgsPrintLayout(QgsProject.instance()) composition.initializeDefaults() # the atlas map atlasMap = QgsLayoutItemMap(composition) atlasMap.attemptSetSceneRect(QRectF(20, 20, 130, 130)) atlasMap.setFrameEnabled(True) atlasMap.setLayers([polygonLayer]) atlasMap.setExtent(QgsRectangle(0, 0, 100, 50)) composition.addLayoutItem(atlasMap) # the atlas atlas = composition.atlas() atlas.setCoverageLayer(polygonLayer) atlas.setEnabled(True) atlasMap.setAtlasDriven(True) atlasMap.setAtlasScalingMode(QgsLayoutItemMap.Auto) atlasMap.setAtlasMargin(0.0) # Testing atlasMap.setMapRotation(0.0) atlas.beginRender() atlas.first() nonRotatedExtent = QgsRectangle(atlasMap.extent()) atlasMap.setMapRotation(45.0) atlas.first() rotatedExtent = QgsRectangle(atlasMap.extent()) self.assertLess(rotatedExtent.width(), nonRotatedExtent.width() * 0.9) self.assertLess(rotatedExtent.height(), nonRotatedExtent.height() * 0.9) QgsProject.instance().removeMapLayer(polygonLayer)
def test_duplicate_chart_in_layout(self): # pylint: disable=too-many-statements """ Test duplicate charts in layout plot up and down """ print('duplicate charts in layout plot up and down') # create project and layout project = QgsProject.instance() layout = QgsPrintLayout(project) layout_name = "PrintLayoutDuplicatePlot" layout.initializeDefaults() layout.setName(layout_name) manager = project.layoutManager() self.assertEqual(True, manager.addLayout(layout)) layout = manager.layoutByName(layout_name) layout_plot = PlotLayoutItem(layout) self.assertEqual(len(layout_plot.plot_settings), 1) # self.assertEqual(len(layout.items()), 0) layout.addLayoutItem(layout_plot) # self.assertEqual(len(layout.items()), 1) plot_dialog = PlotLayoutItemWidget(None, layout_plot) self.assertEqual(len(layout_plot.plot_settings), 1) # edit first plot plot_dialog.setDockMode(True) plot_dialog.show_properties() plot_property_panel = plot_dialog.panel plot_property_panel.set_plot_type('violin') self.assertEqual(plot_property_panel.ptype, 'violin') plot_property_panel.x_combo.setExpression('mid') plot_property_panel.data_defined_properties.setProperty( PlotSettings.PROPERTY_FILTER, QgsProperty.fromExpression('"mid">20')) plot_property_panel.acceptPanel() plot_property_panel.destroy() # duplicate plot plot_dialog.duplicate_plot() self.assertEqual(len(layout_plot.plot_settings), 2) self.assertEqual(layout_plot.plot_settings[0].plot_type, 'violin') self.assertEqual(layout_plot.plot_settings[1].plot_type, 'violin') self.assertEqual((layout_plot.plot_settings[0]).properties['x_name'], 'mid') self.assertEqual((layout_plot.plot_settings[1]).properties['x_name'], 'mid') self.assertEqual( layout_plot.plot_settings[0].data_defined_properties.property( PlotSettings.PROPERTY_FILTER), QgsProperty.fromExpression('"mid">20')) self.assertEqual( layout_plot.plot_settings[1].data_defined_properties.property( PlotSettings.PROPERTY_FILTER), QgsProperty.fromExpression('"mid">20')) # edit second plot plot_dialog.plot_list.setCurrentRow(1) plot_dialog.show_properties() plot_property_panel = plot_dialog.panel plot_property_panel.set_plot_type('bar') self.assertEqual(plot_property_panel.ptype, 'bar') plot_property_panel.x_combo.setExpression('qid') plot_property_panel.data_defined_properties.setProperty( PlotSettings.PROPERTY_FILTER, QgsProperty.fromExpression('"qid">20')) plot_property_panel.acceptPanel() plot_property_panel.destroy() self.assertEqual(layout_plot.plot_settings[0].plot_type, 'violin') self.assertEqual(layout_plot.plot_settings[1].plot_type, 'bar') self.assertEqual((layout_plot.plot_settings[0]).properties['x_name'], 'mid') self.assertEqual((layout_plot.plot_settings[1]).properties['x_name'], 'qid') self.assertEqual( layout_plot.plot_settings[0].data_defined_properties.property( PlotSettings.PROPERTY_FILTER), QgsProperty.fromExpression('"mid">20')) self.assertEqual( layout_plot.plot_settings[1].data_defined_properties.property( PlotSettings.PROPERTY_FILTER), QgsProperty.fromExpression('"qid">20')) # edit first plot plot_dialog.plot_list.setCurrentRow(0) plot_dialog.show_properties() plot_property_panel = plot_dialog.panel plot_property_panel.set_plot_type('scatter') self.assertEqual(plot_property_panel.ptype, 'scatter') plot_property_panel.x_combo.setExpression('uid') plot_property_panel.data_defined_properties.setProperty( PlotSettings.PROPERTY_FILTER, QgsProperty.fromExpression('"uid">20')) plot_property_panel.acceptPanel() plot_property_panel.destroy() self.assertEqual(layout_plot.plot_settings[0].plot_type, 'scatter') self.assertEqual(layout_plot.plot_settings[1].plot_type, 'bar') self.assertEqual((layout_plot.plot_settings[0]).properties['x_name'], 'uid') self.assertEqual((layout_plot.plot_settings[1]).properties['x_name'], 'qid') self.assertEqual( layout_plot.plot_settings[0].data_defined_properties.property( PlotSettings.PROPERTY_FILTER), QgsProperty.fromExpression('"uid">20')) self.assertEqual( layout_plot.plot_settings[1].data_defined_properties.property( PlotSettings.PROPERTY_FILTER), QgsProperty.fromExpression('"qid">20')) self.assertEqual(True, manager.removeLayout(layout))
def test_read_write_project_with_layout(self): """ Test saving/restoring dialog state of layout plot in project """ # print('read write project with layout test') # create project and layout project = QgsProject.instance() layout = QgsPrintLayout(project) layout_name = "PrintLayoutReadWrite" layout.initializeDefaults() layout.setName(layout_name) layout_plot = PlotLayoutItem(layout) layout_plot.setId('plot_item') plot_item_id = layout_plot.id() self.assertEqual(len(layout_plot.plot_settings), 1) # self.assertEqual(len(layout.items()), 0) layout.addLayoutItem(layout_plot) # self.assertEqual(len(layout.items()), 1) plot_dialog = PlotLayoutItemWidget(None, layout_plot) # add second plot plot_dialog.add_plot() self.assertEqual(len(layout_plot.plot_settings), 2) # edit first plot plot_dialog.setDockMode(True) plot_dialog.show_properties() plot_property_panel = plot_dialog.panel plot_property_panel.set_plot_type('violin') self.assertEqual(plot_property_panel.ptype, 'violin') plot_property_panel.acceptPanel() plot_property_panel.destroy() # edit second plot plot_dialog.plot_list.setCurrentRow(1) plot_dialog.show_properties() plot_property_panel = plot_dialog.panel plot_property_panel.set_plot_type('bar') self.assertEqual(plot_property_panel.ptype, 'bar') plot_property_panel.acceptPanel() plot_property_panel.destroy() # write xml xml_doc = QDomDocument('layout') element = layout.writeXml(xml_doc, QgsReadWriteContext()) layout_plot.remove_plot(0) self.assertEqual(len(layout_plot.plot_settings), 1) self.assertEqual(layout_plot.plot_settings[0].plot_type, 'bar') layout_plot.remove_plot(0) self.assertEqual(len(layout_plot.plot_settings), 0) # read xml layout2 = QgsPrintLayout(project) self.assertTrue( layout2.readXml(element, xml_doc, QgsReadWriteContext())) layout_plot2 = layout2.itemById(plot_item_id) self.assertTrue(layout_plot2) self.assertEqual(len(layout_plot2.plot_settings), 2) self.assertEqual(layout_plot2.plot_settings[0].plot_type, 'violin') self.assertEqual(layout_plot2.plot_settings[1].plot_type, 'bar')
def processAlgorithm(self, parameters, context, feedback): """This actually creates the print layout and exporting as .pdf document""" log = feedback.setProgressText input_title = self.parameterAsString(parameters, self.INPUT_TITLE, context) input_subtitle = self.parameterAsString(parameters, self.INPUT_SUBTITLE, context) input_credit_text = self.parameterAsString(parameters, self.INPUT_CREDIT_TEXT, context) output_pdf_path = self.parameterAsString(parameters, self.OUTPUT_PDF_PATH, context) log(f"Title: {input_title}") log(f"Subtitle: {input_subtitle}") log(f"Credit Text: {input_credit_text}") log(f"Output pdf path: {output_pdf_path}") #This creates a new print layout project = context.project() manager = project.layoutManager() layout = QgsPrintLayout(project) layoutName = 'EcoValuator Layout' #layoutName is going to be name of Title. Change this later layouts_list = manager.printLayouts() for layout in layouts_list: if layout.name() == layoutName: manager.removeLayout(layout) layout = QgsPrintLayout(project) layout.initializeDefaults() #create default map canvas layout.setName(layoutName) manager.addLayout(layout) #This adds a map item to the Print Layout map = QgsLayoutItemMap(layout) map.setRect(20, 20, 20, 20) #Set Extent canvas = iface.mapCanvas() map.setExtent(canvas.extent()) #sets map extent to current map canvas layout.addLayoutItem(map) #Move & Resize map.attemptMove(QgsLayoutPoint(5, 27, QgsUnitTypes.LayoutMillimeters)) map.attemptResize( QgsLayoutSize(218, 178, QgsUnitTypes.LayoutMillimeters)) #Gather visible layers in project layer tree and create a list of the map layer objects #Those which are not active (layers_to_remove) will subsequently remove from the legend model tree_layers = project.layerTreeRoot().children() active_layers = [ layer.name() for layer in tree_layers if layer.isVisible() ] layers_to_remove = [ layer for layer in project.mapLayers().values() if layer.name() not in active_layers ] #This adds a legend item to the Print Layout legend = QgsLayoutItemLegend(layout) layout.addLayoutItem(legend) legend.attemptMove( QgsLayoutPoint(219, 5, QgsUnitTypes.LayoutMillimeters)) #Get reference to existing legend model and root group then remove the unchecked layers legend.setAutoUpdateModel(False) #not sure if this line is required model = legend.model() group = model.rootGroup() for layer in layers_to_remove: group.removeLayer(layer) legend.adjustBoxSize() #This adds labels to the map title = QgsLayoutItemLabel(layout) title.setText(input_title) title.setFont(QFont("Arial", 28)) title.adjustSizeToText() layout.addLayoutItem(title) title.attemptMove(QgsLayoutPoint(10, 4, QgsUnitTypes.LayoutMillimeters)) subtitle = QgsLayoutItemLabel(layout) subtitle.setText(input_subtitle) subtitle.setFont(QFont("Arial", 17)) subtitle.adjustSizeToText() layout.addLayoutItem(subtitle) subtitle.attemptMove( QgsLayoutPoint(11, 20, QgsUnitTypes.LayoutMillimeters)) credit_text = QgsLayoutItemLabel(layout) credit_text.setText(input_credit_text) credit_text.setFont(QFont("Arial", 10)) credit_text.adjustSizeToText() layout.addLayoutItem(credit_text) credit_text.attemptMove( QgsLayoutPoint(219, 190, QgsUnitTypes.LayoutMillimeters)) #this creates credit text (line1) in bottom right corner of map layout giving credit to Key-Log Economics keylog_credits1 = QgsLayoutItemLabel(layout) keylog_credits1.setText("Created using EcoValuator Plugin") keylog_credits1.setFont(QFont("Arial", 10)) keylog_credits1.adjustSizeToText() layout.addLayoutItem(keylog_credits1) keylog_credits1.attemptMove( QgsLayoutPoint(219, 195, QgsUnitTypes.LayoutMillimeters)) #this creates credit text (line2) in bottom right corner of map layout giving credit to Key-Log Economics keylog_credits2 = QgsLayoutItemLabel(layout) keylog_credits2.setText("by Key-Log Economics") keylog_credits2.setFont(QFont("Arial", 10)) keylog_credits2.adjustSizeToText() layout.addLayoutItem(keylog_credits2) keylog_credits2.attemptMove( QgsLayoutPoint(219, 200, QgsUnitTypes.LayoutMillimeters)) #This exports a Print Layout as an image manager = QgsProject.instance().layoutManager( ) #this is a reference to the layout Manager, which contains a list of print layouts layout = manager.layoutByName( layoutName ) #this accesses a specific layout, by name (which is a string) exporter = QgsLayoutExporter( layout) #this creates a QgsLayoutExporter object exporter.exportToPdf(output_pdf_path, QgsLayoutExporter.PdfExportSettings()) log("Done!") result = { } #The processAlgorithm wants to return a dictionary. We don't actually need to do this so instead we return an empty one return result
def testSymbolExpressionRender(self): """Test expressions embedded in legend node text""" point_path = os.path.join(TEST_DATA_DIR, 'points.shp') point_layer = QgsVectorLayer(point_path, 'points', 'ogr') layout = QgsPrintLayout(QgsProject.instance()) layout.setName('LAYOUT') layout.initializeDefaults() map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(20, 20, 80, 80)) map.setFrameEnabled(True) map.setLayers([point_layer]) layout.addLayoutItem(map) map.setExtent(point_layer.extent()) legend = QgsLayoutItemLegend(layout) legend.setTitle("Legend") legend.attemptSetSceneRect(QRectF(120, 20, 100, 100)) legend.setFrameEnabled(True) legend.setFrameStrokeWidth(QgsLayoutMeasurement(2)) legend.setBackgroundColor(QColor(200, 200, 200)) legend.setTitle('') legend.setLegendFilterByMapEnabled(False) legend.setStyleFont(QgsLegendStyle.Title, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.Group, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.Subgroup, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.Symbol, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setStyleFont(QgsLegendStyle.SymbolLabel, QgsFontUtils.getStandardTestFont('Bold', 16)) legend.setAutoUpdateModel(False) QgsProject.instance().addMapLayers([point_layer]) s = QgsMapSettings() s.setLayers([point_layer]) group = legend.model().rootGroup().addGroup( "Group [% 1 + 5 %] [% @layout_name %]") layer_tree_layer = group.addLayer(point_layer) counterTask = point_layer.countSymbolFeatures() counterTask.waitForFinished() # does this even work? layer_tree_layer.setCustomProperty( "legend/title-label", 'bbbb [% 1+2 %] xx [% @layout_name %] [% @layer_name %]') QgsMapLayerLegendUtils.setLegendNodeUserLabel(layer_tree_layer, 0, 'xxxx') legend.model().refreshLayerLegend(layer_tree_layer) layer_tree_layer.setLabelExpression( 'Concat(@symbol_id, @symbol_label, count("Class"))') legend.model().layerLegendNodes(layer_tree_layer)[0].setUserLabel( ' sym 1') legend.model().layerLegendNodes(layer_tree_layer)[1].setUserLabel( '[%@symbol_count %]') legend.model().layerLegendNodes(layer_tree_layer)[2].setUserLabel( '[% count("Class") %]') layout.addLayoutItem(legend) legend.setLinkedMap(map) legend.updateLegend() print(layer_tree_layer.labelExpression()) TM = QgsApplication.taskManager() actask = TM.activeTasks() print(TM.tasks(), actask) count = actask[0] count.waitForFinished() map.setExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30)) checker = QgsLayoutChecker('composer_legend_symbol_expression', layout) checker.setControlPathPrefix("composer_legend") sleep(4) result, message = checker.testLayout() self.assertTrue(result, message) QgsProject.instance().removeMapLayers([point_layer.id()])
class TestQgsLayoutAtlas(unittest.TestCase): def setUp(self): self.report = "<h1>Python QgsLayoutAtlas Tests</h1>\n" def tearDown(self): report_file_path = "%s/qgistest.html" % QDir.tempPath() with open(report_file_path, 'a') as report_file: report_file.write(self.report) def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() tmppath = tempfile.mkdtemp() for file in glob.glob(os.path.join(self.TEST_DATA_DIR, 'france_parts.*')): shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath) vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsProject.instance().addMapLayers([mVectorLayer]) self.layers = [mVectorLayer] # create layout with layout map # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) QgsProject.instance().setCrs(crs) self.layout = QgsPrintLayout(QgsProject.instance()) self.layout.initializeDefaults() # fix the renderer, fill with green props = {"color": "0,127,0", 'outline_color': 'black'} fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) mVectorLayer.setRenderer(renderer) # the atlas map self.atlas_map = QgsLayoutItemMap(self.layout) self.atlas_map.attemptSetSceneRect(QRectF(20, 20, 130, 130)) self.atlas_map.setFrameEnabled(True) self.atlas_map.setLayers([mVectorLayer]) self.layout.addLayoutItem(self.atlas_map) # the atlas self.atlas = self.layout.atlas() self.atlas.setCoverageLayer(mVectorLayer) self.atlas.setEnabled(True) # an overview self.overview = QgsLayoutItemMap(self.layout) self.overview.attemptSetSceneRect(QRectF(180, 20, 50, 50)) self.overview.setFrameEnabled(True) self.overview.overview().setLinkedMap(self.atlas_map) self.overview.setLayers([mVectorLayer]) self.layout.addLayoutItem(self.overview) nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887) self.overview.setExtent(nextent) # set the fill symbol of the overview map props2 = {"color": "127,0,0,127", 'outline_color': 'black'} fillSymbol2 = QgsFillSymbol.createSimple(props2) self.overview.overview().setFrameSymbol(fillSymbol2) # header label self.mLabel1 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel1) self.mLabel1.setText("[% \"NAME_1\" %] area") self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.attemptSetSceneRect(QRectF(150, 5, 60, 15)) self.mLabel1.setMarginX(1) self.mLabel1.setMarginY(1) # feature number label self.mLabel2 = QgsLayoutItemLabel(self.layout) self.layout.addLayoutItem(self.mLabel2) self.mLabel2.setText("# [%@atlas_featurenumber || ' / ' || @atlas_totalfeatures%]") self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.attemptSetSceneRect(QRectF(150, 200, 60, 15)) self.mLabel2.setMarginX(1) self.mLabel2.setMarginY(1) self.filename_test() self.autoscale_render_test() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test() self.legend_test() self.rotation_test() shutil.rmtree(tmppath, True) def testReadWriteXml(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setHideCoverage(True) atlas.setFilenameExpression('filename exp') atlas.setCoverageLayer(vector_layer) atlas.setPageNameExpression('page name') atlas.setSortFeatures(True) atlas.setSortAscending(False) atlas.setSortExpression('sort exp') atlas.setFilterFeatures(True) atlas.setFilterExpression('filter exp') doc = QDomDocument("testdoc") elem = l.writeXml(doc, QgsReadWriteContext()) l2 = QgsPrintLayout(p) self.assertTrue(l2.readXml(elem, doc, QgsReadWriteContext())) atlas2 = l2.atlas() self.assertTrue(atlas2.enabled()) self.assertTrue(atlas2.hideCoverage()) self.assertEqual(atlas2.filenameExpression(), 'filename exp') self.assertEqual(atlas2.coverageLayer(), vector_layer) self.assertEqual(atlas2.pageNameExpression(), 'page name') self.assertTrue(atlas2.sortFeatures()) self.assertFalse(atlas2.sortAscending()) self.assertEqual(atlas2.sortExpression(), 'sort exp') self.assertTrue(atlas2.filterFeatures()) self.assertEqual(atlas2.filterExpression(), 'filter exp') def testIteration(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) atlas_feature_changed_spy = QSignalSpy(atlas.featureChanged) context_changed_spy = QSignalSpy(l.reportContext().changed) self.assertTrue(atlas.beginRender()) self.assertTrue(atlas.first()) self.assertEqual(len(atlas_feature_changed_spy), 1) self.assertEqual(len(context_changed_spy), 1) self.assertEqual(atlas.currentFeatureNumber(), 0) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') self.assertEqual(l.reportContext().layer(), vector_layer) f1 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 2) self.assertEqual(len(context_changed_spy), 2) self.assertEqual(atlas.currentFeatureNumber(), 1) self.assertEqual(l.reportContext().feature()[4], 'Bretagne') f2 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 3) self.assertEqual(len(context_changed_spy), 3) self.assertEqual(atlas.currentFeatureNumber(), 2) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') f3 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 4) self.assertEqual(len(context_changed_spy), 4) self.assertEqual(atlas.currentFeatureNumber(), 3) self.assertEqual(l.reportContext().feature()[4], 'Centre') f4 = l.reportContext().feature() self.assertFalse(atlas.next()) self.assertTrue(atlas.seekTo(2)) self.assertEqual(len(atlas_feature_changed_spy), 5) self.assertEqual(len(context_changed_spy), 5) self.assertEqual(atlas.currentFeatureNumber(), 2) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') self.assertTrue(atlas.last()) self.assertEqual(len(atlas_feature_changed_spy), 6) self.assertEqual(len(context_changed_spy), 6) self.assertEqual(atlas.currentFeatureNumber(), 3) self.assertEqual(l.reportContext().feature()[4], 'Centre') self.assertTrue(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 7) self.assertEqual(len(context_changed_spy), 7) self.assertEqual(atlas.currentFeatureNumber(), 2) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') self.assertTrue(atlas.previous()) self.assertTrue(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 9) self.assertFalse(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 9) self.assertTrue(atlas.endRender()) self.assertEqual(len(atlas_feature_changed_spy), 10) self.assertTrue(atlas.seekTo(f1)) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') self.assertTrue(atlas.seekTo(f4)) self.assertEqual(l.reportContext().feature()[4], 'Centre') self.assertTrue(atlas.seekTo(f3)) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') self.assertTrue(atlas.seekTo(f2)) self.assertEqual(l.reportContext().feature()[4], 'Bretagne') self.assertFalse(atlas.seekTo(QgsFeature(5))) def testUpdateFeature(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) self.assertTrue(atlas.beginRender()) self.assertTrue(atlas.first()) self.assertEqual(atlas.currentFeatureNumber(), 0) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') self.assertEqual(l.reportContext().layer(), vector_layer) vector_layer.startEditing() self.assertTrue(vector_layer.changeAttributeValue(l.reportContext().feature().id(), 4, 'Nah, Canberra mate!')) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') l.atlas().refreshCurrentFeature() self.assertEqual(l.reportContext().feature()[4], 'Nah, Canberra mate!') vector_layer.rollBack() def testFileName(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) atlas.setFilenameExpression("'output_' || \"NAME_1\"") self.assertTrue(atlas.beginRender()) self.assertEqual(atlas.count(), 4) atlas.first() self.assertEqual(atlas.currentFilename(), 'output_Basse-Normandie') self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Basse-Normandie.png') self.assertEqual(atlas.filePath('/tmp/output/', '.png'), '/tmp/output/output_Basse-Normandie.png') self.assertEqual(atlas.filePath('/tmp/output/', 'svg'), '/tmp/output/output_Basse-Normandie.svg') atlas.next() self.assertEqual(atlas.currentFilename(), 'output_Bretagne') self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Bretagne.png') atlas.next() self.assertEqual(atlas.currentFilename(), 'output_Pays de la Loire') self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Pays de la Loire.png') atlas.next() self.assertEqual(atlas.currentFilename(), 'output_Centre') self.assertEqual(atlas.filePath('/tmp/output/', 'png'), '/tmp/output/output_Centre.png') # try changing expression, filename should be updated instantly atlas.setFilenameExpression("'export_' || \"NAME_1\"") self.assertEqual(atlas.currentFilename(), 'export_Centre') atlas.endRender() def testNameForPage(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) atlas.setPageNameExpression("\"NAME_1\"") self.assertTrue(atlas.beginRender()) self.assertEqual(atlas.nameForPage(0), 'Basse-Normandie') self.assertEqual(atlas.nameForPage(1), 'Bretagne') self.assertEqual(atlas.nameForPage(2), 'Pays de la Loire') self.assertEqual(atlas.nameForPage(3), 'Centre') def filename_test(self): self.atlas.setFilenameExpression("'output_' || @atlas_featurenumber") self.atlas.beginRender() for i in range(0, self.atlas.count()): self.atlas.seekTo(i) expected = "output_%d" % (i + 1) self.assertEqual(self.atlas.currentFilename(), expected) self.atlas.endRender() # using feature attribute (refs https://issues.qgis.org/issues/19552) self.atlas.setFilenameExpression("'output_' || attribute(@atlas_feature,'NAME_1')") expected = ['output_Basse-Normandie', 'output_Bretagne', 'output_Pays de la Loire', 'output_Centre'] self.atlas.beginRender() for i in range(0, self.atlas.count()): self.atlas.seekTo(i) self.assertEqual(self.atlas.currentFilename(), expected[i]) self.atlas.endRender() def autoscale_render_test(self): self.atlas_map.setExtent( QgsRectangle(332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338)) self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Auto) self.atlas_map.setAtlasMargin(0.10) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_autoscale%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() self.atlas_map.setAtlasDriven(False) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas_map.setAtlasMargin(0) def fixedscale_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_fixedscale%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() def predefinedscales_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Predefined) scales = [1800000, 5000000] self.layout.reportContext().setPredefinedScales(scales) for i, s in enumerate(self.layout.reportContext().predefinedScales()): self.assertEqual(s, scales[i]) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_predefinedscales%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() def hidden_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas.setHideCoverage(True) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_hiding%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() self.atlas.setHideCoverage(False) def sorting_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas.setHideCoverage(False) self.atlas.setSortFeatures(True) self.atlas.setSortKeyAttributeIndex(4) # departement name self.atlas.setSortAscending(False) self.atlas.beginRender() for i in range(0, 2): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_sorting%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() def filtering_render_test(self): self.atlas_map.setExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Fixed) self.atlas.setHideCoverage(False) self.atlas.setSortFeatures(False) self.atlas.setFilterFeatures(True) self.atlas.setFeatureFilter("substr(NAME_1,1,1)='P'") # select only 'Pays de la loire' self.atlas.beginRender() for i in range(0, 1): self.atlas.seekTo(i) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_filtering%d' % (i + 1), self.layout) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testLayout(0, 200) self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() def legend_test(self): self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Auto) self.atlas_map.setAtlasMargin(0.10) # add a point layer ptLayer = QgsVectorLayer("Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)", "points", "memory") pr = ptLayer.dataProvider() f1 = QgsFeature(1) f1.initAttributes(2) f1.setAttribute(0, 1) f1.setAttribute(1, "Test label 1") f1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-0.638, 48.954))) f2 = QgsFeature(2) f2.initAttributes(2) f2.setAttribute(0, 2) f2.setAttribute(1, "Test label 2") f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-1.682, 48.550))) pr.addFeatures([f1, f2]) # categorized symbology r = QgsCategorizedSymbolRenderer("attr", [QgsRendererCategory(1, QgsMarkerSymbol.createSimple({"color": "255,0,0", 'outline_color': 'black'}), "red"), QgsRendererCategory(2, QgsMarkerSymbol.createSimple({"color": "0,0,255", 'outline_color': 'black'}), "blue")]) ptLayer.setRenderer(r) QgsProject.instance().addMapLayer(ptLayer) # add the point layer to the map settings layers = self.layers layers = [ptLayer] + layers self.atlas_map.setLayers(layers) self.overview.setLayers(layers) # add a legend legend = QgsLayoutItemLegend(self.layout) legend.attemptMove(QgsLayoutPoint(200, 100)) # sets the legend filter parameter legend.setLinkedMap(self.atlas_map) legend.setLegendFilterOutAtlas(True) self.layout.addLayoutItem(legend) self.atlas.beginRender() self.atlas.seekTo(0) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_legend', self.layout) myTestResult, myMessage = checker.testLayout() self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() # restore state self.atlas_map.setLayers([layers[1]]) self.layout.removeLayoutItem(legend) QgsProject.instance().removeMapLayer(ptLayer.id()) def rotation_test(self): # We will create a polygon layer with a rotated rectangle. # Then we will make it the object layer for the atlas, # rotate the map and test that the bounding rectangle # is smaller than the bounds without rotation. polygonLayer = QgsVectorLayer('Polygon', 'test_polygon', 'memory') poly = QgsFeature(polygonLayer.fields()) points = [(10, 15), (15, 10), (45, 40), (40, 45)] poly.setGeometry(QgsGeometry.fromPolygonXY([[QgsPointXY(x[0], x[1]) for x in points]])) polygonLayer.dataProvider().addFeatures([poly]) QgsProject.instance().addMapLayer(polygonLayer) # Recreating the layout locally composition = QgsPrintLayout(QgsProject.instance()) composition.initializeDefaults() # the atlas map atlasMap = QgsLayoutItemMap(composition) atlasMap.attemptSetSceneRect(QRectF(20, 20, 130, 130)) atlasMap.setFrameEnabled(True) atlasMap.setLayers([polygonLayer]) atlasMap.setExtent(QgsRectangle(0, 0, 100, 50)) composition.addLayoutItem(atlasMap) # the atlas atlas = composition.atlas() atlas.setCoverageLayer(polygonLayer) atlas.setEnabled(True) atlasMap.setAtlasDriven(True) atlasMap.setAtlasScalingMode(QgsLayoutItemMap.Auto) atlasMap.setAtlasMargin(0.0) # Testing atlasMap.setMapRotation(0.0) atlas.beginRender() atlas.first() nonRotatedExtent = QgsRectangle(atlasMap.extent()) atlasMap.setMapRotation(45.0) atlas.first() rotatedExtent = QgsRectangle(atlasMap.extent()) self.assertLess(rotatedExtent.width(), nonRotatedExtent.width() * 0.9) self.assertLess(rotatedExtent.height(), nonRotatedExtent.height() * 0.9) QgsProject.instance().removeMapLayer(polygonLayer)
class layerOut(QDialog,Ui_decorationDialog): def __init__(self, proj,qssStyle): super(layerOut, self).__init__() self.setupUi(self) self.project = proj print(self.project) self.initLayerOut() self.slot_connect() self.font = QFont('Arial', 24) self.color = QColor('black') # styleFile = './QSS-master/ElegantDark.qss' # qssStyle = CommonHelper.readQSS(styleFile) QDialog.setStyleSheet(self, qssStyle) def initLayerOut(self): self.layout = QgsPrintLayout(self.project) self.layout.initializeDefaults() self.QgsLayerView = QgsLayoutView() self.QgsLayerView.setPreviewModeEnabled(True) self.QgsLayerView.setContentsMargins(0,0,0,0) # self.QgsLayerView.resize(800,600) self.QgsLayerView.setCurrentLayout(self.layout) self.QgsLayerView.setPreviewMode(QgsPreviewEffect.PreviewDeuteranope) # self.QgsLayerView.setPreviewMode(QgsPreviewEffect.PreviewMode) self.QgsLayerView.unlockAllItems() self.layout.refresh() self.QgsLayerView.cursorPosChanged.connect(self.show_lonlat) self.selectTool = QgsLayoutViewToolSelect(self.QgsLayerView) self.selectTool.setLayout(self.layout) Layout = QVBoxLayout(self.widget) Layout.setContentsMargins(0, 0, 0, 0) Layout.addWidget(self.QgsLayerView) for layer in self.project.mapLayers().values(): self.comboBox.addItem(layer.name()) self.effect.addItem('PreviewGrayscale') self.effect.addItem('PreviewMono') self.effect.addItem('PreviewProtanope') self.effect.addItem('PreviewDeuteranope') def slot_connect(self): self.addMap.clicked.connect(self.createMap) self.addTitle.clicked.connect(self.createTittle) self.addLegend.clicked.connect(self.createLegend) self.addScale.clicked.connect(self.createScaleBar) self.exportPDF.clicked.connect(self.saveAsPDF) self.exportIMG.clicked.connect(self.saveAsIMG) self.getFont.clicked.connect(self.setFont) self.getColor.clicked.connect(self.setColor) self.deleteItem.clicked.connect(self.deleteSelectItem) self.changeEffect.clicked.connect(self.setEffect) def createMap(self): try: self.map = QgsLayoutItemMap(self.layout) self.map.setLocked(False) self.map.attemptSetSceneRect(QRectF(8.5, 20, 200, 160)) self.map.setFrameEnabled(True) layer = self.project.mapLayersByName(self.comboBox.currentText())[0] # layer.renderer().setRedBand(3) # layer.renderer().setGreenBand(2) # layer.renderer().setBlueBand(1) self.map.setLayers([layer]) self.map.setBackgroundColor(QColor(255, 255, 255)) self.map.zoomToExtent(layer.extent()) self.layout.addItem(self.map) except: pass # polygon = QPolygonF() # polygon.append(QPointF(0.0, 0.0)) # polygon.append(QPointF(100.0, 0.0)) # polygon.append(QPointF(200.0, 100.0)) # polygon.append(QPointF(100.0, 200.0)) # # polygonItem = QgsLayoutItemPolygon(polygon, self.layout) # self.layout.addItem(polygonItem) # # props = {} # props["color"] = "green" # props["style"] = "solid" # props["style_border"] = "solid" # props["color_border"] = "black" # props["width_border"] = "10.0" # props["joinstyle"] = "miter" # # symbol = QgsFillSymbol.createSimple(props) # polygonItem.setSymbol(symbol) def createTittle(self): title = QgsLayoutItemLabel(self.layout) # title.setLocked(False) title.setText(self.title.text()) title.setFont(self.font) title.setFontColor(self.color) title.adjustSizeToText() self.layout.addLayoutItem(title) title.attemptMove(QgsLayoutPoint(130, 5, QgsUnitTypes.LayoutMillimeters)) def createLegend(self): try: legend = QgsLayoutItemLegend(self.layout) legend.setTitle("Legend") legend.setLinkedMap(self.map) # map is an instance of QgsLayoutItemMap self.layout.addItem(legend) legend.attemptMove(QgsLayoutPoint(230, 15, QgsUnitTypes.LayoutMillimeters)) except: pass def createScaleBar(self): try: scalebar = QgsLayoutItemScaleBar(self.layout) scalebar.setStyle('Line Ticks Up') scalebar.setUnits(QgsUnitTypes.DistanceKilometers) scalebar.setNumberOfSegments(6) scalebar.setNumberOfSegmentsLeft(0) scalebar.setUnitsPerSegment(2) scalebar.setLinkedMap(self.map) scalebar.setUnitLabel('km') scalebar.setFont(QFont('Arial', 14)) scalebar.update() self.layout.addLayoutItem(scalebar) scalebar.attemptMove(QgsLayoutPoint(180, 190, QgsUnitTypes.LayoutMillimeters)) except: pass def saveAsPDF(self): fullpath, format = QFileDialog.getSaveFileName(self, '存储为pdf', '', '*.pdf') print(fullpath) exporter = QgsLayoutExporter(self.layout) exporter.exportToPdf(fullpath, QgsLayoutExporter.PdfExportSettings()) def saveAsIMG(self): fullpath, format = QFileDialog.getSaveFileName(self, '存储为img', '', '*.jpg;;*.png') print(fullpath) exporter = QgsLayoutExporter(self.layout) exporter.exportToImage(fullpath, QgsLayoutExporter.ImageExportSettings()) def setFont(self): font, ok = QFontDialog.getFont() if ok: self.font = font def setColor(self): self.color = QColorDialog.getColor() print(self.color) def show_lonlat(self, point): # print(point) self.mousePos = point def deleteSelectItem(self): print('delete...') # print(self.QgsLayerView.itemFocused()) try: self.QgsLayerView.deleteSelectedItems() except: pass def setEffect(self): # self.effect.addItem('PreviewGrayscale') # self.effect.addItem('PreviewMono') # self.effect.addItem('PreviewProtanope') # self.effect.addItem('PreviewDeuteranope') if self.effect.currentText() == 'PreviewGrayscale': self.QgsLayerView.setPreviewMode(QgsPreviewEffect.PreviewGrayscale) elif self.effect.currentText() == 'PreviewMono': self.QgsLayerView.setPreviewMode(QgsPreviewEffect.PreviewMono) elif self.effect.currentText() == 'PreviewProtanope': self.QgsLayerView.setPreviewMode(QgsPreviewEffect.PreviewProtanope) elif self.effect.currentText() == 'PreviewDeuteranope': self.QgsLayerView.setPreviewMode(QgsPreviewEffect.PreviewDeuteranope)