2

In the print composer, it's possible to add an expression in the window "select attributes", in order to display an attribute that wasn't calculated in the attribute table of a layer, see an example below :

enter image description here

I would like to display 2 attributes containing area values, in hectares (unit of 'sup' and 'supepnd') and in acres, without if possible calculating new fields. I am using the following expression : format_number(field*2.47105,2)

Is it also possible using PyQGIS?

For now, I tried to copy the expression in the list of fields to display, but it's not working :

pdf_table = QgsLayoutItemAttributeTable.create(layout)
pdf_table.setVectorLayer(pdf)
pdf_fields = ['champ','sup','supepnd',format_number('sup'*2.47105,2),format_number('supepnd'*2.47105,2)]
pdf_table.setDisplayedFields(pdf_fields, True)

I thought maybe I should clone the columns, calculate the 2 new fields and set the content of the attribute table, but I don't understand how to call the columns values. I get "AttributeError: 'QgsLayoutTableColumn' object has no attribute 'setContents'".

pdf = project.mapLayersByName('plan_de_ferme')[0]
champ_field = pdf.fields().indexFromName('champ')
sup_field = pdf.fields().indexFromName('sup')
supepend_field = pdf.fields().indexFromName('supepnd')
features = pdf.getFeatures()
champ = []
sup = []
supepend = []
nsup = []
nsupepend = []
length = 0
for feat in features :
    attr0 = feat.attributes()[champ_field]
    attr1 = feat.attributes()[sup_field]
    attr2 = feat.attributes()[supepend_field]
    champ.append((str(attr0)))
    sup.append(round(float(attr1),2))
    supepend.append(round(float(attr2),2))
    nsup.append(round(float(attr1*2.47105),2))
    nsupepend.append(round(float(attr2*2.47105),2))
    length += 1
tab = []

for i in range(length):
    tab.append([str(champ[i]), str(sup[i]), str(supepend[i]), str(nsup[i]), str(nsupepend[i])])

cols = pdf_table.columns()
new_cols = [col.clone() for col in cols]
for i, cloned_col in enumerate(new_cols):
    cloned_col.setContents(tab[i])
pdf_table.setColumns(new_cols)
#refresh layout
layout.refresh()

I also thought of adding the last two columns of the text table created previously next to my attribute table, but I am making an atlas and need the table to show only features visible on the map (changing for each page), and like a text table is not linked to a layer I don't think it will work.

3

Create a list of copies of the existing columns in your table. You can then create additional QgsLayoutTableColumn objects, set their attribute and heading values and append them to the list of columns. Finally, use the setColumns() method on your table passing the updated column list and refresh the layout.

The code below should work for you.

# your existing code
pdf_table = QgsLayoutItemAttributeTable.create(layout)
pdf_table.setVectorLayer(pdf)
pdf_fields = ['champ','sup','supepnd']
pdf_table.setDisplayedFields(pdf_fields, True)

#add this code...

# copy existing columns to a list
new_cols = [col.clone() for col in pdf_table.columns()]

#create and add additional columns
#don't forget double quotes around field names in expessions
add_col_1 = QgsLayoutTableColumn()
add_col_1.setAttribute('format_number("sup"*2.47105,2)')
add_col_1.setHeading('Sup.(ac)')
new_cols.append(add_col_1)

add_col_2 = QgsLayoutTableColumn()
add_col_2.setAttribute('format_number("supepnd"*2.47105,2)')
add_col_2.setHeading('Sup.ép(ac)')
new_cols.append(add_col_2)

pdf_table.setColumns(new_cols)

layout.refresh()

Results should be as below.

Example layout table before:

enter image description here

Columns in layer attribute table used in expressions:

enter image description here

Layout table after running code:

enter image description here

2
  • That works great! thank you very much! Jan 22 at 14:09
  • You're welcome!
    – Ben W
    Jan 22 at 14:40

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.