Python 2D self-avoiding random walk - python

I want to make a self-avoiding 2D random walk in python. Imagine it like the dot is on the square grid and it can only go up, down, left or right but it cannot land twice on the same point. I have an idea how to do it, but my programming skills aren't very good (I'm a beginner) and the code doesn't work.
The end product should look something like this:
enter image description here
My idea was to create two lists: one where I store x and y (i.e. the coordinates I've already been to) and one with the points that are around the point I'm currently at (I marked it as neighbors). I want to create a new variable surviving_neighbors. This would be a list of coordinates of the surrounding points where I have not yet been to (e.g. I am currently at (1,1); I have already been at (0,1) and (1,2) so that my surviving neighbors would be (1,0 ) and (2,1)). I want to get Surviving_neighbors using the difference method: I put neighbors.difference(list of coordinates) and save in a variable what is in the list of neighbors, but not in the list of coordinates I was on. The first problem I have is that I don't have one list with coordinates, but x and y are stored separately. Next, I would use choice(surviving_neighbors) and thus choose new coordinates. This creates another problem: I probably won't be able to call it a trajectory, but I'll have to define it again in terms of x and y...
The teacher suggested that I store x and y as vectors, but I have no idea how to do that.
Code:
from random import choice
import numpy as np
from matplotlib import pyplot as plt
plt.style.use(['science', 'notebook', 'dark background'])
x, y = 0, 0
coordinates = [(x, y)]
for time in range(10):
dx, dy = choice([(0, 1), (-1, 0), (0, 1), (0, -1)])
x, y = x + dx, y + dy
X.append(x)
Y.append(y)
neighbors = [x+1, y
x-1
y
x, y+1
x, y-1]
surviving_neighbors = neighbors.difference(X, Y)
trajectory = choice(surviving_neighbors)
plt.plot()

Hard to know where you are going with this, here is a basic working example;
This is invalid as they don't exist;
plt.style.use(['science', 'notebook', 'dark background'])
Possible values are;
['Solarize_Light2', '_classic_test_patch', '_mpl-gallery',
'_mpl-gallery-nogrid', 'bmh', 'classic', 'dark_background', 'fast',
'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn-v0_8',
'seaborn-v0_8-bright', 'seaborn-v0_8-colorblind', 'seaborn-v0_8-dark',
'seaborn-v0_8-dark-palette', 'seaborn-v0_8-darkgrid',
'seaborn-v0_8-deep', 'seaborn-v0_8-muted', 'seaborn-v0_8-notebook',
'seaborn-v0_8-paper', 'seaborn-v0_8-pastel', 'seaborn-v0_8-poster',
'seaborn-v0_8-talk', 'seaborn-v0_8-ticks', 'seaborn-v0_8-white',
'seaborn-v0_8-whitegrid', 'tableau-colorblind10']
from random import choice
from matplotlib import pyplot as plt
plt.style.use('seaborn-v0_8-darkgrid')
print(plt.style.available)
#2D self-avoiding random walk
def dotty(n):
x, y = 0, 0
path = [(x, y)]
for i in range(n):
# pick the closest point but it must complete without crossing itself
x, y = choice([(x+1, y), (x-1, y), (x, y+1), (x, y-1)])
if (x, y) in path:
return path
path.append((x, y))
return path
# show plot
def show_path(path):
plt.figure(figsize=(10, 10))
# draw points
plt.scatter(*zip(*path), s=5, c='k')
# draw lines in red
plt.plot(*zip(*path), c='r')
plt.show()
# main
if __name__ == '__main__':
path = dotty(100000)
show_path(path)
Output:

Related

How can I draw a line from one point to a list multiple points

I'm quite new(ish) to python, so sorry if my syntax is basic or just downright bad.
I'm trying to create a simple 2D Line of Sight script where one point draws a line to all the other points using Matplotlib.
list of points in Matplotlib
Currently, I have a list of points, but I'm having trouble writing the For loop for it. My idea was to create a For loop to draw the lines from the origin to all the x,y coords as defined in positions, but it unfortunately doesn't work.
quality = 5
x = np.linspace(-1,1,quality)
y = np.linspace(-1,1,quality)
X,Y = np.meshgrid(x,y)
positions = np.vstack([Y.ravel(), X.ravel()])
plt.scatter(*positions[::-1])
plt.show()
origin = [0,0]
for i in range(len(positions)):
for j in range(len(positions[i])):
x1 = positions[0][j]
y1 = positions[1][j]
line = shapely.geometry.LineString([origin, [x1, y1]])
But when i run this script, all i get is this output.
What I'm trying to accomplish is something similar to the image below that I've done in another software.
points connect to all points
'shapely' is something I've never used before, but I've tried to recreate it by introducing a live riley, and I had to assign the coordinate information on shapely to a variable in matplotlib. The answer I was referring to is this.
import numpy as np
import matplotlib.pyplot as plt
from shapely.geometry import LineString
quality = 5
x = np.linspace(-1,1,quality)
y = np.linspace(-1,1,quality)
X,Y = np.meshgrid(x,y)
positions = np.vstack([Y.ravel(), X.ravel()])
plt.scatter(*positions[::-1])
origin = (0, 0)
for i in range(len(positions)):
for j in range(len(positions[i])):
x1 = positions[0][j]
y1 = positions[1][j]
line = LineString([origin, (x1, y1)])
x2, y2 = line.xy
plt.plot(0, 0, x2, y2)
plt.show()

How do I use numpy's polyfit when applied to two lists?

y_boxes_1 = [y[i:i + divisor_1] for i in range(0, len(y), divisor_1)]
x_boxes_1 = [x[i:i + divisor_1] for i in range(0, len(x), divisor_1)]
The above code divides a list by a divisor. What I want to do is use numpy polyfit to create a new list of polynomial coefficients for each individual box of y and box of x.
If:
x_boxes_1 = [[1,2,3,4,5,6,7,8],[9,10,11,12,13,14,15,16]]
y_boxes_1 = [[3,5,2,3,1,2,3,4],[2,3,4,1,5,6,7,10]]
Then polyfit would use only the values from x_boxes_1[0] and y_boxes_1[0] and x_boxes_1[1] and y_boxes_1[1] and produce a new list with the coefficients from each individual calculation.
How would I accomplish this?
As far as I understand x_boxes_1 holds the coordinates, and y_boxes_1 holds the points that you want to fit a polynomial. And, you want to call polyfit two times for each corresponding pair. If that is the case, this should work:
import numpy as np
import matplotlib.pyplot as plt
x_boxes_1 = [[1,2,3,4,5,6,7,8],[9,10,11,12,13,14,15,16]]
y_boxes_1 = [[3,5,2,3,1,2,3,4],[2,3,4,1,5,6,7,10]]
zipped = zip(x_boxes_1, y_boxes_1)
z_boxes_1 = [np.polyfit(x,y,6) for x,y in zipped]
Note that degree of the fitting polynomial is 6.
You can plot to verify:
xp_boxes_1 = [np.linspace(1, 8, 100), np.linspace(9, 16, 100)]
for i in [0,1]:
x = x_boxes_1[i]
y = y_boxes_1[i]
z = z_boxex_1[i]
xp = xp_boxes_1[i]
p = np.poly1d(z)
plt.subplot(1,2,i+1)
plt.plot(x, y, '.', xp, p(xp), '-');

Change colour of data points on selection and remove them with key press in matplotlib 3d scatter plot

I have a 3d scatter plot in matplotlib, and have set up annotations, inspired by answers here, particularly that by Don Cristobal.
I have some basic event-capturing code set up, but after several days of trying, I still have not managed to achieve my objectives. These are:
(i) Change colour of a point (dot) when selected with left mouse button from blue to e.g. dark blue/green.
(ii) Remove any selected dot selected in (i) after pressing the 'delete' key, including any annotations
(iii) Select multiple points in (i) using a selection rectangle and delete using 'delete' key
I have tried many approaches, including animating the chart to update based on changes in data, manipulating artist parameters, changing data points via e.g. xs, ys, zs = graph._offsets3d (which does not appear to be documented), but to no avail.
I have attempted, within the onpick(event) function, to:
(i) Interact with points via event.ind to change colour using event.artist.set_face_colour()
(ii) Remove points using both artist.remove()
(iii) Remove points using xs, ys, zs = graph._offsets3d , removing the relevant point by index (event.ind[0]) from xs, ys, and zs, and then resetting graph points via graph._offsets3d = xs_new, ys_new, zs_new
(iv) Redrawing the chart, or relevant sections of the chart only (blitting?)
with no success!
My current code is roughly as below. In fact, I have several hundred points, not the 3 in the simplified example below. I would like the graph to update smoothly if possible, although just getting something usable would be great. Most of the code to do this should probably reside within 'onpick', as that is the function that deals with picking events (see event handler). I have retained some of my code attempts, commented out, which I hope may be of some use. The 'forceUpdate' function is meant to update the graph object on an event trigger, but I am not convinced that it currently does anything. function on_key(event) also does not currently seem to work: presumably there must be a setting in order to determine points to delete, e.g. all artists that have a facecolor that has been changed from the default (e.g. delete all points that have colour dark blue/green rather than light blue).
Any help is much appreciated.
The code (below) is called with:
visualize3DData (Y, ids, subindustry)
Some sample data points are below:
#Datapoints
Y = np.array([[ 4.82250000e+01, 1.20276889e-03, 9.14501289e-01], [ 6.17564688e+01, 5.95020883e-02, -1.56770827e+00], [ 4.55139000e+01, 9.13454423e-02, -8.12277299e+00]])
#Annotations
ids = ['a', 'b', 'c']
subindustry = 'example'
My current code is here:
import matplotlib.pyplot as plt, numpy as np
from mpl_toolkits.mplot3d import proj3d
def visualize3DData (X, ids, subindus):
"""Visualize data in 3d plot with popover next to mouse position.
Args:
X (np.array) - array of points, of shape (numPoints, 3)
Returns:
None
"""
fig = plt.figure(figsize = (16,10))
ax = fig.add_subplot(111, projection = '3d')
graph = ax.scatter(X[:, 0], X[:, 1], X[:, 2], depthshade = False, picker = True)
def distance(point, event):
"""Return distance between mouse position and given data point
Args:
point (np.array): np.array of shape (3,), with x,y,z in data coords
event (MouseEvent): mouse event (which contains mouse position in .x and .xdata)
Returns:
distance (np.float64): distance (in screen coords) between mouse pos and data point
"""
assert point.shape == (3,), "distance: point.shape is wrong: %s, must be (3,)" % point.shape
# Project 3d data space to 2d data space
x2, y2, _ = proj3d.proj_transform(point[0], point[1], point[2], plt.gca().get_proj())
# Convert 2d data space to 2d screen space
x3, y3 = ax.transData.transform((x2, y2))
return np.sqrt ((x3 - event.x)**2 + (y3 - event.y)**2)
def calcClosestDatapoint(X, event):
""""Calculate which data point is closest to the mouse position.
Args:
X (np.array) - array of points, of shape (numPoints, 3)
event (MouseEvent) - mouse event (containing mouse position)
Returns:
smallestIndex (int) - the index (into the array of points X) of the element closest to the mouse position
"""
distances = [distance (X[i, 0:3], event) for i in range(X.shape[0])]
return np.argmin(distances)
def annotatePlot(X, index, ids):
"""Create popover label in 3d chart
Args:
X (np.array) - array of points, of shape (numPoints, 3)
index (int) - index (into points array X) of item which should be printed
Returns:
None
"""
# If we have previously displayed another label, remove it first
if hasattr(annotatePlot, 'label'):
annotatePlot.label.remove()
# Get data point from array of points X, at position index
x2, y2, _ = proj3d.proj_transform(X[index, 0], X[index, 1], X[index, 2], ax.get_proj())
annotatePlot.label = plt.annotate( ids[index],
xy = (x2, y2), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom',
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
fig.canvas.draw()
def onMouseMotion(event):
"""Event that is triggered when mouse is moved. Shows text annotation over data point closest to mouse."""
closestIndex = calcClosestDatapoint(X, event)
annotatePlot (X, closestIndex, ids)
def onclick(event):
print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
('double' if event.dblclick else 'single', event.button,
event.x, event.y, event.xdata, event.ydata))
def on_key(event):
"""
Function to be bound to the key press event
If the key pressed is delete and there is a picked object,
remove that object from the canvas
"""
if event.key == u'delete':
ax = plt.gca()
if ax.picked_object:
ax.picked_object.remove()
ax.picked_object = None
ax.figure.canvas.draw()
def onpick(event):
xmouse, ymouse = event.mouseevent.xdata, event.mouseevent.ydata
artist = event.artist
# print(dir(event.mouseevent))
ind = event.ind
# print('Artist picked:', event.artist)
# # print('{} vertices picked'.format(len(ind)))
print('ind', ind)
# # print('Pick between vertices {} and {}'.format(min(ind), max(ind) + 1))
# print('x, y of mouse: {:.2f},{:.2f}'.format(xmouse, ymouse))
# # print('Data point:', x[ind[0]], y[ind[0]])
#
# # remove = [artist for artist in pickable_artists if artist.contains(event)[0]]
# remove = [artist for artist in X if artist.contains(event)[0]]
#
# if not remove:
# # add a pt
# x, y = ax.transData.inverted().transform_point([event.x, event.y])
# pt, = ax.plot(x, y, 'o', picker=5)
# pickable_artists.append(pt)
# else:
# for artist in remove:
# artist.remove()
# plt.draw()
# plt.draw_idle()
xs, ys, zs = graph._offsets3d
print(xs[ind[0]])
print(ys[ind[0]])
print(zs[ind[0]])
print(dir(artist))
# xs[ind[0]] = 0.5
# ys[ind[0]] = 0.5
# zs[ind[0]] = 0.5
# graph._offsets3d = (xs, ys, zs)
# print(artist.get_facecolor())
# artist.set_facecolor('red')
graph._facecolors[ind, :] = (1, 0, 0, 1)
plt.draw()
def forceUpdate(event):
global graph
graph.changed()
fig.canvas.mpl_connect('motion_notify_event', onMouseMotion) # on mouse motion
fig.canvas.mpl_connect('button_press_event', onclick)
fig.canvas.mpl_connect('pick_event', onpick)
fig.canvas.mpl_connect('draw_event', forceUpdate)
plt.tight_layout()
plt.show()
OK, I have got at least a partial solution for you, without the rectangle selection, but you can select multiple points and delete them with one key_event.
To change the color, you need to change graph._facecolor3d, the hint was in this bug report about set_facecolor not setting _facecolor3d.
It might also be a good idea to rewrite your function as a class to get rid of any needed global variables.
My solution has parts that are not exactly pretty, I need to redraw the figure after removing data points, I couldn't get removing and updating to work.
Also (see EDIT 2 below).
I have not yet implemented what happens if the last data point is removed.
The reason why your function on_key(event) didn't work was easy: you forgot to connect it.
So this is a solution that should satisfy objectives (i) and (ii):
import matplotlib.pyplot as plt, numpy as np
from mpl_toolkits.mplot3d import proj3d
class Class3DDataVisualizer:
def __init__(self, X, ids, subindus, drawNew = True):
self.X = X;
self.ids = ids
self.subindus = subindus
self.disconnect = False
self.ind = []
self.label = None
if drawNew:
self.fig = plt.figure(figsize = (7,5))
else:
self.fig.delaxes(self.ax)
self.ax = self.fig.add_subplot(111, projection = '3d')
self.graph = self.ax.scatter(self.X[:, 0], self.X[:, 1], self.X[:, 2], depthshade = False, picker = True, facecolors=np.repeat([[0,0,1,1]],X.shape[0], axis=0) )
if drawNew and not self.disconnect:
self.fig.canvas.mpl_connect('motion_notify_event', lambda event: self.onMouseMotion(event)) # on mouse motion
self.fig.canvas.mpl_connect('pick_event', lambda event: self.onpick(event))
self.fig.canvas.mpl_connect('key_press_event', lambda event: self.on_key(event))
self.fig.tight_layout()
self.fig.show()
def distance(self, point, event):
"""Return distance between mouse position and given data point
Args:
point (np.array): np.array of shape (3,), with x,y,z in data coords
event (MouseEvent): mouse event (which contains mouse position in .x and .xdata)
Returns:
distance (np.float64): distance (in screen coords) between mouse pos and data point
"""
assert point.shape == (3,), "distance: point.shape is wrong: %s, must be (3,)" % point.shape
# Project 3d data space to 2d data space
x2, y2, _ = proj3d.proj_transform(point[0], point[1], point[2], plt.gca().get_proj())
# Convert 2d data space to 2d screen space
x3, y3 = self.ax.transData.transform((x2, y2))
return np.sqrt ((x3 - event.x)**2 + (y3 - event.y)**2)
def calcClosestDatapoint(self, event):
""""Calculate which data point is closest to the mouse position.
Args:
X (np.array) - array of points, of shape (numPoints, 3)
event (MouseEvent) - mouse event (containing mouse position)
Returns:
smallestIndex (int) - the index (into the array of points X) of the element closest to the mouse position
"""
distances = [self.distance (self.X[i, 0:3], event) for i in range(self.X.shape[0])]
return np.argmin(distances)
def annotatePlot(self, index):
"""Create popover label in 3d chart
Args:
X (np.array) - array of points, of shape (numPoints, 3)
index (int) - index (into points array X) of item which should be printed
Returns:
None
"""
# If we have previously displayed another label, remove it first
if self.label is not None:
self.label.remove()
# Get data point from array of points X, at position index
x2, y2, _ = proj3d.proj_transform(self.X[index, 0], self.X[index, 1], self.X[index, 2], self.ax.get_proj())
self.label = plt.annotate( self.ids[index],
xy = (x2, y2), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom',
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
self.fig.canvas.draw()
def onMouseMotion(self, event):
"""Event that is triggered when mouse is moved. Shows text annotation over data point closest to mouse."""
closestIndex = self.calcClosestDatapoint(event)
self.annotatePlot (closestIndex)
def on_key(self, event):
"""
Function to be bound to the key press event
If the key pressed is delete and there is a picked object,
remove that object from the canvas
"""
if event.key == u'delete':
if self.ind:
self.X = np.delete(self.X, self.ind, axis=0)
self.ids = np.delete(ids, self.ind, axis=0)
self.__init__(self.X, self.ids, self.subindus, False)
else:
print('nothing selected')
def onpick(self, event):
self.ind.append(event.ind)
self.graph._facecolor3d[event.ind] = [1,0,0,1]
#Datapoints
Y = np.array([[ 4.82250000e+01, 1.20276889e-03, 9.14501289e-01], [ 6.17564688e+01, 5.95020883e-02, -1.56770827e+00], [ 4.55139000e+01, 9.13454423e-02, -8.12277299e+00], [3, 8, -8.12277299e+00]])
#Annotations
ids = ['a', 'b', 'c', 'd']
subindustries = 'example'
Class3DDataVisualizer(Y, ids, subindustries)
To implement your rectangular selection you would have to override what currently happens during dragging (rotating the 3D plot) or an easier solution would be to define your rectangle with two consecutive clicks.
Then use the proj3d.proj_transform to find which data is inside that rectangle, find the index of said data and recolor it using the self.graph._facecolor3d[idx] function and fill self.ind with those indices, after which hitting delete will take care of deleting all data which is specified by self.ind.
EDIT: I added two lines in the __init__ that remove the ax/subplot before adding a new one after data points are deleted. I noticed plot interactions were becoming slow after a few data points were removed as the figure was just plotting over each subplot.
EDIT 2: I found out how you can modify your data instead of redrawing the whole plot, as mention in this answer you will have to modify _offsets3d, which weirdly return a tuple for x and y, but an array for z.
You can modify it using
(x,y,z) = self.graph._offsets3d # or event.artist._offsets3d
xNew = x[:int(idx)] + x[int(idx)+1:]
yNew = y[:int(idx)] + y[int(idx)+1:]
z = np.delete(z, int(idx))
self.graph._offsets3d = (xNew,yNew,z) # or event.artist._offsets3d
But then you'll run into problem with deleting several data points in a loop because the indices that you stored before won't be applicable after the first loop, you'll have to update the _facecolor3d, the list of labels... so I chose to keep the answer as is, because just redrawing the plot with new data seems easier and cleaner than that.

sort points in order to have a continuous curve using python

I have a list of unsorted points:
List = [(-50.6261, 74.3683), (-63.2489, 75.0038), (-76.0384, 75.6219), (-79.8451, 75.7855), (-30.9626, 168.085), (-27.381, 170.967), (-22.9191, 172.928), (-16.5869, 173.087), (-4.813, 172.505), (-109.056, 92.0063), (-96.0705, 91.4232), (-83.255, 90.8563), (-80.7807, 90.7498), (-54.1694, 89.5087), (-41.6419, 88.9191), (-32.527, 88.7737), (-27.6403, 91.0134), (-22.3035, 95.141), (-18.0168, 100.473), (-15.3918, 105.542), (-13.6401, 112.373), (-13.3475, 118.988), (-14.4509, 125.238), (-17.1246, 131.895), (-21.6766, 139.821), (-28.5735, 149.98), (-33.395, 156.344), (-114.702, 83.9644), (-114.964, 87.4599), (-114.328, 89.8325), (-112.314, 91.6144), (-109.546, 92.0209), (-67.9644, 90.179), (-55.2013, 89.5624), (-34.4271, 158.876), (-34.6987, 161.896), (-33.6055, 164.993), (-87.0365, 75.9683), (-99.8007, 76.0889), (-105.291, 76.5448), (-109.558, 77.3525), (-112.516, 79.2509), (-113.972, 81.3335), (2.30014, 171.635), (4.40918, 169.691), (5.07165, 166.974), (5.34843, 163.817), (5.30879, 161.798), (-29.6746, 73.5082), (-42.5876, 74.0206)]
I want to sort those points to have a continuous curve passing by every point just once, starting from start = (-29.6746, 73.5082)
and end = (5.30879, 161.798)
This is what I tried so far:
import matplotlib.pyplot as plt
import numpy as np
from sklearn.neighbors import NearestNeighbors
import networkx as nx
for el in List:
X.append(el[0])
Y.append(el[1])
x = np.array(X)
y = np.array(Y)
points = np.c_[x, y]
# find 2 nearest neighbors
clf = NearestNeighbors(2).fit(points)
G = clf.kneighbors_graph()
T = nx.from_scipy_sparse_matrix(G)
# indexes of the new order
order = list(nx.dfs_preorder_nodes(T, 0))
# sorted arrays
new_x = x[order]
new_y = y[order]
plt.plot(new_x, new_y)
plt.show()
But I still get an unsorted list, and I couldn't find a way to determine the start point and end point.
We can see the problem as a Traveling salesman problem, that we can optimize by looking for the nearest point
def distance(P1, P2):
"""
This function computes the distance between 2 points defined by
P1 = (x1,y1) and P2 = (x2,y2)
"""
return ((P1[0] - P2[0])**2 + (P1[1] - P2[1])**2) ** 0.5
def optimized_path(coords, start=None):
"""
This function finds the nearest point to a point
coords should be a list in this format coords = [ [x1, y1], [x2, y2] , ...]
"""
if start is None:
start = coords[0]
pass_by = coords
path = [start]
pass_by.remove(start)
while pass_by:
nearest = min(pass_by, key=lambda x: distance(path[-1], x))
path.append(nearest)
pass_by.remove(nearest)
return path
# define a start point
start = [x0, y0]
path = optimized_path(List,start)
Not an answer, but too much for a comment
I plotted the data points as scatter and line
I see a visually smooth (low order local derivatve spline curve) with ~10% points 'out of order'
Is this typical of the problem?, is the data mostly in order?
How general or specific does the code have to be
I don't know the "big hammer" libs, but cleaned up the surounding code and did the same plot
List = [(-50.6261, 74.3683), (-63.2489, 75.0038), (-76.0384, 75.6219), (-79.8451, 75.7855), (-30.9626, 168.085), (-27.381, 170.967), (-22.9191, 172.928), (-16.5869, 173.087), (-4.813, 172.505), (-109.056, 92.0063), (-96.0705, 91.4232), (-83.255, 90.8563), (-80.7807, 90.7498), (-54.1694, 89.5087), (-41.6419, 88.9191), (-32.527, 88.7737), (-27.6403, 91.0134), (-22.3035, 95.141), (-18.0168, 100.473), (-15.3918, 105.542), (-13.6401, 112.373), (-13.3475, 118.988), (-14.4509, 125.238), (-17.1246, 131.895), (-21.6766, 139.821), (-28.5735, 149.98), (-33.395, 156.344), (-114.702, 83.9644), (-114.964, 87.4599), (-114.328, 89.8325), (-112.314, 91.6144), (-109.546, 92.0209), (-67.9644, 90.179), (-55.2013, 89.5624), (-34.4271, 158.876), (-34.6987, 161.896), (-33.6055, 164.993), (-87.0365, 75.9683), (-99.8007, 76.0889), (-105.291, 76.5448), (-109.558, 77.3525), (-112.516, 79.2509), (-113.972, 81.3335), (2.30014, 171.635), (4.40918, 169.691), (5.07165, 166.974), (5.34843, 163.817), (5.30879, 161.798), (-29.6746, 73.5082), (-42.5876, 74.0206)]
import matplotlib.pyplot as plt
import numpy as np
from sklearn.neighbors import NearestNeighbors
import networkx as nx
points = np.asarray(List)
# find 2 nearest neighbors
clf = NearestNeighbors(2).fit(points)
G = clf.kneighbors_graph()
T = nx.from_scipy_sparse_matrix(G)
# indexes of the new order
order = list(nx.dfs_preorder_nodes(T, 0))
# sorted arrays
new_points = points[order]
plt.scatter(*zip(*points))
plt.plot(*zip(*new_points), 'r')
plt.show()

pyplot, plotting from left to right

I have some data I want to plot, x and y is in the same format as this small piece of example code.
import matplotlib.pyplot as plt
y = [1,1,3,4]
x = [1,4,2,3]
plt.plot(x,y,'-o')
plt.show()
This results in quite a weird graph.
What pyplot does is drawing a line from the first point inserted to the second, then to the third etc.
I want it to draw a line from low-x to high-x, but I can seem to find a nice way to do this. I want my line to be like this.
What is the easiest way to achieve this, given my x and y data is in the same format but more complex than this example?
To get the graph as you mentioned, you need to have values in x in sorted order, which you can achieve like this:
z = sorted(zip(x,y))
x=[i[0] for i in z]
y=[i[1] for i in z]
and now using x and y for ploting (not tested).
you can sort your x list with simultaneously changing the y,
import matplotlib.pyplot as plt
y = [1,1,3,4]
x = [1,4,2,3]
for i in range(len(x)):
for k in range( len( x ) - 1, i, -1 ):
if ( x[k] < x[k - 1] ):
x[k-1],x[k]=x[k],x[k-1]
y[k-1],y[k]= y[k],y[k-1]
print x,y
plt.plot(x,y,'-o')
plt.show()

Categories

Resources