2

A labeling routing (which is updated often) is being implemented via pyqgis and a QComboBox.

The code below worked great, that is until needs for narrowed column headers spawned the use of pythons '\n' (and subsequent problems thereafter).

This string formatting switch has caused any multiline field reference to return blank labels, while neighboring fields with single lines are displayed correctly.

A remedy I initially sought was to use fieldname (as strings) for the label settings, but this did not work. Then it was supposed that a index based context would work better (avoiding syntax), but such did not solve the problem

I am suspicious that I might be missing a line in my publishing of the QgsPalLayerSettings() class to the layer. Because when I do it manually through the QGIS labeling menu, multiline field names work perfectly fine.

Related to a previous question: Connecting vector label size with map-units?

field = str(self.csvGridFieldNames[index])
activeLayerName = self.iface.activeLayer().name()
csvGrid = ftools_utils.getMapLayerByName(unicode(activeLayerName))
# fieldIdx = csvGrid.fieldNameIndex(field)
textSize = 'coconut hoves'
valLabel = QgsPalLayerSettings()
valLabel.readFromLayer(csvGrid)
valLabel.enabled = True
valLabel.placement = QgsPalLayerSettings.OverPoint
valLabel.fieldName = field
# valLabel.fieldIndex = fieldIdx
valLabel.fontSizeInMapUnits = True
valLabel.setDataDefinedProperty(QgsPalLayerSettings.Size,True,True,'%f' %(textSize),'')
valLabel.writeToLayer(csvGrid)
valLabel.writeToLayer(csvGrid)
iface.legendInterface().refreshLayerSymbology(csvGrid)
iface.mapCanvas().refresh()

For sake of missing information, the following is a list of a few fieldNames (as contained in the list 'self.csvGridFieldNames');

While 'Status' and 'Kx' publish labels correctly, both 'Top\nElevation','Bottom\nElevation' do not.

['Status','Top\nElevation','Bottom\nElevation','Kx']


Per advice, the following also does not work:

(And 'print repr(field)' returns expected 'Top\\nElevation')

    rawField = str(self.csvGridFieldNames[index])
    if '\n' in rawField:
        beginingOfString,endOfString = rawField.split("\n")
        field = beginingOfString+'\\n'+endOfString
    else: field = rawField
    valLable.wrapChar = '\\n'  #<<=== with/without this line, still blank labels

Link to a ultra-beta QgsPointLayer Labeler pulled from a larger (yet unpublished) plugin. Extract contents to Qgis Python Plugins Dir as normal.

ReadMe instructions are a must for functionality.

QgsPointArray Labeler

  • Have you tried to set the wrapChar value, this way? valLabel.wrapChar = "\n" – Germán Carrillo Feb 3 '15 at 15:43
  • Thanks. Admittedly I was surprised I overlooked this command; such will come in handy in the future. Gave it a shot, but it did not have seemed to have worked. – Katalpa Feb 3 '15 at 16:06
  • Excuse me @Katalpa but I still don't understand what is the problem you have. Could you please provide a subset of your data (something I can test on)? – Germán Carrillo Feb 3 '15 at 16:07
  • 1
    Added a few fieldNames (from a long list) to the footer of the question. – Katalpa Feb 3 '15 at 16:16
  • Please test with valLabel.fieldName = "Top\\nElevation". I think it should work. – Germán Carrillo Feb 3 '15 at 16:37
4

After having a look at your CSV data file I have to say that the field names you are handling are not really recommended, since they generate all sorts of problems.

When you stated your question I guessed your field names looked like "Top\nElevation", which is not the case if you look at your data file, since it contains field names in the form:

"Top 
Elevation"

and that is certainly different.

As you have acknowledged, a fieldIndex should be enough to overcome those weird field names, but the fieldIndex is not implemented if you look at the QGIS code.

My Answer

I suggest you to implement a workaround.

I understand you need field names like those you have, mainly for presentation purposes. So, why not setting a multi-line alias for those fields and leaving your original field names in one line?

How to do that?

  1. Change your CSV field names to something like this (concatenate the multiple words with an underscore "_" ):

    enter image description here

  2. Right click on the layer Grid and select Properties.

  3. Go to the menu Fields and in the row corresponding to the "Top_Elevation" field, edit the alias value.

    Write TopElevation. As you can notice any ENTER you press won't start a new line. To insert the new line character you can open a text editor, press ENTER and then select and copy the character created (you need to have faith to do this :D).

    enter image description here

    With such a magic character in your clipboard, edit the alias again and paste the character between Top and Elevation. It will seem that you just entered a space, but you need to keep the faith :D.

    Finally, click on OK to close the dialog. This is how my dialog looks like before I click on OK:

enter image description here

And this is the result running your plugin (see the fields in the attribute table, the one which we defined an alias on is a multi-line field name):

enter image description here

This way you will be able to set a label on all your fields. In case that you have troubles with the code, I'm pasting you the following code snippet for reference:

valLabel=QgsPalLayerSettings()
valLabel.readFromLayer(iface.activeLayer())
field = iface.activeLayer().dataProvider().fields()[6].name()
valLabel.fieldName = field
valLabel.writeToLayer(iface.activeLayer())
iface.mapCanvas().refresh()
  • Indeed, it seems one of the text editors used to check the file prior to posting decided to save word-wrap strangely... very strangely. Such might be an inherent aspect of the bad practice to implementing multi-line headers in the manner I proposed. It seems that an alternative delimiter might be the best option, or furthermore; your concluding suggestion. I wonder if I can accomplish this programtica-pythonically... – Katalpa Feb 4 '15 at 1:25
  • 1
    Also, If I could send you a case of beverages to your chosing - I truly would. You went above and beyond a typical Q&A. Hats off @gcarrillo. – Katalpa Feb 4 '15 at 1:29
  • Thanks for the offer @Katalpa No worries, it was a challenge; each (interesting) post is a new opportunity to learn, e.g., I did't know QGIS supports aliases. – Germán Carrillo Feb 4 '15 at 2:06
  • Regarding how to set aliases from PyQGIS, that's another question I could look at. Feel free to post it. – Germán Carrillo Feb 4 '15 at 2:08
1

I've reproduced your problem. It seems that you need to escape the \n in your field names.

What does that mean?

If you try to pass directly the field name valLabel.fieldName = "Top\nElevation", Python will handle such string as:

"Top
Elevation"

which is not what your field name looks like. But, if you escape the \n, this way: valLabel.fieldName = "Top\\nElevation" Python will know that you actually mean:

"Top\nElevation"

Since you won't provide directly the strings but will use a variable, you need to make use of a function that escapes special characters for you.

My answer

Instead of:

valLabel.fieldName = field

use:

valLabel.fieldName = field.encode('string_escape')
  • While I agree that your logic should have solved the problem - it doesn't seem to have; labels are still blank. Perhaps there is another error in my process, or maybe the stacked fieldNames should be reverted. I should note, this is for a deliminated text layer (CSV) loaded as a point vector. Not sure if that's a factor to consider or not. – Katalpa Feb 3 '15 at 17:44
  • Pushed a QGIS plugin in link @ footer of question. Bear in mind, it is an end member function - so it might be buggy. – Katalpa Feb 3 '15 at 18:31

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.