1

I would like to label points in ArcMap, and the labels contain chemical formulas. These chemical formulas have both subscripts and superscripts (see snip below)

I am unable to use labels that both retain sub/superscript formatting, and have a mask (like the point names in the image below). If I add a text box to manually (copy-paste) label all points with text formatting, I can not add a mask. (This is why they appear as such)

Label Example

Attribute tables don't retain sub/superscript formatting, and as such display as plain text if I label directly from the attribute table.

Attribute Table example

Is there a way to have the formatting of sub/superscripts in the chemical formulas show in the labels, and still be able to use a mask? I have a large number of points so I would like to use the attribute table. However the only way I can think of to accomplish this is by exploding every part of each chemical formula into its own field (seeing as I have hundreds of points this doesn't seem realistic)

OKAY. Lukes code works great but I cannot get it to work with my code. This is my code without sub/super formatting:

def FindLabel ( [Name], [Spring_Exc], [Fall_Exc] ):
  return [Name] + "<SUB><CLR red='255' green='0' blue='255'>" +  [Spring_Exc] + "</CLR>" + "<CLR red='0' green='122' blue='192'>"  + "\r\n"+[Fall_Exc] + "</CLR></SUB>"

& This is what it looks like:

Label Example

I need it to retain the sub/super formatting; This is what Luke came up with:

def FindLabel ([Spring_Exc]):
    formats = {
        'SiO2': 'SiO<sub>2</sub>',
        'CO32-': 'CO<sub>3</sub><sup>2-</sup>',
        'HCO2-': 'HCO<sub>2</sub><sup>-</sup.',
        'HCO3': 'HCO<sub>3</sub>'
    }
    formulas = [Spring_Exc].strip('()').split(',')
    labels = [formats.get(f, f) for f in formulas]
    return '({})'.format(','.join(labels))

& this is what Lukes code looks like, it accomplishes my formatting issue.

enter image description here

I am looking to have [Spring_Exc] & [Fall_Exc] to be labeled with sub/super formatting, as subscripts of the point name. It should look like screenshot #3 but retain formatting.

My most recent thought is that I would have to approach it like this: (However I am not sure if this thinking is correct, as there are errors)

def FindLabel ( [Name], [Spring_Exc], [Fall_Exc] ):
    formats = {
        'SiO2': 'SiO<sub>2</sub>',
        'CO32-': 'CO<sub>3</sub><sup>2-</sup>',
        'HCO2-': 'HCO<sub>2</sub><sup>-</sup.',
        'HCO3': 'HCO<sub>3</sub>'
    }
    formulas = [Spring_Exc].strip('()').split(',')
    formula = [Fall_Exc].strip('()').split(',')
    labels = [formats.get(f, f) for f in formulas]
    labels = [formats.get(f, f) for f in formula]

    return '({[Name] + "<SUB><CLR red='255' green='0' blue='255'>" +  [Spring_Exc] + "</CLR>" + "<CLR red='0' green='122' blue='192'>"  + "\r\n"+[Fall_Exc] + "</CLR></SUB>"})'.format(','.join(labels))

This is how Lukes code appears in my expression popup, I have advanced checked and have selected the python parser:

Label Expression box

I'm not sure how to fix my issue of combining these two codes into one.

  • ArcGIS Formatting Tags can be used in Label Expressions or edited into field values and labeled direct. – PolyGeo Jul 17 '18 at 20:14
  • Done, thanks I couldn't figure out how to make it format nicely on here. – Michael Rodney Sep 4 '18 at 22:02
  • See my edited answer – user2856 Sep 5 '18 at 2:48
2

If you pick the label Expression option in the Labels tab of Layer Properties and take the Python parser from the dropdown menu as Advanced mode ticked, the script below should do the trick (i.e., MY_FIELD below is your labelling field)

def FindLabel ( [MY_FIELD] ):
  result = ''.join([i, '<SUB>%s</SUB>'%i][(i.isdigit())] for i in  [MY_FIELD])
  return result
  • Using <Sub> </SUB> won't help as chemical formulas are all different, contain both sub and superscript characters, and are stores in the attribute table (which does not store sub/superscript formatting). I can not find any way to label these without doing them all manually (and with my quantity of data this is unrealistic) – Michael Rodney Aug 28 '18 at 15:58
  • @MichaelRodney, can you please edit your question adding a few examples as in your attribute table? – fatih_dur Aug 29 '18 at 0:39
  • I thought Luke's code above worked great, but it only formats the first formula and prints the rest as plain text. Can anyone see why?? – Michael Rodney Nov 5 '18 at 17:53
2

I would make a dict with the formulas that require sub/superscript and use that to insert ArcGIS Formatting Tags into your labels.

For example:

def FindLabel ([Spring_Exc]):
    formats = {
        'SiO2': 'SiO<sub>2</sub>',
        'CO32-': 'CO<sub>3</sub><sup>2-</sup>',
        'HCO3': 'HCO<sub>3</sub>'
    }
    # Get rid of the outer brackets and split on the commas
    formulas = [Spring_Exc].strip('()').split(',')
    # Replace any known formulae using a list comprehension
    labels = [formats.get(f, f) for f in formulas]
    # Put the label back together with comma and outer brackets
    return '({})'.format(','.join(labels))

This will check the formats dict (formats.get()) for any formulas that require sub/superscripts and replace them with a formatted formula (or return the original formula if it isn't in the dict) then put the commas and surrounding brackets back and return the result.

Following your edit, I couldn't get nested <SUB> tags to work i.e "Some Name (SiO2,NOx)" Some Name <SUB>(SiO<SUB>2</SUB>,NOx)</SUB> so just used line breaks and made the formula font smaller (with a <FNT scale=""> tag):

def FindLabel ( [NAME] , [F1] , [F2]  ):
    formats = {
        'SiO2': 'SiO<sub>2</sub>',
        'CO32-': 'CO<sub>3</sub><sup>2-</sup>',
        'HCO2-': 'HCO<sub>2</sub><sup>-</sup>',
        'HCO3': 'HCO<sub>3</sub>'
    }
    formula1 = [F1].strip('()').split(',')
    formula2 = [F2].strip('()').split(',')
    label1 = ','.join([formats.get(f, f) for f in formula1])
    label2 = ','.join([formats.get(f, f) for f in formula2])

    return "{} <FNT scale='50'><CLR red='255' green='0' blue='255'>({})</CLR>\r\n<CLR red='0' green='122' blue='192'>({})</CLR></FNT>".format([Name], label1, label2)

enter image description here

  • Thanks Luke! This actually worked very nicely! I am having trouble piecing together this code with my previous code. I need these chemical formulas to appear as a subscript below the point name. I can't figure out how to make this happen as <SUB></SUB> with print(FindLabel( '(abc,def,SiO2)')) keeps returning errors. Can you think of how I can accomplish this? Do I need to make the print = to a variable? I am trying to achieve [Name]<SUB>print(FindLabel( '(abc,def,SiO2)'))</SUB> (I know this exact code doesnt work) but maybe you'll know how to piece these together properly without errors? – Michael Rodney Sep 4 '18 at 19:13
  • Hey Luke, I do have python selected and advanced, My other code is: def FindLabel ( [Name], [Spring_Exc], [Fall_Exc] ): return [Name] + "<SUB><CLR red='255' green='0' blue='255'>" + [Spring_Exc] + "</CLR>" + "<CLR red='0' green='122' blue='192'>" + [Fall_Exc] + "</CLR></SUB>" End Function This didn't retain the chemical formula formatting, so I am trying to combine my expression with 'lack of formatting' with the code you helped me develop to retain formatting in these subscripts. – Michael Rodney Sep 4 '18 at 20:49
  • I was only using print as I thought it might help me code the two together.. but should I have tried to code it into the return'({})', and add [Name] & [Fall_Exc] to the def FindLabel ( [Name], [Spring_Exc], [Fall_Exc] ) ? I feel like I am treating this as two sepperate codes when I should be treating it as one. – Michael Rodney Sep 4 '18 at 20:59
  • This code only formats the first formula in the label. Does anyone know why? I.e If you look at the screenshot at the bottom of Luke's response you can see multiple formulas for spring exceedance (pink text). On my map SIO2 is formatting correctly, but all the remaining formulas for that exceedance period (subscript color) are printing as plain text and are ignoring the formatted dictionary. – Michael Rodney Oct 29 '18 at 19:32

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.