FE 'tkGooies'

the 'MAPtools' group



a Tk GUI ('tkGooie') script

(To show OSM tiles at various zoom levels
--- for a specified latitude and longitude.)

(OSM = Open Street Map)
(FE = Freedom Environment)

FE Home Page > FE Downloads Page > FE 'tkGooies' Description Page >

FE 'tkGooies' 'MAPtools' Page > This 'tkFetchOSMtiles_atLatLon_oneTileAtVariousZoomLevels' Code-Page

Code for a 'tkFetchOSMtiles_atLatLon_oneTileAtVariousZoomLevels' 'app'

For several years (circa 2014-2016), I had been planning to make various 'map making' Tk GUI's that

  • provide 'vector' (outline) maps (drawn with line-segments) and image-file maps (assembled from 'tiles'),

  • while allowing for a lot of control in making the maps --- either 'directly' through the GUI scripts I present in the 'tkGooies' system --- or 'indirectly' by providing scripts that can be altered to provide even more features,

  • eventually, provide additional map utility GUI's that allow for reading a 'marker-locations' file and then apply markers to a previously created map image (vector-map or tiles-map).

On the page 'tkReadOutlineFile_drawOutlineOnCanvas', I presented my first map-making 'tkGooie' script --- to make 'vector' maps from outline-data files in a simple format --- each line of the file containing x,y coordinates (which may be a longitude-latitude pair, in decimal degrees) on each data line of the input file.

This 'tkGooie' page is intended to show the first of a set of 'tile-map' utilities.

In doing some web searches on building maps like those provided by Google Maps, I ran across an OSM 'slippy map tiles' page, which explains OSM 'zoom-levels', where OSM = Open Street Map.

This 'slippy map tiles' page points out that 'tiles' can be retrieved from an OSM server using URL names like 'http://tile.openstreetmap.org/zoom/x/y.png' where 'zoom' represents an integer between 0 and 18 --- and the 'slippy tiles' page provides pseudo-code for how to determine the integers x and y from a given latitude and longitude location.

I realized that I could use the 'wget' command (on Linux) to retrieve tiles for specified 'zoom/x/y' --- I just needed to make a Tk GUI script that would accept a latitude and longitude (and a zoom level) and do the calculation to determine the integers 'x' and 'y'.

Nature of the 'slippy tiles':

The OSM 'slippy map tile' page indicates that the tiles at any zoom level cover most of the Earth, but not all of it.

The tiles cover from the equator to about 85 degrees North and 85 degrees South in terms of latitude --- but not all the way to the North and South poles, in this 'vertical direction'.

The tiles DO cover the Earth 360 degrees in the 'horizontal' direction --- from minus-180-degrees to plus-180-degrees, where 0 degrees is the longitude line through Greenwich, England.

At the zoom-level-zero, there is one 256x256 pixel tile that shows that portion of the Earth (-180 to +180 longitude, and about -85 to +85 latitude) --- and here is a copy of that tile as fetched on 1 Dec 2016.

FROM http://tile.openstreetmap.org/0/0/0.png

At the zoom-level-one, there are 2 x 2 = 4 tiles that cover most of the Earth --- and here are those 4 tiles (as fetched on 1 Dec 2016).

http://tile.openstreetmap.org/1/0/0.png (column 0, row 0)
http://tile.openstreetmap.org/1/1/0.png (column 1, row 0)
http://tile.openstreetmap.org/1/0/1.png (column 0, row 1)
http://tile.openstreetmap.org/1/1/1.png (column 1, row 1)

http://tile.openstreetmap.org/2/0/0.png (column 0, row 0)
http://tile.openstreetmap.org/2/1/0.png (column 1, row 0)
http://tile.openstreetmap.org/2/2/0.png (column 2, row 0)
http://tile.openstreetmap.org/2/3/0.png (column 3, row 0)

http://tile.openstreetmap.org/2/0/1.png (column 0, row 1)
http://tile.openstreetmap.org/2/1/1.png (column 1, row 1)
http://tile.openstreetmap.org/2/2/1.png (column 2, row 1)
http://tile.openstreetmap.org/2/3/1.png (column 3, row 1)

