Python Shapely – Why LineString is Not Split at Point and How to Fix It

pythonshapely

I have a LineString and want to split it at a Point that obviously is on the LineString. But the shape is self intersecting, therefore the point to split is the start node, end node and middle node. I only want to cut the middle. For some reason the LineString is not split. Why?

import unittest

from shapely.geometry import LineString, Point
from shapely.ops import split


class EdgesConverterTest(unittest.TestCase):

    def test_split_linestring(self):
        geometry = LineString(
            [Point(2.2477456, 48.711216), # 1. occurence
             Point(2.2476711, 48.7111928),
             Point(2.2475945, 48.7111448),
             Point(2.2475531, 48.7111464),
             Point(2.2475882, 48.7111809),
             Point(2.2476592, 48.7112127),
             Point(2.2476592, 48.7112127),
             Point(2.2477456, 48.711216 ),# 2. occurence -> split
             Point(2.2477454, 48.7112725),
             Point(2.2478279, 48.7112615),
             Point(2.2480043, 48.711178),
             Point(2.2478743, 48.7111757),
             Point(2.2477939, 48.7112111),
             Point(2.2477456, 48.711216) # 3. occurence
             ]
        )

        point = Point((2.2477456, 48.711216))

        splitted = split(geometry, point)
        self.assertEqual(2, len(splitted))

I also added a manual check. within is True and the distance is 0, so it should split.

within = point.within(geometry) # True
distance = geometry.distance(point) == 0 # True

I use shapely 2.0.0

Best Answer

The problem is your LineString.

The point (in blue) correspond to a self_intersection of the LineString

enter image description here

  geometry.is_valid
  True
  # but
  from shapely.validation import explain_validity
  ring = LinearRing(list(geometry.coords))
  print(explain_validity(ring))
  Ring Self-intersection[2.2477456 48.711216] 
  # = Point(2.2477456, 48.711216)

Now, how to split many segments at once ? (there are 3 nodes with the same coordinates, Point(2.2477456, 48.711216) in your LineString)

New

You cannot split the line by the point because of its position. It is equal to the position of the first node of the line, the last node of the line and an intersection point, all summarized by node 1 below. (Point(2.2477456, 48.711216)

enter image description here

You can split by node 2 for example (not first node or last node) enter image description here

or by node 11

enter image description here

But not by the first node or the last node of a LineString (result = original LineString)