[{"data":1,"prerenderedAt":1227},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Fautomated-map-layout-generation\u002Fadd-map-item-and-set-extent-pyqgis":3},{"id":4,"title":5,"body":6,"description":1216,"extension":1217,"meta":1218,"navigation":229,"path":1223,"seo":1224,"stem":1225,"__hash__":1226},"docs\u002Fspatial-data-processing-automation\u002Fautomated-map-layout-generation\u002Fadd-map-item-and-set-extent-pyqgis\u002Findex.md","Add a Map Item and Set Its Extent in PyQGIS",{"type":7,"value":8,"toc":1203},"minimark",[9,13,17,26,164,169,186,190,349,371,375,476,498,505,509,512,554,578,665,669,672,762,779,862,866,869,943,960,964,1032,1043,1047,1092,1096,1104,1108,1114,1123,1133,1139,1149,1166,1170,1199],[10,11,5],"h1",{"id":12},"add-a-map-item-and-set-its-extent-in-pyqgis",[14,15,16],"p",{},"The map item is the one part of a layout that has to be right. A title in the wrong font is a nuisance; a map showing the wrong extent, at a scale nobody chose, with a layer that happened to be switched off, is a wrong map — and in a batch of two hundred it is two hundred wrong maps.",[14,18,19,20,25],{},"This recipe belongs to ",[21,22,24],"a",{"href":23},"\u002Fspatial-data-processing-automation\u002Fautomated-map-layout-generation\u002F","Automated Map Layout Generation",". It covers creating a map item, positioning it in page units, choosing between an extent and a scale, locking the layers and their styles, adding an overview frame, and the aspect-ratio behaviour that surprises everybody once.",[14,27,28],{},[29,30,35,39,43,50,67,76,86,92,102,108,113,119,123,129,134,142,147,153,157,160],"svg",{"viewBox":31,"role":32,"ariaLabel":33,"xmlns":34},"0 0 760 288","img","Diagram of a layout page with a map item positioned in millimetres, showing how the requested extent is widened to match the frame aspect ratio","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[36,37,38],"title",{},"The frame decides the extent, not the other way round",[40,41,42],"desc",{},"A map item occupies a rectangle on the page measured in millimetres. When an extent is requested that does not match the frame's proportions, QGIS keeps the requested extent fully visible and expands it in the shorter dimension to fill the frame. The map therefore shows more than was asked for, never less.",[44,45],"rect",{"x":46,"y":46,"width":47,"height":48,"fill":49},"0","760","288","#f6f3ea",[51,52,53],"defs",{},[54,55,62],"marker",{"id":56,"viewBox":57,"refX":58,"refY":59,"markerWidth":60,"markerHeight":60,"orient":61},"mapItemArrow","0 0 10 10","8","5","7","auto-start-reverse",[63,64],"path",{"d":65,"fill":66},"M0 0 L10 5 L0 10 z","#2f3b35",[68,69,75],"text",{"x":70,"y":71,"style":72,"fill":73,"textAnchor":74},"380","28","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","You get at least the extent you asked for, and often more",[44,77],{"x":78,"y":79,"width":80,"height":81,"rx":82,"fill":83,"stroke":84,"style":85},"40","52","300","204","6","#fffdf7","#59645f","stroke-width:2",[68,87,91],{"x":88,"y":89,"style":90,"fill":73,"textAnchor":74},"190","74","text-anchor:middle;font-size:11px;font-weight:bold;font-family:sans-serif","A4 landscape page",[44,93],{"x":94,"y":95,"width":96,"height":97,"rx":98,"fill":99,"stroke":100,"style":101},"66","90","180","120","4","#eef7f4","#0f766e","stroke-width:2.5",[68,103,107],{"x":104,"y":105,"style":106,"fill":100,"textAnchor":74},"156","154","text-anchor:middle;font-size:11px;font-family:sans-serif","map item",[68,109,112],{"x":104,"y":110,"style":111,"fill":84,"textAnchor":74},"174","text-anchor:middle;font-size:10px;font-family:sans-serif","180 by 120 mm",[114,115],"line",{"x1":94,"y1":116,"x2":117,"y2":116,"stroke":84,"style":118},"228","246","stroke-width:1.5;marker-end:url(#mapItemArrow)",[68,120,122],{"x":104,"y":121,"style":111,"fill":84,"textAnchor":74},"244","x, y set from the top left",[44,124],{"x":125,"y":126,"width":127,"height":128,"rx":58,"fill":83,"stroke":84,"style":85},"400","72","330","164",[68,130,133],{"x":131,"y":132,"style":90,"fill":73,"textAnchor":74},"565","96","requested versus shown",[44,135],{"x":136,"y":137,"width":138,"height":139,"rx":98,"fill":140,"stroke":141,"style":85},"470","112","80","100","#fdf2e2","#b45309",[68,143,146],{"x":144,"y":145,"style":111,"fill":141,"textAnchor":74},"510","166","requested",[44,148],{"x":149,"y":137,"width":150,"height":139,"rx":98,"fill":151,"stroke":100,"style":152},"430","240","none","stroke-width:2.5;stroke-dasharray:6 4",[68,154,156],{"x":155,"y":145,"style":111,"fill":100,"textAnchor":74},"600","actually shown",[68,158,159],{"x":131,"y":116,"style":111,"fill":84,"textAnchor":74},"widened to match the frame proportions",[68,161,163],{"x":70,"y":162,"style":106,"fill":84,"textAnchor":74},"276","Set a scale instead when the exact scale matters more than the exact extent",[165,166,168],"h2",{"id":167},"prerequisites","Prerequisites",[170,171,172,180,183],"ul",{},[173,174,175,179],"li",{},[176,177,178],"strong",{},"QGIS 3.34 LTR"," (bundled Python 3.12) or newer.",[173,181,182],{},"A project with layers, and either an existing layout or a willingness to create one.",[173,184,185],{},"Page units are millimetres throughout unless you change them.",[165,187,189],{"id":188},"create-the-layout-and-the-map-item","Create the layout and the map item",[191,192,197],"pre",{"className":193,"code":194,"language":195,"meta":196,"style":196},"language-python shiki shiki-themes github-dark","from qgis.core import (QgsProject, QgsPrintLayout, QgsLayoutItemMap,\n                       QgsLayoutPoint, QgsLayoutSize, QgsUnitTypes)\n\nproject = QgsProject.instance()\nlayout = QgsPrintLayout(project)\nlayout.initializeDefaults()                 # one A4 landscape page\nlayout.setName(\"Ward map\")\nproject.layoutManager().addLayout(layout)\n\nmap_item = QgsLayoutItemMap(layout)\nmap_item.setId(\"main map\")\nmap_item.attemptMove(QgsLayoutPoint(15, 20, QgsUnitTypes.LayoutMillimeters))\nmap_item.attemptResize(QgsLayoutSize(180, 120, QgsUnitTypes.LayoutMillimeters))\nlayout.addLayoutItem(map_item)\n","python","",[198,199,200,218,224,231,243,254,264,277,283,288,299,310,329,343],"code",{"__ignoreMap":196},[201,202,204,208,212,215],"span",{"class":114,"line":203},1,[201,205,207],{"class":206},"snl16","from",[201,209,211],{"class":210},"s95oV"," qgis.core ",[201,213,214],{"class":206},"import",[201,216,217],{"class":210}," (QgsProject, QgsPrintLayout, QgsLayoutItemMap,\n",[201,219,221],{"class":114,"line":220},2,[201,222,223],{"class":210},"                       QgsLayoutPoint, QgsLayoutSize, QgsUnitTypes)\n",[201,225,227],{"class":114,"line":226},3,[201,228,230],{"emptyLinePlaceholder":229},true,"\n",[201,232,234,237,240],{"class":114,"line":233},4,[201,235,236],{"class":210},"project ",[201,238,239],{"class":206},"=",[201,241,242],{"class":210}," QgsProject.instance()\n",[201,244,246,249,251],{"class":114,"line":245},5,[201,247,248],{"class":210},"layout ",[201,250,239],{"class":206},[201,252,253],{"class":210}," QgsPrintLayout(project)\n",[201,255,257,260],{"class":114,"line":256},6,[201,258,259],{"class":210},"layout.initializeDefaults()                 ",[201,261,263],{"class":262},"sjoCn","# one A4 landscape page\n",[201,265,267,270,274],{"class":114,"line":266},7,[201,268,269],{"class":210},"layout.setName(",[201,271,273],{"class":272},"sU2Wk","\"Ward map\"",[201,275,276],{"class":210},")\n",[201,278,280],{"class":114,"line":279},8,[201,281,282],{"class":210},"project.layoutManager().addLayout(layout)\n",[201,284,286],{"class":114,"line":285},9,[201,287,230],{"emptyLinePlaceholder":229},[201,289,291,294,296],{"class":114,"line":290},10,[201,292,293],{"class":210},"map_item ",[201,295,239],{"class":206},[201,297,298],{"class":210}," QgsLayoutItemMap(layout)\n",[201,300,302,305,308],{"class":114,"line":301},11,[201,303,304],{"class":210},"map_item.setId(",[201,306,307],{"class":272},"\"main map\"",[201,309,276],{"class":210},[201,311,313,316,320,323,326],{"class":114,"line":312},12,[201,314,315],{"class":210},"map_item.attemptMove(QgsLayoutPoint(",[201,317,319],{"class":318},"sDLfK","15",[201,321,322],{"class":210},", ",[201,324,325],{"class":318},"20",[201,327,328],{"class":210},", QgsUnitTypes.LayoutMillimeters))\n",[201,330,332,335,337,339,341],{"class":114,"line":331},13,[201,333,334],{"class":210},"map_item.attemptResize(QgsLayoutSize(",[201,336,96],{"class":318},[201,338,322],{"class":210},[201,340,97],{"class":318},[201,342,328],{"class":210},[201,344,346],{"class":114,"line":345},14,[201,347,348],{"class":210},"layout.addLayoutItem(map_item)\n",[14,350,351,354,355,358,359,362,363,366,367,370],{},[176,352,353],{},"Breakdown:"," ",[198,356,357],{},"initializeDefaults()"," gives the layout a page so items have somewhere to go — without it, everything is added to a layout with no pages and nothing renders. ",[198,360,361],{},"attemptMove()"," and ",[198,364,365],{},"attemptResize()"," are named that way because a locked or constrained item may refuse; they take a point and a size carrying their own units, so mixing millimetres and pixels is impossible by construction. Setting an ",[198,368,369],{},"id"," matters more than it looks: it is how you find the item again in a later script, and how a legend or scale bar is told which map it belongs to. The item must be added to the layout after configuration, or the layout does not own it and it disappears.",[165,372,374],{"id":373},"set-an-extent-or-set-a-scale","Set an extent, or set a scale",[191,376,378],{"className":193,"code":377,"language":195,"meta":196,"style":196},"from qgis.core import QgsRectangle\n\nwards = project.mapLayersByName(\"Wards\")[0]\n\nmap_item.zoomToExtent(wards.extent())          # fit the layer\n\nmap_item.setExtent(QgsRectangle(432000, 186000, 435000, 188000))\n\nmap_item.setScale(10000)                       # 1:10 000, centre unchanged\n",[198,379,380,391,395,416,420,428,432,458,462],{"__ignoreMap":196},[201,381,382,384,386,388],{"class":114,"line":203},[201,383,207],{"class":206},[201,385,211],{"class":210},[201,387,214],{"class":206},[201,389,390],{"class":210}," QgsRectangle\n",[201,392,393],{"class":114,"line":220},[201,394,230],{"emptyLinePlaceholder":229},[201,396,397,400,402,405,408,411,413],{"class":114,"line":226},[201,398,399],{"class":210},"wards ",[201,401,239],{"class":206},[201,403,404],{"class":210}," project.mapLayersByName(",[201,406,407],{"class":272},"\"Wards\"",[201,409,410],{"class":210},")[",[201,412,46],{"class":318},[201,414,415],{"class":210},"]\n",[201,417,418],{"class":114,"line":233},[201,419,230],{"emptyLinePlaceholder":229},[201,421,422,425],{"class":114,"line":245},[201,423,424],{"class":210},"map_item.zoomToExtent(wards.extent())          ",[201,426,427],{"class":262},"# fit the layer\n",[201,429,430],{"class":114,"line":256},[201,431,230],{"emptyLinePlaceholder":229},[201,433,434,437,440,442,445,447,450,452,455],{"class":114,"line":266},[201,435,436],{"class":210},"map_item.setExtent(QgsRectangle(",[201,438,439],{"class":318},"432000",[201,441,322],{"class":210},[201,443,444],{"class":318},"186000",[201,446,322],{"class":210},[201,448,449],{"class":318},"435000",[201,451,322],{"class":210},[201,453,454],{"class":318},"188000",[201,456,457],{"class":210},"))\n",[201,459,460],{"class":114,"line":279},[201,461,230],{"emptyLinePlaceholder":229},[201,463,464,467,470,473],{"class":114,"line":285},[201,465,466],{"class":210},"map_item.setScale(",[201,468,469],{"class":318},"10000",[201,471,472],{"class":210},")                       ",[201,474,475],{"class":262},"# 1:10 000, centre unchanged\n",[14,477,478,480,481,484,485,488,489,493,494,497],{},[176,479,353],{}," These three are alternatives, not a sequence. ",[198,482,483],{},"zoomToExtent()"," is the usual starting point and adds a small margin. ",[198,486,487],{},"setExtent()"," takes coordinates in the ",[490,491,492],"em",{},"map's"," coordinate system, which is the project CRS unless the item overrides it — passing latitude and longitude to a map in a national grid produces an empty map centred on the origin, which is the most common version of this mistake. ",[198,495,496],{},"setScale()"," keeps the centre and changes the zoom, and is what you want whenever the printed scale is a requirement rather than an outcome: a plan that must be at 1:1250 is set by scale, and the extent follows.",[14,499,500,501,504],{},"The aspect ratio rule matters for both: QGIS guarantees the requested extent is ",[490,502,503],{},"visible",", so a wide extent in a tall frame is padded vertically. If pages must show exactly the same ground area, size the frame to the data's proportions or set a scale instead.",[165,506,508],{"id":507},"lock-the-layers-so-the-map-cannot-drift","Lock the layers so the map cannot drift",[14,510,511],{},"By default a map item draws whatever the project currently shows, which means a colleague toggling a layer changes every layout in the project.",[191,513,515],{"className":193,"code":514,"language":195,"meta":196,"style":196},"map_item.setFollowVisibilityPreset(False)\nmap_item.setKeepLayerSet(True)\nmap_item.setLayers([wards, roads, buildings])   # drawn top to bottom\nmap_item.setKeepLayerStyles(True)\n",[198,516,517,527,537,545],{"__ignoreMap":196},[201,518,519,522,525],{"class":114,"line":203},[201,520,521],{"class":210},"map_item.setFollowVisibilityPreset(",[201,523,524],{"class":318},"False",[201,526,276],{"class":210},[201,528,529,532,535],{"class":114,"line":220},[201,530,531],{"class":210},"map_item.setKeepLayerSet(",[201,533,534],{"class":318},"True",[201,536,276],{"class":210},[201,538,539,542],{"class":114,"line":226},[201,540,541],{"class":210},"map_item.setLayers([wards, roads, buildings])   ",[201,543,544],{"class":262},"# drawn top to bottom\n",[201,546,547,550,552],{"class":114,"line":233},[201,548,549],{"class":210},"map_item.setKeepLayerStyles(",[201,551,534],{"class":318},[201,553,276],{"class":210},[14,555,556,354,558,561,562,565,566,569,570,573,574,577],{},[176,557,353],{},[198,559,560],{},"setKeepLayerSet(True)"," with an explicit list freezes what this map draws, in the order given — first in the list is drawn on top, matching the layer tree convention. ",[198,563,564],{},"setKeepLayerStyles(True)"," goes further and freezes the ",[490,567,568],{},"styling"," as it is now, so a later change to the project's symbology leaves the layout looking as it was designed; that is right for an archived map and wrong for a template meant to reflect the current styling. The alternative is a map theme: ",[198,571,572],{},"setFollowVisibilityPreset(True)"," with ",[198,575,576],{},"setFollowVisibilityPresetName(\"Print\")"," ties the map to a named theme, which is the cleanest arrangement when several layouts need different layer sets from one project.",[14,579,580],{},[29,581,584,587,590,593,596,602,607,612,618,621,625,629,633,637,642,646,649,653,655,657,659,662],{"viewBox":582,"role":32,"ariaLabel":583,"xmlns":34},"0 0 760 254","Comparison of a map item following the project layer tree against one with a locked layer set, showing what happens when a colleague toggles a layer",[36,585,586],{},"What a toggled layer does to your layout",[40,588,589],{},"A map item that follows the project draws whatever is currently checked, so a colleague switching off a layer silently changes every export from that layout. A map item with a locked layer set keeps drawing the layers it was given, regardless of what the layer tree shows, which is what a finished layout needs.",[44,591],{"x":46,"y":46,"width":47,"height":592,"fill":49},"254",[68,594,595],{"x":70,"y":71,"style":72,"fill":73,"textAnchor":74},"A layout that follows the project is a layout somebody can break",[44,597],{"x":325,"y":598,"width":599,"height":600,"rx":601,"fill":140,"stroke":141,"style":101},"48","348","184","10",[68,603,606],{"x":604,"y":89,"style":605,"fill":141,"textAnchor":74},"194","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","follows the layer tree",[44,608],{"x":609,"y":95,"width":80,"height":610,"rx":82,"fill":83,"stroke":84,"style":611},"44","30","stroke-width:1.5",[68,613,617],{"x":614,"y":615,"style":616,"fill":66},"60","110","font-size:11px;font-family:sans-serif","designed with 3 layers checked",[44,619],{"x":609,"y":620,"width":80,"height":610,"rx":82,"fill":83,"stroke":84,"style":611},"126",[68,622,624],{"x":614,"y":623,"style":616,"fill":66},"146","a colleague unchecks buildings",[44,626],{"x":609,"y":627,"width":80,"height":628,"rx":82,"fill":49,"stroke":141,"style":85},"162","46",[68,630,632],{"x":604,"y":631,"style":90,"fill":141,"textAnchor":74},"182","tonight's 200 pages have no buildings",[68,634,636],{"x":604,"y":635,"style":111,"fill":66,"textAnchor":74},"200","and nothing reported an error",[44,638],{"x":639,"y":598,"width":599,"height":600,"rx":601,"fill":640,"stroke":641,"style":101},"392","#edf8e9","#15803d",[68,643,645],{"x":644,"y":89,"style":605,"fill":641,"textAnchor":74},"566","locked layer set",[44,647],{"x":648,"y":95,"width":80,"height":610,"rx":82,"fill":83,"stroke":100,"style":611},"416",[68,650,652],{"x":651,"y":615,"style":616,"fill":66},"432","setKeepLayerSet with an explicit list",[44,654],{"x":648,"y":620,"width":80,"height":610,"rx":82,"fill":83,"stroke":100,"style":611},[68,656,624],{"x":651,"y":623,"style":616,"fill":66},[44,658],{"x":648,"y":627,"width":80,"height":628,"rx":82,"fill":83,"stroke":641,"style":85},[68,660,661],{"x":644,"y":631,"style":90,"fill":641,"textAnchor":74},"the layout is unaffected",[68,663,664],{"x":644,"y":635,"style":111,"fill":66,"textAnchor":74},"it draws what it was given",[165,666,668],{"id":667},"add-an-overview-frame","Add an overview frame",[14,670,671],{},"An overview map showing where the main map sits is two items and one link.",[191,673,675],{"className":193,"code":674,"language":195,"meta":196,"style":196},"overview_map = QgsLayoutItemMap(layout)\noverview_map.setId(\"overview\")\noverview_map.attemptMove(QgsLayoutPoint(210, 20, QgsUnitTypes.LayoutMillimeters))\noverview_map.attemptResize(QgsLayoutSize(60, 45, QgsUnitTypes.LayoutMillimeters))\noverview_map.zoomToExtent(wards.extent())\nlayout.addLayoutItem(overview_map)\n\noverview = overview_map.overview()\noverview.setLinkedMap(map_item)\noverview.setEnabled(True)\n",[198,676,677,686,696,710,724,729,734,738,748,753],{"__ignoreMap":196},[201,678,679,682,684],{"class":114,"line":203},[201,680,681],{"class":210},"overview_map ",[201,683,239],{"class":206},[201,685,298],{"class":210},[201,687,688,691,694],{"class":114,"line":220},[201,689,690],{"class":210},"overview_map.setId(",[201,692,693],{"class":272},"\"overview\"",[201,695,276],{"class":210},[201,697,698,701,704,706,708],{"class":114,"line":226},[201,699,700],{"class":210},"overview_map.attemptMove(QgsLayoutPoint(",[201,702,703],{"class":318},"210",[201,705,322],{"class":210},[201,707,325],{"class":318},[201,709,328],{"class":210},[201,711,712,715,717,719,722],{"class":114,"line":233},[201,713,714],{"class":210},"overview_map.attemptResize(QgsLayoutSize(",[201,716,614],{"class":318},[201,718,322],{"class":210},[201,720,721],{"class":318},"45",[201,723,328],{"class":210},[201,725,726],{"class":114,"line":245},[201,727,728],{"class":210},"overview_map.zoomToExtent(wards.extent())\n",[201,730,731],{"class":114,"line":256},[201,732,733],{"class":210},"layout.addLayoutItem(overview_map)\n",[201,735,736],{"class":114,"line":266},[201,737,230],{"emptyLinePlaceholder":229},[201,739,740,743,745],{"class":114,"line":279},[201,741,742],{"class":210},"overview ",[201,744,239],{"class":206},[201,746,747],{"class":210}," overview_map.overview()\n",[201,749,750],{"class":114,"line":285},[201,751,752],{"class":210},"overview.setLinkedMap(map_item)\n",[201,754,755,758,760],{"class":114,"line":290},[201,756,757],{"class":210},"overview.setEnabled(",[201,759,534],{"class":318},[201,761,276],{"class":210},[14,763,764,766,767,770,771,774,775,778],{},[176,765,353],{}," The overview is a property of the ",[490,768,769],{},"overview"," map, pointing at the map it should draw a frame for — the direction catches people out, since it reads more naturally the other way. ",[198,772,773],{},"setLinkedMap()"," makes the frame follow the main map automatically, including through every page of an atlas, so a ward series gets a correct locator map for free. The frame's symbol can be styled like any other fill symbol, and a semi-transparent fill with a strong outline reads better at small sizes than an outline alone. Multiple overviews are supported through ",[198,776,777],{},"overviews().addOverview()"," when a layout needs both a regional and a national locator.",[14,780,781],{},[29,782,785,788,791,794,801,804,807,811,815,819,823,828,833,838,843,848,854,859],{"viewBox":783,"role":32,"ariaLabel":784,"xmlns":34},"0 0 760 250","Diagram of a layout page with a main map and a smaller overview map, where the overview draws a frame showing the main map's extent",[36,786,787],{},"How the locator frame is produced",[40,789,790],{},"The overview map covers a wider area at a smaller scale. Its overview property points at the main map, so it draws a rectangle showing where the main map's extent falls. Because the link is to the map item rather than to a fixed rectangle, the frame follows every page of an atlas without further configuration.",[44,792],{"x":46,"y":46,"width":47,"height":793,"fill":49},"250",[51,795,796],{},[54,797,799],{"id":798,"viewBox":57,"refX":58,"refY":59,"markerWidth":60,"markerHeight":60,"orient":61},"ovArrow",[63,800],{"d":65,"fill":100},[68,802,803],{"x":70,"y":71,"style":72,"fill":73,"textAnchor":74},"The overview points at the map, not at a rectangle",[44,805],{"x":78,"y":79,"width":80,"height":806,"rx":82,"fill":99,"stroke":100,"style":101},"170",[68,808,810],{"x":88,"y":809,"style":90,"fill":100,"textAnchor":74},"76","main map item",[63,812],{"d":813,"fill":151,"stroke":100,"style":814},"M70 150 C110 120 150 170 190 130 C230 96 270 140 310 110","stroke-width:3",[63,816],{"d":817,"fill":151,"stroke":818,"style":101},"M92 190 L150 160 L210 182 L270 150","#2563eb",[68,820,822],{"x":88,"y":821,"style":111,"fill":84,"textAnchor":74},"212","the extent for this page",[44,824],{"x":825,"y":126,"width":826,"height":827,"rx":82,"fill":83,"stroke":84,"style":85},"440","280","130",[68,829,832],{"x":830,"y":831,"style":90,"fill":73,"textAnchor":74},"580","94","overview map item",[44,834],{"x":835,"y":836,"width":116,"height":138,"rx":98,"fill":49,"stroke":84,"style":837},"466","106","stroke-width:1.2",[44,839],{"x":840,"y":620,"width":97,"height":78,"rx":841,"fill":141,"fillOpacity":842,"stroke":141,"style":85},"520","3",0.25,[68,844,847],{"x":830,"y":845,"style":846,"fill":141,"textAnchor":74},"150","text-anchor:middle;font-size:10px;font-weight:bold;font-family:sans-serif","this page",[114,849],{"x1":850,"y1":827,"x2":851,"y2":852,"stroke":100,"style":853},"340","434","140","stroke-width:2;marker-end:url(#ovArrow)",[68,855,858],{"x":856,"y":857,"style":111,"fill":100,"textAnchor":74},"387","122","setLinkedMap",[68,860,861],{"x":70,"y":150,"style":106,"fill":84,"textAnchor":74},"so every atlas page gets a correct locator with no extra work",[165,863,865],{"id":864},"find-and-reuse-an-existing-map-item","Find and reuse an existing map item",[14,867,868],{},"Scripts that update a template rather than building one need to find the item:",[191,870,872],{"className":193,"code":871,"language":195,"meta":196,"style":196},"map_item = layout.itemById(\"main map\")\nif map_item is None:\n    raise RuntimeError(\"layout has no item with id 'main map'\")\n\nmap_item.setScale(5000)\nmap_item.refresh()\nlayout.refresh()\n",[198,873,874,887,904,920,924,933,938],{"__ignoreMap":196},[201,875,876,878,880,883,885],{"class":114,"line":203},[201,877,293],{"class":210},[201,879,239],{"class":206},[201,881,882],{"class":210}," layout.itemById(",[201,884,307],{"class":272},[201,886,276],{"class":210},[201,888,889,892,895,898,901],{"class":114,"line":220},[201,890,891],{"class":206},"if",[201,893,894],{"class":210}," map_item ",[201,896,897],{"class":206},"is",[201,899,900],{"class":318}," None",[201,902,903],{"class":210},":\n",[201,905,906,909,912,915,918],{"class":114,"line":226},[201,907,908],{"class":206},"    raise",[201,910,911],{"class":318}," RuntimeError",[201,913,914],{"class":210},"(",[201,916,917],{"class":272},"\"layout has no item with id 'main map'\"",[201,919,276],{"class":210},[201,921,922],{"class":114,"line":233},[201,923,230],{"emptyLinePlaceholder":229},[201,925,926,928,931],{"class":114,"line":245},[201,927,466],{"class":210},[201,929,930],{"class":318},"5000",[201,932,276],{"class":210},[201,934,935],{"class":114,"line":256},[201,936,937],{"class":210},"map_item.refresh()\n",[201,939,940],{"class":114,"line":266},[201,941,942],{"class":210},"layout.refresh()\n",[14,944,945,354,947,950,951,954,955,959],{},[176,946,353],{},[198,948,949],{},"itemById()"," is why setting an id when the layout is built matters — the alternative is iterating ",[198,952,953],{},"layout.items()"," and matching on type, which breaks the moment a second map is added. Refreshing the item and then the layout applies the change and updates anything that depends on it, such as a scale bar or a linked overview; skipping the refresh leaves a scale bar reporting the old scale in the exported PDF, which is a genuinely embarrassing failure. This is the shape most production scripts take: a cartographer builds the template, the script finds items by id and changes only what varies, following the template pattern in ",[21,956,958],{"href":957},"\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-projects\u002F","Working with QGIS Projects in PyQGIS",".",[165,961,963],{"id":962},"qgis-version-compatibility","QGIS version compatibility",[965,966,967,983],"table",{},[968,969,970],"thead",{},[971,972,973,977,980],"tr",{},[974,975,976],"th",{},"QGIS version",[974,978,979],{},"Python",[974,981,982],{},"Notes",[984,985,986,1001,1011,1022],"tbody",{},[971,987,988,992,995],{},[989,990,991],"td",{},"3.22 LTR",[989,993,994],{},"3.9",[989,996,997,1000],{},[198,998,999],{},"QgsLayoutItemMap"," with all methods shown.",[971,1002,1003,1006,1008],{},[989,1004,1005],{},"3.28 LTR",[989,1007,994],{},[989,1009,1010],{},"Identical.",[971,1012,1013,1016,1019],{},[989,1014,1015],{},"3.34 LTR",[989,1017,1018],{},"3.12",[989,1020,1021],{},"Baseline for this page.",[971,1023,1024,1027,1029],{},[989,1025,1026],{},"3.40 \u002F 3.44",[989,1028,1018],{},[989,1030,1031],{},"Identical; newer releases add map item elevation and 3D options that do not affect these calls.",[14,1033,1034,1035,1038,1039,1042],{},"QGIS 2's ",[198,1036,1037],{},"QgsComposerMap"," is gone entirely. Any example using ",[198,1040,1041],{},"QgsComposition"," predates 3.0 and needs rewriting against the layout API.",[165,1044,1046],{"id":1045},"troubleshooting","Troubleshooting",[170,1048,1049,1055,1063,1069,1075,1081],{},[173,1050,1051,1054],{},[176,1052,1053],{},"The map is empty."," The extent is in the wrong coordinate system, or the layer set is locked to layers that are not valid.",[173,1056,1057,354,1060,1062],{},[176,1058,1059],{},"Nothing appears on the page.",[198,1061,357],{}," was not called, so the layout has no page, or the item was never added.",[173,1064,1065,1068],{},[176,1066,1067],{},"The extent shows more than requested."," Expected — the frame's aspect ratio wins. Set a scale, or resize the frame.",[173,1070,1071,1074],{},[176,1072,1073],{},"The scale bar disagrees with the map."," The item was changed without a refresh, or the scale bar is linked to a different map.",[173,1076,1077,1080],{},[176,1078,1079],{},"A layer vanished from an old layout."," It follows the project and somebody unchecked it. Lock the layer set.",[173,1082,1083,1091],{},[176,1084,1085,1087,1088,959],{},[198,1086,949],{}," returns ",[198,1089,1090],{},"None"," No id was set when the layout was built. Set ids on every item a script will touch.",[165,1093,1095],{"id":1094},"conclusion","Conclusion",[14,1097,1098,1099,362,1101,1103],{},"Create the map item, place and size it in millimetres with ",[198,1100,361],{},[198,1102,365],{},", and give it an id. Choose deliberately between an extent and a scale — the frame's proportions win over a requested extent, so set a scale when the printed scale matters. Lock the layer set for anything finished, link an overview map to the main one for a locator that follows an atlas, and refresh both item and layout after any change so dependent items stay correct.",[165,1105,1107],{"id":1106},"frequently-asked-questions","Frequently Asked Questions",[14,1109,1110,1113],{},[176,1111,1112],{},"Why does my map show more area than the extent I set?","\nThe frame's aspect ratio differs from the extent's. QGIS expands the extent so all of it is visible rather than cropping.",[14,1115,1116,1119,1122],{},[176,1117,1118],{},"How do I set the map to a specific CRS?",[198,1120,1121],{},"map_item.setCrs(QgsCoordinateReferenceSystem(\"EPSG:27700\"))",". Without it the map uses the project CRS, and the extent you pass must match whichever applies.",[14,1124,1125,1128,1129,1132],{},[176,1126,1127],{},"Can the map rotate?","\nYes — ",[198,1130,1131],{},"setMapRotation()"," rotates the map content within the frame, which is how north-up-on-the-route sheets are made.",[14,1134,1135,1138],{},[176,1136,1137],{},"How do I stop labels being cut off at the frame edge?","\nSet a larger extent, or enable label margins on the map item so labels near the edge are drawn inside it.",[14,1140,1141,1144,1145,1148],{},[176,1142,1143],{},"Does the map item redraw automatically when the data changes?","\nIn the interface yes; in a script call ",[198,1146,1147],{},"refresh()"," explicitly before exporting, or you may export the previous state.",[14,1150,1151,1154,1155,1158,1159,1161,1162,959],{},[176,1152,1153],{},"How do I add a legend for this map?","\nCreate a ",[198,1156,1157],{},"QgsLayoutItemLegend"," and call ",[198,1160,773],{}," on it with this item — see ",[21,1163,1165],{"href":1164},"\u002Fspatial-data-processing-automation\u002Fautomated-map-layout-generation\u002Fadd-legend-to-layout-pyqgis\u002F","Add a Legend to a Layout in PyQGIS",[165,1167,1169],{"id":1168},"related","Related",[170,1171,1172,1177,1181,1187,1193],{},[173,1173,1174,1176],{},[21,1175,24],{"href":23}," — the guide this recipe belongs to",[173,1178,1179],{},[21,1180,1165],{"href":1164},[173,1182,1183],{},[21,1184,1186],{"href":1185},"\u002Fspatial-data-processing-automation\u002Fautomated-map-layout-generation\u002Fexporting-multiple-qgis-layouts-to-pdf\u002F","Exporting Multiple QGIS Layouts to PDF",[173,1188,1189],{},[21,1190,1192],{"href":1191},"\u002Fspatial-data-processing-automation\u002Fautomating-atlas-map-series\u002Fconfigure-atlas-coverage-layer-pyqgis\u002F","Configure an Atlas Coverage Layer in PyQGIS",[173,1194,1195],{},[21,1196,1198],{"href":1197},"\u002Fpyqgis-cartography-visualization\u002Fmap-canvas-and-image-export\u002Fadd-scalebar-and-north-arrow-pyqgis\u002F","Add a Scale Bar and North Arrow in PyQGIS",[1200,1201,1202],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sjoCn, html code.shiki .sjoCn{--shiki-default:#9AA79F}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":196,"searchDepth":220,"depth":220,"links":1204},[1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215],{"id":167,"depth":220,"text":168},{"id":188,"depth":220,"text":189},{"id":373,"depth":220,"text":374},{"id":507,"depth":220,"text":508},{"id":667,"depth":220,"text":668},{"id":864,"depth":220,"text":865},{"id":962,"depth":220,"text":963},{"id":1045,"depth":220,"text":1046},{"id":1094,"depth":220,"text":1095},{"id":1106,"depth":220,"text":1107},{"id":1168,"depth":220,"text":1169},"Place the map on a layout from code — create the map item, size and position it, set extent or scale, lock the layer set, add an overview frame, and keep the frame's aspect ratio honest.","md",{"slug":1219,"type":1220,"breadcrumb":1221,"datePublished":1222,"dateModified":1222},"add-map-item-and-set-extent-pyqgis","article","Map Item & Extent","2026-08-15","\u002Fspatial-data-processing-automation\u002Fautomated-map-layout-generation\u002Fadd-map-item-and-set-extent-pyqgis",{"title":5,"description":1216},"spatial-data-processing-automation\u002Fautomated-map-layout-generation\u002Fadd-map-item-and-set-extent-pyqgis\u002Findex","xHyx8SwLKgVBWhOmJVf_mxefniOSmZjEhP5FJCAP-KM",1786789585992]