FE 'tkGooies'

the 'MAPtools' group



a Tk GUI ('tkGooie') script

(To make a map in a PNG file -- from OSM tiles
around a specified latitude-longitude, at
One OSM 'zoom level', using NxM OSM tiles.)

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

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

This 'tkMakePNGmapFromOSMtiles_aroundLatLon_OneZoomLevel_NxMtiles' Code-Page

to Code for a
'tkMakePNGmapFromOSMtiles_aroundLatLon_OneZoomLevel_NxMtiles' '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,

  • and, 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.

Soon after making that 'tkGooie', I made a
'tkFetchOSMtiles_atLatLon_oneTileAtVariousZoomLevels' Tk GUI script, which was meant to be an aid to a PNG-file map-maker 'tkGooie' script.

This 'tkGooie' page is intended to show that maker of PNG-file maps --- maps which are composed of NxM columns and rows of OSM 256x256-pixel image 'tiles'.

On the 'tkFetchOSMtiles_atLatLon_oneTileAtVariousZoomLevels' page, I pointed out that an OSM 'slippy map tiles' page, explains OSM 'zoom-levels', where OSM = Open Street Map.

I also pointed out on that page many of the properties of OSM 'tiles'. See that page for many details --- in a 'Nature of the slippy tiles' section.

For this 'tkMakePNGmapFromOSMtiles' utility, the plan is/was to use the 'wget' command (on Linux) to retrieve tiles for triplets of integers 'zoom/x/y' --- where 'zoom' is an integer between 0 and 18 --- and 'x' and 'y' are determined based on a user-specified latitude and longitude (in decimal degrees).

Basic Goals of the Tk Script:

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

  • a latitude-longitude location (in decimal degrees) of a 'central' tile,

  • 4 integers to indicate number of tiles west, east, south, and north of a 'central' tile (say, integers N1, N2, M1, M2) , and

  • a zoom-level integer (between 0 and 18)

from the user.

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

Then the script will use the 'wget' command to fetch the 'central' tile and the tiles around it (where each tile is a 256x256 pixel PNG file) and join the rows and columns of tiles into a single PNG file --- whose size will be (N x 256) pixels by (M x 256) pixels where N = N1 + 1 + N2 and M = M1 + 1 + M2.

After the tiles are joined, the resulting joined PNG file is displayed 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'.

             Make a PNG-file MAP - from OSM Tiles (256x256 PNG files) - for a Latitude-Longitude & OSM Zoom-Level
             [window title]
 .fRbuttons  {Exit} {Help} {GetLatLon} {MakePNGfileMAP}  ZoomLevel (0 to 18): -__+
 .fRlatlon   Central Tile Location in decimal degrees - Latitude: ___________ Longitude: __________

 .fRcols     Number of Columns of tiles - To Left: -__+  To Right: -__+  of a central tile.

 .fRrows     Number of Rows of tiles - Above: -___+  Below: -__+  a central tile.

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

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

   -  4 LARGE button widgets -- plus 10 SMALL minus (-) and plus (+) buttons on either side of
                                five small entry fields for integers (up to 2 digits each)
   - 10 label widgets
   -  7 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 the 'tkFetchOSMtiles_atLatLon_oneTileAtVariousZoomLevels' script --- which also used '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 --- and a zoom-level to enter --- as well as the 4 integers referred to as N1, N2, M1, and M2.

For initial values in the entry fields of this GUI, 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.

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

To make a map of the entire island of Tenerife, I found that for a zoom-level of 12 and the latitude-longitude of the capital city, the integers 8, 1, 6, and 1 for N1 (left), N2 (right), M1 (below), and M2 (above) were appropriate. Those integers are the initial values in those 4 entry fields.

    You can change the initial latitude and longitude, the initial zoom level, and the initial four integers (N1, N2, M1, and M2) by editing the proc 'reset_parms' in this 'tkMakePNGmapFromOSMtiles' script.

I simply clicked on the 'Fetch' button and the following PNG file was created from N x M tiles that were fetched from an OSM server ---
where N = N1 + 1 + N2 = 8 + 1 + 1 = 10 and
where M = M1 + 1 + M2 = 6 + 1 + 1 = 8.

The size of the resulting joined PNG file was (10 x 256) x (8 x 256) = 2560 x 2048 pixels.

During the time that the tiles are being fetched and being joined into a single large PNG file, a 'FETCH-and-JOIN PROCESSING IS STARTING' message is shown in the red message area --- along with the number of tiles being fetched and an estimate of the number of seconds required for the fetch-and-join --- roughly 2 seconds per tile. (There is more on execution-time in a section below.)

