Suppose you have an array of points that have a chance to be flipped symmetrically (shown below)
from matplotlib import pyplot as plt
import numpy as np
# Data
a = np.array([0.1,-0.325,-0.55,0.775,1]) # x-axis
b = np.array([10,-3.077,-1.818,1.2903,1]) # y-axis
c = np.array([-0.1,0.325,0.55,-0.775,-1]) # x-axis
d = np.array([-10,3.077,1.818,-1.2903,-1])# y-axis
y = [a,b,c,d] # The array is created this way intentionally for when I apply it to my case
plt.plot(y[0],y[1],'k.')
plt.plot(y[2],y[3],'r.')
plt.show()
How do I automatically check each array elements and write a condition that corrects the position of these points, assuming that we know what form it is supposed to have?
edit:
This is the graph I am trying to get
For this example will work
a = np.absolute(a)
b = np.absolute(b)
c = -np.absolute(c)
d = -np.absolute(d)
but other situations may need minus for different lists. So it can be bigg problem to recognize which list need minus.
Better can be to create pairs (x,y) and split them to two list by x > 0 x < 0 (or y > 0 y < 0) and later convert pairs back to lists x and y
(maybe with numpy you could do it easier and faster)
all_pairs = list(zip(a,b)) + list(zip(c,d))
# ---
lower = []
higher = []
for pair in all_pairs:
if pair[0] > 0:
higher.append(pair)
else:
lower.append(pair)
# ---
a, b = list(zip(*higher))
c, d = list(zip(*lower))
Minimal working code
import numpy as np
import matplotlib.pyplot as plt
# Data
a = np.array([0.1,-0.325,-0.55,0.775,1]) # x-axis
b = np.array([10,-3.077,-1.818,1.2903,1]) # y-axis
c = np.array([-0.1,0.325,0.55,-0.775,-1]) # x-axis
d = np.array([-10,3.077,1.818,-1.2903,-1])# y-axis
all_pairs = list(zip(a,b)) + list(zip(c,d))
print(all_pairs)
higher = []
lower = []
for pair in all_pairs:
if pair[0] > 0:
higher.append(pair)
else:
lower.append(pair)
print(higher)
print(lower)
a, b = list(zip(*higher))
c, d = list(zip(*lower))
y = [a,b,c,d] # The array is created this way intentionally for when I apply it to my case
#plt.plot(y[0],y[1],'k.')
#plt.plot(y[2],y[3],'r.')
plt.plot(*y[0:2], 'k.')
plt.plot(*y[2:4], 'r.')
plt.show()
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.
I am trying to get a plot of a Mandelbrot set and having trouble plotting the expected plot.
As I understand, the Mandelbrot set is made up of values c, which would converge if are iterated through the following equation z = z**2 + c. I used the initial value of z = 0.
Initially, I was getting a straight line. I look for solutions online to see where I went wrong. Using the following link in particular, I attempted to improve my code:
https://scipy-lectures.org/intro/numpy/auto_examples/plot_mandelbrot.html
Here is my improved code. I don't really understand the reason of using np.newaxis and why I am plotting the final z values that converge. Am I misunderstanding the definition of the Mandelbrot set?
# initial values
loop = 50 # number of interations
div = 600 # divisions
# all possible values of c
c = np.linspace(-2,2,div)[:,np.newaxis] + 1j*np.linspace(-2,2,div)[np.newaxis,:]
z = 0
for n in range(0,loop):
z = z**2 + c
plt.rcParams['figure.figsize'] = [12, 7.5]
z = z[abs(z) < 2] # removing z values that diverge
plt.scatter(z.real, z.imag, color = "black" ) # plotting points
plt.xlabel("Real")
plt.ylabel("i (imaginary)")
plt.xlim(-2,2)
plt.ylim(-1.5,1.5)
plt.savefig("plot.png")
plt.show()
and got the following image, which looks closer to the Mandelbrot set than anything I got so far. But it looks more of a starfish with scattered dots around it.
Image
For reference, here is my initial code before improvement:
# initial values
loop = 50
div = 50
clist = np.linspace(-2,2,div) + 1j*np.linspace(-1.5,1.5,div) # range of c values
all_results = []
for c in clist: # for each value of c
z = 0 # starting point
for a in range(0,loop):
negative = 0 # unstable
z = z**2 + c
if np.abs(z) > 2:
negative +=1
if negative > 2:
break
if negative == 0:
all_results.append([c,"blue"]) #converging
else:
all_results.append([c,"black"]) # not converging
Alternatively, with another small change to the code in the question, one can use the values of z to colorize the plot. One can store the value of n where the absolute value of the series becomes larger than 2 (meaning it diverges), and color the points outside the Mandelbrot set with it:
import pylab as plt
import numpy as np
# initial values
loop = 50 # number of interations
div = 600 # divisions
# all possible values of c
c = np.linspace(-2,2,div)[:,np.newaxis] + 1j*np.linspace(-2,2,div)[np.newaxis,:]
# array of ones of same dimensions as c
ones = np.ones(np.shape(c), np.int)
# Array that will hold colors for plot, initial value set here will be
# the color of the points in the mandelbrot set, i.e. where the series
# converges.
# For the code below to work, this initial value must at least be 'loop'.
# Here it is loop + 5
color = ones * loop + 5
z = 0
for n in range(0,loop):
z = z**2 + c
diverged = np.abs(z)>2
# Store value of n at which series was detected to diverge.
# The later the series is detected to diverge, the higher
# the 'color' value.
color[diverged] = np.minimum(color[diverged], ones[diverged]*n)
plt.rcParams['figure.figsize'] = [12, 7.5]
# contour plot with real and imaginary parts of c as axes
# and colored according to 'color'
plt.contourf(c.real, c.imag, color)
plt.xlabel("Real($c$)")
plt.ylabel("Imag($c$)")
plt.xlim(-2,2)
plt.ylim(-1.5,1.5)
plt.savefig("plot.png")
plt.show()
The plot doesn't look correct, because in the code in the question z (i.e. the iterated variable) is plotted. Iterating z = z*z + c, the Mandelbrot set is given by those real, imaginary part pairs of c, for which the series doesn't diverge. Hence the small change to the code as shown below gives the correct Mandelbrot plot:
import pylab as plt
import numpy as np
# initial values
loop = 50 # number of interations
div = 600 # divisions
# all possible values of c
c = np.linspace(-2,2,div)[:,np.newaxis] + 1j*np.linspace(-2,2,div)[np.newaxis,:]
z = 0
for n in range(0,loop):
z = z**2 + c
plt.rcParams['figure.figsize'] = [12, 7.5]
p = c[abs(z) < 2] # removing c values for which z has diverged
plt.scatter(p.real, p.imag, color = "black" ) # plotting points
plt.xlabel("Real")
plt.ylabel("i (imaginary)")
plt.xlim(-2,2)
plt.ylim(-1.5,1.5)
plt.savefig("plot.png")
plt.show()
I currently have the code and I having some trouble trying to plot it, I know that trying to plot both ymax and y won't work in this case, but how would I go about plotting just the value for y? I have plotted the function before by removing the ymax from the return, but I need to print the values and plot the solution for y.
import numpy as np
import matplotlib.pyplot as plt
def GaussElimination(A):
'''
Description: Use Gauss elimination to solve a set of simultaneous equations
Parameters: A a matrix of coefficient and constant value for the system
Return: a matrix holding the solution to the equation. This corresponds to the last n
'''
nr,nc=A.shape
B= A.copy()
# start the gauss elimination
for r in range(nr):
#pivoting
max=abs(B[r][r])
maxr = r
for rr in range(r,nr):
if max < abs(B[rr][r]):
max = abs(B[rr][r])
maxr = rr
if max == 0:
print("Singular Matrix")
return []
# swap if needed
if (maxr != r):
for c in range(nc):
temp = B[r][c]
B[r][c]=B[maxr][c]
B[maxr][c] = temp
# scale the row
scale = B[r][r]
for c in range(r,nc):
B[r][c] = B[r][c]/scale
# eliminate values in the columns
for rr in range(nr):
if rr != r:
scale = B[rr][r]
for c in range(r,nc):
B[rr][c]=B[rr][c] - scale*B[r][c]
if (nc == nr+1):
return B[:,nc-1]
else:
return B[:,(nr):nc]
def SimplySupportedBeam(n):
M = np.zeros([n+1,n+1])
C = np.array([[0],[150],[0],[0],[0],[0]])
for r in range(n-3):
M[r][r] = 1
M[r][r+1] = -4
M[r][r+2] = 6
M[r][r+3] = -4
M[r][r+4] = 1
M[n-3][1] = 1
M[n-2][n-1] = 1
M[n-1][n-5] = 1
M[n-1][n-4] = -2
M[n-1][n-3] = 1
M[n][n-2] = 1
M[n][n-1] = -2
M[n][n] = 1
A = np.concatenate((M,C), axis=1)
y0 = GaussElimination(A)
y = y0[1:n]
ymax = np.amax(abs(y))
return y, ymax
n = int(input("Index of the last node: "))
print (SimplySupportedBeam(n))
plt.figure(1)
plt.plot(SimplySupportedBeam(n))
plt.show()
How would I plot just the value I get for y from my code?
It seems like y is 1D numpy array.
If you just want to plot its values against their indices you should be able to do so using either
plt.plot(SimplySupportedBeam(n)[0])
or
y, ymax = SimplySupportedBeam(n)
plt.plot(y)
The problem was that your function returns two values, i.e. y and ymax.
(I did not
I need to discriminate against non physical data in my heatmaps. I am using python(bokeh and holoviews).
Example Code:
import numpy as np
import holoviews as hv
import warnings\
warnings.filterwarnings("ignore")
hv.extension('bokeh')
%opts Image [colorbar=True tools=['hover']
%opts Image (cmap='rainbow')
%output max_frames=3000
import Definitions as def #these are my equations
a = 2
b = .2
c = .3
d = .4
e = 0
f = 0
g = 0
h = 0
i = .2
j = 0
l = .2
m = 1
N = 100 # number of points
yval = np.linspace(0.1,1,N)
xval = np.linspace(0,5,N)
bounds = (0,.1,5,1) #this sets the bounds from .1 to 1 on y axis and 0 to 5 on x axis
xval,yval = np.meshgrid(xval, yval, indexing 'xy')
v1val = def.v1(yval,b,a,m,l,xval) #Calling my these definitions from a seperate file
v2val = def.v2(b,m,a)
Zlist = def.Z(a,v2val/d,v2val/c,h,e,i,j,xval,l,v1val,f,g)
plot = hv.Image(np.flipud(Zlist), label = "Z Heat Map" \
,bounds = bounds, vdims = hv.Dimension('Z', range=(0,1))).redimlabel(x = 'x', y = 'y')
plot
This code makes a heat map where the value of the function Z is mapped as a color for a region of x and y. So Z depends on x and y and for different values of x and y, Z will have different colors.
My problem: I need to discriminate against any situations where v1val < c . The code I currently have plots all of the data but I need it to plot only the data for v1val > c and maybe assign a color like white or black to portion of the graph corresponding to v1val < c. I also similarly need to white out or blackout any region where v2val < d. Essentially I want to black out or white out regions of my heatmap that correspond to non physical data ie when v1val < c and when v2val < d.
I have been trying different things but each time I have some idea I get an error like " The truth of a value of an array with more than one element is ambiguous. Use a.any() or a.all()"
Help with blacking out this non physical data would be much appreciated.
You can see how to black out or white out regions of a heatmap in http://pyviz.org/tutorial/01_Workflow_Introduction.html :
def nansum(a, **kwargs):
return np.nan if np.isnan(a).all() else np.nansum(a, **kwargs)
heatmap = df.hvplot.heatmap('Year', 'State', 'measles', reduce_function=nansum)
I want to visualize the magnetic field of a wire with the quiver function.
#Calculation of a magnetic field of a wire
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
I = 100000000000
constant = 1e-7/(4*np.pi)
# wire elements; always lenght one
coord = [(10,10,0), (11,10,0), (12,10,0), (13,10,0), (14,10,0), (15,10,0), (16,10,0), (17,10,0), (18,10,0),
(19,10,0), (19,11,0), (19,12,0), (19,13,0)]
xwidth = 3
ywidth = 3
z = 1
b = np.zeros((xwidth,ywidth))
# calculate the b-field
def bfield(x,y,z,c):
for x in range(xwidth):
for y in range(ywidth):
# number of wire elements
for i in range(1,12):
rx = x-(coord[i][0]+coord[i+1][0])/2.
ry = y-(coord[i][1]+coord[i+1][1])/2.
rz = z * 1.0 # = z-0
r = (rx**2+ry**2+rz**2)**0.5 # distance r between field and middle of the wire
dl = np.array([(coord[i+1][0]-coord[i][0]), (coord[i+1][1]-coord[i][1]), 0])
bb = np.cross(dl, np.array([rx,ry,rz]))
e = constant*I*bb/r**3
print e
#print e[0], e[1]
b[x,y] += e[c] # EDIT
return b
X,Y = meshgrid(arange(0,xwidth,1),arange(0,ywidth,1))
U = bfield(X,Y,z,0)
V = bfield(X,Y,z,1)
quiver(X,Y,U,V)
xlim(0,xwidth)
ylim(0,ywidth)
show()
EDIT 2: How can I plot lines of the coords in the plot?
EDIT 3: I want to use quiver, but it doesn't work.
it looks like quiver only supports 2d plots right now, but you could make it 3d by plotting multiple 2d layers into a 3d plot. You can follow my example to see how to do these layers.
ValueError: too many values to unpack
That means you have more values on the RHS than variables on the LHS