Essentially all I'm trying to do is produce as set of points via an IFS and use a color map to show the multiplicity of each point. In other words, if we assume a color map where high values are more yellow and lower ones are more red, then values repeatedly produced by the IFS will be more yellow.
I'm struggling to get correct results for this. Each thing I've tried has resulted in an image that looks interesting, but is clearly incorrect as it differs wildly from what you get from simply plotting the points without color mapping.
Below is the base code that I'm comfortable with, without the failed attempts at color mapping. What can I do to get a proper color map?
The basic strategy, I think, is to make a matrix 'mat' holding the point multiplicities and do something like plt.imshow(xs, ys, c=mat. cmap="..."). I've tried different approaches to this but keep coming up with incorrect results.
import numpy as np
import matplotlib.pyplot as plt
import random
def f(x, y, n):
N = np.array([[x, y]])
M = np.array([[1, 0], [0, 1]])
b = np.array([[.5], [0]])
b2 = np.array([[0], [.5]])
if n == 0:
return np.dot(M, N.T)
elif n == 1:
return np.dot(M, N.T) + b
elif n == 2:
return np.dot(M, N.T) + b2
elif n == 3:
return np.dot(M, N.T) - b
elif n == 4:
return np.dot(M, N.T) - b2
xs = [] # x coordinates
ys = [] # y coordinates
D = {} # point multiplicities
random.seed()
x = 1
y = 1
for i in range(0, 100000):
n = random.randint(1, 4)
V = f(x, y, n)
x = V.item(0)
y = V.item(1)
xs.append(x)
ys.append(y)
xi = round(x, 3)
yi = round(y, 3)
if (xi, yi) in D:
D[(xi, yi)] += 1
else:
D[(xi, yi)] = 1
plt.xlabel('x')
plt.ylabel('y')
plt.scatter(xs,ys, s=.05)
plt.autoscale(True, True, True)
plt.show()
If I understand your problem, it sounds like you want to use a 2D histogram to get the density of points,
H, x, y = np.histogram2d(xs,ys,bins=100)
X, Y = np.meshgrid(x[:-1],y[:-1],indexing='ij')
plt.pcolormesh(X,Y,H,alpha=0.8, cmap = plt.cm.YlOrRd_r)
plt.colorbar()
Which gives,
This is a transparent colormesh plotted over the scatter plot.
You could also colour your scatter plot by the value at point,
pc = some_fn_to_get_color_at_points(X, Y, H, xs, yx)
plt.scatter(xs,ys, s=.05, c=pc)
Related
I want to generate random points in a box (a=0.2m, b=0.2m, c=1m). This points should have random distance between each other but minimum distance between two points is should be 0.03m, for this I used random.choice. When I run my code it generates random points but distance management is so wrong. Also my float converting approximation is terrible because I don't want to change random values which I generate before but I couldn't find any other solution. I'm open to suggestions.
Images
graph1
graph2
import random
import matplotlib.pyplot as plt
# BOX a = 0.2m b=0.2m h=1m
save = 0 #for saving 3 different plot.
for k in range(3):
pointsX = [] #information of x coordinates of points
pointsY = [] #information of y coordinates of points
pointsZ = [] #information of z coordinates of points
for i in range(100): #number of the points
a = random.uniform(0.0,0.00001) #for the numbers generated below are float.
x = random.choice(range(3, 21,3)) #random coordinates for x
x1 = x/100 + a
pointsX.append(x1)
y = random.choice(range(3, 21,3)) #random coordinates for y
y1 = y/100 + a
pointsY.append(y1)
z = random.choice(range(3, 98,3)) #random coordinates for z
z1 = z/100 + a
pointsZ.append(z1)
new_pointsX = list(set(pointsX)) # deleting if there is a duplicates
new_pointsY = list(set(pointsY))
new_pointsZ = list(set(pointsZ))
# i wonder max and min values it is or not between borders.
print("X-Min", min(new_pointsX))
print("X-Max", max(new_pointsX))
print("Y-Min", min(new_pointsY))
print("Y-Max", max(new_pointsY))
print("Z-Min", min(new_pointsZ))
print("Z-Max", max(new_pointsZ))
if max(new_pointsX) >= 0.2 or max(new_pointsY) >= 0.2:
print("MAX VALUE GREATER THAN 0.2")
if max(new_pointsZ) >= 0.97:
print("MAX VALUE GREATER THAN 0.97")
#3D graph
fig = plt.figure(figsize=(18,9))
ax = plt.axes(projection='3d')
ax.set_xlim([0, 0.2])
ax.set_ylim([0, 0.2])
ax.set_zlim([0, 1])
ax.set_title('title',fontsize=18)
ax.set_xlabel('X',fontsize=14)
ax.set_ylabel('Y',fontsize=14)
ax.set_zlabel('Z',fontsize=14)
ax.scatter3D(new_pointsX, new_pointsY, new_pointsZ);
save += 1
plt.savefig("graph" + str(save) + ".png", dpi=900)
As mentioned in the comments by #user3431635, you can check each point with all previous points before appending that new point to the list. I would do that something like this:
import random
import numpy as np
import matplotlib.pyplot as plt
plt.close("all")
a = 0.2 # x bound
b = 0.2 # y bound
c = 1.0 # z bound
N = 1000 # number of points
def distance(p, points, min_distance):
"""
Determines if any points in the list are less than the minimum specified
distance apart.
Parameters
----------
p : tuple
`(x,y,z)` point.
points : ndarray
Array of points to check against. `x, y, z` points are columnwise.
min_distance : float
Minimum allowable distance between any two points.
Returns
-------
bool
True if point `p` is at least `min_distance` from all points in `points`.
"""
distances = np.sqrt(np.sum((p+points)**2, axis=1))
distances = np.where(distances < min_distance)
return distances[0].size < 1
points = np.array([]) # x, y, z columnwise
while points.shape[0] < 1000:
x = random.choice(np.linspace(0, a, 100000))
y = random.choice(np.linspace(0, b, 100000))
z = random.choice(np.linspace(0, c, 100000))
p = (x,y,z)
if len(points) == 0: # add first point blindly
points = np.array([p])
elif distance(p, points, 0.03): # ensure the minimum distance is met
points = np.vstack((points, p))
fig = plt.figure(figsize=(18,9))
ax = plt.axes(projection='3d')
ax.set_xlim([0, a])
ax.set_ylim([0, b])
ax.set_zlim([0, c])
ax.set_title('title',fontsize=18)
ax.set_xlabel('X',fontsize=14)
ax.set_ylabel('Y',fontsize=14)
ax.set_zlabel('Z',fontsize=14)
ax.scatter(points[:,0], points[:,1], points[:,2])
Note, this might not be the randomness you're looking for. I have written it to take the range of x, y, and z values and split it into 100000 increments; a new x, y, or z point is then chosen from those values.
With some help I have produced the following code. Below are some of the desired outputs for given inputs. However I am having some trouble completing the last task of this code. Looking for some help with this, any guidance or help is greatly appreciated, thanks!
flops = 0
def add(x1, x2):
global flops
flops += 1
return x1 + x2
def multiply(x1, x2):
global flops
flops += 1
return x1 * x2
def poly_horner(A, x):
global flops
flops = 0
p = A[-1]
i = len(A) - 2
while i >= 0:
p = add(multiply(p, x), A[i])
i -= 1
return p
def poly_naive(A, x):
global flops
p = 0
flops = 0
for i, a in enumerate(A):
xp = 1
for _ in range(i):
xp = multiply(xp, x)
p = add(p, multiply(xp, a))
return p
Given the following inputs, I got the following outputs:
poly_horner([1,2,3,4,5], 2)
129
print(flops)
8
poly_naive([1,2,3,4,5, 2])
129
print(flops)[![enter image description here][1]][1]
20
np.polyval([5,4,3,2,1], 2)
129
I assume you want to create a figure, though your question is quite vague...but I have a few minutes to kill while my code runs. Anyway, it seems you MIGHT be having difficulty plotting.
import numpy as np
import pylab as pl
x = np.arange(10)
y = x * np.pi
# you can calculate a line of best fit (lobf) using numpy's polyfit function
lobf1 = np.polyfit(x, y, 1) # first degree polynomial
lobf2 = np.polyfit(x, y, 2) # second degree polynomial
lobf3 = np.polyfit(x, y, 3) # third degree polynomial
# you can now use the lines of best fit to calculate the
# value anywhere within the domain using numpy's polyval function
# FIRST, create a figure and a plotting axis within the fig
fig = pl.figure(figsize=(3.25, 2.5))
ax0 = fig.add_subplot(111)
# now use polyval to calculate your y-values at every x
x = np.arange(0, 20, 0.1)
ax0.plot(x, np.polyval(lobf1, x), 'k')
ax0.plot(x, np.polyval(lobf2, x), 'b')
ax0.plot(x, np.polyval(lobf3, x), 'r')
# add a legend for niceness
ax0.legend(('Degree 1', 'Degree 2', 'Degree 3'), fontsize=8, loc=2)
# you can label the axes whatever you like
ax0.set_ylabel('My y-label', fontsize=8)
ax0.set_xlabel('My x-label', fontsize=8)
# you can show the figure on your screen
fig.show()
# and you can save the figure to your computer in different formats
# specifying bbox_inches='tight' helps eliminate unnecessary whitespace around
# the axis when saving...it just looks better this way.
pl.savefig('figName.png', dpi=500, bbox_inches='tight')
pl.savefig('figName.pdf', bbox_inches='tight')
# don't forget to close the figure
pl.close('all')
I am trying to find the fundamental TE mode of the dielectric waveguide. The way I try to solve it is to compute two function and try to find their intersection on graph. However, I am having trouble get the intersect point on the plot.
My code:
def LHS(w):
theta = 2*np.pi*1.455*10*10**(-6)*np.cos(np.deg2rad(w))/(900*10**(-9))
if(theta>(np.pi/2) or theta < 0):
y1 = 0
else:
y1 = np.tan(theta)
return y1
def RHS(w):
y = ((np.sin(np.deg2rad(w)))**2-(1.440/1.455)**2)**0.5/np.cos(np.deg2rad(w))
return y
x = np.linspace(80, 90, 500)
LHS_vals = [LHS(v) for v in x]
RHS_vals = [RHS(v) for v in x]
# plot
fig, ax = plt.subplots(1, 1, figsize=(6,3))
ax.plot(x,LHS_vals)
ax.plot(x,RHS_vals)
ax.legend(['LHS','RHS'],loc='center left', bbox_to_anchor=(1, 0.5))
plt.ylim(0,20)
plt.xlabel('degree')
plt.ylabel('magnitude')
plt.show()
I got plot like this:
The intersect point is around 89 degree, however, I am having trouble to compute the exact value of x. I have tried fsolve, solve to find the solution but still in vain. It seems not able to print out solution if it is not the only solution. Is it possible to only find solution that x is in certain range? Could someone give me any suggestion here? Thanks!
edit:
the equation is like this (m=0):
and I am trying to solve theta here by finding the intersection point
edit:
One of the way I tried is as this:
from scipy.optimize import fsolve
def f(wy):
w, y = wy
z = np.array([y - LHS(w), y - RHS(w)])
return z
fsolve(f,[85, 90])
However it gives me the wrong answer.
I also tried something like this:
import matplotlib.pyplot as plt
x = np.arange(85, 90, 0.1)
f = LHS(x)
g = RHS(x)
plt.plot(x, f, '-')
plt.plot(x, g, '-')
idx = np.argwhere(np.diff(np.sign(f - g)) != 0).reshape(-1) + 0
plt.plot(x[idx], f[idx], 'ro')
print(x[idx])
plt.show()
But it shows:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
First, you need to make sure that the function can actually handle numpy arrays. Several options for defining piecewise functions are shown in
Plot Discrete Distribution using np.linspace(). E.g.
def LHS(w):
theta = 2*np.pi*1.455*10e-6*np.cos(np.deg2rad(w))/(900e-9)
y1 = np.select([theta < 0, theta <= np.pi/2, theta>np.pi/2], [np.nan, np.tan(theta), np.nan])
return y1
This already allows to use the second approach, plotting a point at the index which is closest to the minimum of the difference between the two curves.
import numpy as np
import matplotlib.pyplot as plt
def LHS(w):
theta = 2*np.pi*1.455*10e-6*np.cos(np.deg2rad(w))/(900e-9)
y1 = np.select([theta < 0, theta <= np.pi/2, theta>np.pi/2], [np.nan, np.tan(theta), np.nan])
return y1
def RHS(w):
y = ((np.sin(np.deg2rad(w)))**2-(1.440/1.455)**2)**0.5/np.cos(np.deg2rad(w))
return y
x = np.linspace(82.1, 89.8, 5000)
f = LHS(x)
g = RHS(x)
plt.plot(x, f, '-')
plt.plot(x, g, '-')
idx = np.argwhere(np.diff(np.sign(f - g)) != 0).reshape(-1) + 0
plt.plot(x[idx], f[idx], 'ro')
plt.ylim(0,40)
plt.show()
One may then also use scipy.optimize.fsolve to get the actual solution.
idx = np.argwhere(np.diff(np.sign(f - g)) != 0)[-1]
from scipy.optimize import fsolve
h = lambda x: LHS(x)-RHS(x)
sol = fsolve(h,x[idx])
plt.plot(sol, LHS(sol), 'ro')
plt.ylim(0,40)
plt.show()
Something quick and (very) dirty that seems to work (at least it gave theta value of ~89 for your parameters) - add the following to your code before the figure, after RHS_vals = [RHS(v) for v in x] line:
# build a list of differences between the values of RHS and LHS
diff = [abs(r_val- l_val) for r_val, l_val in zip(RHS_vals, LHS_vals)]
# find the minimum of absolute values of the differences
# find the index of this minimum difference, then find at which angle it occured
min_diff = min(diff)
print "Minimum difference {}".format(min_diff)
print "Theta = {}".format(x[diff.index(min_diff)])
I looked in range of 85-90:
x = np.linspace(85, 90, 500)
I want to use matplotlib.pyplot.pcolormesh to plot a depth plot.
What I have is a xyz file
Three columns i.e. x(lat), y(lon), z(dep).
All columns are of equal length
pcolormesh require matrices as input.
So using numpy.meshgrid I can transform the x and y into matrices:
xx,yy = numpy.meshgrid(x_data,y_data)
This works great...However, I don't know how to create Matrix of my depth (z) data...
How do I create a matrix for my z_data that corresponds to my x_data and y_data matrices?
Depending on whether you're generating z or not, you have at least two different options.
If you're generating z (e.g. you know the formula for it) it's very easy (see method_1() below).
If you just have just a list of (x,y,z) tuples, it's harder (see method_2() below, and maybe method_3()).
Constants
# min_? is minimum bound, max_? is maximum bound,
# dim_? is the granularity in that direction
min_x, max_x, dim_x = (-10, 10, 100)
min_y, max_y, dim_y = (-10, 10, 100)
Method 1: Generating z
# Method 1:
# This works if you are generating z, given (x,y)
def method_1():
x = np.linspace(min_x, max_x, dim_x)
y = np.linspace(min_y, max_y, dim_y)
X,Y = np.meshgrid(x,y)
def z_function(x,y):
return math.sqrt(x**2 + y**2)
z = np.array([z_function(x,y) for (x,y) in zip(np.ravel(X), np.ravel(Y))])
Z = z.reshape(X.shape)
plt.pcolormesh(X,Y,Z)
plt.show()
Which generates the following graph:
This is relatively easy, since you can generate z at whatever points you want.
If you don't have that ability, and are given a fixed (x,y,z). You could do the following. First, I define a function that generates fake data:
def gen_fake_data():
# First we generate the (x,y,z) tuples to imitate "real" data
# Half of this will be in the + direction, half will be in the - dir.
xy_max_error = 0.2
# Generate the "real" x,y vectors
x = np.linspace(min_x, max_x, dim_x)
y = np.linspace(min_y, max_y, dim_y)
# Apply an error to x,y
x_err = (np.random.rand(*x.shape) - 0.5) * xy_max_error
y_err = (np.random.rand(*y.shape) - 0.5) * xy_max_error
x *= (1 + x_err)
y *= (1 + y_err)
# Generate fake z
rows = []
for ix in x:
for iy in y:
z = math.sqrt(ix**2 + iy**2)
rows.append([ix,iy,z])
mat = np.array(rows)
return mat
Here, the returned matrix looks like:
mat = [[x_0, y_0, z_0],
[x_1, y_1, z_1],
[x_2, y_2, z_2],
...
[x_n, y_n, z_n]]
Method 2: Interpolating given z points over a regular grid
# Method 2:
# This works if you have (x,y,z) tuples that you're *not* generating, and (x,y) points
# may not fall evenly on a grid.
def method_2():
mat = gen_fake_data()
x = np.linspace(min_x, max_x, dim_x)
y = np.linspace(min_y, max_y, dim_y)
X,Y = np.meshgrid(x, y)
# Interpolate (x,y,z) points [mat] over a normal (x,y) grid [X,Y]
# Depending on your "error", you may be able to use other methods
Z = interpolate.griddata((mat[:,0], mat[:,1]), mat[:,2], (X,Y), method='nearest')
plt.pcolormesh(X,Y,Z)
plt.show()
This method produces the following graphs:
error = 0.2
error = 0.8
Method 3: No Interpolation (constraints on sampled data)
There's a third option, depending on how your (x,y,z) is set up. This option requires two things:
The number of different x sample positions equals the number of different y sample positions.
For every possible unique (x,y) pair, there is a corresponding (x,y,z) in your data.
From this, it follows that the number of (x,y,z) pairs must be equal to the square of the number of unique x points (where the number of unique x positions equals the number of unique y positions).
In general, with sampled data, this will not be true. But if it is, you can avoid having to interpolate:
def method_3():
mat = gen_fake_data()
x = np.unique(mat[:,0])
y = np.unique(mat[:,1])
X,Y = np.meshgrid(x, y)
# I'm fairly sure there's a more efficient way of doing this...
def get_z(mat, x, y):
ind = (mat[:,(0,1)] == (x,y)).all(axis=1)
row = mat[ind,:]
return row[0,2]
z = np.array([get_z(mat,x,y) for (x,y) in zip(np.ravel(X), np.ravel(Y))])
Z = z.reshape(X.shape)
plt.pcolormesh(X,Y,Z)
plt.xlim(min(x), max(x))
plt.ylim(min(y), max(y))
plt.show()
error = 0.2
error = 0.8
This SO question provides some help in order to keep annotations from overlapping on each other, but it just stacks the annotations upwards instead of keeping it as close to possible to the (x,y) position it was supposed to be at. Now it just stacks things straight up to where their original x,y position is meaningless.
The relevant part is this:
def get_text_positions(x_data, y_data, txt_width, txt_height):
a = zip(y_data, x_data)
text_positions = y_data.copy()
for index, (y, x) in enumerate(a):
local_text_positions = [i for i in a if i[0] > (y - txt_height)
and (abs(i[1] - x) < txt_width * 2) and i != (y,x)]
if local_text_positions:
sorted_ltp = sorted(local_text_positions)
if abs(sorted_ltp[0][0] - y) < txt_height: #True == collision
differ = np.diff(sorted_ltp, axis=0)
a[index] = (sorted_ltp[-1][0] + txt_height, a[index][1])
text_positions[index] = sorted_ltp[-1][0] + txt_height
for k, (j, m) in enumerate(differ):
#j is the vertical distance between words
if j > txt_height * 2: #if True then room to fit a word in
a[index] = (sorted_ltp[k][0] + txt_height, a[index][1])
text_positions[index] = sorted_ltp[k][0] + txt_height
break
return text_positions
I think the magic is happening at the line j > txt_height, but I want to start moving things left and right if there is overlap.
Edit: I did not adjust anything from the outer for loop, because it looks to be calculating if any of the text positions are in the same 'neighborhood'. if local_text_positions: then runs if any of them are overlapping. np.diff is taking the first order difference... but I don't know what is going on after the j>txt_height like I mentioned in the question.
Check out my library which does this:
https://github.com/Phlya/adjustText
import matplotlib.pyplot as plt
from adjustText import adjust_text
import numpy as np
np.random.seed(2016)
N = 50
scatter_data = np.random.rand(N, 3)
fig, ax = plt.subplots()
bubbles = ax.scatter(scatter_data[:, 0], scatter_data[:, 1],
c=scatter_data[:, 2], s=scatter_data[:, 2] * 150)
labels = ['ano_{}'.format(i) for i in range(N)]
texts = []
for x, y, text in zip(scatter_data[:, 0], scatter_data[:, 1], labels):
texts.append(ax.text(x, y, text))
adjust_text(texts, force_text=0.05, arrowprops=dict(arrowstyle="-|>",
color='r', alpha=0.5))
plt.show()