http://tile.openstreetmap.org/2/0/2.png (column 0, row 2)
http://tile.openstreetmap.org/2/1/2.png (column 1, row 2)
http://tile.openstreetmap.org/2/2/2.png (column 2, row 2)
http://tile.openstreetmap.org/2/3/2.png (column 3, row 2)

http://tile.openstreetmap.org/2/0/3.png (column 0, row 3)
http://tile.openstreetmap.org/2/1/3.png (column 1, row 3)
http://tile.openstreetmap.org/2/2/3.png (column 2, row 3)
http://tile.openstreetmap.org/2/3/3.png (column 3, row 3)

You can see the pattern that is emerging here: At each zoom-level, the tiles come from dividing each tile of the previous zoom-level into 4 tiles. And the number of tiles for each zoom level is growing exponentially --- as 4^N where N is the zoom-level.

In fact, there are more than 68 billion tiles at zoom-level 18 --- and each zoom level goes up a factor of 4 tiles, as the following list indicates.

  • Zoom-level-0 has 2^0 x 2^0 = 1 x 1 = 1 tile
  • Zoom-level-1 has 2^1 x 2^1 = 2 x 2 = 4 tiles
  • Zoom-level-2 has 2^2 x 2^2 = 4 x 4 = 4^2 = 16 tiles
  • Zoom-level-3 has 2^3 x 2^3 = 8 x 8 = 4^3 = 64 tiles
  • Zoom-level-4 has 2^4 x 2^4 = 16 x 16 = 4^4 = 256 tiles
  • Zoom-level-5 has 2^5 x 2^5 = 4^5 = 1,024 tiles
  • Zoom-level-6 has 2^6 x 2^6 = 4^6 = 4,096 tiles
  • Zoom-level-7 has 2^7 x 2^7 = 4^7 = 16,384 tiles
  • Zoom-level-8 has 2^8 x 2^8 = 4^8 = 65,536 tiles
  • Zoom-level-9 has 2^9 x 2^9 = 4^9 = 262,144 tiles
  • Zoom-level-10 has 2^10 x 2^10 = 4^10 = 1,048,576 tiles
  • Zoom-level-11 has 2^11 x 2^11 = 4^11 = 4,194,304 tiles
  • Zoom-level-12 has 2^12 x 2^12 = 4^12 = 16,777,216 tiles
  • Zoom-level-13 has 2^13 x 2^13 = 4^13 = 67,108,864 tiles
  • Zoom-level-14 has 2^14 x 2^14 = 4^14 = 268,435,456 tiles
  • Zoom-level-15 has 2^15 x 2^15 = 4^15 = 1,073,741,824 tiles
  • Zoom-level-16 has 2^16 x 2^16 = 4^16 = 4,294,967,296 tiles
  • Zoom-level-17 has 2^17 x 2^17 = 4^17 = 17,179,869,184 tiles
  • Zoom-level-18 has 2^18 x 2^18 = 4^18 = 68,719,476,736 tiles

On some OpenStreetMap servers, there may be a zoom-level-19, but typically level-19 is incomplete.

The total number of tiles for zoom levels 0 through 18 can be calculated from the fact that a sum of powers, like

    Sn = 1 + a + a^2 + a^3 + ... + a^n

is given by the formula

    Sn = (a^(n+1) - 1) / (a - 1).

For a = 4 and n = 18, this means that the total of the tile numbers listed above is

    (4^19 - 1) / 3  =  (4 * 68719476736 - 1) / 3  =  274877906943 / 3  =  91,625,968,981
--- about 91.6 billion tiles.

So an OpenStreetMap server would need to be able to store about 91.6 billion tiles that are 256x256 pixels each.

    The size of the tiles range from about 0.1 kilobyte to about 30 kilobytes --- depending on the variety of colors in the tile. A solid blue tile (an ocean tile) is only about 0.1 kilobyte in size. A level 16 tile consisting of streets in a downtown area will be about 28 kilobytes.