If your internet connection is not 'up', you will get a reminder message in a popup window.

The joined PNG file is put in the file '/tmp/userid_FINAL_MAP.png'. You can move the file to a 'permanent' directory if you plan to use it --- and rename the file there.


Note that you may go through quite a few runs with various values of N1,N2,M1,M2 (and zoom-level and latitude-longitude) before creating a joined PNG file that suits your needs.

    A section below indicates how you can change the directory location and filename for this file. But note that use of the '/tmp' directory is advantageous --- because, if you leave the various files used for the join operations in the '/tmp' directory, the files will all be automatically removed in a shutdown or reboot of a Linux machine.

Execution time:   (for the Tenerife island map)

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

But more time-consuming, is the join process --- in which tiles are joined into row-images --- and then the row-images are joined into the final PNG file image.

The joins are done with the ImageMagick 'convert' program. (You can change the command used to perform the joins by changing the 'set CONVERTpgm' statement near the bottom of the Tk script. I probably should have used the name JOINpgm.)

The fetch-AND-join processing takes, on average, roughly 1.5 to 2 seconds per tile.

Hence, for this Tenerife-island map consisting of about 8 rows and 10 columns of tiles (2560 x 2048 pixels in a large PNG file), the fetch-AND-join of the 10 x 8 = 80 tiles takes on the order of 80 x 1.5 ~ 120 seconds --- roughly 2 minutes --- on my medium-powered desktop computer.

On the accuracy of the latitude-longitude specification :

On the 'tkFetchOSMtiles_atLatLon_oneTileAtVariousZoomLevels' script page, it was pointed out how many decimal places you will need in your latitude-longitude specification to accurately 'pinpoint' a location of interest.

It was pointed out that, at the equator (zero degrees latitude):

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

    A note on that 'tkGooie' script page and at the OSM Zoom Levels page 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.

So a specification of 28.4667 for the latitude of the capital city of Tenerife was actually more precise than was needed for a map of the island --- a value of 28.47 would have been sufficient.

On the image-viewer program :

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 slow-starting GIMP.)

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

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

On the location and name of the fetched tile-files :

In addition to changing factors like the image-viewer program and the image-joiner command, 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 'target' 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 fetched-tile filenames are built in the form '$env(USER)_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.

The joined-into-rows filenames are built in the form '$env(USER)_row__y.png' where 'y' is a row-number.

The final (joined-rows) PNG filename is built in the form '$env(USER)_FINAL_MAP.png'.

If you do not like those names, you can simply edit the Tk script to change the filename format.

    The userid is put in the filenames in case the computer being used is a multi-user machine.


Below, I provide the Tk script code for this
'tkMakePNGmapFromOSMtiles_aroundLatLon_OneZoomLevel_NxMtiles' '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 latitude and longitude 'entry' widgets will expand/contract suitably when the GUI window size is changed --- and 'button' and 'label' widgets stay fixed in size and relative-location if the window size is changed.

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 'Sites-LatLon' button

  'z_lat_lon_TO_col_row'     - called by proc 'make_PNG_map'

  'make_PNG_map'             - called by the 'MakePNGfileMAP' button.

  'advise_user'              - called by the 'make_PNG_map' proc and in
                               the 'Additional GUI Initialization' section
                               at the bottom of the script.

  'zlevel_increment'         - called via the zoom-level '+' button
  'zlevel_decrement'         - called via the zoom-level '-' button

  'colsleft_increment'       - called via the cols-left '+' button
  'colsleft_decrement'       - called via the cols-left '-' button

  'colsright_increment'       - called via the cols-right '+' button
  'colsright_decrement'       - called via the cols-right '-' button

  'rowsvert1_increment'       - called via the rows-above '+' button
  'rowsvert1_decrement'       - called via the rows-above '-' button

  'rowsvert2_increment'       - called via the rows-below '+' button
  'rowsvert2_decrement'       - called via the rows-below '-' button

  'popup_msgVarWithScroll'   - called by the 'Help' button, to show $HELPtext var
                               and to popup warning messages from the 'make_PNG_map' proc.

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' and 'make_PNG_map' procs, 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, which are invariably answered (nowadays) starting with the word 'LOOK' --- even though they REALLY want us to 'LISTEN'. (Or are they trying to say 'Look at me, The Great.'?)

Potential Tclers:
When you get tired of looking at (and listening at) TV-interviews-with-politicians-and-the-like, 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
--- 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.