The following idea can be given:
Read the file and put data into a 2D NumPy array.
arr = []
with open(str(Path('example.csv'))) as csv_file:
reader = csv.reader(csv_file, delimiter=',')
for row in reader:
arr.append([float(row[0]),float(row[1])])
arr = np.array(arr)
Since the data is unordered then when we connect points subsequently, we observe an ugly graph.
fig0 = go.Figure(go.Scatter(x=arr[:,0],y=arr[:,1], mode='lines'))
fig0.show()

To get an appropriate picture we need to sort points from some starting point in such a way that only the nearest points are connected
arx, x0, xmin, xmax = sort_by_nearest(arr)
x = arx[:,0]
y = arx[:,1]
After sorting the data y looks like:
And the not bijective behavior is gone, and we can easily find the first peak for only y data using find_peaks function. prominence is the minimal height of descent and ascent from a peak to the next peak. Thus, small noisy peaks will be discarded. height is responsible for a parameter where peaks will be searched only in regions where y>height
peaks, props = find_peaks(y, prominence=0.01, height=0.4)
Here we have several candidates
print('rmax candidates=', y[peaks])
Of course, we take the first one
rmax = y[peaks[0]]
x_rmax = x[peaks[0]] - x0
Let's draw the result:

fig0 = go.Figure(go.Scatter(y=arx[:,1], mode='lines'))
fig0.show()
fig0 = go.Figure(go.Scatter(x=arx[:,0]-x0, y=arx[:,1], name='my_line', mode='lines'))
fig0.add_trace(go.Scatter(x=[x_rmax,x_rmax], y=[0,0.5], name='peak coord', mode='lines', line=dict(color='black', width=2, dash='dot')))
fig0.show()
Let's focus on the algorithm for sorting data by neighbors.
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import csv
from scipy.signal import find_peaks
import scipy.spatial.distance as ds
from pathlib import Path
A function for searching the closest point is tricky, we need to somehow flag points which are already observed to avoid infinite cycles. We do it just by modifying point coords by big number a copy of the array arr_full
def closest_point(arr_full, xi, yi, inds):
N = arr_full.shape[0]
arr_full[inds] = 1e+30
dist = (arr_full[:, 0] - xi)**2 + (arr_full[:, 1] - yi)**2
i_min = dist.argmin()
#returns an index of the nearest point and its coordinate
return i_min, arr_full[i_min][0], arr_full[i_min][1]
def sort_by_nearest(arr):
N = arr.shape[0]
nearest_point = [None]*N
#find initial point
xmin = min(arr[:,0])
xmax = max(arr[:,0])
# we copy the original array
arr_cut = np.copy(arr)
# the area in which we are 100% sure in absence of the starting point we flag by big value
arr_cut[arr[:,0] > 0.5*(xmin + xmax)] = 10e+30
iymin = arr_cut[:,1].argmin()
# the staring points are
x0, y0 = arr[iymin, 0], arr[iymin, 1]
# we initialize the sorted value nearest_point
nearest_point[0] = [arr[iymin,0],arr[iymin,1]]
print('Starting point:', x0, y0)
# we put in it the indices of visited points
observed = [iymin]
i_min = iymin
for i in range(1,N):
xi, yi = arr[i_min]
i_min, xip, yip = closest_point(arr, xi, yi, i_min)
nearest_point[i] = [xip, yip]
observed.append(i_min)
nearest_point = np.array(nearest_point)
return np.array(nearest_point), x0, xmin, xmax