Related
I would like to fill a polygon using basemap/shapefile data, but only a certain %. For example, in the example below, we fill based on the values, but let's say I wanted to fill a % of the polygon based on these values (code from here):
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
import numpy as np
fig= plt.figure()
ax= fig.add_subplot(111)
m=Basemap(projection='cyl',llcrnrlat=34.5,llcrnrlon=19,
urcrnrlat=42,urcrnrlon=28.5,resolution='h')
m.drawmapboundary(fill_color='aqua')
m.fillcontinents(color='w',lake_color='aqua')
m.drawcoastlines()
m.readshapefile('data/nomoi/nomoi','nomoi')
dict1={14464: 1.16, 14465: 1.35, 14466: 1.28, 14467: 1.69, 14468: 1.81, 14418: 1.38}
colvals = dict1.values()
cmap=plt.cm.RdYlBu
norm=plt.Normalize(min(colvals),max(colvals))
patches = []
for info, shape in zip(m.nomoi_info, m.nomoi):
if info['ID_2'] in list(dict1.keys()):
color=cmap(norm(dict1[info['ID_2']]))
patches.append( Polygon(np.array(shape), True, color=color) )
pc = PatchCollection(patches, match_original=True, edgecolor='k', linewidths=1., zorder=2)
ax.add_collection(pc)
#colorbar
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array(colvals)
fig.colorbar(sm, ax=ax)
plt.show()
Thank you.
import math
from shapely.geometry import Polygon as shpoly
#shapefile of main massachusetts shape
iowpoly = state_shapes['Massachusetts'][32]
def return_xy(coords):
return [np.asarray([i[0] for i in coords]), np.asarray([i[1] for i in coords])]
def return_area(coords):
x, y = return_xy(coords)
return 0.5*np.abs(np.dot(x,np.roll(y,1))-np.dot(y,np.roll(x,1)))
def return_bounding_box(coords):
x, y = return_xy(coords)
return [[min(x), min(y)], [max(x), max(y)]]
def split_x_wise(bbox, weights, split = 2):
lleft = bbox[0]
uright = bbox[1]
dx = abs(uright[0] - lleft[0])
weights = np.cumsum(sorted(weights, reverse=True))
xcoords = [lleft[0]+weights[x-1]*dx for x in range(1, split)]
return xcoords
def generate_splits_by_area(coords, bbox, weights, tolerance = 0.03, div = 100):
xareasplits = {}
weights = np.cumsum(sorted(weights, reverse=True))[:-1]
lleft = bbox[0]
uright = bbox[1]
dx = abs(uright[0] - lleft[0])
xsplit = [lleft[0]+(dx/div)*x for x in range(1, div)]
for w in weights:
xareasplits[str(w)] = None
mainarea = shpoly(coords).area
for i, s in enumerate(xsplit):
poly = []
if i == 0:
continue
for ip, p in enumerate(coords):
if p[0] < s:
poly.append(p)
shpl = shpoly(poly).area
frac = shpl/mainarea
for w in weights:
if abs(w-frac) <= tolerance:
if xareasplits[str(w)] == None:
xareasplits[str(w)] = s
return list(xareasplits.values())
def return_split(coords, weights, split = 2, by_area = False, tolerance = 0.03, div = 100):
polys = {}
for x in range(0, split):
polys[str(x+1)] = {'points':[], 'maxit' : None}
bbox = return_bounding_box(coords)
if not by_area:
xsplit = split_x_wise(bbox, weights, split)
#test = generate_splits_by_area(coords, bbox, weights, tolerance=tolerance, div=div)
else:
xsplit = generate_splits_by_area(coords, bbox, weights, tolerance=tolerance, div=div)
xsplit.append(bbox[0][0])
xsplit.append(bbox[1][0])
xsplit = sorted(xsplit)
#print(xsplit)
#print(test)
for ip, p in enumerate(coords):
for i, splt in enumerate(xsplit):
if i > 0:
if (p[0] > xsplit[i-1]) & (p[0] < splt):
if len(polys[str(i)]['points']) == 0:
polys[str(i)]['points'].append(coords[ip-1])
polys[str(i)]['points'].append(p)
polys[str(i)]['maxit'] = ip
for poly, data in polys.items():
tmaxit = data['maxit']+1
if tmaxit >= len(coords):
data['points'].append(coords[0])
else:
data['points'].append(coords[tmaxit])
return polys
#return [p for p in coords if p[0] > xsplit[0]]
#bboxiowa = return_bounding_box(iowpoly)
splitpoly = return_split(iowpoly, weights = [0.2780539772727273, 0.1953716856060606, 0.19513494318181818, 0.18329782196969696, 0.14814157196969696],by_area = True,split = 5)
for k, v in splitpoly.items():
print (k, len(v['points']))
print (v['maxit'])
test = shpoly(splitpoly["1"]['points'])
test
I managed to write my own code to split and fill shapel polygons from shapefiles. The above code example splits the Massachusetts shapefile into 5 segments, weighted according to weights and by area.
The first 2 parts of the split look like this:
I am trying to build a logistic regression model for a dataset consisting of two parameters
x1 and x2, but instead of analyzing just the two of them, I have added their squares as well - x12, x22 and x1· x2.
At the first glance everything looks fine and the error function is decreasing, but whilist drawing the plot of the decision boundary I have noticed, that after circa 500 iterations something strange happens to it.
Here is an animation of the error function as a function of iterations and a respective plot of the decision boundary:
Now,I interpret the decision boundary as a quadratic function
x2=f(x1), where
the relation between both parameters is given like this:
0.5 = θ0 + θ1x1 + θ2x2 + θ3x12 + θ4x1x2
+ θ5x22
Here is the python code I use to do everything:
#!/usr/bin/python3
import numpy as np
import matplotlib.pyplot as plt
from math import log
from matplotlib.animation import FuncAnimation
def sigmoid(x):
return 1.0 / (1.0 + np.exp(-x))
def loadData(filepath):
source=""
try:
f = open(filepath, "r")
source = f.read()
f.close()
except IOError:
print("Error while reading file (" + filepath + ")")
return ""
raw_data = source.split("\n")
raw_data = [x.split(",") for x in raw_data if x !=""]
raw_data = np.matrix(raw_data).astype(float)
return (raw_data[:,:np.size(raw_data,1)-1], raw_data[:,np.size(raw_data, 1)-1:])
def standardize(dataset, skipfirst=True):
means = np.amin(dataset, 0)
deviation = np.std(dataset, 0)
if skipfirst:
dataset[:,1:] -= means[:,1:]
dataset[:,1:] /= deviation[:,1:]
return dataset
else:
dataset -= means
dataset /= deviation
return dataset
def error(X, Y, Theta):
"Calculates error values"
v_sigm = np.vectorize(sigmoid)
h_x = X # Theta
sigmo = v_sigm(h_x)
partial_vect = (Y-1).T # np.log(1-sigmo) - Y.T # np.log(sigmo)
return 1/(2*np.size(Y, axis=0))*np.sum(partial_vect)
def gradientStep(X, Y, Theta, LR):
"Returns new theta Values"
v_sigm = np.vectorize(sigmoid)
h_x = X # Theta
modif = -1*LR/np.size(Y, 0)*(h_x-Y)
sums = np.sum(modif.T # X, axis = 0)
return Theta + sums.T
X, Y = loadData("ex2data1.txt")
#add bias to X
X = np.append(np.ones((np.size(X, 0), 1)), X, axis=1)
added_params = [[x[1]**2, x[1]*x[2], x[2]**2] for x in np.array(X)]
X = np.append(X, np.matrix(added_params), axis=1)
#standardize X
X = standardize(X)
#create vector of parameters
Theta=np.zeros((np.size(X, 1), 1))
iterations = 3000
Theta_vals = []
Error_vals = []
for i in range(0, iterations):
Theta_vals.append(np.asarray(Theta).flatten())
Error_vals.append(error(X, Y, Theta))
Theta = gradientStep(X, Y, Theta, 0.07)
#CALCULATING FINISHES HERE
#plot data:
fig = plt.figure()
def_ax = fig.add_subplot(211)
def_ax.set_xlim(np.amin(X[:,1:2]), np.amax(X[:,1:2]))
def_ax.set_ylim(np.amin(X[:,2:3]), np.amax(X[:,2:3]))
err_ax = fig.add_subplot(212)
err_ax.set_ylim(0, error(X, Y, Theta))
err_ax.set_xlim(0, iterations)
positive_X1 = []
positive_X2 = []
negative_X1 = []
negative_X2 = []
for i in range(0, np.size(Y, 0)):
if(Y[i, 0] == 1):
positive_X1.append(X[i, 1])
positive_X2.append(X[i, 2])
else:
negative_X1.append(X[i, 1])
negative_X2.append(X[i, 2])
err_ax.set_ylim(np.amin(Error_vals), np.amax(Error_vals))
def animation(frame):
global Theta_vals, Error_vals, def_ax, err_ax, positive_X1, positive_X2, negative_X1, negative_X2
def_limX = def_ax.get_xlim()
def_limY = def_ax.get_ylim()
err_limX = err_ax.get_xlim()
err_limY = err_ax.get_ylim()
def_ax.clear()
err_ax.clear()
def_ax.set_xlim(def_limX)
def_ax.set_ylim(def_limY)
err_ax.set_xlim(err_limX)
err_ax.set_ylim(err_limY)
def_ax.scatter(positive_X1, positive_X2, marker="^")
def_ax.scatter(negative_X1, negative_X2, marker="o")
Theta = Theta_vals[frame]
res_x = np.linspace(*def_ax.get_xlim(), num=5)
delta_x = [(Theta[4]*x+Theta[2])**2-4*Theta[5]*(Theta[3]*x**2+Theta[1]*x+Theta[0]-0.5) for x in res_x]
delta_x = [np.sqrt(x) if x >= 0 else 0 for x in delta_x]
minb = [-(Theta[4]*x+Theta[2]) for x in res_x]
res_1 = []
res_2 = []
for i in range(0, len(res_x)):
if Theta[5] == 0:
res_1.append(0)
res_2.append(0)
else:
res_1.append((minb[i]+delta_x[i])/(2*Theta[5]))
res_2.append((minb[i]-+delta_x[i])/(2*Theta[5]))
def_ax.plot(res_x, res_1)
def_ax.plot(res_x, res_2)
err_x = np.linspace(0, frame, frame)
err_y = Error_vals[0:frame]
err_ax.plot(err_x, err_y)
anim = FuncAnimation(fig, animation, frames=iterations, interval=3, repeat_delay=2000)
print(error(X, Y, Theta))
anim.save("anim.mp4")
What could be the reason of such a strange behaviour?
I want to plot different lines using a class method. In order to plot a line. Similar to Passing plots out of a class I use this class to plot a line
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
class Plotter(object):
def __init__(self, xval=None, yval=None, dim1=None, dim2=None):
self.xval = xval
self.yval = yval
self.dim1 = dim1
self.dim2 = dim2
def plotthing(self):
fig, ax = plt.subplots(figsize=(self.dim1,self.dim2))
ax.plot(self.xval, self.yval, 'o-')
return fig
app = Plotter(xval=range(0,10), yval=range(0,10), dim1=5, dim2=5)
plot = app.plotthing()
However I would like to plot different curves in the same plot and define a function inside the class to do so.
Xval = []
Yval = []
xval=range(0,10)
yval=range(0,10)
Xval.append(xval)
Yval.append(yval)
xval=range(0,10)
yval=np.sin(range(0,10))
Xval.append(xval)
Yval.append(yval)
How can I define a function to pass to plotthing?
class Plotter(object):
def __init__(self, xval=None, yval=None, dim1=None, dim2=None):
self.xval = xval
self.yval = yval
self.dim1 = dim1
self.dim2 = dim2
def function_do_plot(x, y):
do something
def plotthing(self):
fig, ax = plt.subplots(figsize=(self.dim1,self.dim2))
for i in range(0, len(self.xval)):
x = xval[i]
y = yval[i]
fig = function_do_plot(x, y)
return fig
Consider looping through your lists of inputs without needing a separate method:
class Plotter(object):
def __init__(self, xval=None, yval=None, dim1=None, dim2=None):
self.xval = xval # LIST
self.yval = yval # LIST
self.dim1 = dim1
self.dim2 = dim2
def plotthing(self):
fig, ax = plt.subplots(figsize=(self.dim1,self.dim2))
for i, j in zip(self.xval, self.yval):
ax.plot(i, j, 'o-')
return fig
# POPULATE LIST OF RANGES
Xval = []; Yval = []
xval = range(0,10)
yval = range(0,10)
Xval.append(xval)
Yval.append(yval)
xval = range(0,10)
yval = np.sin(range(0,10))
Xval.append(xval)
Yval.append(yval)
# PASS IN LIST OF RANGES
app = Plotter(xval=Xval, yval=Yval, dim1=5, dim2=5)
plot = app.plotthing()
I'm working on an animation that involves two stages, a "rotate" phase and a "fade" phase. The initial graph looks like this:
What I want is to first rotate the graph so that the black line is on the horizontal. Once that's accomplished, I want to fade out the red lines and blue points, so only the red points and black line are visible. My code for attempting this is below (this is in a jupyter cell).
data = m
def init():
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
ax.set(xlim=(-1.2, 1.2), ylim=(-1.2, 1.2))
ax.axis('off')
# Calculate Projections
best_u = get_best_u(m)
projected_points = line_projection(best_u, m)
projection_main_line, = ax.plot(projected_points[0], projected_points[1], c='black')
projection_points, = ax.plot(projected_points[0], projected_points[1], 'or')
projection_lines = []
for i in range(projected_points.shape[1]):
temp_line = ax.plot([m[0, i], projected_points[0, i]], [m[1, i], projected_points[1, i]], '-r')
projection_lines.append(temp_line)
data_line, = ax.plot(m[0], m[1], linestyle='', marker='o')
proj_lines = update_helper(projection_lines, 0)
return [data_line, projection_main_line, projection_points, *proj_lines]
def update_helper(projection_lines, i):
return_list = []
if i < len(projection_lines):
line, = projection_lines[0]
return [line]
else:
line, = projection_lines[i]
return_list.append(line)
next_list = update_helper(projection_lines, i+1)
return return_list + next_list
def rotate_stage(deg, data):
data = rotate_matrix(data, -deg).T
best_u = get_best_u(data)
projected_points = line_projection(best_u, data)
projection_main_line.set_data(projected_points[0], projected_points[1])
projection_points.set_data(projected_points[0], projected_points[1])
for i in range(len(projection_lines)):
line, = projection_lines[i]
line.set_data(
[data[0, i], projected_points[0, i]],[data[1, i], projected_points[1, i]]
)
data_line.set_data(data[0], data[1])
proj_lines = update_helper(projection_lines, 0)
return [data_line, projection_main_line, projection_points, *proj_lines]
def fade_stage(i):
for i in range(len(projection_lines)):
line, = projection_lines[i]
line.set_alpha(max(1 - i*0.05, 0))
data_line.set_alpha(max(1 - i*0.05, 0))
proj_lines = update_helper(projection_lines, 0)
return [data_line, *proj_lines]
def update(i, data):
if i < 45:
return rotate_stage(i, data)
else:
return fade_stage(i - 44)
anim = FuncAnimation(fig, update, interval=1, init_func=init, fargs=[data],frames=64, blit=True)
HTML(anim.to_html5_video())
anim.save('test.mp4', fps=20, dpi=80)
The resulting output looks like this:
I don't quite understand why this is happening - I thought it would first cycle through the rotation and then cycle through the fade, but clearly that's not what's happening. Any insights would be appreciated.
This class plots a curve. However, the inputs are currently set in main(). I'd like to set them as user-driven from mouse interaction. Some of this is possible and in the Matplotlib docs (see referenced sites below) but it's still not really setting it up to be a 'click and plot'. So, ideally the user would click a button to set the P and then whatever point (on the curve, has to be on the curve) they clicked next would be the new P. Same with Q. I'm sure this is a very simple question for anyone who's used Matplotlib but I'm teaching myself it right now, but it would probably take an entry-level dev just a few minutes to do something that I'm getting nowhere with.
Code:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid.axislines import SubplotZero
from math import sqrt
class ECC123(object):
def __init__(self,a,b,px,qx,qy):
self.a = a
self.b = b
self.pxlam = px
self.qxlam = qx
self.invertQy = qy
self.fig = plt.figure(1)
self.ax = SubplotZero(self.fig, 111)
def drawAxis(self):
#fig = plt.figure(1)
#ax = SubplotZero(fig, 111)
self.fig.add_subplot(self.ax)
for direction in ["xzero", "yzero"]:
self.ax.axis[direction].set_axisline_style("->")
self.ax.axis[direction].set_visible(True)
def plotGraph(self):
self.drawAxis()
y, x = np.ogrid[-10:10:100j, -10:10:100j] # range grid [from : to : how_many_points]
xlist = x.ravel(); ylist = y.ravel()
plt.contour(xlist, ylist, self.elliptic_curve(x,y), [0])
pylam = self.ecclambda(self.pxlam,self.a,self.b) # calculate P from pxlam
qylam = self.ecclambda(self.qxlam,self.a,self.b) # calculate Q from qxlam
if self.invertQy == 1: qylam = -qylam # optional, inverts qy to negative on the plot
plt.plot([self.pxlam,self.qxlam], [pylam,qylam], color = "c", linewidth=1)
plt.plot([self.pxlam], [pylam], "mo"); plt.plot([self.qxlam], [qylam], "mo")
plt.text(self.pxlam-0.25,pylam+0.5, '$P$'); plt.text(self.qxlam-0.25,self.qxlam+0.5, '$Q$')
s = (pylam - qylam)/(self.pxlam - self.qxlam) # calculate s slope
xr = s**2 - self.pxlam - self.qxlam # x-value of R
yr = pylam + s*(xr - self.pxlam) # y-value of -R; -y is R (inverted across x-axis)
plt.plot([xr],[yr],"mo")
plt.plot([xr],[-yr],"co")
plt.plot([self.qxlam,xr], [qylam,yr], color = "c", linewidth=1)
plt.plot([xr,xr], [yr,-yr], "x--")
plt.text(xr+0.25,yr, '$-R$'); plt.text(xr+0.25,-yr, '$R$')
plt.grid(True)
plt.show()
I've been going over the docs in Matplotlib, the scipy cookbook, and related questions here on SO and still not seeing exactly how to do this:
http://matplotlib.org/users/event_handling.html
http://matplotlib.org/1.3.1/api/widgets_api.html#matplotlib.widgets.Button.on_clicked
Cursors for data selection in matplotlib
How can I create a frontend for matplotlib?
http://wiki.scipy.org/Cookbook/Matplotlib
So far, I'm getting little red x's all over when I click and they don't even fall within the curve.
I modified your code a little, so that you can set location of P & Q by left & right click, I didn't accomplish all the graph data updates, the rest is left for you:
from mpl_toolkits.axes_grid.axislines import SubplotZero
import numpy as np
import matplotlib.pyplot as plt
from math import sqrt
class ECC(object):
"""
class to implement elliptic curve and find P+Q=R on the plot
"""
def __init__(self,a,b,px,qx,qy):
"""
initialize input variables
"""
self.a = a
self.b = b
self.pxlam = px
self.qxlam = qx
self.invertQy = qy
self.fig = plt.figure(1)
self.ax = SubplotZero(self.fig, 111)
def drawAxis(self):
"""
draw main x,y axis
"""
#fig = plt.figure(1)
#ax = SubplotZero(fig, 111)
self.fig.add_subplot(self.ax)
for direction in ["xzero", "yzero"]:
self.ax.axis[direction].set_axisline_style("->")
self.ax.axis[direction].set_visible(True)
def ecclambda(self,xl,a,b):
"""
returns points elliptic curve for P and Q
y**2 = x**3 + a*x + b
"""
return sqrt(xl**3 + a*xl + b)
def elliptic_curve(self,x,y):
"""
takes in x,y as set of points, returns the elliptic curve
y**2 = x**3 + a*x + b
"""
return pow(y, 2) - pow(x, 3) - x * self.a - self.b
def onclick(self, event):
x = event.xdata
if event.button == 1:
self.pxlam = x
if event.button == 3:
self.qxlam = x
self.update()
def update(self):
pylam = self.ecclambda(self.pxlam,self.a,self.b) # calculate P from pxlam
qylam = self.ecclambda(self.qxlam,self.a,self.b) # calculate Q from qxlam
self.p.set_data([self.pxlam], [pylam])
self.q.set_data([self.qxlam], [qylam])
self.pt.set_x(self.pxlam-0.25)
self.pt.set_y(pylam+0.5)
self.qt.set_x(self.qxlam-0.25)
self.qt.set_y(qylam+0.5)
plt.gcf().canvas.draw()
def plotGraph(self):
"""
main plotting of elliptic curve and points/line for P+Q=R
P+Q=R --->>> -R is plotted (xr,yr), R is plotted (xr, -yr)
conditional with invertQy allows inversion of Q across x-axis; set option in main()
"""
self.drawAxis()
y, x = np.ogrid[-10:10:100j, -10:10:100j] # range grid [from : to : how_many_points]
xlist = x.ravel(); ylist = y.ravel()
plt.contour(xlist, ylist, self.elliptic_curve(x,y), [0])
pylam = self.ecclambda(self.pxlam,self.a,self.b) # calculate P from pxlam
qylam = self.ecclambda(self.qxlam,self.a,self.b) # calculate Q from qxlam
if self.invertQy == 1: qylam = -qylam # optional, inverts qy to negative on the plot
plt.plot([self.pxlam,self.qxlam], [pylam,qylam], color = "c", linewidth=1)
self.p = plt.plot([self.pxlam], [pylam], "mo")[0]
self.q = plt.plot([self.qxlam], [qylam], "mo")[0]
self.pt = plt.text(self.pxlam-0.25,pylam+0.5, '$P$')
self.qt = plt.text(self.qxlam-0.25,self.qxlam+0.5, '$Q$')
s = (pylam - qylam)/(self.pxlam - self.qxlam) # calculate s slope
xr = s**2 - self.pxlam - self.qxlam # x-value of R
yr = pylam + s*(xr - self.pxlam) # y-value of -R; -y is R (inverted across x-axis)
plt.plot([xr],[yr],"mo")
plt.plot([xr],[-yr],"co")
plt.plot([self.qxlam,xr], [qylam,yr], color = "c", linewidth=1)
plt.plot([xr,xr], [yr,-yr], "x--")
plt.text(xr+0.25,yr, '$-R$'); plt.text(xr+0.25,-yr, '$R$')
plt.text(-9,6,' P: (%s ,%s) \n Q: (%s ,%s) \n R: (%s ,%s) \n a: %s \n b: %s '
%(self.pxlam,pylam,self.qxlam,qylam,xr,-yr,self.a,self.b),
fontsize=10, color = 'blue',bbox=dict(facecolor='tan', alpha=0.5))
plt.title(r"Elliptic Curve Implementation $y^{2} = x^{3} + a*x + b$", fontsize = 16, color = 'b')
self.fig.canvas.mpl_connect('button_press_event', self.onclick)
#[xi,yi] = plt.ginput(0)
##print "ginput ",xi,yi
plt.grid(True)
plt.show()
def main():
a = -2; b = 1; px = -1.55; qx = -0.1
invertQy = 0 # set to 1 if q should be inverted to negative along its y axis
ec = ECC(a,b,px,qx,invertQy)
ec.plotGraph()
if __name__ == '__main__':
main()