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

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

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

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

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

import pandas as pd
import matplotlib.pyplot as plt
from shapely.geometry import Point
import geopandas as gpd
from geopandas import GeoDataFrame
import json 

#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
def createLatitudeLongitudeDataFrame(inputJsonFolder, inputJsonFilename):
    data = json.load(open(inputJsonFolder + "\\" + inputJsonFilename))
    latitudes = []
    longitudes = []
    for location in data["locations"]:
        latitudes.append(location["coordinates"]["latitude"])
        longitudes.append(location["coordinates"]["longitude"])
    
    data_tuples = list(zip(latitudes, longitudes))
    df = pd.DataFrame(data_tuples, columns=["Latitudes", "Longitudes"])

    return df

#This function creates the map of the locations based on the dataframe.
def createMapOfLocations(df):
    geometry = [Point(yx) for yx in zip(df['Longitudes'], df['Latitudes'])]   
    gdf = GeoDataFrame(df, geometry=geometry)   

    #This is a simple map that goes with geopandas
    world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
    gdf.plot(ax=world.plot(figsize=(10, 6)), marker='o', color='red', markersize=15)

    plt.show()
        

def main():
    inputJsonFolder = "\\inputFolder"

    
    inputJsonFilename = "testing.json"

    df = createLatitudeLongitudeDataFrame(inputJsonFolder, inputJsonFilename)
    createMapOfLocations(df) 

main()
gc0ot86w

gc0ot86w1#

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

Content of "testing.json"
The `locations` data should contain:
- (long, lat) of the location
- name, i.e. "City_A"
- (shift_long, shift_lat) for positioning of the `name` away from the location to avoid clashing

{"locations": [
    {"coordinates": {"latitude": 12, "longitude": 99, "name": "City_A", "shift": [-19,-16]}},
    {"coordinates": {"latitude": 55, "longitude": 68, "name": "City_B", "shift": [15,15]}},
    {"coordinates": {"latitude": 36, "longitude": 35, "name": "City_C", "shift": [-17,18]}} ]}

代码:

import pandas as pd
import matplotlib.pyplot as plt
from shapely.geometry import Point
import geopandas as gpd
from geopandas import GeoDataFrame
import json 

def createLatitudeLongitudeDataFrame(inputJsonFolder, inputJsonFilename):
    data = json.load(open(inputJsonFolder + "/" + inputJsonFilename))
    latitudes = []
    longitudes = []
    names = []   # annotation name
    shifts = []  # annotation shift(dlong, dlat)
    for location in data["locations"]:
        latitudes.append(location["coordinates"]["latitude"])
        longitudes.append(location["coordinates"]["longitude"])
        names.append(location["coordinates"]["name"])
        shifts.append(location["coordinates"]["shift"])

    data_tuples = list(zip(latitudes, longitudes, names, shifts))
    df = pd.DataFrame(data_tuples, columns=["Latitudes", "Longitudes", "Names", "Shifts"])
    return df

#This function creates the map of the locations based on the dataframe.
def createMapOfLocations(df):
    geometry = [Point(yx) for yx in zip(df['Longitudes'], df['Latitudes'])]   
    gdf1 = GeoDataFrame(df, geometry=geometry)   

    #This is a simple map that goes with geopandas
    world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))

    # Need ax1 for reuse
    fig, ax1 = plt.subplots(figsize=(8, 5))
    world.plot(ax=ax1, alpha=0.5)
    gdf1.plot(ax=ax1, marker='o', color='red', markersize=15)

    # ---------------
    # Plot annotation
    # Note the values of xytext, it needs good offset to avoid clashes
    # ---------------
    gdf1.apply(lambda ro: 
               ax1.annotate(
                text=ro['Names'], 
                xy=ro.geometry.centroid.coords[0], 
                xytext=[ro.geometry.centroid.coords[0][0]+ro['Shifts'][0], 
                        ro.geometry.centroid.coords[0][1]+ro['Shifts'][1]], 
                xycoords='data',
                size="small", color="k",
                ha="center", va="center",
                arrowprops=dict(
                            arrowstyle='->', 
                            connectionstyle="arc3,rad=-0.05",
                            color="k"
                        )
                ), axis=1)

    # Set extent of the required map
    ax1.set_xlim(-25,120)
    ax1.set_ylim(-15,75)

    plt.show()


def main():
    inputJsonFolder = "./inputFolder"
    inputJsonFilename = "testing.json"
    df = createLatitudeLongitudeDataFrame(inputJsonFolder, inputJsonFilename)
    createMapOfLocations(df)
    print(df)

main()

相关问题