tomschimansky / tkintermapview Goto Github PK
View Code? Open in Web Editor NEWA python Tkinter widget to display tile based maps like OpenStreetMap or Google Satellite Images.
License: Creative Commons Zero v1.0 Universal
A python Tkinter widget to display tile based maps like OpenStreetMap or Google Satellite Images.
License: Creative Commons Zero v1.0 Universal
self.map_widget.set_tile_server("https://a.tile.openstreetmap.org/{z}/{x}/{y}.png") # OpenStreetMap (default)
self.map_widget.set_tile_server("https://mt0.google.com/vt/lyrs=m&hl=en&x={x}&y={y}&z={z}&s=Ga", max_zoom=22) # google normal
self.map_widget.set_tile_server("https://mt0.google.com/vt/lyrs=s&hl=en&x={x}&y={y}&z={z}&s=Ga", max_zoom=22) # google satellite
self.map_widget.set_tile_server("http://c.tile.stamen.com/watercolor/{z}/{x}/{y}.png") # painting style
self.map_widget.set_tile_server("http://a.tile.stamen.com/toner/{z}/{x}/{y}.png") # black and white
self.map_widget.set_tile_server("https://tiles.wmflabs.org/hikebike/{z}/{x}/{y}.png") # detailed hiking
self.map_widget.set_tile_server("https://tiles.wmflabs.org/osm-no-labels/{z}/{x}/{y}.png") # no labels
self.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
Last entry has an extra set of quotations.
Hi Tom,
I'm trying to display a "donut" polygon that has an outer ring and an inner ring. The way the polygon is with a None type point separating the outer ring points from the inner ring. Something like this (Note, these are just example points from a more complex polygon):
[ (35.966916026000035, -119.73706605599995),
(35.963160585000026, -119.73713219299998),
(35.96310003800005, -119.75422644199995),
(35.96358683400007, -119.75421395799998),
(35.963579872000025, -119.75467458899999),
(35.96310092900006, -119.75467313499996),
(35.96313411600005, -119.77193926999996),
(35.96316571400007, -119.78990182199999),
(35.963125637000076, -119.79867769199996),
(35.96308466200003, -119.80750611499997),
(35.96311094600003, -119.82515756999999),
None,
(36.04973748100008, -119.80665732999995),
(36.04978930400006, -119.80665667099998),
(36.049910225000076, -119.80665513499997),
(36.05006180300006, -119.82450578099997) ]
I've been racking my brain on how to display it in your widget (very awesome btw), but can't think of a better method that this one: https://stackoverflow.com/questions/50071801/erase-area-within-polygon-in-tkinter-canvas. This would work for the most part, but I thought I ask if you had any ideas?
At the moment, the zoom step size is 1. Is it possible to set it to something like 0.1 to make a smooth zoom effect?
Thought I'd try to implement your TkinterMapView into my program today and as soon as I tried to display an instance of TkinterMapView:
agency_map = TkinterMapView(map_window, width=1920, height=1080, corner_radius=0) agency_map.grid(row=0, column=0)
I got the error mentioned in the title, referring to a series of tkintermapview functions.
Has support ended for this library?
Thanks,
JR
When a marker is activated by pressing the mouse, what name will it get? Can this name be used directly to to delete the marker by "marker".delete?
Hello Tom,
Would it be possible to add similar functionality to paths that you added recently to markers? (styling, colours, callbacks?)
I've taken it upon myself to learn Python (a bit) and am trying to recreate some basic GUI items that I already have in a Matlab application. Amongst these items is the drawing of multiple polylines. I've found your tkintermapview and already succeeded in drawing a polyline by using your path option. However, for multiple paths of different categories, I'd like to have a visual difference between the paths.
In this respect, I'm trying to understand how the paths work with the canvas of tkinter. Are these essentially sparsely filled bitmaps stacked ontop of each other or are these actually "clickable" lines? In the basis I'm trying to get a feeling how scalable the approach of using the canvas is to draw many polylines on a map.
Marcel
Hey first of all great Project,
i have a quick question, is it possible to use this offline without the workaround with a local hosted map tile server?
e.g something like a caching function or a setting to specify a local map/tiles?
I am trying to have a marker change color when I click it. the command looks like this
def click_command(self, marker):
marker.marker_color_circle=self.blue
marker.draw()
print(marker.text)
This does not work until I move the screen so the marker goes out of view, and when it comes back into view it works.
The offline map: https://github.com/TomSchimansky/TkinterMapView/blob/main/examples/map_with_offline_tiles.py
Is not showing the content downloaded and stored in the db file.
I have used the load_offline_tiles.py to generate the nyc database and afterwards the [map_with_offline_tiles.py] (https://github.com/TomSchimansky/TkinterMapView/ blob/main/examples/map_with_offline_tiles.py)
The window showed is blank and nothing is displayed. If I change the property of the "use_database_only" to False, everythin is loaded except to nyc, which means that the database is not properly created with the script or the widget is not properly getting the information from the database.
Answer: It a matter of the osm tile policies, this means the tiles requested by the downloader do not have the tile.
Thanks in advance
I exactly followed your example codes but not working inside my async Tkinter app... you example files works fine but don't working inside my app... is there a compatibility problem with async_tkinter_loop?
This is how I add your widget just after my other widgets
map_widget = tkintermapview.TkinterMapView(root, width=200, height=200, corner_radius=0) map_widget.pack() map_widget.set_position(48.860381, 2.338594) # Paris, France map_widget.set_zoom(15)
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Exception ignored in: <function PhotoImage.del at 0x7f831923b0e0>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Exception ignored in: <function PhotoImage.del at 0x7f831923b0e0>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Exception ignored in: <function PhotoImage.del at 0x7f831923b0e0>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Exception ignored in: <function PhotoImage.del at 0x7f831923b0e0>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Exception ignored in: <function PhotoImage.del at 0x7f831923b0e0>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Exception ignored in: <function PhotoImage.del at 0x7f831923b0e0>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Exception ignored in: <function PhotoImage.del at 0x7f831923b0e0>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Exception ignored in: <function PhotoImage.del at 0x7f831923b0e0>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Exception ignored in: <function PhotoImage.del at 0x7f831923b0e0>
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/ImageTk.py", line 146, in del
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Hi,
Thanks for the wonderful library you created.
I'd like to get the attributes of an already placed marker on the map so that I can edit it. Similar to the "Properties" feature of Google Earth when a user right-clicks on the pin mark to see the attributes and to change the pin name or description. I understand the entire process will be a function or another class to specify the process. However, I'm wondering how to obtain the address/id of an already placed marker by clicking on the area covered by the marker.
I'd appreciate your input.
Thanks
When adding a valid position, using the path.add_position() function, the map is not redrawn.
This is because Line 49 of canvas_path.py is commented out.
Line 49 of canvas_path.py needs uncommenting to fix this issue
I do a map app wich reads names of places from an xlsx file. So i say map_widget.set_text(myplaces) and this works fine for my xlsx file i wrote by myself, but iwant to use another file that has the same colums an rows in it but i did not create this one. It is some kind of export. Any idea would be much appreciatet.
marker.set_text(df_someplace['name'][ind])
Error is: AttributeError: bool object has no attribute set_text
Hi,
request_image()
supports online mapservers and offline database. But it would be great if it would also support offline directories in the form of tileserver = /path/{z}/{x}/{y}.jpg
. It could access the images directly with Image.open
, without inserting requests.get
. But I don't know how you would detect whether the supplied tileserver is an url or a path.
Usecase would be e.g. a standalone PC as a kiosk with its own local tileserver, without the need to install a webserver.
Cheers
I've been using your library for about a week without any issues, and it's been working as intended. But without making any changes to my code, today the map stopped displaying tiles. I've tried messing with environments and even used one of your examples, but it's still just a grey image. Upon further debugging, it seems like it fails in the request and returns a 403 restricted in this line of code.
image = Image.open(requests.get(url, stream=True).raw)
But if I add a User-Agent header it works again. Not sure exactly what's going on, but there is this section on their Tile Usage Policy. Here are some resources on their help site: 1, 2. It may be the case that you have to specify a custom User-Agent to adhere to their technical usage requirements since it's not being requested from a browser.
In windows
Toplevel window stop showing when i add the
top.resizable(width=False,height=False)
in mac os it's ok
could u please check it
code
//
import customtkinter as t
root=t.CTk()
root.geometry('600x300+100+100')
root.resizable(width=False,height=False)
def win():
top=t.CTkToplevel(root)
top.geometry('200x200+600+600')
top.resizable(width=False,height=False)
t.CTkButton(root,text='new win',command=win).pack()
root.mainloop()
//
Hello,
Firstly, let me thank you for sharing the module.
I would like to know is there any way to click on the map and get Lat/Lon or City Name from it in pop-up window so I can manipulate this info for my needs.
Thanks in advance.
Hi Tom,
I was trying to add a call back function when left clicking.
Basically I was using the following snippet to create a polygon and aggregate its information:
kwargs = {'fill_color':'',
'border_width':3,
'outline_color': "#e74c3c",
'data': {'btrn': row[self.btrn_col],
'gba_id_e': row[self.gba_id_e_col],
'name': row['name']},}
self.map_widget.set_polygon(coordinates, command=self.display_polygon_info, **kwargs)
As you can see, coordinates are stored in a list (I created when starting the iteration in the for loop), then, I modified certain attributes of the polygon to be created (fill_color, border_width, outline_color , and data). As you can see I added the method within my class called self.display_polygon_info, as callback.
I declared at the beginning this method as well to be added as left_click_method as follows:
self.map_widget.add_left_click_map_command(self.display_polygon_info)
The command or method for this sake, contains the following information:
def display_polygon_info(self, polygon):
print(f"polygon clicked - text: {polygon.data['name']}")
So my problem, is: when I left click on the polygon being displayed on the tkintermapview, only in the terminal the information I am interested on is displayed, but not in the map. Is there something wrong with the approach I am taking to display information of a polygon on the map view?
Kind Regards
And thank you for the valuable contribution with this package!
Evening Tom,
Hope you're well, we talked earlier because I thought there was an issue with your software. I thought I'd open a discussion with you if you're happy to discuss the scope of the project? What are your plans for TkinterMapView?
I'm particularly interested in different coloured markers and adding labels to markers (tooltips/popups). I had a peep on some of your source files to see if I could change some attributes and maybe affect the colour of the markers. Unfortunately I could only find the attribute for the colour of the dark red circle inside the marker.
It has occurred to me however that the map may be displayed on a canvas? Since this is the case, is it possible for people to add their own images on top of the OSM map?
Thanks!
Hello,
Great work !
I was looking for resources to create a prototype tool with data entry on a map and your work meets my needs perfectly.
I started adding new methods to the TkinterMapView class to manually edit the map. I'll share those code parts once I'm done if you're interested.
I have a question about the zoom value limit which is set to 19. I would like to zoom a bit more (20 or 21) but even changing the max_value in the library doesn't seem to work. Is there a reason for this limit?
Another question, I saw on Reddit and in the logs that you had implemented auto-resizing. Is it for the map widget to keep the same size as the window? If so, I can't get it to work. If I enlarge the window, the widget keeps the same size as when it was created.
Regards,
Hi!
As I was trying out your nice program, I saw that mouse-scrolling does not work under linux. Event.delta always returns zero. As taken from this example online, I got it to work by adding the following lines to map_widget.py:
self.canvas.bind("<MouseWheel>", self.mouse_zoom)
self.canvas.bind("<Button-4>", self.mouse_zoom)
self.canvas.bind("<Button-5>", self.mouse_zoom)
and
def mouse_zoom(self, event):
relative_mouse_x = event.x / self.width
relative_mouse_y = event.y / self.height
print(event.num)
if sys.platform == "darwin":
new_zoom = self.zoom + event.delta * 0.1
elif "win" in sys.platform:
new_zoom = self.zoom + event.delta * 0.01
elif event.num == 4:
new_zoom = self.zoom + 1
elif event.num == 5:
new_zoom = self.zoom - 1
Cheers.
Hi Tom,
The current icon for position marker looks good. However, sometimes it can be crowded when there are a lot of position markers in a small area. Would it be better if the icons for position markers are customizable? For example, dots, circles, crosses, stars, or squares with adjustable size, line width, line colour, filling colour, etc.
And thank you for your great work on this package!
Kind Regards
Can you confirm there is no configuration needed for map_with_customtkinter example?
Does not seem to run as written. Thanks!
As written in the title, since version 1.10 (released on April 24 2022) of this module, "from tkintermapview import coordinate_convert_functions" results in:
Import Error: cannot import name 'coordinate_convert_functions' from 'tkintermapview' (XXX/.local/pathon3.10/site-packages/tkintermapview/init.py)
This behaviour is not present in 1.9
I used the num2deg function of the coordinate_convert_functions to determine the coordinates of the position on the map, which I clicked on.
x_ratio = event.x/map_widget.winfo_width()
y_ratio = event.y/map_widget.winfo_height()
click_pos = math.num2deg(map_widget.upper_left_tile_pos[0] + (map_widget.lower_right_tile_pos[0] - map_widget.upper_left_tile_pos[0]) * x_ratio,
map_widget.upper_left_tile_pos[1] + (map_widget.lower_right_tile_pos[1] - map_widget.upper_left_tile_pos[1]) * y_ratio,
round(map_widget.zoom))
have the coordinate_convert_functions been renamed and if so, what is their new name? alternatively, what is currently the best way to retrieve the coordinates of a location on the map, that I clicked on?
The link on the github page to the 'using offline map tiles' example is pointing to the wrong link. It exists in the folder and I looked there instead, just thought you should know.
edit: it's this one https://github.com/TomSchimansky/TkinterMapView/blob/main/examples/map_with%20offline_tiles.py
Great job! Thank you for creating this super handy widget.
Feature Request: The ability to add a range circle centered on the specified lat, long with a radius in meters? [with a specified stroke/fill color w/alpha]. This could also be used as a smaller alternate waypoint indicator which would vary in size based on zoom level.
Regards
Hi, thanks for Tkintermapview.
Here is a support question, I hope you have the time to point me in the right direction.
I am trying to create an app where the user can choose two points on a map, and then let the app create an animated panning movement between the two points. I am using my own local tileserver, which are basically tiles of high resolution scans from antique maps. They aren't georeferenced, so it's just basically pixel coordinates.
I'm struggling with getting the map to move. I had hoped the self.map_widget.draw_move()
call would do it, but it doesn't seem to.
Thanks for the project and I have a suggestion:
Currently if I drag and release the mouse, your map moves very smoothly when it is fading automatically. If I use my mouse to drag the map roughly in the same velocity like the fading part does, the movement look slightly less smooth, exactly like your gif here. Is there a way to fix?
I create an ip location tracker with a GUI. The app supposed to show details of an specific ip from an API. Everything works right, but when I want to display a map for that specific location, the canvas for map appear but the map is not appear.
To display map I used tkintermapview from tkinter. To display the map I used latitude and longitude from that API to parse them to my map.
Here is the code:
import tkinter as tk
import tkintermapview
import requests
import ipaddress
from tkinter import *
from tkinter.ttk import *
def ipFinder(outputMsg, inputValue):
try:
ipAddress = inputValue.get()
ipaddress.ip_address(ipAddress)
response = requests.get(f'https://ipapi.co/{ipAddress}/json/').json()
ip_version = response.get("version")
city = response.get("city")
region = response.get("region")
country = response.get("country_name")
postalcode = response.get("postal")
continent = response.get("continent_code")
lat = response.get("latitude")
lng = response.get("longitude")
outputMsg.config(text= "Information for " + inputValue.get() + " are:" + "\n"
"IP Version" + ' : ' + str(ip_version) + "\n"
"CITY" + ' : ' + str(city) + "\n"
"REGION" + ' : ' + str(region) + "\n"
"Country" + ' : ' + str(country) + "\n"
"Postal Code" + ' : ' + str(postalcode) + "\n"
"Continent" + ' : ' + str(continent) + "\n"
"Latitude" + ' : ' + str(lat) + "\n"
"Longitude" + ' : ' + str(lng) + "\n")
except:
outputMsg.config(text="Please Enter Correct IP")
# Define LabelFrame to show the map on my app
my_label = tk.LabelFrame(Tk)
my_label.grid(pady=20)
# tkintermapview to fullfield my label with exact location of phone using lat and lng
map_widget = tkintermapview.TkinterMapView(my_label, width=300, height=300, corner_radius=0)
map_widget.set_position(lat, lng)
# set_marker to set the marker on my map to see the location
map_widget.set_marker(lat, lng, text = "Ip Location")
# set_zoom to set the zoom on my map to actually see something
map_widget.set_zoom(10)
map_widget.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
map_widget.grid()
Tk = tk.Tk()
Tk.geometry("600x600+{}+{}".format(600, 600))
authorLable = tk.Label(Tk, text="Robert", background='#28334A', foreground="#FFFFFF")
authorLable.grid(row=0, columnspan=4)
inputString = tk.StringVar()
websiteName = tk.Label(Tk, text="Enter ip", background='#28334A', foreground="#F65058")
input_entry = tk.Entry(Tk, textvariable=inputString)
websiteName.grid(row=1)
input_entry.grid(row=1, column=1)
outputMsg = tk.Label(Tk, background='#28334A', foreground="#F65058")
outputMsg.grid(row=3, columnspan=4)
button = tk.Button(Tk, text="Check IP", command=lambda : ipFinder(outputMsg, inputString))
button.grid(row=2, columnspan=4)
Tk.title('IP Checker')
Tk.configure(background='#28334A')
Tk.rowconfigure(0, weight=1)
Tk.columnconfigure(0, weight=1)
Tk.rowconfigure(2, weight=1)
Tk.columnconfigure(2, weight=1)
contents = tk.Frame(Tk)
contents.grid(row=1, column=1)
Tk.mainloop()
Any help will be welcome. Thanks in advenced.
https://wiki.openstreetmap.org/wiki/Tile_servers
It would be EXTREMELY useful if you could get many of these additional Tile Servers to work and Overlay Tile Servers.
Also if you could add a function to enter in whatever registration key or whatnot in order to use these Tile Servers that require registration would be absolutely amazing.
Hi Tom. I am very happy to see such a well developed tool as this one. I think it would be very useful for a project I am developing. My goal for now is to make something similar to the web tool geojson.io (https://geojson.io)
I need to be able to not only draw markers and path, but also to be able to draw a polygon and export it in a geopackage. I have made a couple of trials around your code. As far as I understand the TkinterMapView object is based on Tkinter.Canvas and on top of it you can draw markers and lines between points (I have seen that for this there are utilities that allow to transform OSM basemap coordinates to canvas coordinates).
I took this idea to modify the code in such a way:
def set_marker(self, deg_x: float, deg_y: float, text: str = None, **kwargs) -> CanvasPositionMarker:
marker = CanvasPositionMarker(self, (deg_x, deg_y), text=text, **kwargs)
marker.draw()
self.canvas_marker_list.append(marker)
return marker
def create_polygon(self, position_list: list) -> CanvasPolygon:
polygon = CanvasPolygon(self, position_list)
polygon.draw()
return polygon
def set_path(self, position_list: list, **kwargs) -> CanvasPath:
path = CanvasPath(self, position_list, **kwargs)
path.draw()
self.canvas_path_list.append(path)
return path`
the create_polygon function I put it between the methods set_marker and set_path of the TkinterMapView class, and as you can see a polygon for this class is created by calling the draw method of this new class I created called CanvasPolygon (I stored it as a new python file called canvas_polygon.py).
I simply copied everything from CanvasPath class from the canvas_path.py file, and tried to figure out how to make it draw me a polygon, passing the stored coordinates (naturally I have restrictions to be able to make polygon based on at least 3 points (markers)).
When I draw on the canvas, it does so, however, when I zoom out or zoom in, this polygon is lost, it appears and disappears continuously. This does not happen with the CanvasPaths and CanvasPositionMarkers, and I wonder if it has to do with being able to add features that allow me to resize the polygon automatically when the zoom changes.
I would be very grateful if you could help me with this issue. Below is the code for the CanvasPolygon Builder. Thank you very much for your excellent work.
Roger
import tkinter
import sys
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .map_widget import TkinterMapView
from .coordinate_convert_functions import deg2num, num2deg
class CanvasPolygon:
def __init__(self, map_widget: "TkinterMapView", position_list, color="#3E69CB", command=None, name=None):
self.map_widget = map_widget
self.position_list = position_list
self.canvas_polygon_positions = []
self.connection_list = []
self.deleted = False
self.path_color = color
self.command = command
self.canvas_line = None
self.name = name
self.last_upper_left_tile_pos = None
self.last_position_list_length = len(self.position_list)
#def __del__(self):
# self.map_widget.canvas.delete(self.canvas_line)
# self.canvas_line = None
#def delete(self):
# self.__del__()
def appear(self):
self.deleted = False
self.draw()
#def add_position(self, deg_x, deg_y, index=-1):
# if index == -1:
# self.position_list.append((deg_x, deg_y))
# else:
# self.position_list.insert(index, (deg_x, deg_y))
# self.draw()
#def remove_position(self, deg_x, deg_y):
# self.position_list.remove((deg_x, deg_y))
# self.draw()
def get_canvas_pos(self, position, widget_tile_width, widget_tile_height):
tile_position = deg2num(*position, round(self.map_widget.zoom))
canvas_pos_x = ((tile_position[0] - self.map_widget.upper_left_tile_pos[0]) / widget_tile_width) * self.map_widget.width
canvas_pos_y = ((tile_position[1] - self.map_widget.upper_left_tile_pos[1]) / widget_tile_height) * self.map_widget.height
return canvas_pos_x, canvas_pos_y
#def mouse_enter(self, event=None):
# if sys.platform == "darwin":
# self.map_widget.canvas.config(cursor="pointinghand")
# elif sys.platform.startswith("win"):
# self.map_widget.canvas.config(cursor="hand2")
# else:
# self.map_widget.canvas.config(cursor="hand2") # not tested what it looks like on Linux!
#def mouse_leave(self, event=None):
# self.map_widget.canvas.config(cursor="arrow")
#def click(self, event=None):
# if self.command is not None:
# self.command(self)
def draw(self, move=False):
self.last_position_list_length = len(self.position_list)
widget_tile_width = self.map_widget.lower_right_tile_pos[0] - self.map_widget.upper_left_tile_pos[0]
widget_tile_height = self.map_widget.lower_right_tile_pos[1] - self.map_widget.upper_left_tile_pos[1]
if move is True and self.last_upper_left_tile_pos is not None: #and new_line_length is False:
x_move = ((self.last_upper_left_tile_pos[0] - self.map_widget.upper_left_tile_pos[0]) / widget_tile_width) * self.map_widget.width
y_move = ((self.last_upper_left_tile_pos[1] - self.map_widget.upper_left_tile_pos[1]) / widget_tile_height) * self.map_widget.height
for i in range(0, len(self.position_list)* 2, 2):
self.canvas_polygon_positions[i] += x_move
self.canvas_polygon_positions[i + 1] += y_move
else:
self.canvas_polygon_positions = []
for position in self.position_list:
canvas_positions = self.get_canvas_pos(position, widget_tile_width, widget_tile_height)
#canvas_positions = [item for t in canvas_positions for item in t]
self.canvas_polygon_positions.append(canvas_positions)
#self.canvas_line_positions.append(canvas_position[0])
#self.canvas_line_positions.append(canvas_position[1])
if not self.deleted:
if self.canvas_line is None:
self.map_widget.canvas.delete(self.canvas_line)
self.canvas_polygon = self.map_widget.canvas.create_polygon(self.canvas_polygon_positions)
#width=9, fill=self.path_color,
#capstyle=tkinter.ROUND, joinstyle=tkinter.ROUND,
#tag="path")
if self.command is not None:
self.map_widget.canvas.tag_bind(self.canvas_line, "<Enter>", self.mouse_enter)
self.map_widget.canvas.tag_bind(self.canvas_line, "<Leave>", self.mouse_leave)
self.map_widget.canvas.tag_bind(self.canvas_line, "<Button-1>", self.click)
else:
self.map_widget.canvas.coords(self.canvas_line, self.canvas_line_positions)
else:
self.map_widget.canvas.delete(self.canvas_line)
self.canvas_line = None
self.map_widget.manage_z_order()
self.last_upper_left_tile_pos = self.map_widget.upper_left_tile_pos
Adding Scale (Distance) would be really nice here.
Thank you very much for this library! Is there an easy way to display the required attribution, e.g. "Map data (C) OpenStreetMap contributors", inside the map?
def pins():
global translation
global rdata
conn = sqlite3.connect('address_book.db')
c = conn.cursor()
c.execute("SELECT * FROM parking")
data1 = c.fetchone()
rdata = (data1[0])
print(rdata)
marker_1 = map_widget.set_marker(rdata, text="52.55, 13.4")
conn.commit()
conn.close()
53.727830, -1.353003
not sure what to do as when I paste that co ordinate or address manually instead of 'rdata' or 'data1[0]' it works fine and loads the map up with the pin in the location I want, but when I put in rdata it seems to be having none of it even if I translate it into an address and put it through. New to Tkinter so Im probs missing something silly, help would be appreciated. cheers
Hi, I'm having a problem with a moving map for aircraft. If I just let it run it works great, but if I move the map display with the mouse or change the zoom with the mouse, the next time this code is run, it intermittently centers in Brazil. Once that happens, it never centers in the correct place again. Can you help?
This code runs on a timer:
self.map_widget.set_position(self.address_lat, self.address_lon)
if self.auto_zoom_flag.get() == True:
# Set zoom level based on aircraft speed 1 is zoomed all the way out,
# 19 all the way in
zoom_level = 19-int(flight_position_data[0].get("speed")/600*19)
if zoom_level <= 3:
zoom_level = 3
elif zoom_level >= 14: zoom_level = 14
self.map_widget.set_zoom(zoom_level)
self.airplaneMarker.set_position(self.aircraft_lat, self.aircraft_lon)
It’ll allow me to manually put the co ordinates in but will not allow me to put a variable containing the exact same co ordinates in the same format. Would anyone have a solution to this thanks.
Hi Tom,
It would be useful to provide the ability to add an attributes object to the marker object so that when it is returned to the marker_click(marker) command, the marker object carries with it this attributes object.
I have called it 'attributes' in the modified constructor for the CanvasPositionMarker object.
class CanvasPositionMarker
def __init__(self, map_widget: "TkinterMapView", position, text=None, attributes=None, text_color="#652A22", font=None,
marker_color_circle="#9B261E", marker_color_outside="#C5542D", command=None, image=None,
image_zoom_visibility=(13, float("inf"))):
self.map_widget = map_widget
self.position = position
self.text_color = text_color
self.marker_color_circle = marker_color_circle
self.marker_color_outside = marker_color_outside
self.text = text
self.image = image
self.image_hidden = False
self.image_zoom_visibility = image_zoom_visibility
self.connection_list = []
self.deleted = False
self.command = command
self.polygon = None
self.big_circle = None
self.canvas_text = None
self.canvas_image = None
self.attributes = None #added line here.
if font is None:
if sys.platform == "darwin":
self.font = "Tahoma 13 bold"
else:
self.font = "Tahoma 11 bold"
else:
self.font = font
I suggest modifying the CanvasPath in the same way would also be extremely useful as it would provide for having this data within the command on path_click event.
I am adding an attributes dictionary to the marker object as per the modified constructor above in my test app and having this data available within the marker_click handler method is pretty valuable.
Just a suggestion!
Thanks again for taking the time to build this awesome little library.
David.
Question
based on https://github.com/TomSchimansky/TkinterMapView/blob/main/examples/map_with_customtkinter.py
i would like to change the function of " Set marker" to "draw polygon" to digitze a polygon and set get coordinates
I 'm a noob in tkinter , tried to implement it via https://stackoverflow.com/questions/42381856/drawing-a-rectangle-using-tkinter
and then use marker.position to get the coords
maybe such an example would be nize: digitzing is a common use case
I am wanting to preview KML files in a larger python script, as to not separately use google earth. Is there a way to load in a KML file (specifically a line and several points) into the map, and make it viewed? My KMLs are 3d, but are okay to be viewed in 2d.
Hi Tom,
Great map control, really enjoying exploring the functionality it has.
When adding multiple events using the tkintermapview.add_right_click_menu_command() method, the user is correctly presented with a list of labelled of options on right click. However, the command invoked is always the command added last (i.e. the bottom most one) and not the command for the selected item.
I'm assuming the intention was to allow for multiple options on right-click?
David
I would like to thank the author of this module, Tom Schimansky, for upgrading the module to a newer version, so that it works. Thanks a ton for the modification.
Good Morning Tom. I am building up an application, and part of it is to plot polygons and display some information from their properties (name, survey date etc). I was wondering if this is possible by iterating over a table with the coordinates for every polygon, and then the properties of the polygon could be stored in the .data attribute of the CanvasPolygon object declared in yhe canvas_polygon.py file.
Kind Regards
class CanvasPolygon:
def __init__(self,
map_widget: "TkinterMapView",
position_list: list,
outline_color: str = "#3e97cb",
fill_color: str = "gray95",
border_width: int = 5,
command: Callable = None,
name: str = None,
data: any = None):
self.map_widget = map_widget
self.position_list = position_list # list with decimal positions
self.canvas_polygon_positions = [] # list with canvas coordinates positions
self.canvas_polygon = None
self.deleted = False
self.name = name
self.data = data
I am looking at changing the line thickness and colors of GPS path, but I cannot see the option.
Ideally I would like to change the line color with other metrics (e.g. speed, altitude...) , using rainbow or parula chart
Is there any methods to control these line options?
It would be nice to be able to add a "width" keyword argument to the CanvasPath class, so then the line width could be set instead of just using a single default value.
Lots of people are flying drones and make their own hi res orthophoto map tiles.
It would be very useful if one could add custom lokal map tiles in your tkintermapview.OfflineLoader and add them to an existing downloaded local database at an higher zoom level, maybe up to 22 or 23.
I have tried to understand your code to do this myself, but i suck at sql.
Tkintermapview is an awsome base for a lot of cool innovative applications and projects.
Thank you!
Hi, thank you for creating this lib & customtkinter. Both are my favourite libs and I'm using them for every Python GUI project :)
I started to use this lib recently and I feel that the marker on the map is a bit too big. Is it possible to allow us to configure the size of the marker? Like extra args when creating it.
Thank you :)
Hello,
is it possible to show only the image and hide the orange/red marker at map_view_marker_example? So show the choosen image instead of the marker.
Thanks your answer in advance!
BR,
Aron
Hi. I love this project, but I sometimes receive these errors upon closing a window containing this widget. I experimented a bit, but I couldn't find a pattern for when it happens. It looks like it's trying to update the images and when you close the window right while the update happens, you get this error. But I could be wrong. It was never harmful anyways. It's just a mysterious text in the console, but it causes no problems. Still, I would like to find a way to remove/avoid this error. Can you give me some insight into it?
Exception in thread Thread-1 (pre_cache):
Traceback (most recent call last):
File "/usr/lib/python3.10/threading.py", line 1009, in _bootstrap_inner
self.run()
File "/usr/lib/python3.10/threading.py", line 946, in run
self._target(*self._args, **self._kwargs)
File "/home/milan/.local/lib/python3.10/site-packages/tkintermapview/map_widget.py", line 278, in pre_cache
self.request_image(zoom, x, self.pre_cache_position[1] + radius, db_cursor=db_cursor)
File "/home/milan/.local/lib/python3.10/site-packages/tkintermapview/map_widget.py", line 348, in request_image
image_tk = ImageTk.PhotoImage(image)
File "/usr/lib/python3.10/site-packages/PIL/ImageTk.py", line 112, in __init__
self.__photo = tkinter.PhotoImage(**kw)
File "/usr/lib/python3.10/tkinter/__init__.py", line 4093, in __init__
Image.__init__(self, 'photo', name, cnf, master, **kw)
File "/usr/lib/python3.10/tkinter/__init__.py", line 4026, in __init__
master = _get_default_root('create image')
File "/usr/lib/python3.10/tkinter/__init__.py", line 297, in _get_default_root
raise RuntimeError(f"Too early to {what}: no default root window")
RuntimeError: Too early to create image: no default root window
Exception ignored in: <function PhotoImage.__del__ at 0x7fa69afba5f0>
Traceback (most recent call last):
File "/usr/lib/python3.10/site-packages/PIL/ImageTk.py", line 118, in __del__
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Whenever, the map widget is called using the tkintermapview.TkinterMapView(), the result is just a box with the zoom in an out buttons. I was able to see the map, two days before, but I am unable to see it now. As I said earlier, just a box is only visible. Hope this would be resolved as soon as possible. Thank you
Hello. Error when creating a mapview with arguments corner_radius and bg_color.
Version
tkintermapview==1.14
Test script: mapviewtest.py
import tkinter
import tkintermapview
# create tkinter window
root_tk = tkinter.Tk()
root_tk.geometry(f"{640}x{480}")
root_tk.title("map_view_example.py")
# create map widget
map_widget = tkintermapview.TkinterMapView(root_tk, corner_radius=30, bg_color="red")
map_widget.pack(expand=True, fill="both")
root_tk.mainloop()
Error message:
Traceback (most recent call last):
File "/home/alejandro/Privado/projects/pygubu-project/issues/designer/mapviewtest.py", line 10, in <module>
map_widget = tkintermapview.TkinterMapView(root_tk, corner_radius=30, bg_color="red")
File "/home/alejandro/.local/share/fades/23e7c1fd-ebeb-4f2b-bdd9-3e00791ade44/lib/python3.10/site-packages/tkintermapview/map_widget.py", line 153, in __init__
self.draw_rounded_corners()
File "/home/alejandro/.local/share/fades/23e7c1fd-ebeb-4f2b-bdd9-3e00791ade44/lib/python3.10/site-packages/tkintermapview/map_widget.py", line 167, in draw_rounded_corners
style=tkinter.ARC, tag="corner", width=10, outline=self.bg_color, start=-90)
AttributeError: 'TkinterMapView' object has no attribute 'bg_color'
Regards
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.