Search code examples
geopandasfoliumshapely

Connecting markers with PolyLine does not work


I'm having a geopandas table that looks like:

+----+---------+------------+-------------+--------+--------+--------------------------------+
|    |   Score |   LATITUDE |   LONGITUDE | Name   | From   | geometry                       |
|----+---------+------------+-------------+--------+--------+--------------------------------|
|  0 |       9 |    47.0989 |     6.81907 | a      | a      | POINT (6.81906939 47.09885642) |
|  1 |       4 |    47.0993 |     6.82133 | b      | a      | POINT (6.82133392 47.09932583) |
|  2 |      12 |    47.1006 |     6.82169 | c      | a      | POINT (6.821687 47.10058986)   |
|  3 |      12 |    47.1006 |     6.82169 | d      | f      | POINT (6.821687 47.10058986)   |
|  4 |       2 |    47.0985 |     6.81926 | e      | b      | POINT (6.81926344 47.09847967) |
|  5 |       4 |    47.0998 |     6.82126 | f      | b      | POINT (6.82126031 47.09980364) |
|  6 |       2 |    47.0993 |     6.82197 | g      | b      | POINT (6.82197033 47.09929947) |
+----+---------+------------+-------------+--------+--------+--------------------------------+

One column shows the Name of the datapoints and another column where they come From.
Now I want to connect the markers/datapoints with their sources. I tried following code, but it doesn't work:

df2 = pd.merge(df, df[["Name", "LATITUDE", "LONGITUDE"]],
        on="Name", how="left", suffixes=["_to", "_from"])

latlong_from = zip(df2["LATITUDE_from"], df2["LONGITUDE_from"])
latlong_to = zip(df2["LATITUDE_to"], df2["LONGITUDE_to"])


for _from, _to in zip(latlong_from, latlong_to):
    folium.PolyLine([[_from[0], _from[1]], 
                     [_to[0], _to[1]]]).add_to(m)
    
m

It still looks like:

enter image description here

Does somebody see what I'm droing wrong?


Update

Now I tried to create a new geopandas-df with only the lines. But they also do not appear.

from shapely.geometry import LineString

df2 = pd.merge(df, df[["Name", "LATITUDE", "LONGITUDE"]],
        on="Name", how="left", suffixes=["_to", "_from"])
df2["from_geometry"] = geopandas.points_from_xy(df2["LONGITUDE_from"], df2["LATITUDE_from"])
df2['line'] = df2.apply(lambda row: LineString([row['from_geometry'], row['geometry']]), axis=1) #Create a linestring column

gdf2 = geopandas.GeoDataFrame(
    df2, 
    geometry=df2["line"])
gdf2.drop(["line", "from_geometry"], axis=1, inplace=True)
gdf2.crs = "EPSG:4326"

gdf2.explore(color="red")

For better overview I don't copy again a screenshot. But it zooms to the right area in map, so coords should be fine, but there are no lines. I'm lost, can somebody give a hint? I don't need a properly coded solution, just an idea what I could try or what I'm doing wrong.


Goal

Here an example for expected output:

enter image description here

MWE

import geopandas
import pandas as pd

dict_data = {'Score': {0: 9, 1: 4, 2: 12, 3: 12, 4: 2, 5: 4, 6: 2},
 'LATITUDE': {0: 47.09885642,
  1: 47.09932583,
  2: 47.10058986,
  3: 47.10058986,
  4: 47.09847967,
  5: 47.09980364,
  6: 47.09929947},
 'LONGITUDE': {0: 6.81906939,
  1: 6.82133392,
  2: 6.821687,
  3: 6.821687,
  4: 6.81926344,
  5: 6.82126031,
  6: 6.82197033},
 'Name': {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g'},
 'From': {0: 'a', 1: 'a', 2: 'a', 3: 'f', 4: 'b', 5: 'b', 6: 'b'}}

df = pd.DataFrame(dict_data)

gdf = geopandas.GeoDataFrame(
    df, 
    geometry=geopandas.points_from_xy(df["LONGITUDE"], df["LATITUDE"]))

gdf.crs = "EPSG:4326"

m = gdf.explore(
    column="Name",
    tiles="CartoDB positron",
    cmap="Set1"
)

Note:

I created a new question, as the old one was to general.


Solution

  • I can't work out why this does not generate the graph you want. Basically generating a LineString for each pair of points defined by pairs of Name and From

    from shapely.geometry import LineString
    
    gdf2 = gdf.assign(From_point=gdf.set_index("Name").loc[gdf["From"],"geometry"].values)
    
    gdf2["line"] = gdf2[["geometry","From_point"]].apply(LineString, axis=1)
    
    gdf2.set_crs(gdf.crs).set_geometry("line").explore(m=m)