Related
I have a function g(psi, k) where psi is a two components array and k is a real parameter. I would like to display the g function in a 3D contour plot with respect to the coordinates psi given a selected parameter k. How can I do that in Python?
I tried using the function contour3D with a wrapper function in the following way:
import numpy as np
import matplotlib.pyplot as plt
k = 32 # Change this value to display different plots
# Wrapper of the g function
def f(x, y):
psi = np.array([x, y])
return g(psi, k)
x = np.linspace(-6, 6, 30)
y = np.linspace(-6, 6, 30)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.contour3D(X, Y, Z, 50, cmap='binary')
plt.show()
But I get the following error relative to the line Z = f(X, Y):
ValueError: setting an array element with a sequence.
Running simply:
print(f(-0.33, -0.5))
I obtain a real value as expected:
28.08105396614395
How can I fix it? Is there any other way more straightforward to display the plot of g(psi, 32)?
Your function g(psi, k) is probably only working with psi being a 1D array, meaning only accepting x and y being scalars. Either call f in a loop, or vectorize the g function. Here is how to call the function f in a loop:
Z = np.empty(shape=(X.shape))
for row, (xx, yy) in enumerate(zip(X,Y)): # into rows
for col, (xxx, yyy) in enumerate(zip(xx,yy)): # rows to single values
Z[row, col] = f(xxx, yyy)
I am trying to create a 2d Histogram from a scatter plot. But I get the error: ValueError: too many values to unpack (expected 2) using the code below
If I alter the input data to contain one list for the xy coordinates it works fine. It also works if I only select the first list in the 2dhistogram line. e.g
zi, xi, yi = np.histogram2d(x[0], y[0], bins=bins).
import matplotlib.pyplot as plt
import numpy as np
import random
from functools import partial
##create list of lists (x,y coordinates)
x_list = partial(random.sample, range(80), 10)
y_list = partial(random.sample, range(80), 10)
x = [x_list() for _ in range(10)]
y = [y_list() for _ in range(10)]
fig, ax = plt.subplots()
ax.set_xlim(0,80)
ax.set_ylim(0,80)
bins = [np.linspace(*ax.get_xlim(), 80),
np.linspace(*ax.get_ylim(), 80)]
##error occurs in this line
zi, xi, yi = np.histogram2d(x, y, bins=bins)
zi = np.ma.masked_equal(zi, 0)
ax.pcolormesh(xi, yi, zi.T)
ax.set_xticks(bins[0], minor=True)
ax.set_yticks(bins[1], minor=True)
ax.grid(True, which='minor')
scat = ax.scatter(x, y, s = 1)
The only post I could find about this suggested to try and change the x,y to a numpy array. I tried this but still get the same error code.
zi, xi, yi = np.histogram2d(np.asarry(x), np.asarray(y), bins=bins)
Any other suggestions?
np.histogram2d expects flat lists of x and y coordinates, not list-of-lists. You can fix this pretty easily. Just change the lines that populate x and y to flattening list comprehensions:
x = [num for _ in range(10) for num in x_list()]
y = [num for _ in range(10) for num in y_list()]
Alternatively, you could skip the whole complexity of using random.sample and partial and just use np.random.randint instead, which can create random integer arrays of any given shape:
x = np.random.randint(0, 80, size=100)
y = np.random.randint(0, 80, size=100)
I made a program for polynomial regression, at fitting the best line. I have two lists, X and Y. Its working when list X is in order.
X = np.array([1,2,3,4,5])
Y = np.array([2,3,8,13,20])
This is the graph when I get when list X is in order:
But, if have values in list X, that are not in order, for example
X = np.array([1,5,3,4,2])
Y = np.array([2,3,8,13,20])
I get graph like this (not polynomial):
The important thing is that number 1 in X corresponds to number 2 in Y, number 5 in X corresponds to number 3 in Y and so on. What am I doing wrong? This is the code:
import numpy as np
import matplotlib.pyplot as plt
X = np.array([1,5,3,4,2])
Y = np.array([2,3,8,13,20])
koeficienti = np.polyfit(X, Y, 2)
a=koeficienti[0]
b=koeficienti[1]
c=koeficienti[2]
print(a)
print(b)
print(c)
regression=[(a*x*x)+b*x + c for x in X]
predX = float(input("Enter: "))
predY = (a * predX*predX ) + b*predX + c
plt.scatter(X,Y)
plt.scatter(predX, predY, color="red")vrednosti
plt.plot(X, regression)
plt.grid()
print("predvidjanje: ", round(predY,2))
plt.show()
In order to plot the regression one would need to use a sorted array.
import numpy as np
import matplotlib.pyplot as plt
X = np.array([1,5,3,4,2])
Y = np.array([2,3,8,13,20])
a,b,c = np.polyfit(X, Y, 2)
plt.scatter(X,Y)
xval = np.linspace(np.min(X), np.max(X))
plt.plot(xval, a*xval**2+b*xval+c)
plt.grid()
plt.show()
I have data of a plot on two arrays that are stored in unsorted way, so the plot jumps from one place to another discontinuously:
I have tried one example of finding the closest point in a 2D array:
import numpy as np
def distance(pt_1, pt_2):
pt_1 = np.array((pt_1[0], pt_1[1]))
pt_2 = np.array((pt_2[0], pt_2[1]))
return np.linalg.norm(pt_1-pt_2)
def closest_node(node, nodes):
nodes = np.asarray(nodes)
dist_2 = np.sum((nodes - node)**2, axis=1)
return np.argmin(dist_2)
a = []
for x in range(50000):
a.append((np.random.randint(0,1000),np.random.randint(0,1000)))
some_pt = (1, 2)
closest_node(some_pt, a)
Can I use it somehow to "clean" my data? (in the above code, a can be my data)
Exemplary data from my calculations is:
array([[ 2.08937872e+001, 1.99020033e+001, 2.28260611e+001,
6.27711094e+000, 3.30392288e+000, 1.30312878e+001,
8.80768833e+000, 1.31238275e+001, 1.57400130e+001,
5.00278061e+000, 1.70752624e+001, 1.79131456e+001,
1.50746185e+001, 2.50095731e+001, 2.15895974e+001,
1.23237801e+001, 1.14860312e+001, 1.44268222e+001,
6.37680265e+000, 7.81485403e+000],
[ -1.19702178e-001, -1.14050879e-001, -1.29711421e-001,
8.32977493e-001, 7.27437322e-001, 8.94389885e-001,
8.65931116e-001, -6.08199292e-002, -8.51922900e-002,
1.12333841e-001, -9.88131292e-324, 4.94065646e-324,
-9.88131292e-324, 4.94065646e-324, 4.94065646e-324,
0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
-4.94065646e-324, 0.00000000e+000]])
After using radial_sort_line (of Joe Kington) I have received the following plot:
This is actually a problem that's tougher than you might think in general.
In your exact case, you might be able to get away with sorting by the y-values. It's hard to tell for sure from the plot.
Therefore, a better approach for somewhat circular shapes like this is to do a radial sort.
For example, let's generate some data somewhat similar to yours:
import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(.2, 1.6 * np.pi)
x, y = np.cos(t), np.sin(t)
# Shuffle the points...
i = np.arange(t.size)
np.random.shuffle(i)
x, y = x[i], y[i]
fig, ax = plt.subplots()
ax.plot(x, y, color='lightblue')
ax.margins(0.05)
plt.show()
Okay, now let's try to undo that shuffle by using a radial sort. We'll use the centroid of the points as the center and calculate the angle to each point, then sort by that angle:
x0, y0 = x.mean(), y.mean()
angle = np.arctan2(y - y0, x - x0)
idx = angle.argsort()
x, y = x[idx], y[idx]
fig, ax = plt.subplots()
ax.plot(x, y, color='lightblue')
ax.margins(0.05)
plt.show()
Okay, pretty close! If we were working with a closed polygon, we'd be done.
However, we have one problem -- This closes the wrong gap. We'd rather have the angle start at the position of the largest gap in the line.
Therefore, we'll need to calculate the gap to each adjacent point on our new line and re-do the sort based on a new starting angle:
dx = np.diff(np.append(x, x[-1]))
dy = np.diff(np.append(y, y[-1]))
max_gap = np.abs(np.hypot(dx, dy)).argmax() + 1
x = np.append(x[max_gap:], x[:max_gap])
y = np.append(y[max_gap:], y[:max_gap])
Which results in:
As a complete, stand-alone example:
import numpy as np
import matplotlib.pyplot as plt
def main():
x, y = generate_data()
plot(x, y).set(title='Original data')
x, y = radial_sort_line(x, y)
plot(x, y).set(title='Sorted data')
plt.show()
def generate_data(num=50):
t = np.linspace(.2, 1.6 * np.pi, num)
x, y = np.cos(t), np.sin(t)
# Shuffle the points...
i = np.arange(t.size)
np.random.shuffle(i)
x, y = x[i], y[i]
return x, y
def radial_sort_line(x, y):
"""Sort unordered verts of an unclosed line by angle from their center."""
# Radial sort
x0, y0 = x.mean(), y.mean()
angle = np.arctan2(y - y0, x - x0)
idx = angle.argsort()
x, y = x[idx], y[idx]
# Split at opening in line
dx = np.diff(np.append(x, x[-1]))
dy = np.diff(np.append(y, y[-1]))
max_gap = np.abs(np.hypot(dx, dy)).argmax() + 1
x = np.append(x[max_gap:], x[:max_gap])
y = np.append(y[max_gap:], y[:max_gap])
return x, y
def plot(x, y):
fig, ax = plt.subplots()
ax.plot(x, y, color='lightblue')
ax.margins(0.05)
return ax
main()
Sorting the data base on their angle relative to the center as in #JoeKington 's solution might have problems with some parts of the data:
In [1]:
import scipy.spatial as ss
import matplotlib.pyplot as plt
import numpy as np
import re
%matplotlib inline
In [2]:
data=np.array([[ 2.08937872e+001, 1.99020033e+001, 2.28260611e+001,
6.27711094e+000, 3.30392288e+000, 1.30312878e+001,
8.80768833e+000, 1.31238275e+001, 1.57400130e+001,
5.00278061e+000, 1.70752624e+001, 1.79131456e+001,
1.50746185e+001, 2.50095731e+001, 2.15895974e+001,
1.23237801e+001, 1.14860312e+001, 1.44268222e+001,
6.37680265e+000, 7.81485403e+000],
[ -1.19702178e-001, -1.14050879e-001, -1.29711421e-001,
8.32977493e-001, 7.27437322e-001, 8.94389885e-001,
8.65931116e-001, -6.08199292e-002, -8.51922900e-002,
1.12333841e-001, -9.88131292e-324, 4.94065646e-324,
-9.88131292e-324, 4.94065646e-324, 4.94065646e-324,
0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
-4.94065646e-324, 0.00000000e+000]])
In [3]:
plt.plot(data[0], data[1])
plt.title('Unsorted Data')
Out[3]:
<matplotlib.text.Text at 0x10a5c0550>
See x values between 15 and 20 are not sorted correctly.
In [10]:
#Calculate the angle in degrees of [0, 360]
sort_index = np.angle(np.dot((data.T-data.mean(1)), np.array([1.0, 1.0j])))
sort_index = np.where(sort_index>0, sort_index, sort_index+360)
#sorted the data by angle and plot them
sort_index = sort_index.argsort()
plt.plot(data[0][sort_index], data[1][sort_index])
plt.title('Data Sorted by angle relatively to the centroid')
plt.plot(data[0], data[1], 'r+')
Out[10]:
[<matplotlib.lines.Line2D at 0x10b009e10>]
We can sort the data based on a nearest neighbor approach, but since the x and y are of very different scale, the choice of distance metrics becomes an important issue. We will just try all the distance metrics available in scipy to get an idea:
In [7]:
def sort_dots(metrics, ax, start):
dist_m = ss.distance.squareform(ss.distance.pdist(data.T, metrics))
total_points = data.shape[1]
points_index = set(range(total_points))
sorted_index = []
target = start
ax.plot(data[0, target], data[1, target], 'o', markersize=16)
points_index.discard(target)
while len(points_index)>0:
candidate = list(points_index)
nneigbour = candidate[dist_m[target, candidate].argmin()]
points_index.discard(nneigbour)
points_index.discard(target)
#print points_index, target, nneigbour
sorted_index.append(target)
target = nneigbour
sorted_index.append(target)
ax.plot(data[0][sorted_index], data[1][sorted_index])
ax.set_title(metrics)
In [6]:
dmetrics = re.findall('pdist\(X\,\s+\'(.*)\'', ss.distance.pdist.__doc__)
In [8]:
f, axes = plt.subplots(4, 6, figsize=(16,10), sharex=True, sharey=True)
axes = axes.ravel()
for metrics, ax in zip(dmetrics, axes):
try:
sort_dots(metrics, ax, 5)
except:
ax.set_title(metrics + '(unsuitable)')
It looks like standardized euclidean and mahanalobis metrics give the best result. Note that we choose a starting point of the 6th data (index 5), it is the data point this the largest y value (use argmax to get the index, of course).
In [9]:
f, axes = plt.subplots(4, 6, figsize=(16,10), sharex=True, sharey=True)
axes = axes.ravel()
for metrics, ax in zip(dmetrics, axes):
try:
sort_dots(metrics, ax, 13)
except:
ax.set_title(metrics + '(unsuitable)')
This is what happens if you choose the starting point of max. x value (index 13). It appears that mahanalobis metrics is better than standardized euclidean as it is not affected by the starting point we choose.
If we do the assumption that the data are 2D and the x axis should be in an increasing fashion, then you could:
sort the x axis data, e.g. x_old and store the result in a different variable, e.g. x_new
for each element in the x_new find its index in the x_old array
re-order the elements in the y_axis array according to the indices that you got from previous step
I would do it with python list instead of numpy array due to list.index method been more easily manipulated than the numpy.where method.
E.g. (and assume that x_old and y_old are your previous numpy variables for x and y axis respectively)
import numpy as np
x_new_tmp = x_old.tolist()
y_new_tmp = y_old.tolist()
x_new = sorted(x_new_tmp)
y_new = [y_new_tmp[x_new_tmp.index(i)] for i in x_new]
Then you can plot x_new and y_new
Given a function g(x), I want to find a fixed point to this function using
fixed point iteration. Except for finding the point itself, I want to plot the graph to the function using matplotlib.pyplot, and include the vertical and horizontal bars that show how the iteration closes in on the fixed point (if one exists). Example picture
All help appreciated!
/programming newbie
EDIT: Since I'm no too comfortable with generator objects yet, I've written the following code. It doesn't quite work though: what's wrong with it?
from matlibplot.axes import vlines, hlines
def fixpt(f, x, epsilon=1.0E-4, N=500, store=False):
y = f(x)
n = 0
if store: Values = [(x, y)]
while abs(y-x) >= epsilon and n < N:
x = f(x)
n += 1
y = f(x)
if store: Values.append((x, y))
vlines(x, min(x, y), max(x, y), color='b')
hlines(y, min(y, x), max(y, x), color='b')
if store:
return y, Values
else:
if n >= N:
return "No fixed point for given start value"
else:
return x, n, y
def fixedpoint(f,x):
while x != f(x):
yield x
x = f(x)
yield x
Usage: fixedpoint(g,some_starting_value).
Vertical and horizontal bars depend on plotting library. Specify which one you use.
Your function looks fine. I am not familiar with vlines and hlines. I used your store arg to get the points, and plot them outside the function (it is generally better to separate problems like this).
I used only the plot function from matplotlib.pyplot, and the show function to display the graph.
from matplotlib import pyplot as plt
import numpy as np
def fixpt(f, x, epsilon=1.0E-4, N=500, store=False):
y = f(x)
n = 0
if store: Values = [(x, y)]
while abs(y-x) >= epsilon and n < N:
x = f(x)
n += 1
y = f(x)
if store: Values.append((x, y))
if store:
return y, Values
else:
if n >= N:
return "No fixed point for given start value"
else:
return x, n, y
# define f
def f(x):
return 0.2*x*x
# find fixed point
res, points = fixpt(f, 3, store = True)
# create mesh for plots
xx = np.arange(0, 6, 0.1)
#plot function and identity
plt.plot(xx, f(xx), 'b')
plt.plot(xx, xx, 'r')
# plot lines
for x, y in points:
plt.plot([x, x], [x, y], 'g')
plt.plot([x, y], [y, y], 'g')
# show result
plt.show()
Here is how I thought it through :
from pylab import *
def f(x):
return 8*x/(1 + 2*x)
def cobweb(x0, n, ax):
xs = [x0]
ys = [0]
for i in range(1,n):
if i % 2 == 0:
xs.append(ys[-1])
ys.append(ys[-1])
else:
xs.append(xs[-1])
ys.append(f(xs[-1]))
ax.plot(xs, ys, 'k--', lw=2.0)
x = linspace(0, 4, 100)
fig = figure()
ax = fig.add_subplot(111)
ax.plot(x, x, 'k', lw=2.0)
ax.plot(x, f(x), 'r', lw=2.0)
cobweb(0.5, 50, ax)
ax.set_xlabel(r'$x$')
ax.set_ylabel(r'$f(x)$')
grid()
show()