Perhaps a more useful table (or list) would be one that shows, for each zoom-level, the approximate distance across a tile --- say in kilometers.

That can help us (roughly) estimate an appropriate zoom-level to use to fetch tiles for a particular type of map.

Since the circumference of the Earth is about 40,050 kilometers (24,870 miles), and there are 360 degrees around the Earth, each degree of longitude around the Earth represents about 40050 / 360 = 111 kilometers or 24870 / 360 = 69 miles --- at the equator.

The following table indicates the degrees across each tile --- from which we can give an estimate of the width of the tile in number of kilometers (or meters) ... at the equator.

    (For a tile at 60 degrees latitude, take half of these distance figures for the width of the tile. In other words, use the cosine of the latitude angle as a factor to adjust the width. For heights of the tiles, you do not have to adjust these distance figures.)

Reference: The OSM Zoom Levels page.

  • Zoom-level-0 tile width is 360 degrees --- about 40,050 kilometers
  • Zoom-level-1 tile width is 180 degrees --- about 20,025 kilometers
  • Zoom-level-2 tile width is 90.0 degrees --- about 10,012.5 kilometers
  • Zoom-level-3 tile width is 45.0 degrees --- about 5,006 kilometers
  • Zoom-level-4 tile width is 22.5 degrees --- about 2,503 kilometers
  • Zoom-level-5 tile width is 11.25 degrees --- about 1,252 kilometers
  • Zoom-level-6 tile width is 5.625 degrees --- about 626 kilometers
  • Zoom-level-7 tile width is 2.813 degrees --- about 313 kilometers
  • Zoom-level-8 tile width is 1.406 degrees --- about 156 kilometers
  • Zoom-level-9 tile width is 0.703 degrees --- about 78 kilometers
  • Zoom-level-10 tile width is 0.352 degrees --- about 39 kilometers
  • Zoom-level-11 tile width is 0.176 degrees --- about 19.5 kilometers
  • Zoom-level-12 tile width is 0.088 degrees --- about 9.8 kilometers
  • Zoom-level-13 tile width is 0.044 degrees --- about 4.9 kilometers
  • Zoom-level-14 tile width is 0.022 degrees --- about 2.44 kilometers
  • Zoom-level-15 tile width is 0.011 degrees --- about 1.22 kilometers
  • Zoom-level-16 tile width is 0.0055 degrees --- about 611 meters
  • Zoom-level-17 tile width is 0.0028 degrees --- about 306 meters
  • Zoom-level-18 tile width is 0.0014 degrees --- about 152 meters

So, at zoom-level-18, a tile covers an area about the size of a football/fusbol/soccer field or stadium.

If you want more information on Open Street Map or 'slippy tiles', you can do a WEB SEARCH on keywords like

Let us return to presentation of the code for this 'tkGooie'.

A Motivation for this Tk Script:

To determine an appropriate zoom-level to be used
in a separate tile-map-making 'tkGooies' utility
--- by looking at various zoom-levels of tiles
at the area of interest.

A major motivation for this Tk script is to serve as an aid to using a separate utility that builds a map --- at a particular zoom level --- from an array of tiles (rows and columns of 256x256 pixel PNG files).

In that utility, the user can experiment with the number of rows and columns to use to adequately cover the area of interest.

The table above (of distances across tiles at various zoom-levels) is often not enough to determine an appropriate zoom level to use for a map. It is often necessary to look at actual tiles, at various zoom levels, at the area of interest (at a latitude-longitude location).

Basic Goals of the Tk Script:

My purpose for this Tk GUI script is/was to accept

  • a latitude-longitude location (in decimal degrees), and
  • a set of zoom-levels (integers between 0 and 18)
from the user.

For each zoom level (and for the given latitude-longitude), the Tk script will use the OSM algorithm to determine the 'zoom/x/y' integers that specify an OSM tile.

Then the script will use the 'wget' command to fetch the several tiles --- and show them in a user-specifiable image viewer.


