Creating a map with aeroplane positions and a circle depicting their range

Hi community !

I am trying to create a map to showcase planes position with a circle highlighting their range in km.

So far I have played around with go.Scattermapbox and was able to create the below map

Code:

data = {'Name':['Cessna C150','Cirrus SR22','Cessna C182'], 'lat':[52.52, 53.55, 48.85], 'lon':[13.4, 9.99, 2.35], 'Range':[700, 2000, 1700]}

plane_df = pd.DataFrame(data)

token = "pk.eyJ1IjoiYXRoYXJ2YWthdHJlIiwiYSI6ImNrZ2dkNHQ5MzB2bDUyc2tmZWc2dGx1eXQifQ.lVdNfajC6maADBHqsVrpcg"

fig = go.Figure(go.Scattermapbox(
    mode = "markers+text",
    lon = plane_df['lon'], lat = plane_df['lat'],
    marker = {'size': 20, 'symbol': "airport", 'allowoverlap': False,},
    hoverinfo='none',
    text = plane_df['Name'],
    textposition = "bottom right",
    textfont={'size':20, 'color':'blue'}
))

fig.add_trace(go.Scattermapbox(
    mode = "markers",
    lon = plane_df['lon'], lat = plane_df['lat'],
    marker = {'size': plane_df['Range']*50, 'sizemode':'area', 'symbol': "circle", 'opacity':0.3, 'allowoverlap': True,},
    hoverinfo='skip',
    text = plane_df['Name'],textposition = "bottom right"))

fig.update_layout(
    mapbox = {
        'accesstoken': token,
        'style': "streets",
        'bearing': 0,
        'pitch': 0,
        'center':{'lat':51, 'lon':8},
        'zoom': 4.6
    },
    showlegend = False)

fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})

fig.show()

By default the circle marker changes its size when zooming in or out.
plane

I want the circle to be of fixed size as it represents the area covered.

Also in my data the β€œRange” values are in km, is there a way to match the circle radius on map to the distance of Range in my data?
Currently the size is just relative to the value in my Range column i.e higher range value bigger the circle radius and smaller range value small circle radius. I would like the circle radius to match the real distance (in km), is this possible?

Thanks in advance!

  #Funcion para entregar todos los puntos a radio de distancia
  def puntos(lat,lon,radio):
    #radio en metros angeguros
    radio = radio/1000
    R = 6373.0
    lat = radians(lat)
    lon = radians(lon)
    lat_list = []
    lon_list = [] 
    zk=[]
    for i in range(0, 360, 10):
        d = radio / R
        #convertir a coordenadas
        x = d * np.cos(lat) * np.cos(lon + radians(i))
        y = d * np.cos(lat) * np.sin(lon + radians(i))
        z = d * np.sin(lat)
        #convertir a coordenadas cartesianas
        x = x + lon
        y = y + lat
        z = z + lat
        #convertir a coordenadas geograficas
        x = degrees(x)
        y = degrees(y)
        z = degrees(z)
        #convertir a coordenadas cartesianas
        lat_list.append(y)
        lon_list.append(x)        
    return [lat_list, lon_list]


for i in range(0,len(df)):
                                                                                                 #5000 metros de distancia
        [lat_list,lon_list] = puntos(df.latitud[i],df.longitud[i],5000)
        fig.add_trace(go.Scattermapbox(
        fill = "toself",
        lon = lon_list, lat = lat_list,
        # desactivar marcador de puntos
        marker = { 'size': 0 },
        # desactivar hover
        #hoverinfo = "none"
        # texto ayuda
        text = df.id[i],
        # nombre del trace de la figura
        name = df.id[i]
            
            ))
    #tipo de mapa  y centrado en la posicion 
    fig.update_layout(
        mapbox = {
            'style': "open-street-map",
            'center': {'lon':  df.longitud[i], 'lat': df.latitud[i] },
            'zoom': 10},
        showlegend = False)
    # ocultar marcadores
    fig.update_traces(marker=dict(opacity=0))   

    # nombre al trace de la figura
    fig.update_layout(title_text="Mapa ")


fig.show()