flags_iso3166svg
Rolf presents:
Fun with Flags - A homage to The Big Bang Theory.
flags_iso3166svg.py is a series of base64 encoded svg images of Country's Flags and Regional Flags, with a small set of country details, capital, languages etc and standard UTC timezone information, designed to work with wxPython.
Developed and tested on Linux, wxPython 4.2.1 gtk3 wxWidgets 3.2.2.1
They accessed via their ISO 3166 country codes
See: https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
The SVG images were a proverbial pain in the arse and there was me thinking svg images were the next big thing and standardised.
The SVG images of Flags out there, are a complete mishmash of structure and size. Sizes go from 100+ bytes for simple coloured flags to 2+ MegaBytes for regional flags, which seem to have a penchant for adding coats of arms, shields, castles, animals, you name it.
The structure of the files runs from pure SVG xml to Inkscape type structures that embed PNG images in base64.
Basically, svg files that exceeded 50Kb, have been excluded and replaced with Inkscape versions, simply to keep the size of flags_iso3166svg.py manageable.
flags_iso3166svg.py attempts to use Cairo via 'cairosvg' to convert the svg images and I recommend you install it, as wx.svg cannot handle some of the files and especially the Inkscape created ones.
pip3 install --upgrade cairosvg
These images are aimed at being used in Menus, BitmapComboBox, ListCtrl, TreeCtrl etc. wherever a bitmap can be inserted, to add some clarity and Va-Va-Voom, to your code.
There are currently 249 Country flags and 315 Regional flags (at last count) in flags_iso3166svg.py.
Regional flags are currently for Australia, Canada, Germany, Spain, France, Italy, Great Britain, Japan, Russia and the USA
You simply need to import flags_iso3166svg and you will be able to access the flag images.
For those that do not want to access, or to load all the flags, there are versions by continent, that only contain countries within that continental area, namely:
flags_iso3166svg_Africa.py
flags_iso3166svg_Americas.py
flags_iso3166svg_Asia.py
flags_iso3166svg_Europe.py
flags_iso3166svg_Oceania.py
flags_iso3166svg_NoRegions.py (is world flags but omits the regional flags)
The decision on which country belongs in which continent is based on the United Nations geoscheme:
https://en.wikipedia.org/wiki/United_Nations_geoscheme
Russia straddling 2 continents, is divided, roughly, by the Ural mountain range <= UTC+04:00 is Europe whilst > UTC+04:00 is Asia
I'll admit now, the majority of the images were originally pinched from wikipedia.org, so cheers Wiki.
It is based on the ISO 3166-1 country codes.
The images are stored under 'b64_' and the ISO 3166-1 alpha-2 code and that code is linked to it, so:
b64_ES = EmbeddedSvgImage(
b'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB4bWxucz0iaHR0'
b'cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iNjAwIj4KPHJl'
b'Y3Qgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIGZpbGw9IiNjNjBiMWUiLz4KPHJlY3Qgd2lk'
b'dGg9IjkwMCIgaGVpZ2h0PSIzMDAiIHk9IjE1MCIgZmlsbD0iI2ZmYzQwMCIvPgo8L3N2Zz4=', 'ES')
would be the entry for Spain's national flag.
Where the first item is the SVG in base64 and the 2nd item, is the iso2 code used internally to build a cache of a small sized version of the bitmap, for speed purposes.
If the small bitmap has already been generated for a menu for example, the cached bitmap is available, should you subsequently need to add it to a combobox or other widget.
Access to the Flag of Spain would be via flags_iso3166svg.ES which would provide the following properties:
• Bitmap,
• ScaledBitmap,
• Data,
• Icon,
• Image,
• Png,
• MediumScaledBitmap
•and LargeScaledBitmap
and methods:
• GetBitmap(tx=0.0, ty=0.0, scale=1.0, width=-1, height=-1, stride=-1)
this utilises cairosvg.svg2png(width, height)
or wx.svg ConvertToBitmap(tx=0.0, ty=0.0, scale=1.0, width=-1, height=-1, stride=-)
• GetScaledBitmap(size=small_flag_size, window=None)
this utilises cairosvg.svg2png(size[0], size[1])
or wx.svg ConvertToScaledBitmap(wx.Size(size), window)
• GetData()
• GetIcon()
• GetImage()
•and GetPng()
small_flag_size = (24, 16)
medium_flag_size = (32, 24)
large_flag_size = (48, 32)
flags_iso3166svg also contains a list of entries called:
index
and 6 dictionaries:
• catalog,
• country,
• lookup,
• regional,
• details,
• languages,
• timezone
The index allows a simple check if an entry exists e.g,:
>>> if "USA" in flags_iso3166svg.index: True
True
>>> if "United States of America" in flags_iso3166svg.index: True
True
________________________________________________________________________________
*** Warning: you made need to brush up on list comprehension over dictionaries ***
There is built in redundancy, to provide multiple ways to access the data
________________________________________________________________________________
flags_iso3166svg.catalog iso2 = image
catalog["ES"] = ES
iso3 = image
catalog["ESP"] = ES (Not regional entries)
name = image
catalog["Spain"] = ES
flags_iso3166svg.country name = (iso2, is03, regional(True/False)
country["Spain"] = ('ES', 'ESP', 0)
flags_iso3166svg.lookup iso2 = (iso2, iso3, name, regional(True/False)
lookup["ES"] = ('ES', 'ESP', 'Spain', 0)
iso3 = (iso2, iso3, name, regional(True/False)
lookup["ESP"] = ('ES', 'ESP', 'Spain', 0)
name = (iso2, iso3, name, regional(True/False)
lookup["Spain"] = ('ES', 'ESP', 'Spain', 0)
capital = (iso2, iso3, name, regional(True/False)
lookup["Madrid Spain"] = ('ES', 'ESP', 'Spain', 0)
and rarely
altname = (iso2, iso3, name, regional(True/False)
For regional entries in the above, the iso2 entry is a concatenation of country, underscore "_" and region code
e.g. US_AL = United State of America Alabama and there is no iso3 code, it is blank
flag_iso3166svg.regional regional_iso = (region_iso, region_name, regional(True))
flags_iso3166svg.regional["US_AL"] =
('US_AL', 'United States of America Alabama', 1)
flags_iso3166svg.regional['United States of America Alabama'] =
('US_AL', 'United States of America Alabama', 1)
flag_iso3166svg.details iso2 = {"continent": continent name,
"capital": city name,
"currency": currency name",
"web": country's Top-Level domain,
"lang": list of language codes
"tz": timezone using UTC standard time offset,
"altname": Alternate name, mainly for Russian oblasts e.g. Severnaya Osetiya Respublika = North Ossetia
}
See: https://en.wikipedia.org/wiki/Country_code_top-level_domain (“web”)
https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes ("lang")
Timezone may differ if it is a regional code or a main entry
Where a main entry has multiple time zones, this value may be a range e.g.
"-08:00 | -03:30" for Canada from British Columbia in the West to Newfoundland in the East the regional entry should contain just the timezone appropriate for the region.
Where a region has more than one timezone, the main one is listed e.g.
most of British Columbia is in -08:00 whilst it's South East is in -07:00
flags_iso3166svg.languages language code = language description
There are 489 language entries
flags_iso3166svg.timezone iso2 = iana timezone name
There are 542 timezone entries
links the country's alpha-2 code, the alpha-3 code and the country's name to the EmbeddedImage(..)
links the country name with the alpha-2 code, the alpha-3 and a final country/region parameter False (0) if this is a main country or True (1) if this is a regional entry
links the alpha-2 code, the alpha-3 code and the country's name and contains a final country/region parameter False (0) if this is a main country or True (1) if this is a regional entry
It includes entries for the capital city and rarely any alternative name.
(These are included to extend search facilities.)
links the iso3166-2 regional code with the country region name.
The dictionary key is the iso3166-1 alpha-2 code and the additional regional code, which may be 2 or 3 chars
For example the code for Andalucia, Spain is ES-AN ES for Spain and AN for Andalucia, this is stored as ES_AN in the catalog.
The code for England, Great Britain is GB-ENG GB for Great Britain and ENG for England, this would be stored as GB_ENG
links the country's alpha-2 code with another dictionary of country details, namely:
which continent it is on;
the name of the capital;
the name of the currency;
the Top_level domain code;
timezone
alternate name
and the codes of languages used in the country.
The language codes conform ISO 639-1 and ISO 639-3
See: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
https://en.wikipedia.org/wiki/List_of_ISO_639-3_codes
The timezones are the iana timezone names
See: https://www.iana.org/time-zones
Links the iso country/regional code to the iana timezone name, or my best attempt :)
________________________________________________________________________________
A full entry for Spain would look like this:
b64_ES = EmbeddedSvgImage(
b'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB4bWxucz0iaHR0'
b'cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MDAiIGhlaWdodD0iNjAwIj4KPHJl'
b'Y3Qgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIGZpbGw9IiNjNjBiMWUiLz4KPHJlY3Qgd2lk'
b'dGg9IjkwMCIgaGVpZ2h0PSIzMDAiIHk9IjE1MCIgZmlsbD0iI2ZmYzQwMCIvPgo8L3N2Zz4=', 'ES')
ES = b64_ES
index.append("ES")
index.append("ESP")
index.append("Spain")
catalog["ES"] = ES
catalog["ESP"] = ES
catalog["Spain"] = ES
country["Spain"] = ('ES', 'ESP', 0)
lookup["ES"] = ('ES', 'ESP', 'Spain', 0)
lookup["ESP"] = ('ES', 'ESP', 'Spain', 0)
lookup["Spain"] = ('ES', 'ESP', 'Spain', 0)
details["ES"] = {"continent":"Europe","capital":"Madrid","currency":"Euro","web":".es","lang":"es-ES | ca | gl | eu | oc","tz":"+01:00","altname":""}
Regions are a limited effort to include the flags of the major regions of key countries included for example would be the flags of US states and the regions of Spain.
The images are stored under the ISO 3166-1 alpha-2 code and the ISO 3166-2 code,
so US_AL = EmbeddedImage(..)
There is no alpha-3 code so that is left blank and in both the country dictionary and missing in the regional dictionary.
Both contain a 1 (True) as the final parameter, denoting this is a regional flag
The full entry for the flag of Alabama, USA for example is this:
b64_US_AL = EmbeddedSvgImage(
b'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MDAiIGhl'
b'aWdodD0iNDAwIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMCAwaDYwMHY0MDBIMHoiLz48cGF0'
b'aCBkPSJNMCwwIDYwMCw0MDBNMCw0MDAgNjAwLDAiIHN0cm9rZT0iI2IxMDAyMSIgc3Ryb2tl'
b'LXdpZHRoPSI2OCIvPjwvc3ZnPg==', 'US_AL')
US_AL = b64_US_AL
index.append("US_AL")
index.append("United States of America Alabama")
catalog["US_AL"] = US_AL
catalog["United States of America Alabama"] = US_AL
country["United States of America Alabama"] = ('US_AL', '', 1)
lookup["US_AL"] = ('US_AL', '', 'United States of America Alabama', 1)
lookup["United States of America Alabama"] = ('US_AL', '', 'United States of America Alabama', 1)
details["US_AL"] = {"continent":"Americas","capital":"","currency":"","web":"","lang":"","tz":"-06:00","altname":""}
regional["US_AL"] = ('US_AL', 'United States of America Alabama', 1)
regional["United States of America Alabama"] = ('US_AL', 'United States of America Alabama', 1)
Other than:
>>> flags_iso3166svg.ES
<wx.lib.embeddedimage.EmbeddedSvgImage object at 0x7fd7f4a95de0>
Access via properties using the catalog via the iso alpha-2 code, iso alpha-3 code or the country's name:
>>> flags_iso3166svg.catalog['ES'].Bitmap
<wx._core.Bitmap object at 0x7fd7f4a2d090>
>>> flags_iso3166svg.catalog['ESP'].Bitmap
<wx._core.Bitmap object at 0x7fd7f4a2cdc0>
>>> flags_iso3166svg.catalog['Spain'].Bitmap
<wx._core.Bitmap object at 0x7fd7f4a2cee0>
ditto for Image:
flags_iso3166svg.catalog['Spain'].Image
<wx._core.Image object at 0x7fd7f4a2d090>
or Icon:
>>> flags_iso3166svg.catalog['Spain'].Icon
<wx._core.Icon object at 0x7fd7f4a2cee0>
or Data:
>>> flags_iso3166svg.catalog['Spain'].Data
b'<?xml version="1.0" encoding="utf-8"?>\n<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600">\n<rect width="900" height="600" fill="#c60b1e"/>\n<rect width="900" height="300" y="150" fill="#ffc400"/>\n</svg>’
The same is true of access via the methods:
>>> flags_iso3166svg.catalog['Spain'].GetBitmap()
<wx._core.Bitmap object at 0x7fd7f4a2d090>
>>> flags_iso3166svg.catalog['ES'].GetImage()
<wx._core.Image object at 0x7fd7f4a2cee0>
Use the lookup dictionary to get iso2, iso3, country name and if it's a main entry or a regional map e.g. ES ESP Spain 0
>>> flags_iso3166svg.lookup.get("ES")
('ES', 'ESP', 'Spain', 0)
>>> flags_iso3166svg.lookup.get("ESP")
('ES', 'ESP', 'Spain', 0)
>>> flags_iso3166svg.lookup.get("Spain")
('ES', 'ESP', 'Spain', 0)
This also works for Regional entries (although you will notice the missing iso3 code and the 1 at the end, indicating a regional map):
>>> flags_iso3166svg.lookup.get("ES_AN")
('ES_AN', '', 'Spain Andalucia', 1)
>>> flags_iso3166svg.lookup.get("Spain Andalucia")
('ES_AN', '', 'Spain Andalucia', 1)
Access is the same:
>>> flags_iso3166svg.regional.get("ES_AN")
('ES_AN', 'Spain Andalucia', 1)
>>> flags_iso3166svg.regional.get("Spain Andalucia")
('ES_AN', 'Spain Andalucia', 1)
>>> flags_iso3166svg.ES_AN
< wx.lib.embeddedimage.EmbeddedSvgImage object at 0x7f7cb21ada80>
>>> flags_iso3166svg.catalog['ES_AN']
<wx.lib.embeddedimage.EmbeddedSvgImage object at 0x7f7cb21ada80>
>>> flags_iso3166svg.catalog['ES_AN'].GetBitmap()
<wx._core.Bitmap object at 0x7f7cb167c280>
>>> flags_iso3166svg.catalog['Spain Andalucia'].GetBitmap()
<wx._core.Bitmap object at 0x7f7cb167c310>
>>> flags_iso3166svg.catalog['Spain Andalucia'].GetImage()
<wx._core.Image object at 0x7f7cb167c280>
>>> flags_iso3166svg.details["ES"]
{'continent': 'Europe', 'capital': 'Madrid', 'currency': 'Euro', 'web': '.es', 'lang': 'es-ES | ca | gl | eu | oc', 'tz': '+01:00', 'altname': ''}
>>> flags_iso3166svg.details["ES"].get("currency")
'Euro'
>>> flags_iso3166svg.details["ES"].get("lang")
'es-ES | ca | gl | eu | oc'
>>> flags_iso3166svg.details["ES"].get("tz")
'+01:00'
>>> flags_iso3166svg.language.get('es')
['Spanish - Castilian']
>>> flags_iso3166svg.language.get('wa')
['Walloon']
>>> flags_iso3166svg.language.get('wol')
['Wolof']
>>> flags_iso3166svg.language.get('oc')
['Occitan (post 1500)']
The zoneinfo module was introduced with python3.9
https://docs.python.org/3.9/library/zoneinfo.html#module-zoneinfo
>>> flags_iso3166svg.timezone.get('AF')
['Asia/Kabul']
>>> flags_iso3166svg.timezone.get('US_IL')
['America/Chicago']
>>> flags_iso3166svg.timezone.get('AU_NSW')
['Australia/Sydney']
The timezone dictionary is a clumsy attempt to tie the iso3166-1 and iso3166-2 country and region codes to the iana timezone names.
Where there is no direct link, I attempt to tie the iso3166-2 code to the nearest or most appropriate name.
I fully expect that somewhere in there, I will have made an error.
For countries with multiple timezones, that I didn't get around to subdividing, I've selected the commonest or the capital region.
Country entries that are unused, for whatever reason, have been retained but given a number as a suffix to keep them out of the way but still available for future use.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
zone = flags_iso3166svg.timezone.get('AU_NSW')
datetime.now(ZoneInfo(zone[0]))
datetime.datetime(2023, 9, 11, 2, 48, 19, 153133, tzinfo=zoneinfo.ZoneInfo(key='Australia/Sydney'))
For clarity with many of the examples below, the import statement for flags_iso3166svg will have been:
import flags_iso3166svg as flags
A list of countries excluding regions (the last entry is False (0) indicating it's not a regional entry)
countries = [item for item in flags.country.items() if not item[1][-1]]
('Andorra', ('AD', 'AND', 0))
('United Arab Emirates', ('AE', 'ARE', 0))
('Afghanistan', ('AF', 'AFG', 0))
('Antigua and Barbuda', ('AG', 'ATG', 0))
('Anguilla', ('AI', 'AIA', 0))
...
A list of regions for a country: e.g. for the US
us_regions = [item for item in flags.regional.items() if item[0].startswith('US')]
('US_AK', ('US_AK', 'United States of America Alaska', 1))
('US_AL', ('US_AL', 'United States of America Alabama', 1))
('US_AR', ('US_AR', 'United States of America Arkansas', 1))
...
A list of regions for a country: e.g. for the US excluding the individual iso3166-2 entries like USAK
us_regions = [item for item in flags.regional.items() if item[0].startswith('United States ')]
('United States of America Alaska', ('US_AK', 'United States of America Alaska', 1))
('United States of America Alabama', ('US_AL', 'United States of America Alabama', 1))
('United States of America Arkansas', ('US_AR', 'United States of America Arkansas', 1))
...
Alternatively you could use the country dictionary: (the last entry if True indicating it's a regional entry)
us_regions = [item for item in flags.country.items() if item[0].startswith("United States") and item[1][-1]]
for i in us_regions: print(i)
('United States of America Alaska', ('US_AK', '', 1))
('United States of America Alabama', ('US_AL', '', 1))
('United States of America Arkansas', ('US_AR', '', 1))
...
flags_iso3166svg.Regional_Entries
returns a list of all entries in the country dictionary that are regional entries
So len(flags_iso3166svg.Regional_Entries) would tell you how many Regional entries there are
flags_iso3166svg.Country_Entries
returns a list of all entries in the country dictionary that are NOT regional entries
So len(flags_iso3166svg.Country_Entries) would tell you how many Countries there are
function lookupiso2(value) will return the iso2 code for any value
>>> flags.lookupiso2('Japan')
'JP'
>>> flags.lookupiso2('JPN')
'JP'
>>> flags.lookupiso2('JP')
'JP'
function lookupiso3(value) will return the iso2 code for any value
function lookupname(value) will return the country or region name for any value
function isregional(value) will return True/False for any value
function lookupbasecountry(value) will return the iso2 code for any value (if isregional returns True for example)
>>> import flags_iso3166 as flags
>>> flags.lookupbasecountry('United States of America Alabama')
('US', 'USA', 'United States of America', 0)
>>> flags.lookupbasecountry('US_AL')
('US', 'USA', 'United States of America', 0)
>>> flags.lookupbasecountry('JP_22')
('JP', 'JPN', 'Japan', 0)
>>> if flags.isregional('JP_17'):
flags.lookupname('JP_17')
flags.lookupbasecountry('JP_17')
'Japan Ishikawa'
('JP', 'JPN', 'Japan', 0)
The demonstration programs (flagsdemosvg.py, flagsdemosvg2.py, flagsdemosvg3.py and flagsdemo4.py) attempt to give an example of many of the methods and properties, so even if much of the above, is gobbledigook, hopefully you will see how it can be used.
Flag images are demonstrated for Menus, Comboboxes, a Button, StaticBitmaps, a ListCtrl, a TreeCtrl and SuperToolTips.
Have fun with Flags!
Dear dear, will Sheldon ever forgive me? :)
Regards,
Rolf
Anyone with insights into any misuses or misinterpretations I’ve made concerning svg files or their manipulation, feel free to point them out.
Also if you have access to better sources for svg flags, let me know.
As always, errors, bugs and insults, on a postcard please.
Demo 1
Demo 2
Demo 3
Demo 4