As I have done with other Tk scripts that I have written in the past year or so, I laid out a 'text image' of the GUI --- to aid me as I coded the frames and widgets.

I used the following conventions to make the sketch, with a text editor.

  SQUARE-BRACKETS indicate a comment (not to be placed on the GUI).
  BRACES          indicate a Tk 'button' widget.
  A COLON         indicates that the text before the colon is on a 'label' widget.
  <---O--->       indicates a Tk 'scale' widget (if any).
  CAPITAL-X       indicates a Tk 'checkbutton' widget (if any).
  CAPITAL-O       indicates a Tk 'radiobutton' widget (if any).
  UNDERSCORES     indicate a Tk 'entry' widget (if any).

According to those conventions, I created the following 'text sketch'.

             Fetch OSM Tiles (256x256 PNG files) - for a Latitude-Longitude - Various Zoom-Levels
             [window title]
 .fRbuttons  {Exit} {Help} {SomeLatLonSites} {FetchAndShowTiles} ZoomLevels (0 to 18): 4_8_12_16______
 .fRlatlon   Earth Location in decimal degrees - Latitude: ____________ Longitude: __________

 .fRmsg      [---------- a message line goes here in a label widget -------------------------]

From the diagram above, I could see that this GUI will contain about:

   -  4 button widgets
   -  4 label widgets
   -  3 entry widgets

   -  0 radiobutton widgets
   -  0 checkbutton widgets
   -  0 scale widgets
   -  0 listbox widgets
   -  0 canvas widgets
   -  0 text widgets

Assembling the pieces   (The GUI)

Now it was a matter of putting the pieces together. I took 'code-pieces' from one of my other Tk scripts that use 'button' and 'label' and 'entry' widgets.

I ended up with the following GUI as an initial display, when the GUI is started up.

The message area (in red) indicates that the first step for the user is to choose a latitude and longitude to enter. (The user may wish to change some of the zoom-levels in the zoom-level entry field.)

For an example, I looked up the latitude,longitude location of the capital city of the island of Tenerife in the Canary Islands and found that 'Santa Cruz de Tenerife' is located at Latitude 28.466667, Longitude -16.25.

    (I clicked on the coordinates in degrees-minutes-seconds and was taken to a page that showed the latitude and longitude in decimal-degrees.)

A table above lets you know about how many decimal places you will need in your latitude-longitude specification to accurately 'pinpoint' a location of interest.

Namely, at the equator (zero degrees latitude):

  • 1.0 degree is roughly 100 kilometers,
  • 0.1 degree is about 10 kilometers,
  • 0.01 degree is about 1 kilometer,
  • 0.001 degree is about 100 meters (about a football/fusbol/soccer field), and
  • 0.0001 degree is about 10 meters (about the width of a house).

    A note at the table indicates that at a latitude of 60 degrees, you would need to halve these distance values.

As a consequence of these considerations:

  • If you want to specify a city,
    you may need about 2 decimal places in the longitude and latitude degrees values.

  • If you want to specify a city neighborhood,
    you may need about 3 decimal places in the longitude and latitude degrees values.

  • If you want to specify a street address,
    you may need about 4 decimal places in the longitude and latitude degrees values.


After clicking on the 'Fetch' button, within a few seconds, the tiles at zoom-levels '16 14 12 10 8 6 4' starting popping up in an image viewer.

    (I ended up using the 'mtpaint' image editor, after trying the 'eog' = 'Eye of Gnome' image viewer. 'mtpaint' is a 'light-weight' image editor that starts up quickly.)

The following tiles were displayed (for the capital of the island of Tenerife):

Zoom-level 4

Zoom-level 6

Zoom-level 8

Zoom-level 10

Zoom-level 12

Zoom-level 14

Zoom-level 16

The Tk script can use almost any GUI image viewer. (You will find it best to use a 'light-weight', quick-starting viewer --- NOT like the slow-starting GIMP image editor.)

