Hello Richard, thank you, your suggestion worked.
I’m trying to annotate the distance between 2 points. I calculate the distance, convert it to string, and I’m trying to annotate the distance in the midpoint of 2 coordinate points. But the annotation is placed too away from the red line. I would like it to be placed near the red line. Could you please have a look at the code below? Thank you.
Full code is below. "ne_110m_admin_0_countries.shp"
map file can be downloaded from this page .You should put the sample code inside the map file directory.
import wx
import math
import pandas
from math import sin, cos, sqrt, atan2, radians
import matplotlib
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
import geopandas as gpd
import random
this_directory = pathlib.Path(__file__).parent.resolve()
WORLDX = os.path.join(this_directory, "ne_110m_admin_0_countries.shp")
WATER = '#defafc'
LAND = '#807e7e'
LEFT_MOUSE = matplotlib.backend_bases.MouseButton.LEFT
class MapFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Map",
style=wx.DEFAULT_FRAME_STYLE,
size=wx.Size(1200, 900))
self.main_panel = MapPanel(self)
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, _event):
self.Destroy()
wx.Exit()
class MapPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.SetDoubleBuffered(True)
self.figure = Figure()
self.result_frame = parent
self.canvas = FigureCanvas(self, -1, self.figure)
self.axes = self.figure.add_axes([0, 0, 1, 1])
self.axes.margins(0.0)
self.axes.set_anchor('C')
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
self.SetSizer(self.sizer)
self.Fit()
self.Layout()
self.countries = ["US", "FR", "GB", "BR", "IN", "AU", "NZ", "IT", "DE"]
self.gdf = None
self.canvas.mpl_connect('button_press_event', self.onLeftClick)
self.world_data = gpd.read_file(WORLDX)
self.map_plot = None
self.drawMap()
def drawMap(self, country_highlight=None):
"""Draw the map on the canvas. """
self.axes.clear()
self.axes.axis('off')
self.figure.set_facecolor(WATER)
self.map_plot = self.world_data.to_crs(epsg=4326).plot(ax=self.axes, color=LAND)
ax_aspect = self.map_plot.get_aspect()
print("country highlight: ", country_highlight)
if country_highlight:
ylim = self.map_plot.get_ylim()
xlim = self.map_plot.get_xlim()
self.world_data[self.world_data.ISO_A2_EH == country_highlight].plot(edgecolor=u'gray', color='#fa8a48', ax=self.map_plot)
self.map_plot.set_ylim(*ylim)
self.map_plot.set_xlim(*xlim)
self.map_plot.plot([-0.118092, -118.243683], [51.509865, 34.052235], linewidth=2, color="red", alpha=0.5)
self.annotate_distance_between_two_locations(51.509865, -0.118092, 34.052235, -118.243683)
self.map_plot.set_aspect(ax_aspect)
self.canvas.draw()
def annotate_distance_between_two_locations(self, lat1z, lon1z, lat2z, lon2z):
mid_lat, mid_lon = self.get_midpoint(lat1z, lon1z, lat2z, lon2z)
distance = int(self.get_distance(lat1z, lon1z, lat2z, lon2z))
df = pandas.DataFrame(
{
'Distance': str(distance) + " km",
'Latitude': [mid_lat],
'Longitude': [mid_lon]})
gdf = gpd.GeoDataFrame(
df, geometry=gpd.points_from_xy(df.Longitude, df.Latitude))
x_off = 0.1
y_off = 0.1
for x, y, distancex in zip(gdf.geometry.x, gdf.geometry.y, gdf["Distance"]):
self.map_plot.annotate(distancex, xy=(x, y), xytext=(x_off, y_off),textcoords="offset pixels",
size=8,
color="red")
def get_midpoint(self, lat1x, lon1x, lat2x, lon2x):
lat1 = math.radians(lat1x)
lon1 = math.radians(lon1x)
lat2 = math.radians(lat2x)
lon2 = math.radians(lon2x)
bx = math.cos(lat2) * math.cos(lon2 - lon1)
by = math.cos(lat2) * math.sin(lon2 - lon1)
lat3 = math.atan2(math.sin(lat1) + math.sin(lat2), \
math.sqrt((math.cos(lat1) + bx) * (math.cos(lat1) \
+ bx) + by**2))
lon3 = lon1 + math.atan2(by, math.cos(lat1) + bx)
return [round(math.degrees(lat3), 2), round(math.degrees(lon3), 2)]
def get_distance(self, lat1, lon1, lat2, lon2):
if not all(type(item) in [int, float] for item in [lat1, lon1, lat2, lon2]):
return 999999
R = 6371.2
theta = lon2-lon1
dista = math.acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(theta))
if dista < 0:
dista = dista + math.pi
dista = dista*6371.2
return dista #kilometers
def onLeftClick(self, event):
if event.button == LEFT_MOUSE:
self.drawMap(random.choice(self.countries))
class MyApp(wx.App):
def OnInit(self):
frame = MapFrame()
frame.Show()
return True
if __name__ == "__main__":
app = MyApp()
app.MainLoop()