Synchronizing views in QGIS print composer?

The only way that I found at this moment it to create a small script in python, maybe this could migrate into a plugin but I have no experience in that.

Is a really basic code, selecting the right composer and maps:

from qgis.core import *
from qgis.utils import *

composerList = iface.activeComposers()

comp = composerList[4]

maps = comp.composition().composerMapItems()

masterMap = maps[0]
slave1 = maps[1]
slave2 = maps[4]

slave1.setNewExtent(masterMap.extent())
slave2.setNewExtent(masterMap.extent())

Other option would be maintaining the initial scale in slave maps to set after the new extent if maps have different shapes, but in my personal case with this code was enough:

enter image description here

I'm open for improve this solution (I almost have no experience with PyQGIS).


Dealing with different extents and scales

The code above works great with the same extent (and consequently, shape) and scale. Now I have a code improved tested with differents extents, shapes and scales:

from qgis.core import *
from qgis.utils import *

composerList = iface.activeComposers()

comp = composerList[0]

maps = comp.composition().composerMapItems()

masterMap = maps[2]
slave1 = maps[1]
slave2 = maps[0]

centroid = masterMap.extent().center()

diffx1 = slave1.extent().xMaximum() - slave1.extent().xMinimum()
diffy1 = slave1.extent().yMaximum() - slave1.extent().yMinimum()

diffx2 = slave2.extent().xMaximum() - slave2.extent().xMinimum()
diffy2 = slave2.extent().yMaximum() - slave2.extent().yMinimum()

newExtent1 = QgsRectangle(centroid[0]-(diffx1/2),centroid[1]-(diffy1/2),centroid[0]+(diffx1/2),centroid[1]+(diffy1/2))
newExtent2 = QgsRectangle(centroid[0]-(diffx2/2),centroid[1]-(diffy2/2),centroid[0]+(diffx2/2),centroid[1]+(diffy2/2))

slave1.setNewExtent(newExtent1)
slave2.setNewExtent(newExtent2)

And the resulting test:

enter image description here


I just had the same problem and was able to get the desired result using expressions on the dependent maps. This assumes all maps have the same dimensions in the layout.

  1. Give your master map an item ID, e.g. 'map1' (at the bottom of the item properties)

  2. On each dependent map, add an expression to each of the extent values:

    x_min(map_get(item_variables('map1'), 'map_extent'))
    

The code will get the variables for the composer item 'map1', get the extent as geometry from it and finally get its x_min value from the geometry. Change the x_min to y_min, x_max and y_max accordingly.

Only downside is that you need to refresh the dependent maps each time you moved the master map. On export it should update automatically though.


Just an little tip to do it with no code. It's less efficient then aldo's answer but it does the trick in the end if it's for doing a final map. You don't need to have a master view either, it's the map canvas extent that counts :

  1. Move map A as you wish (it will be the master map)
  2. Click on "View extent in map canvas"
  3. Switch to map B
  4. Click on "Set to map canvas extent"
  5. Switch to map C
  6. Click in "Set to map canvas extent"

etc.

map canvas view/extent

When you need another map to be a master, just click on the other map then "view extent in map canvas" before setting the others.

Should you like to keep a specific view for later, i recommend you use the Spatial bookmark panel. Set the map canvas to a choosen extent then click on Set to map canvas in each slave you need :)