You can edit the script to change the 'set IMGviewer' command near the bottom of the Tk script, to use a different viewer.

    Since the image viewer I was using puts each window over the previous one that popped up, and I wanted to see the lower/cruder zoom levels on the top of the stack, I ordered the zoom-levels in the zoom-level entry field from largest integer to smallest --- which causes the higher zoom levels to be fetched first.

    You can change the number and order of the zoom-levels that first come up in the GUI by editing the 'set ENTRYzoomlevels' statement at the bottom of the Tk script.

In addition, one can edit the script to change the name of the directory to which the tile (PNG) files are fetched. This Tk script is released with the output directory set to '/tmp' in a 'set DIRtemp' statement near the bottom of the Tk script. Edit that statement if you want to change the target directory.

The output filenames are built in the form 'tile_zoom_x_y.png' where 'zoom' and 'x' and 'y' are integers that were calculated by the Tk script to fetch the several tiles. If you do not like those names, you can simply edit the Tk script to change the filename format.

Execution time:   (and implication for the map-making 'tkGooie')

It is gratifying that the fetch of the 256x256 pixel 'tile' files, using 'wget', proceeded very quickly --- about half a second per file (or less).

This bodes well for the performance of the tile-map making 'tkGooie' that will be published on a separate web page.

Even if the user chooses to make a map consisting of about 10 rows and columns of tiles (about 2,560 x 2,560 pixels in a large PNG file), the fetch of the 100 tiles should take on the order of 100 x 0.5 = 50 seconds --- less than a minute.


Below, I provide the Tk script code for this
'tkFetchOSMtiles_atLatLon_oneTileAtVariousZoomLevels' 'app'.

I follow my usual 'canonical' structure for Tk code, for this Tk script:

  0) Set general window & widget parms (win-name, win-position,
     win-color-scheme, fonts, widget-geometry-parms, win-size-control).

  1a) Define ALL frames (and sub-frames, if any).
  1b) Pack   ALL frames and sub-frames.

  2) Define & pack all widgets in the frames, frame by frame.
              Within each frame, define ALL the widgets.
              Then pack the widgets.

  3) Define keyboard and mouse/touchpad/touch-sensitive-screen action
     BINDINGS, if needed.

  4) Define PROCS, if needed.

  5) Additional GUI initialization (typically with one or more of
     the procs), if needed.

This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.

This Tk coding structure makes it easy for me to find code sections --- while generating and testing this script, and when looking for code snippets to include in other scripts (code re-use).

Experimenting with the GUI

As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus Tk scripts, so far), I provide the four main pack parameters --- '-side', '-anchor', '-fill', and '-expand' --- on all the 'pack' commands for the frames and widgets.

I think I have found a good setting of the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets of this GUI. In particular ...

The 'entry' widgets will expand/contract appropriately when the GUI window size is changed --- and button and label widgets stay fixed in size and relative-location as the window size changes.

If anyone wants to change the way the GUI configures itself as the main (top-level) window size is changed, they can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets --- to get the widget behavior that they want.


Additional experimentation: You could change the fonts used for the various GUI widgets. For example, you could change '-weight' from 'bold' to 'normal' --- or '-slant' from 'roman' to 'italic'. Or change font families.

In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.

Furthermore, there are variables used to set geometry parameters of widgets --- parameters such as border-widths and padding. And you could change the '-relief' values for frames and widgets. Feel free to experiment with those 'appearance' parameters as well.

Some features of the code

There are plenty of comments in the code to describe what most of the code-sections are doing.

See the top of the 'PROCS' section of the script for a list of the procs used in this Tk script. See comments in the procs for details on the purpose of each proc and for details on the methods by which each proc was implemented.

Here is a quick overview of the procs --- to give an idea of the 'guts' of this utility:

  'get_lat_lon'              - called by the 'SomeLatLonSites' button

  'fetch_and_show_tiles'     - called by the 'FetchAndShowTiles' button.

  'z_lat_lon_TO_col_row'     - called by proc 'fetch_and_show_tiles'

  'advise_user'              - called in the 'Additional GUI Initialization'
                               section at the bottom of the script

  'edit_inputs'              - called by the 'fetch_and_show_tiles' proc

  'decimal_check'            - called by the 'edit_inputs' proc

  'popup_msgVarWithScroll'   - called by 'Help' button to show HELPtext var.

