matplotlib 如何在python geodatrame中给点添加箭头标签?

oxalkeyp  于 2023-03-19  发布在  Python
关注(0)|答案(1)|浏览(166)

我的代码当前输出的可视化效果如下所示:

我希望能够添加一个特征,它有指向每个位置点的箭头,其中每个箭头都有一个标签名称。基本上,我希望得到如下所示的输出:

我想让程序自动选择一个箭头间距,这样标签名称(如“A”,“B:等)就不会相互冲突/相互冲突。这有可能自动做到吗?
下面是我目前为止显示第一个图像的代码:

  1. import pandas as pd
  2. import matplotlib.pyplot as plt
  3. from shapely.geometry import Point
  4. import geopandas as gpd
  5. from geopandas import GeoDataFrame
  6. import json
  7. #This function creates the pandas dataframe where each row is the (latitude, longitude) of a location. The first column is latitude, and the second column is longitude
  8. def createLatitudeLongitudeDataFrame(inputJsonFolder, inputJsonFilename):
  9. data = json.load(open(inputJsonFolder + "\\" + inputJsonFilename))
  10. latitudes = []
  11. longitudes = []
  12. for location in data["locations"]:
  13. latitudes.append(location["coordinates"]["latitude"])
  14. longitudes.append(location["coordinates"]["longitude"])
  15. data_tuples = list(zip(latitudes, longitudes))
  16. df = pd.DataFrame(data_tuples, columns=["Latitudes", "Longitudes"])
  17. return df
  18. #This function creates the map of the locations based on the dataframe.
  19. def createMapOfLocations(df):
  20. geometry = [Point(yx) for yx in zip(df['Longitudes'], df['Latitudes'])]
  21. gdf = GeoDataFrame(df, geometry=geometry)
  22. #This is a simple map that goes with geopandas
  23. world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
  24. gdf.plot(ax=world.plot(figsize=(10, 6)), marker='o', color='red', markersize=15)
  25. plt.show()
  26. def main():
  27. inputJsonFolder = "\\inputFolder"
  28. inputJsonFilename = "testing.json"
  29. df = createLatitudeLongitudeDataFrame(inputJsonFolder, inputJsonFilename)
  30. createMapOfLocations(df)
  31. main()
gc0ot86w

gc0ot86w1#

下面的数据和代码无法满足您的所有要求。它显示了您需要的数据和在Map上绘制注解文本的代码。当Map上有许多文本时,很难在不发生冲突的情况下正确放置它们。一个可以在所有情况下对它们进行排列以获得完美结果的程序既长又复杂。
输入数据:

  1. Content of "testing.json"
  2. The `locations` data should contain:
  3. - (long, lat) of the location
  4. - name, i.e. "City_A"
  5. - (shift_long, shift_lat) for positioning of the `name` away from the location to avoid clashing
  6. {"locations": [
  7. {"coordinates": {"latitude": 12, "longitude": 99, "name": "City_A", "shift": [-19,-16]}},
  8. {"coordinates": {"latitude": 55, "longitude": 68, "name": "City_B", "shift": [15,15]}},
  9. {"coordinates": {"latitude": 36, "longitude": 35, "name": "City_C", "shift": [-17,18]}} ]}

代码:

  1. import pandas as pd
  2. import matplotlib.pyplot as plt
  3. from shapely.geometry import Point
  4. import geopandas as gpd
  5. from geopandas import GeoDataFrame
  6. import json
  7. def createLatitudeLongitudeDataFrame(inputJsonFolder, inputJsonFilename):
  8. data = json.load(open(inputJsonFolder + "/" + inputJsonFilename))
  9. latitudes = []
  10. longitudes = []
  11. names = [] # annotation name
  12. shifts = [] # annotation shift(dlong, dlat)
  13. for location in data["locations"]:
  14. latitudes.append(location["coordinates"]["latitude"])
  15. longitudes.append(location["coordinates"]["longitude"])
  16. names.append(location["coordinates"]["name"])
  17. shifts.append(location["coordinates"]["shift"])
  18. data_tuples = list(zip(latitudes, longitudes, names, shifts))
  19. df = pd.DataFrame(data_tuples, columns=["Latitudes", "Longitudes", "Names", "Shifts"])
  20. return df
  21. #This function creates the map of the locations based on the dataframe.
  22. def createMapOfLocations(df):
  23. geometry = [Point(yx) for yx in zip(df['Longitudes'], df['Latitudes'])]
  24. gdf1 = GeoDataFrame(df, geometry=geometry)
  25. #This is a simple map that goes with geopandas
  26. world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
  27. # Need ax1 for reuse
  28. fig, ax1 = plt.subplots(figsize=(8, 5))
  29. world.plot(ax=ax1, alpha=0.5)
  30. gdf1.plot(ax=ax1, marker='o', color='red', markersize=15)
  31. # ---------------
  32. # Plot annotation
  33. # Note the values of xytext, it needs good offset to avoid clashes
  34. # ---------------
  35. gdf1.apply(lambda ro:
  36. ax1.annotate(
  37. text=ro['Names'],
  38. xy=ro.geometry.centroid.coords[0],
  39. xytext=[ro.geometry.centroid.coords[0][0]+ro['Shifts'][0],
  40. ro.geometry.centroid.coords[0][1]+ro['Shifts'][1]],
  41. xycoords='data',
  42. size="small", color="k",
  43. ha="center", va="center",
  44. arrowprops=dict(
  45. arrowstyle='->',
  46. connectionstyle="arc3,rad=-0.05",
  47. color="k"
  48. )
  49. ), axis=1)
  50. # Set extent of the required map
  51. ax1.set_xlim(-25,120)
  52. ax1.set_ylim(-15,75)
  53. plt.show()
  54. def main():
  55. inputJsonFolder = "./inputFolder"
  56. inputJsonFilename = "testing.json"
  57. df = createLatitudeLongitudeDataFrame(inputJsonFolder, inputJsonFilename)
  58. createMapOfLocations(df)
  59. print(df)
  60. main()

展开查看全部

相关问题