I have some problems with the contour plot in matplotlib. I divided my plot in 4 areas,
a1=zeros((100,100))
a2=zeros((100,100))
a3=zeros((100,100))
a4=zeros((100,100))
x=np.linspace(x1,x2,100) #x1,x2,y1,y2 and so on are boundaries I didnt include here
y=np.linspace(y1,y2,100)
xneu=np.linspace(x2,x3,100)
yneu=np.linspace(y1,y2,100)
yo=np.linspace(y1,y3,100)
#Four areas X,Y X1,Y1 X2,Y2 X3,Y3
X, Y=np.meshgrid(x, y)
X1, Y1=np.meshgrid(xneu, y)
X2,Y2=np.meshgrid(x,yo)
X3,Y3=np.meshgrid(xneu,yo)
#filling my arrays with wanted values , f's are functions I haven't included here
for i in arange(0,len(y)):
werte[i]=f(y[i])
for j in arange(0, len(xneu)):
for i in arange(0, len(yneu)):
werte2[i][j]=f1(xneu[i],yneu[j]) + f3(xneu[i],yneu[j]) + f5(xneu[i],yneu[j]) + f7(xneu[i],yneu[j]) + f9(xneu[i],yneu[j])
for i in arange(0,len(yo)):
werte3[i]=f(y[i])
for j in arange(0, len(xneu)):
for i in arange(0, len(yo)):
werte4[i][j]=f1(xneu[i],yo[j]) + f3(xneu[i],yo[j]) + f5(xneu[i],yo[j]) + f7(xneu[i],yo[j]) + f9(xneu[i],yo[j])
cs = plt.contourf(X, Y, werte, 10)
ds = plt.contourf(X1, Y1, werte2, 10)
es = plt.contourf(X2, Y2, werte3, 10)
fs = plt.contourf(X3, Y3, werte4, 10)
That's the plot im getting:
The problem is, that the proportians are not the same. Normally it should "flow in each other". And I'm not saying that the plot isn't smooth or so, I know i can change this by increasing the 10 in the plt.contourf functions.
Does this problem occur because I "divided" the plot in four areas?
So I solved the problem. I has to do with the nature of contourf. If you have a plot with a 3x2 grid then in the first row you have your values for your
y1->x1,x2,x3
second row would be
y2->x1,x2,x3
and third row
y3->x1,x2,x3
That means that your matrix with the values must have this structure.
I didnt know this and because I had to deal with 4 times 100x100 grid areas there was no problem with the matrix (but values). After I've changed the matrix shape I could figure out what the problem was.
The FIGURE and the code:
from numpy import pi,arange,cos,sinh, zeros
import numpy as np
import matplotlib.pyplot as plt
w=100
b=40
V0=10.0
a=200.0
x1=0
x2=w/2.0
x3=a/2
y1=0
y2=-b/2.0
y3=b/2.0
A1=(8*V0)/((1**2)*(pi**2)*sinh(((1*pi)/(2*b))*(a-w)))
A2=(8*V0)/((3**2)*(pi**2)*sinh(((3*pi)/(2*b))*(a-w)))
A3=(8*V0)/((5**2)*(pi**2)*sinh(((5*pi)/(2*b))*(a-w)))
A4=(8*V0)/((7**2)*(pi**2)*sinh(((7*pi)/(2*b))*(a-w)))
A5=(8*V0)/((9**2)*(pi**2)*sinh(((9*pi)/(2*b))*(a-w)))
werte=zeros((20, 50))
werte2=zeros((20, 50))
werte3=zeros((20, 50))
werte4=zeros((20, 50))
def f(y):
global V0, b
return (2*V0/b)*y + V0
def f1(x,y):
global A1,b,a, w
return A1*cos(pi*y/b)*sinh((pi/b)*(a/2.0-x))
def f3(x,y):
global A2, b, a, w
return A2*cos(3*pi*y/b)*sinh((3*pi/b)*(a/2.0-x))
def f5(x,y):
global A3, b, a, w
return A3*cos(5*pi*y/b)*sinh((5*pi/b)*(a/2.0-x))
def f7(x,y):
global A4, b, a, w
return A4*cos(7*pi*y/b)*sinh((7*pi/b)*(a/2.0-x))
def f9(x,y):
global A5, b, a, w
return A5*cos(9*pi*y/b)*sinh((9*pi/b)*(a/2.0-x))
x=np.linspace(x1,x2,50)
y=np.linspace(y1,y2,20)
xneu=np.linspace(x2,x3,50)
yo=np.linspace(y1,y3,20)
X, Y = np.meshgrid(x, y)
X1, Y1=np.meshgrid(xneu, y)
X2,Y2=np.meshgrid(x,yo)
X3,Y3=np.meshgrid(xneu,yo)
for i in arange(0,len(y)):
for j in arange(0, len(x)):
werte[i][j]=f(y[i])
for i in arange(0, len(xneu)):
for j in arange(0, len(y)):
werte2[j][i]=f1(xneu[i],y[j]) + f3(xneu[i],y[j]) + f5(xneu[i],y[j]) + f7(xneu[i],y[j]) + f9(xneu[i],y[j])
for i in arange(0,len(yo)):
for j in arange(0,len(x)):
werte3[i][j]=f(y[i])
for i in arange(0, len(xneu)):
for j in arange(0, len(yo)):
werte4[j][i]=f1(xneu[i],yo[j]) + f3(xneu[i],yo[j]) + f5(xneu[i],yo[j]) + f7(xneu[i],yo[j]) + f9(xneu[i],yo[j])
print(werte2)
cs = plt.contourf(X, Y, werte, 10)
ds = plt.contourf(X1, Y1, werte2, 10)
es = plt.contourf(X2, Y2, werte3, 10)
fs = plt.contourf(X3, Y3, werte4, 10)
plt.colorbar(cs)
#plt.colorbar(ds)
#plt.clabel(cs,inline=0, fontsize=10, colors='black')
#plt.clabel(ds,inline=0, fontsize=10, colors='black')
This is the whole working code. I hope this will help someone out.
Related
I need an tensorflow alternative of a PILLOW ImageDraw.Polygon as a part of tensorflow graph ( gradients are not needed). I have corners of a parallelogram and need to use this parallelogram as a binary mask to fill with zeroes anything except the area inside the parallelogram. Coping between gpu and cpu to use the pillow is extremely slow. Any way to draw it with tensorflow? Or on gpu? Any lib?
def fill(A, B, fill_below_or_right=True, resolution = (800, 480), meshGrid = None, tfMode = False):
xs, ys = resolution
if (tfMode):
# select whether, >=0 is True, or, <=0 is True, to determine whether to
# fill above or below the line
op = tf.math.greater_equal if fill_below_or_right else tf.math.less_equal
op_rev = tf.math.less_equal if fill_below_or_right else tf.math.greater_equal
close_op = tf.experimental.numpy.allclose
else:
op = np.greater_equal if fill_below_or_right else np.less_equal
close_op = np.allclose
if(meshGrid is None):
Y, X = np.mgrid[0:ys, 0:xs]
if (tfMode): # Just cache X, Y tuple and pass as a meshGrid to make is fast
Y = cast_f32(tf.convert_to_tensor(Y))
X = cast_f32(tf.convert_to_tensor(X))
else:
Y, X = meshGrid
if(close_op(B[0], A[0])): #X = A
a = B[0]
return op(X, a)
elif(close_op(B[1], A[1])): #Y = A
a = B[1]
return op(Y, a)
else:
m = (B[1]-A[1])/(B[0]-A[0]) # m = (y2 - y1)/(x2 - x1) = slope
# the equation for a line is y = m*x + b, so calculate
# m and b from the two points on the line
b = A[1] - m*A[0] # b = y1 - m*x1 = y intercept
# for each points of the grid, calculate whether it's above, below, or on
# the line. Since y = m*x + b, calculating m*x + b - y will give
# 0 when on the line, <0 when above, and >0 when below
L = m*X + b - Y
if m < 1.0:
return op_rev(L, 0.0)
else:
return op(L, 0.0)
def draw_quad(pts, resolution = (800, 480), meshGrid = None, tfMode = False):
pts = [cast_f32(item) for item in pts]
x0, y0, x1, y1, x2, y2, x3, y3 = pts
r = fill((x0, y0), (x1, y1), True, resolution, meshGrid, tfMode) & \
fill((x1, y1), (x2, y2), False, resolution, meshGrid, tfMode) & \
fill((x2, y2), (x3, y3), False, resolution, meshGrid, tfMode) & \
fill((x3, y3), (x0, y0), True, resolution, meshGrid, tfMode)
return r
Context: I'm trying to display the gradients as fixed-length lines on a plot of gradient noise. Each "gradient" can be seen as a tangent on a given point. The issue is, even if I make sure the lines have the same length, the aspect ratio stretches them:
The complete code to generate this:
from math import sqrt, floor, modf, sin
import matplotlib.pyplot as plt
mix = lambda a, b, x: a*(1-x) + b*x
interpolant = lambda t: ((6*t - 15)*t + 10)*t*t*t
rng01 = lambda x: modf(sin(x) * 43758.5453123)[0]
def _gradient_noise(t):
i = floor(t)
f = t - i
s0 = rng01(i) * 2 - 1
s1 = rng01(i + 1) * 2 - 1
v0 = s0 * f;
v1 = s1 * (f - 1);
return mix(v0, v1, interpolant(f))
def _plot_noise(n, interp_npoints=100):
xdata = [i/interp_npoints for i in range(n * interp_npoints)]
gnoise = [_gradient_noise(x) for x in xdata]
plt.plot(xdata, gnoise, label='gradient noise')
plt.xlabel('t')
plt.ylabel('amplitude')
plt.grid(linestyle=':')
plt.legend()
for i in range(n + 1):
a = rng01(i) * 2 - 1 # gradient slope
norm = sqrt(1 + a**2)
norm *= 4 # 1/4 length
vnx, vny = 1/norm, a/norm
x = (i-vnx/2, i+vnx/2)
y = (-vny/2, vny/2)
plt.plot(x, y, 'r-')
plt.show()
if __name__ == '__main__':
_plot_noise(15)
The red-lines drawing is located in the for-loop.
hypot(x[1]-x[0], y[1]-y[0]) gives me a constant .25 for every vector, which corresponds to my target length (¼). Which means my segments are actually in the correct length for the given aspect. This can also be "verified" with .set_aspect(1):
I've tried several things, such as translating the coordinates into display coordinates (plt.gca().transData.transform(...)), scale them, then back again (plt.gca().transData.inverted().transform(...)), without success (as if the aspect was applied on top of the display coordinates). Doing that would probably also actually change the angles as well anyway.
So to sum up: I'm looking for a way to display lines with a fixed length (expressed in the x data coordinates system), and oriented (rotated) in the xy data coordinates system.
Welcome to SO. What a well asked first question. It made me question my sanity for a hot second once I reproduced the plot and the math checked out...
However, you identified the core problem yourself: the issue is that in your code the length of the gradient lines is determined in data coordinates, when it should be dependent on the aspect ratio of the plot.
So, if you want the gradient lines to be of uniform length in display space then you need to rescale the either the dx or the dy component by the aspect ratio of the plot (or its inverse, respectively) when computing then norm:
import matplotlib.pyplot as plt
from math import sqrt, floor
mix = lambda a, b, x: a*(1-x) + b*x
interpolant = lambda t: ((6*t - 15)*t + 10)*t*t*t
rng01 = lambda x: ((1103515245*x + 12345) % 2**32) / 2**32
def _gradient_noise(t):
i = floor(t)
f = t - i
s0 = rng01(i) * 2 - 1
s1 = rng01(i + 1) * 2 - 1
v0 = s0 * f;
v1 = s1 * (f - 1);
return mix(v0, v1, interpolant(f))
def _plot_noise(n, interp_npoints=100):
xdata = [i/interp_npoints for i in range(n * interp_npoints)]
gnoise = [_gradient_noise(x) for x in xdata]
fig, ax = plt.subplots()
ax.plot(xdata, gnoise, label='gradient noise')
ax.set_xlabel('t')
ax.set_ylabel('amplitude')
ax.grid(linestyle=':')
ax.legend(loc=1)
x0, x1, y0, y1 = ax.axis()
aspect = (y1 - y0) / (x1 - x0)
for i in range(n + 1):
dy = rng01(i) * 2 - 1 # gradient slope
dx = 1
norm = sqrt(dx**2 + (dy / aspect)**2)
# norm *= 4 # 1/4 length
vnx, vny = dx/norm, dy/norm
x = (i-vnx/2, i+vnx/2)
y = (-vny/2, vny/2)
ax.plot(x, y, 'r-')
plt.show()
if __name__ == '__main__':
_plot_noise(15)
Final code with proper aspect ratio and resize event handled:
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from math import hypot, floor, modf, sin
mix = lambda a, b, x: a*(1-x) + b*x
interpolant = lambda t: ((6*t - 15)*t + 10)*t*t*t
rng01 = lambda x: modf(sin(x) * 43758.5453123)[0]
def _gradient_noise(t):
i = floor(t)
f = t - i
s0 = rng01(i) * 2 - 1
s1 = rng01(i + 1) * 2 - 1
v0 = s0 * f;
v1 = s1 * (f - 1);
return mix(v0, v1, interpolant(f))
def _get_ar(ax):
fs = ax.figure.get_size_inches()
pos = ax.get_position(original=False)
return 1 / (ax.get_data_ratio() * (fs[0] * pos.width) / (fs[1] * pos.height))
def _get_line_coords(aspect, i):
dx, dy = 1, rng01(i) * 2 - 1 # gradient slope
norm = hypot(dx, dy * aspect)
vnx, vny = dx/norm, dy/norm
x = (i-vnx/2, i+vnx/2)
y = (-vny/2, vny/2)
return x, y
def _plot_noise(n, interp_npoints=100):
xdata = [i/interp_npoints for i in range(n * interp_npoints)]
gnoise = [_gradient_noise(x) for x in xdata]
fig, ax = plt.subplots()
ax.plot(xdata, gnoise, label='gradient noise')
ax.set_xlabel('t')
ax.set_ylabel('amplitude')
ax.grid(linestyle=':')
ax.legend(loc=1)
xlim = ax.get_xlim()
ylim = ax.get_ylim()
aspect = _get_ar(ax)
resize_objects = []
for i in range(n + 1):
lx, ly = _get_line_coords(aspect, i)
line = ax.plot(lx, ly, 'r-')[0]
ellipse = Ellipse(xy=(i, 0), width=1, height=1/aspect, fill=False, linestyle=':')
ax.add_patch(ellipse)
resize_objects.append((line, ellipse))
def _onresize(event):
ar = _get_ar(ax)
for i, (line, ellipse) in enumerate(resize_objects):
ellipse.set_height(1 / ar)
lx, ly = _get_line_coords(ar, i)
line.set_xdata(lx)
line.set_ydata(ly)
ax.figure.canvas.mpl_connect('resize_event', _onresize)
ax.set_xlim(xlim)
ax.set_ylim(ylim)
plt.show()
if __name__ == '__main__':
_plot_noise(10)
Some notes:
the same question was asked on matplotlib discourse, where jklymak provided the correct answer for the ratio computation: https://discourse.matplotlib.org/t/drawing-segments-tangents-of-fixed-lengths-preserving-the-aspect-angles-with-matplotlib/21844/14
the ax.get_{x,y}lim() → ax.set_{x,y}lim() roundtrip seems necessary because the aspect is computed based on the initial axis, which changes when plotting the lines/ellipses
the resize events is not necessary in case of export
I have the following code. It is taking forever in Python. There must be a way to translate this calculation into a broadcast...
def euclidean_square(a,b):
squares = np.zeros((a.shape[0],b.shape[0]))
for i in range(squares.shape[0]):
for j in range(squares.shape[1]):
diff = a[i,:] - b[j,:]
sqr = diff**2.0
squares[i,j] = np.sum(sqr)
return squares
You can use np.einsum after calculating the differences in a broadcasted way, like so -
ab = a[:,None,:] - b
out = np.einsum('ijk,ijk->ij',ab,ab)
Or use scipy's cdist with its optional metric argument set as 'sqeuclidean' to give us the squared euclidean distances as needed for our problem, like so -
from scipy.spatial.distance import cdist
out = cdist(a,b,'sqeuclidean')
I collected the different methods proposed here, and in two other questions, and measured the speed of the different methods:
import numpy as np
import scipy.spatial
import sklearn.metrics
def dist_direct(x, y):
d = np.expand_dims(x, -2) - y
return np.sum(np.square(d), axis=-1)
def dist_einsum(x, y):
d = np.expand_dims(x, -2) - y
return np.einsum('ijk,ijk->ij', d, d)
def dist_scipy(x, y):
return scipy.spatial.distance.cdist(x, y, "sqeuclidean")
def dist_sklearn(x, y):
return sklearn.metrics.pairwise.pairwise_distances(x, y, "sqeuclidean")
def dist_layers(x, y):
res = np.zeros((x.shape[0], y.shape[0]))
for i in range(x.shape[1]):
res += np.subtract.outer(x[:, i], y[:, i])**2
return res
# inspired by the excellent https://github.com/droyed/eucl_dist
def dist_ext1(x, y):
nx, p = x.shape
x_ext = np.empty((nx, 3*p))
x_ext[:, :p] = 1
x_ext[:, p:2*p] = x
x_ext[:, 2*p:] = np.square(x)
ny = y.shape[0]
y_ext = np.empty((3*p, ny))
y_ext[:p] = np.square(y).T
y_ext[p:2*p] = -2*y.T
y_ext[2*p:] = 1
return x_ext.dot(y_ext)
# https://stackoverflow.com/a/47877630/648741
def dist_ext2(x, y):
return np.einsum('ij,ij->i', x, x)[:,None] + np.einsum('ij,ij->i', y, y) - 2 * x.dot(y.T)
I use timeit to compare the speed of the different methods. For the comparison, I use vectors of length 10, with 100 vectors in the first group, and 1000 vectors in the second group.
import timeit
p = 10
x = np.random.standard_normal((100, p))
y = np.random.standard_normal((1000, p))
for method in dir():
if not method.startswith("dist_"):
continue
t = timeit.timeit(f"{method}(x, y)", number=1000, globals=globals())
print(f"{method:12} {t:5.2f}ms")
On my laptop, the results are as follows:
dist_direct 5.07ms
dist_einsum 3.43ms
dist_ext1 0.20ms <-- fastest
dist_ext2 0.35ms
dist_layers 2.82ms
dist_scipy 0.60ms
dist_sklearn 0.67ms
While the two methods dist_ext1 and dist_ext2, both based on the idea of writing (x-y)**2 as x**2 - 2*x*y + y**2, are very fast, there is a downside: When the distance between x and y is very small, due to cancellation error the numerical result can sometimes be (very slightly) negative.
Another solution besides using cdist is the following
difference_squared = np.zeros((a.shape[0], b.shape[0]))
for dimension_iterator in range(a.shape[1]):
difference_squared = difference_squared + np.subtract.outer(a[:, dimension_iterator], b[:, dimension_iterator])**2.
I am trying to train the MNIST data (which I downloaded from Kaggle) with simple multi-class logistic regression, but the scipy.optimize functions hang.
Here's the code:
import csv
from math import exp
from numpy import *
from scipy.optimize import fmin, fmin_cg, fmin_powell, fmin_bfgs
# Prepare the data
def getIiter(ifname):
"""
Get the iterator from a csv file with filename ifname
"""
ifile = open(ifname, 'r')
iiter = csv.reader(ifile)
iiter.__next__()
return iiter
def parseRow(s):
y = [int(x) for x in s]
lab = y[0]
z = y[1:]
return (lab, z)
def getAllRows(ifname):
iiter = getIiter(ifname)
x = []
l = []
for row in iiter:
lab, z = parseRow(row)
x.append(z)
l.append(lab)
return x, l
def cutData(x, y):
"""
70% training
30% testing
"""
m = len(x)
t = int(m * .7)
return [(x[:t], y[:t]), (x[t:], y[t:])]
def num2IndMat(l):
t = array(l)
tt = [vectorize(int)((t == i)) for i in range(10)]
return array(tt).T
def readData(ifname):
x, l = getAllRows(ifname)
t = [[1] + y for y in x]
return array(t), num2IndMat(l)
#Calculate the cost function
def sigmoid(x):
return 1 / (1 + exp(-x))
vSigmoid = vectorize(sigmoid)
vLog = vectorize(log)
def costFunction(theta, x, y):
sigxt = vSigmoid(dot(x, theta))
cm = (- y * vLog(sigxt) - (1 - y) * vLog(1 - sigxt)) / m / N
return sum(cm)
def unflatten(flatTheta):
return [flatTheta[i * N : (i + 1) * N] for i in range(n + 1)]
def costFunctionFlatTheta(flatTheta):
return costFunction(unflatten(flatTheta), trainX, trainY)
def costFunctionFlatTheta1(flatTheta):
return costFunction(flatTheta.reshape(785, 10), trainX, trainY)
x, y = readData('train.csv')
[(trainX, trainY), (testX, testY)] = cutData(x, y)
m = len(trainX)
n = len(trainX[0]) - 1
N = len(trainY[0])
initTheta = zeros(((n + 1), N))
flatInitTheta = ndarray.flatten(initTheta)
flatInitTheta1 = initTheta.reshape(1, -1)
In the last two lines we flatten initTheta because the fmin{,_cg,_bfgs,_powell} functions seem to only take vectors as the initial value argument x0. I also flatten initTheta using reshape in hope this answer can be of help.
There is no problem computing the cost function which takes up less than 2 seconds on my computer:
print(costFunctionFlatTheta(flatInitTheta), costFunctionFlatTheta1(flatInitTheta1))
# 0.69314718056 0.69314718056
But all the fmin functions hang, even if I set maxiter=0.
e.g.
newFlatTheta = fmin(costFunctionFlatTheta, flatInitTheta, maxiter=0)
or
newFlatTheta1 = fmin(costFunctionFlatTheta1, flatInitTheta1, maxiter=0)
When I interrupt the program, it seems to me it all hangs at lines in optimize.py calling the cost functions, lines like this:
return function(*(wrapper_args + args))
For example, if I use fmin_cg, this would be line 292 in optimize.py (Version 0.5).
How do I solve this problem?
OK I found a way to stop fmin_cg from hanging.
Basically I just need to write a function that computes the gradient of the cost function, and pass it to the fprime parameter of fmin_cg.
def gradient(theta, x, y):
return dot(x.T, vSigmoid(dot(x, theta)) - y) / m / N
def gradientFlatTheta(flatTheta):
return ndarray.flatten(gradient(flatTheta.reshape(785, 10), trainX, trainY))
Then
newFlatTheta = fmin_cg(costFunctionFlatTheta, flatInitTheta, fprime=gradientFlatTheta, maxiter=0)
terminates within seconds, and setting maxiter to a higher number (say 100) one can train the model within reasonable amount of time.
The documentation of fmin_cg says the gradient would be numerically computed if no fprime is given, which is what I suspect caused the hanging.
Thanks to this notebook by zgo2016#Kaggle which helped me find the solution.
I have the following problem while plotting with Plots.jl. I like to plot the rosenbrock function
rosenbrock(x) = (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2
as surface, which expects a 2d Tuple{Float64,Float64} as input.
What I could come up with, is the following:
using Plots
gr()
rosenbrock(x) = (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2
ts = linspace(-1.0, 1.0, 100)
x = ts
y = map(rosenbrock, [(x, z) for (x,z) in zip(ts,ts)])
z = map(rosenbrock, [(x, y) for (x,y) in zip(ts,ts)])
# plot(x, x, z)
plot(x, y, z, st = [:surface, :contourf])
which yields this plot:
I think I messed up some dimensions, but I don't see what I got wrong.
Do I have to nest the calculation of the mappings for y and x to get the result?
After a quick investigation of the Rosenbrock function I found, and correct me if Im wrong, but you need to specify the y-vector you arent supposed to nest it within z or anything like that
Someone else tried this same thing as shown here but using Plots
the solution is as follows as done by Patrick Kofod Mogensen
using Plots
function rosenbrock(x::Vector)
return (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2
end
default(size=(600,600), fc=:heat)
x, y = -1.5:0.1:1.5, -1.5:0.1:1.5
z = Surface((x,y)->rosenbrock([x,y]), x, y)
surface(x,y,z, linealpha = 0.3)
This results in
side note
Im glad I searched for this as I've been searching for a 3D plotter for Julia other than PyPlot (as it can be a bit of a hassle to set up for the users of my program) and this even looks better and images can be rotated.