Plotting In Python, Peicewise, Holoveiws, Bokeh, Heatmaps - python

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)

Related

Efficient way to swap array elements that are flipped

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()

displaying Mandelbrot set in python using matplotlib.pyplot and numpy

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()

How do I only plot the values I want?

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

Level sets of a gaussian

I would like to plot the level sets of this 2-arguments function :
def xi_gaussian_x(x,y):
sigma = 0.8
mu = 1.2
return (1.0/(sigma*np.sqrt(2*np.pi)))*(np.exp(-(x-mu)**2/(2*sigma**2)))
where x and y are between -pi and pi. My code is the following :
plt.ion()
xInterval = np.linspace(-np.pi,np.pi,num=1000)
yInterval = np.linspace(-np.pi,np.pi,num=1000)
levels_xi_gaussian_x=np.zeros((len(xInterval),len(yInterval)))
for i in range(len(xInterval)):
for j in range(len(yInterval)):
levels_xi_gaussian_x[i,j]=xi_gaussian_x(xInterval[i],yInterval[j])
plt.figure()
c = plt.contour(xInterval,yInterval,levels_xi_gaussian_x.T,50)
Even if I increase the resolution of the x and y intervals, I still get regions in the -pi,pi plane which are empty :
How can I make all the plane be filled with vertical lines ?

magnetic field visualization with quiver-function in Python

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

Categories