10

I found a question very similar to my problem: How to link dataframes in ArcGIS or QGIS?. But the solution for QGIS doesn't work now (Dual View plug-in is not available anymore).

I want to sync three views:

enter image description here

The idea is to move the three map views at the same time with a master map in QGIS print composer.

Is there a way or plug-in to do this?

2

Another elegant "no code" solution for the synchronization of composer maps uses the built-in "Overview" mechanism of QGIS:

enter image description here

Therefor we add a "Master Map Frame" overview to every map window, that should be synchronized with the master map. Then we set frame style to No Brush/ No Pen and enable "Center on overview".

To fix the scale of the child map, we enter an Expression value: enter image description here

That's all.

Very easy and very dynamic!

  • Great! So simple... excellent work around – aldo_tapia Feb 26 '18 at 1:01
4

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

  • Don't forget to accept your answer by clicking the green-faded tick on the left-hand side to show your problem has been solved :) – Joseph Oct 10 '17 at 13:37
  • 1
    @Joseph thanks, but is half-solved. I'll accept my own answer after converting this in a plug-in to provide a complete solution. Still a challenge for me – aldo_tapia Oct 10 '17 at 13:41
2

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.

  • Which version of QGIS are you using? I tried in 3.0.2 without success – aldo_tapia Jun 7 '18 at 21:16
  • @aldo_tapia QGIS 3.0.3 on Ubuntu 16.04 – leak_my_brain Jun 9 '18 at 11:17
  • Weird, I can not make it run... But upvoted! – aldo_tapia Jun 12 '18 at 16:06
1

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 :)

  • Yes, I used to do in this way. Is a great option, but scales in map B and C always change, so there are two more steps – aldo_tapia Aug 3 '17 at 18:34
  • nice answer of yours, i need to try it ^^ – gisnside Aug 4 '17 at 1:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.