A fervent hope

It is my hope that the copious comments in the code might help Tcl-Tk coding 'newbies' get started in making GUI's like this. Without the comments --- especially in the 'z_lat_lon_TO_col_row' proc and in most of the other procs --- the code might look much more cryptic.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to look for videos of TV 'news' (opinion?) organizations interviewing politicians and their 'surrogates' and their 'experts' --- and asking them questions, even though it is quite predictable how they will answer them.

    (How about some man-on-the-street interviews as a refreshing break from the usual propaganda from the usual propagandists?)

Isn't it clear that the media outlet is mainly filling time between the commercials that bring in the dough? The dough is the main goal of the media outlet. It is pretty clear that their main goal is NOT shedding more light than heat. In fact, 'more HEAT than light' gets more viewers of the commercials.

Potential Tclers:
When you get tired of looking at devoid-of-useful-content-TV-interviews-with-politicians-and-the-like-(sandwiched-between-ridiculous-numbers-of-lengthy-commercial-breaks), try installing-using-changing-enhancing the following Tk GUI script.

To help out in making scripts like this, here is a page that provides sources of Tcl-Tk code snippets by providing links to various 'tkGooies' scripts (and wiki.tcl.tk scripts) that can make it relatively quick work to compose

  • widget definitions,
  • bind statements, and
  • procedure code.

And when you get to the testing-and-debugging phase of development of a script, here is a page that describes the wonderfulness of the 'wish' 'stack trace' facility, which can make the testing-and-debugging go relatively quickly and painlessly.

The Tk Script CODE

Here is a link to CODE for the Tk script

With your web browser, you can 'right-click' on this link --- and in the menu that pops up, select an item like 'Save Link Target As ...' --- to save this file to your local computer.

Then you can rename the file to remove the '.txt' suffix. Make sure that you have execute permission set on the file --- in order to execute the script.


There are some enhancements that could be considered for this script, such as:

  1. Allow for specifying the image-viewer to use --- on the GUI :

    An entry field could be added to the GUI, to allow the user to enter a command-name --- to use an image-viewer/editor of the user's choice --- and to allow for easily switching between different viewers.

  2. Allow for specifying an output directory --- on the GUI :

    An entry field could be added to the GUI, to allow the user to enter a (fully-qualified) directory name to use for the fetched files.

The bottom line here is that there are almost always non-trivial enhancements that could be made to (or 'forks' that could be made from) a Tk GUI 'app' like this.

One advantage of this Tk script is that it is 'open' code --- available to anyone for enhancement. So if you would like to take a different approach to implementing this script, you are welcome to take this code and build on it (or reconstruct it).


As I have said on several other code-donation pages on this freedomenv.com site and on the Tclers' wiki at wiki.tcl.tk ...

There's a lot to like about a utility that is 'free freedom' --- that is, no-cost and open-source so that you can modify/enhance/fix it without having to wait for someone else to do it for you (which may be never).

A BIG THANK YOU to Ousterhout for starting Tcl-Tk, and a BIG THANK YOU to the Tcl-Tk developers and maintainers who have kept the simply MAH-velous 'wish' interpreter going.

Bottom of a web page for presenting Code for
'tkFetchOSMtiles_atLatLon_oneTileAtVariousZoomLevels' ---
a Tk script 'app' in the FE 'tkGooies' system, in the 'MAPtools' group.

To return to a previously visited web page location, click on the
Back button of your web browser a sufficient number of times.
OR, use the History-list option of your web browser.
OR ...

< Go to Top of Page, above. >

This code may someday be posted in a page on the Tcler's Wiki ---
wiki.tcl.tk. If I do that, I will put a link to the page here.

This FE web page was created 2016 Dec 01.
Page was changed 2018 Jan 16. (Fixed some exponents. Added some text.)