A Python issue with generating value formatters in pygal Worldmaps

79 views Asked by At

I have a dictionary of country names, for each country I have stored a numerical value and a tag. the numerical value is a simple frequency I pass to the pygal Worldmap and the tag is a string I want to add to the tooltip.

For example suppose country 'af' and 'cn' have corresponding numerical values 20 and 10, and tags 'AA' and 'BB'. Then the below code works just fine.

import pygal
worldmap_chart = pygal.maps.world.World()

worldmap_chart.add('2012', [{'value': ('af',20), 
                              'formatter': lambda x: '{}: {}'.format(x[0], x[1]) + 'AA'},
                            {'value': ('cn',10), 
                              'formatter': lambda x: '{}: {}'.format(x[0], x[1]) + 'BB'}])

But if I create a list like this

countries=[{'value': ('af',20), 'tag':'AA'}, {'value': ('cn',10), 'tag':'BB'}]

And pass it to the above function like this

worldmap_chart.add('2012', [{'value': i['value'], 
                      'formatter': lambda x: '{}: {}'.format(x[0], x[1]) + i['tag']} for i in countries])

It doesn't give me the same thing! both of the tooltips now show the same tag BB corresponding to the last element in the countries.

In fact I have tens of countries and with the last code, the tooltips are all the same and they are the tag for the last country. but the first code at the top works fine and I wonder how can I generate them correctly.

1

There are 1 answers

1
BoobyTrap On BEST ANSWER

The variable i is changing. You do not call formatter function until later, at which point i already points to the last element of the for loop. If you could call the formatter straight after it finishes the first element and before it continues to the second, you would get AA. What you need to do is bind i['tag'] to a parameter of the lambda - tag=i["tag"] so that the value itself will be saved.

def main():
    countries=[{'value': ('af',20), 'tag': 'AA'}, 
               {'value': ('cn',10), 'tag': 'BB'}]
    regular = [{'value': ('af',20), 'formatter': lambda x: f'{x[0]}: {x[1]}AA'},
               {'value': ('cn',10), 'formatter': lambda x: f'{x[0]}: {x[1]}BB'}]
    generated = [{'value': i['value'],
                  'formatter':
                      lambda x, tag=i["tag"]:
                      f'{x[0]}: {x[1]}{tag}'} for i in countries]

    print(regular[0]['formatter']((5, 3)))
    print(generated[0]['formatter']((5, 3)))


if __name__ == '__main__':
    main()

What it prints is:

5: 3AA
5: 3AA