![PyPI](https://img.shields.io/pypi/v/tkintermapview)
![PyPI - Downloads](https://img.shields.io/pypi/dm/tkintermapview?color=green&label=pip%20downloads)
![PyPI - License](https://img.shields.io/pypi/l/customtkinter)
# TkinterMapView - simple Tkinter map component
![](documentation_images/map_view_example.png)
TkinterMapView is a tile based interactive map renderer widget for the python Tkinter library.
By default, it displays the OpenStreetMap map, but you can change the tile server to
whatever you like, and it also supports a second tile server for overlays like OpenSeaMap.
You can set the current focus of the widget by a position or address, and place markers
or a path on the map.
The above image program is produced by the code example `map_view_simple_example.py`.
But you can also embed the widget into a program like the following image shows.
For example by using the [CustomTkinter](https://github.com/TomSchimansky/CustomTkinter#readme) library,
which provides rounded buttons and frames in a light and dark mode:
https://user-images.githubusercontent.com/66446067/199613538-6be7bc5c-c88b-42d7-8cf5-a9ed2b011fa4.mp4
|`examples/map_with_customtkinter.py` on macOS
# Installation
```
pip3 install tkintermapview
```
Update: ``pip3 install tkintermapview --upgrade``
https://pypi.org/project/tkintermapview/
# Documentation / Tutorial
- [Importing](#importing)
- [Create the widget](#create-the-widget)
- [Set coordinate position](#set-coordinate-position)
- [Set address position](#set-address-position)
- [Set position with marker](#set-position-with-marker)
- [Set position and zoom to fit bounding box](#set-position-and-zoom-to-fit-bounding-box)
- [Create position markers](#create-position-markers)
- [Create path from position list](#create-path-from-position-list)
- [Create polygon from position list](#create-polygon-from-position-list)
- [Mouse events on the map](#mouse-events-on-the-map)
- [Utility methods](#utility-methods)
- [Use other tile servers](#use-other-tile-servers)
- [Use offline tiles](#use-offline-tiles)
---
### Importing
Import tkinter as normal and from tkintermapview import the TkinterMapView widget.
```python
import tkinter
import tkintermapview
```
---
### Create the widget
Create the standard tkinter window and place a TkinterMapView in the middle of the window.
The first argument must be the widgets master, then you specify the `width`, `height` and `corner_radius`
of the widget.
```python
# create tkinter window
root_tk = tkinter.Tk()
root_tk.geometry(f"{800}x{600}")
root_tk.title("map_view_example.py")
# create map widget
map_widget = tkintermapview.TkinterMapView(root_tk, width=800, height=600, corner_radius=0)
map_widget.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER)
```
If you also call `root_tk.mainloop()` at the end, this is already a fully working example to test the map widget.
---
### Set coordinate position
The standard position on which the map is focused is Berlin, Germany,
but you can change the position and zoom with the following commands.
The position must be given in decimal coordinates and the zoom ranges from
0 to 19 where 19 is the highest zoom level.
```python
# set current widget position and zoom
map_widget.set_position(48.860381, 2.338594) # Paris, France
map_widget.set_zoom(15)
```
---
### Set address position
But you can not only set the position by decimal coordinates, but also by
an address string like ` "colosseo, rome, italy" ` or ` "3 St Margaret St, London, United Kingdom" `.
The address is converted to a position by the OpenStreetMap geocode service
Nomatim.
```python
# set current widget position by address
map_widget.set_address("colosseo, rome, italy")
```
---
### Set position with marker
If you also want a red marker at the set position with a text of the current location,
then you can pass the `marker=True` argument to the `set_position` or `set_address`
funtions. You get back a PositionMarker object, so that you can modify or delete the marker
later:
```python
# set current widget position by address
marker_1 = map_widget.set_address("colosseo, rome, italy", marker=True)
print(marker_1.position, marker_1.text) # get position and text
marker_1.set_text("Colosseo in Rome") # set new text
# marker_1.set_position(48.860381, 2.338594) # change position
# marker_1.delete()
```
---
### Set position and zoom to fit bounding box
If you have two decimal coordinates (<lat1>, <long1>) and (<lat2>, <long2>), that define a box, so that the first coordinate is the top-left corner and the second coordinate is the bottom-right corner. Then you can use the `fit_bounding_box` method of the map widget to fit this box into the map widget:
```python
map_widget.fit_bounding_box((<lat1>, <long1>), (<lat2>, <long2>))
```
---
### Create position markers
You can also set a position marker without focusing the widget on it.
You can pass a ``text`` argument to the function and get back the marker
object, so that you can store the marker and modify or delete it later.
```python
# set a position marker
marker_2 = map_widget.set_marker(52.516268, 13.377695, text="Brandenburger Tor")
marker_3 = map_widget.set_marker(52.55, 13.4, text="52.55, 13.4")
# methods
marker_3.set_position(...)
marker_3.set_text(...)
marker_3.change_icon(new_icon)
marker_3.hide_image(True) # or False
marker_3.delete()
```
A marker can be also customized by passing the following arguments to .set_marker(),
.set_address() or .set_position(): `text, font, icon, icon_anchor, image (PhotoImage), image_zoom_visibility,
marker_color_circle, marker_color_outside, text_color, command`.
The command function will be called when the marker is clicked and will
pass the clicked marker as an argument to the functin which gets called.
The given image will be visible above the marker when the zoom level is in the range specified
by `image_zoom_visibility`, which is tuple like the following (min_zoom, max_zoom).
`image_zoom_visibility=(0, float('inf'))` means the image will be visible alle the time.
The image can also be hidden by calling: `marker.hide_image(True)` or `marker.hide_image(False)`.
To check if the image is currently hidden you can access: `marker.image_hidden` which is True or False.
You can also store an object or some reference inside the marker with the ``data`` attribute, which
can be set when creating a marker, and accessed or modified with ``marker.data``. This data attribute
also exists for path and polygons.
With the `icon` attribute you can pass a PIL.ImageTk.PhotoImage object to a marker, which will be
displayed instead of the standard location icon. With `icon_anchor` you can specify the anchor
for the icon image (center, n, nw, w, sw, s, ew, e, ne), corresponding to the position of the marker, standard is center, where the icon
image is centered over the marker position. With the `.change_icon(new_icon)` method you can change
the icon image later, but only if the marker already has an icon image from the beginning.
In ``examples/map_view_marker_icon_images.py`` you can find example code for the ``icon`` attributes.
<img src="documentation_images/marker_with_image.png" width="500"/>
With `map_widget.delete_all_marker()` all marker on the map will be deleted.
---
### Create path from position list
You can also create a path which connects multiple markers or completely new positions.
You pass a list with position tuples to the function `set_path` and get back a path object.
The path object can be modified by adding a new position or remove a specific position.
The `set_path` method accepts the following arguments: `position_list`, `color`, `command` (on click),
`name` (string for identification), `width`, `data (anything can be stored in the path object).
````python
# set a path
path_1 = map_widget.set_path([marker_2.position, marker_3.position, (52.57, 13.4), (52.55, 13.35)])
# methods
path_1.set_position_list(new_position_list)
path_1.add_position(position)
path_1.remove_position(position)
path_1.