5

I have a project on QGIS 3.16 with several layouts. I would like to change the scalebar width according to the value of a Python variable, either a fixed sized of 1000 or 500 units (for instance).

First, I tried to do it without the Python variable, by using the value of 1000 units. I think the following code I use try to create a new scalebar, instead of calling the existing one. Here, the name of the actual layout is 'cumul_eoliennes':

(once the QGIS projet is opened)

project = QgsProject.instance() 
projectLayoutManager = project.layoutManager()
composeur_eol = 'cumul_eoliennes'
layout_eol= projectLayoutManager.layoutByName(composeur_eol)
scalebar=QgsLayoutItemScaleBar(layout_eol)

scalebar.setHeight(1)
 # scalebar.height() gives the default value of 3 mm
scalebar.setFixedSize(1000)

The last code gives :

TypeError: QgsLayoutItemScaleBar.setFixedSize(): argument 1 has unexpected type 'int

In conclusion, I meet two problems:

  • it seems I am not able to call the actual scalebar of a layout
  • I don't know how to change the "FixedSize" of a scalebar

[EDIT about the FixedSize] I am looking for the scalebar fixed size function like below:

enter image description here

1 Answer 1

8

This line in your code: scalebar=QgsLayoutItemScaleBar(layout_eol) is creating a new QgsLayoutItemScaleBar object. This is not the way to access an existing scale bar object. In order to do that you can do something like:

scale_bar = [i for i in layout_eol.items() if isinstance(i, QgsLayoutItemScaleBar)][0]

Which works fine if you only have one scale bar in your layout. Alternatively, you could use the method itemById().

For your second problem, the setFixedSize() method takes a QgsLayoutSize() argument. The QgsLayoutSize() class constructor takes width and height arguments as well as a units argument which defaults to QgsUnitTypes.LayoutMillimeters.

Try the following:

project = QgsProject.instance() 
projectLayoutManager = project.layoutManager()
composeur_eol = 'cumul_eoliennes'
layout_eol= projectLayoutManager.layoutByName(composeur_eol)
scale_bar = [i for i in layout_eol.items() if isinstance(i, QgsLayoutItemScaleBar)][0]
#print(scale_bar)
scale_bar.setFixedSize(QgsLayoutSize(100, 20))
5
  • Excellent solution to access an existing scale bar! Thank you. However, I realize the function to change scalebar width is not FixedSize which is the one of the box containing the scale bar. I have edited my post with a screenshort of the function I am looking for. I assume first I have to set up the size mode to "fixed size" using scale_bar.setSegmentSizeMode(0). But then, how I can change the width value?
    – Remi79
    Commented Oct 7, 2021 at 14:39
  • 1
    Try scale_bar.setUnitsPerSegment(1000) (tested, so it should work) You can play manually with your units in the GUI and then use scale_bar.unitsPerSegment() to confirm.
    – ThomasG77
    Commented Oct 7, 2021 at 17:06
  • Perfect! Thank you very much for your help. Last question regarding the initial goal: how shoud I write the Python variable associated to this value (e.g. 1000)? I tried: scale_width='1000' and scale_bar_eol.setUnitsPerSegment(scale_width) but I got an error about "str" type. I tried with simple and double quotes too... I guess this is basic Python but I am newby.
    – Remi79
    Commented Oct 8, 2021 at 6:55
  • Just 1000 with no quotes, exactly as per @ThomasG77's comment. The method takes a double as argument which in C++ is a datatype which holds numerical data e.g. not a string! So passing an integer value in the Python bindings works fine.
    – Ben W
    Commented Oct 8, 2021 at 7:16
  • I think I missed something on the first place, since no quotes works fine indeed: scale_width=1000 and scale_bar_eol.setUnitsPerSegment(scale_width). Thanks!
    – Remi79
    Commented Oct 8, 2021 at 7:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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