{"id":15058928,"url":"https://github.com/tomschimansky/tkintermapview","last_synced_at":"2025-05-15T17:07:04.731Z","repository":{"id":37904213,"uuid":"435254102","full_name":"TomSchimansky/TkinterMapView","owner":"TomSchimansky","description":"A python Tkinter widget to display tile based maps like OpenStreetMap or Google Satellite Images. ","archived":false,"fork":false,"pushed_at":"2024-07-11T08:40:28.000Z","size":43033,"stargazers_count":666,"open_issues_count":85,"forks_count":92,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-04-03T20:09:05.504Z","etag":null,"topics":["googlemaps","interactive","map","openstreetmap","osm","positioning","positions","python","satelite-images","tile-rendering","tilemap","tkinter","tkinter-widgets"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TomSchimansky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-05T19:03:55.000Z","updated_at":"2025-03-30T15:13:17.000Z","dependencies_parsed_at":"2024-11-28T02:12:00.808Z","dependency_job_id":null,"html_url":"https://github.com/TomSchimansky/TkinterMapView","commit_stats":{"total_commits":111,"total_committers":5,"mean_commits":22.2,"dds":"0.39639639639639634","last_synced_commit":"0bf4ae37100aa32e749264d196a54f4c3b797250"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomSchimansky%2FTkinterMapView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomSchimansky%2FTkinterMapView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomSchimansky%2FTkinterMapView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomSchimansky%2FTkinterMapView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TomSchimansky","download_url":"https://codeload.github.com/TomSchimansky/TkinterMapView/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248489128,"owners_count":21112507,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["googlemaps","interactive","map","openstreetmap","osm","positioning","positions","python","satelite-images","tile-rendering","tilemap","tkinter","tkinter-widgets"],"created_at":"2024-09-24T22:33:22.574Z","updated_at":"2025-04-11T22:28:42.579Z","avatar_url":"https://github.com/TomSchimansky.png","language":"Python","readme":"![PyPI](https://img.shields.io/pypi/v/tkintermapview)\n![PyPI - Downloads](https://img.shields.io/pypi/dm/tkintermapview?color=green\u0026label=pip%20downloads)\n![PyPI - License](https://img.shields.io/pypi/l/customtkinter)\n\n# TkinterMapView - simple Tkinter map component\n\n![](documentation_images/map_view_example.png)\n\nTkinterMapView is a tile based interactive map renderer widget for the python Tkinter library.\nBy default, it displays the OpenStreetMap map, but you can change the tile server to\nwhatever you like, and it also supports a second tile server for overlays like OpenSeaMap.\nYou can set the current focus of the widget by a position or address, and place markers \nor a path on the map.\n\nThe above image program is produced by the code example `map_view_simple_example.py`.\n\nBut you can also embed the widget into a program like the following image shows.\nFor example by using the [CustomTkinter](https://github.com/TomSchimansky/CustomTkinter#readme) library,\nwhich provides rounded buttons and frames in a light and dark mode:\n\n\nhttps://user-images.githubusercontent.com/66446067/199613538-6be7bc5c-c88b-42d7-8cf5-a9ed2b011fa4.mp4\n\n|`examples/map_with_customtkinter.py` on macOS\n\n# Installation\n\n\n```\npip3 install tkintermapview\n```\nUpdate: ``pip3 install tkintermapview --upgrade``\n\nhttps://pypi.org/project/tkintermapview/\n\n# Documentation / Tutorial\n\n- [Importing](#importing)\n- [Create the widget](#create-the-widget)\n- [Set coordinate position](#set-coordinate-position)\n- [Set address position](#set-address-position)\n- [Set position with marker](#set-position-with-marker)\n- [Set position and zoom to fit bounding box](#set-position-and-zoom-to-fit-bounding-box)\n- [Create position markers](#create-position-markers)\n- [Create path from position list](#create-path-from-position-list)\n- [Create polygon from position list](#create-polygon-from-position-list)\n- [Mouse events on the map](#mouse-events-on-the-map)\n- [Utility methods](#utility-methods)\n- [Use other tile servers](#use-other-tile-servers)\n- [Use offline tiles](#use-offline-tiles)\n\n---\n### Importing\n\nImport tkinter as normal and from tkintermapview import the TkinterMapView widget.\n```python\nimport tkinter\nimport tkintermapview\n```\n---\n### Create the widget\n\nCreate the standard tkinter window and place a TkinterMapView in the middle of the window.\nThe first argument must be the widgets master, then you specify the `width`, `height` and `corner_radius`\nof the widget.\n```python\n# create tkinter window\nroot_tk = tkinter.Tk()\nroot_tk.geometry(f\"{800}x{600}\")\nroot_tk.title(\"map_view_example.py\")\n\n# create map widget\nmap_widget = tkintermapview.TkinterMapView(root_tk, width=800, height=600, corner_radius=0)\nmap_widget.place(relx=0.5, rely=0.5, anchor=tkinter.CENTER)\n```\nIf you also call `root_tk.mainloop()` at the end, this is already a fully working example to test the map widget.\n\n---\n### Set coordinate position\n\nThe standard position on which the map is focused is Berlin, Germany,\nbut you can change the position and zoom with the following commands.\nThe position must be given in decimal coordinates and the zoom ranges from\n0 to 19 where 19 is the highest zoom level.\n```python\n# set current widget position and zoom\nmap_widget.set_position(48.860381, 2.338594)  # Paris, France\nmap_widget.set_zoom(15)\n```\n---\n### Set address position\n\nBut you can not only set the position by decimal coordinates, but also by\nan address string like ` \"colosseo, rome, italy\" ` or ` \"3 St Margaret St, London, United Kingdom\" `.\nThe address is converted to a position by the OpenStreetMap geocode service\nNomatim.\n```python\n# set current widget position by address\nmap_widget.set_address(\"colosseo, rome, italy\")\n```\n---\n### Set position with marker\n\nIf you also want a red marker at the set position with a text of the current location,\nthen you can pass the `marker=True` argument to the `set_position` or `set_address`\nfuntions. You get back a PositionMarker object, so that you can modify or delete the marker\nlater:\n```python\n# set current widget position by address\nmarker_1 = map_widget.set_address(\"colosseo, rome, italy\", marker=True)\n\nprint(marker_1.position, marker_1.text)  # get position and text\n\nmarker_1.set_text(\"Colosseo in Rome\")  # set new text\n# marker_1.set_position(48.860381, 2.338594)  # change position\n# marker_1.delete()\n```\n---\n### Set position and zoom to fit bounding box\nIf you have two decimal coordinates (\u003clat1\u003e, \u003clong1\u003e) and (\u003clat2\u003e, \u003clong2\u003e), 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:\n```python\nmap_widget.fit_bounding_box((\u003clat1\u003e, \u003clong1\u003e), (\u003clat2\u003e, \u003clong2\u003e))\n```\n---\n### Create position markers\n\nYou can also set a position marker without focusing the widget on it.\nYou can pass a ``text`` argument to the function and get back the marker\nobject, so that you can store the marker and modify or delete it later.\n```python\n# set a position marker\nmarker_2 = map_widget.set_marker(52.516268, 13.377695, text=\"Brandenburger Tor\")\nmarker_3 = map_widget.set_marker(52.55, 13.4, text=\"52.55, 13.4\")\n\n# methods\nmarker_3.set_position(...)\nmarker_3.set_text(...)\nmarker_3.change_icon(new_icon)\nmarker_3.hide_image(True)  # or False\nmarker_3.delete()\n```\nA marker can be also customized by passing the following arguments to .set_marker(),\n.set_address() or .set_position(): `text, font, icon, icon_anchor, image (PhotoImage), image_zoom_visibility,\nmarker_color_circle, marker_color_outside, text_color, command`.\n\nThe command function will be called when the marker is clicked and will\npass the clicked marker as an argument to the functin which gets called.\n\nThe given image will be visible above the marker when the zoom level is in the range specified\nby `image_zoom_visibility`, which is tuple like the following (min_zoom, max_zoom).\n`image_zoom_visibility=(0, float('inf'))` means the image will be visible alle the time.\nThe image can also be hidden by calling: `marker.hide_image(True)` or `marker.hide_image(False)`.\nTo check if the image is currently hidden you can access: `marker.image_hidden` which is True or False.\n\nYou can also store an object or some reference inside the marker with the ``data`` attribute, which\ncan be set when creating a marker, and accessed or modified with ``marker.data``. This data attribute\nalso exists for path and polygons.\n\nWith the `icon` attribute you can pass a PIL.ImageTk.PhotoImage object to a marker, which will be\ndisplayed instead of the standard location icon. With `icon_anchor` you can specify the anchor\nfor 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\nimage is centered over the marker position. With the `.change_icon(new_icon)` method you can change\nthe icon image later, but only if the marker already has an icon image from the beginning.\nIn ``examples/map_view_marker_icon_images.py`` you can find example code for the ``icon`` attributes.\n\n\u003cimg src=\"documentation_images/marker_with_image.png\" width=\"500\"/\u003e\n\nWith `map_widget.delete_all_marker()` all marker on the map will be deleted.\n    \n---\n### Create path from position list\n\nYou can also create a path which connects multiple markers or completely new positions.\nYou pass a list with position tuples to the function `set_path` and get back a path object.\nThe path object can be modified by adding a new position or remove a specific position.\nThe `set_path` method accepts the following arguments: `position_list`, `color`, `command` (on click),\n`name` (string for identification), `width`, `data (anything can be stored in the path object).\n\n````python\n# set a path\npath_1 = map_widget.set_path([marker_2.position, marker_3.position, (52.57, 13.4), (52.55, 13.35)])\n\n# methods\npath_1.set_position_list(new_position_list)\npath_1.add_position(position)\npath_1.remove_position(position)\npath_1.delete()\n````\nWith `map_widget.delete_all_path()` all path on the map will be deleted.\n    \n---\n### Create polygon from position list\n\nTo create a polygon on the map call the ``map_widget.set_polygon()`` function\nand pass a list of coordinate tuples from which the polygon will be created.\nYou can edit the appearance with the following arguments: ``fill_color, outline_color, border_width``.\nYou can also set a command function which will be called when the polygon gets clicked and\nwhich will get the polygon object as an argument.\n````python\ndef polygon_click(polygon):\n    print(f\"polygon clicked - text: {polygon.name}\")\n    \npolygon_1 = map_widget.set_polygon([(46.0732306, 6.0095215),\n                                    ...\n                                    (46.3772542, 6.4160156)],\n                                   # fill_color=None,\n                                   # outline_color=\"red\",\n                                   # border_width=12,\n                                   command=polygon_click,\n                                   name=\"switzerland_polygon\")\n\n# methods\npolygon_1.remove_position(46.3772542, 6.4160156)\npolygon_1.add_position(0, 0, index=5)\npolygon_1.delete()\n````\n\nIn ``examples/map_view_polygon_example.py`` you can find the full example program,\nwhich results in the following:\n\n![](documentation_images/map_view_polygon_example.png)\n\nWith `map_widget.delete_all_polygon()` all polygons on the map will be deleted.\n    \n---\n### Mouse events on the map\n\nWhen you click on the map with the right mouse button, a menu pops up, where you can view the\ncurrent decimal coordinates and copy them into the clipboard by clicking them.\nYou can also add other options to this menu, with the ``map_widget.add_right_click_menu_command`` method:\n```python\ndef add_marker_event(coords):\n    print(\"Add marker:\", coords)\n    new_marker = map_widget.set_marker(coords[0], coords[1], text=\"new marker\")\n    \n\nmap_widget.add_right_click_menu_command(label=\"Add Marker\",\n                                        command=add_marker_event,\n                                        pass_coords=True)\n```\nWith the `label` argument you set the text inside the menu, and if `pass_coords`\nis True, the clicked coordinates will be passed to the command function as a tuple. \n\n\u003cimg src=\"documentation_images/right_click_menu_example.png\" width=\"400\"/\u003e\n\nYou can also assign a callback function for a left click event on the map with:\n```python\ndef left_click_event(coordinates_tuple):\n    print(\"Left click event with coordinates:\", coordinates_tuple)\n    \nmap_widget.add_left_click_map_command(left_click_event)\n```\nThe callback function will get the decimal coordinates of the clicked location as a tuple.\n\n---\n### Utility methods\n\nThe following methods can be useful when working with coordinates and address strings,\nthey all use the geocoder library with the OSM provider: https://geocoder.readthedocs.io/providers/OpenStreetMap.html:\n\nConvert decimal coords to address object:\n```python\nadr = tkintermapview.convert_coordinates_to_address(51.5122057, -0.0994014)\nprint(adr.street, adr.housenumber, adr.postal, adr.city, adr.state, adr.country, adr.latlng)\n# Output: Knightrider Street None EC4 City of London England United Kingdom [51.512284050000005, -0.09981746110011651]\n```\nConvert decimal coords to city name:\n\n```python\ncity = tkintermapview.convert_coordinates_to_city(51.5122057, -0.0994014)\n# city: \"City of London\"\n```\n\nConvert decimal coords to country name:\n```python\ncountry = tkintermapview.convert_coordinates_to_city(51.5122057, -0.0994014)\n# country: \"United Kingdom\"\n```\n\nConvert address string to decimal coords. If the address isn't found, the function returns None.\n\n```python\naddress = tkintermapview.convert_address_to_coordinates(\"London\")\n# address: (51.5073219, -0.1276474)\n```\n\n---\n### Use other tile servers\n\nTkinterMapView uses OpenStreetMap tiles by default, but you can also change the\ntile server to every url that includes ``{x} {y} {z}`` coordinates.\nFor example, you can use the standard Google Maps map style or Google Maps\nsatellite images:\n````python\n# example tile sever:\nself.map_widget.set_tile_server(\"https://a.tile.openstreetmap.org/{z}/{x}/{y}.png\")  # OpenStreetMap (default)\nself.map_widget.set_tile_server(\"https://mt0.google.com/vt/lyrs=m\u0026hl=en\u0026x={x}\u0026y={y}\u0026z={z}\u0026s=Ga\", max_zoom=22)  # google normal\nself.map_widget.set_tile_server(\"https://mt0.google.com/vt/lyrs=s\u0026hl=en\u0026x={x}\u0026y={y}\u0026z={z}\u0026s=Ga\", max_zoom=22)  # google satellite\nself.map_widget.set_tile_server(\"http://c.tile.stamen.com/watercolor/{z}/{x}/{y}.png\")  # painting style\nself.map_widget.set_tile_server(\"http://a.tile.stamen.com/toner/{z}/{x}/{y}.png\")  # black and white\nself.map_widget.set_tile_server(\"https://tiles.wmflabs.org/hikebike/{z}/{x}/{y}.png\")  # detailed hiking\nself.map_widget.set_tile_server(\"https://tiles.wmflabs.org/osm-no-labels/{z}/{x}/{y}.png\")  # no labels\nself.map_widget.set_tile_server(\"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg\")  # swisstopo map\n\n# example overlay tile server\nself.map_widget.set_overlay_tile_server(\"http://tiles.openseamap.org/seamark//{z}/{x}/{y}.png\")  # sea-map overlay\nself.map_widget.set_overlay_tile_server(\"http://a.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png\")  # railway infrastructure\n````\n---\n\n### Use offline tiles\n\nYou can load tiles into a database to use them offline when there is no connection to \nthe tile server. Check out [examples/load_offline_tiles.py](https://github.com/TomSchimansky/TkinterMapView/blob/main/examples/map_with_offline_tiles.py) for more information.\n\nIf you then create the TkinterMapView widget you pass the database path as an argument.\nAn example of this can be found here: [examples/map_with_offline_tiles.py](https://github.com/TomSchimansky/TkinterMapView/blob/main/examples/map_with_offline_tiles.py)\nYou can also pass a max_zoom argument to limit the possible zoom range if the database just holds\nthe tiles until a specific zoom range which is not the limit of the used server.\n\n---\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomschimansky%2Ftkintermapview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomschimansky%2Ftkintermapview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomschimansky%2Ftkintermapview/lists"}