Matplotlib axis showing weird behavior - python

I am trying to plot these functions using matplotlib
def fn_dydx(x):
return 4 * x ** 3
def fn_diff_dydx(x, delta_val):
diff_map = {}
diff_map[0.001] = -1000.0*x**4 + 1000.0*(x + 0.001)**4
diff_map[0.01] = -100.0 * x ** 4 + 100.0 * (x + 0.01) ** 4
diff_map[0.1] = -10.0 * x ** 4 + 10.0 * (x + 0.1) ** 4
diff_map[1] = -1 * x ** 4 + 1.0 * (x + 1) ** 4
return diff_map[delta_val]
Using the following code
line_colors = ['r', 'c', 'y', 'b', 'm']
plot_range = np.linspace(-2, 2, 4000)
y_val = fn_dydx(plot_range)
fig = self.plot.figure()
ax = fig.add_subplot(1, 1, 1)
ax.spines['left'].set_position('center')
ax.spines['bottom'].set_position('center')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
#ax.xaxis.set_ticks_position('bottom')
#ax.yaxis.set_ticks_position('left')
ax.get_yaxis().get_major_formatter().set_useOffset(False)
ax.get_xaxis().get_major_formatter().set_useOffset(False)
ax.set_xlabel('x', loc='right')
ax.set_ylabel('dy/dx', loc='top')
ax.set_title('Differentiation of y = x^4 using sympy and finite perturbance')
self.plot.plot(plot_range, y_val, label='dy/dx using sympy', color='k')
ax.legend(bbox_to_anchor=(1.04, 1),
loc="upper left", fontsize='6')
for delta, color in zip(delta_range, line_colors):
y_diff_val = fn_diff_dydx(plot_range, delta)
self.plot.plot(plot_range, y_diff_val, label=f'dy/dx using perturbance for delta = {delta}', color=color)
ax.legend(bbox_to_anchor=(1.04, 1),
loc="upper left", fontsize='6')
self.plot.show()
I have initialized the plot parameters as follows
self.plot = matplotlib.pyplot
font = {'family': 'serif',
'weight': 'light',
'size': '6'}
self.plot.rc('font', **font)
self.plot.rcParams['figure.constrained_layout.use'] = True
self.plot.rcParams['figure.dpi'] = 150
self.plot.rcParams['figure.autolayout'] = True
self.plot.rc('xtick', labelsize=6)
self.plot.rc('ytick', labelsize=6)
self.plot.rc('axes', labelsize=6)
But the resultant plot behaves weirdly(shifts downwards) for the following list of delta_range [1, 0.001, 0.01, 0.1]
The output is
I want to fix the given code, to compare all these four equations correctly

Related

I want to Plot Circle and its Solid Revolution (Sphere) but get Error: loop of ufunc does not support argument 0 o

I have add the assumption of nonnegative for variables x and r so why I can't plot this?
this is my code:
# Calculate the surface area of y = sqrt(r^2 - x^2)
# revolved about the x-axis
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
x = sy.Symbol("x", nonnegative=True)
r = sy.Symbol("r", nonnegative=True)
def f(x):
return sy.sqrt(r**2 - x**2)
def fd(x):
return sy.simplify(sy.diff(f(x), x))
def f2(x):
return sy.sqrt((1 + (fd(x)**2)))
def vx(x):
return 2*sy.pi*(f(x)*sy.sqrt(1 + (fd(x) ** 2)))
vxi = sy.Integral(vx(x), (x, -r, r))
vxf = vxi.simplify().doit()
vxn = vxf.evalf()
n = 100
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
x = np.linspace(1, 3, 3)
# Plot the circle
y = np.sqrt(r ** 2 - x ** 2)
t = np.linspace(0, np.pi * 2, n)
xn = np.outer(x, np.cos(t))
yn = np.outer(x, np.sin(t))
zn = np.zeros_like(xn)
for i in range(len(x)):
zn[i:i + 1, :] = np.full_like(zn[0, :], y[i])
ax1.plot(x, y)
ax1.set_title("$f(x)$")
ax2.plot_surface(xn, yn, zn)
ax2.set_title("$f(x)$: Revolution around $y$")
# find the inverse of the function
y_inverse = x
x_inverse = np.sqrt(r ** 2 - y_inverse ** 2)
xn_inverse = np.outer(x_inverse, np.cos(t))
yn_inverse = np.outer(x_inverse, np.sin(t))
zn_inverse = np.zeros_like(xn_inverse)
for i in range(len(x_inverse)):
zn_inverse[i:i + 1, :] = np.full_like(zn_inverse[0, :], y_inverse[i])
ax3.plot(x_inverse, y_inverse)
ax3.set_title("Inverse of $f(x)$")
ax4.plot_surface(xn_inverse, yn_inverse, zn_inverse)
ax4.set_title("$f(x)$: Revolution around $x$ \n Surface Area = {}".format(vxn))
plt.tight_layout()
plt.show()
That's because at this line of code:
y = np.sqrt(r ** 2 - x ** 2)
r is still a Sympy's symbol. You need to assign a number to r.

Matplotlib cmap - custom color definition

I am plotting a graph using matplotlib.
Here is the code:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_title("Grid search results - " + model_name)
ax.set_xlabel("Log10(Wight decay)")
ax.set_ylabel("Log10(Learning rate)")
ax.set_zlabel("Batch size")
ax.set_xticks(weightdecay)
ax.set_yticks(learningrate)
ax.set_zticks(trainbatchsize)
scat_plot = ax.scatter(xs=weightdecay, ys=learningrate, zs=trainbatchsize, c=f1, cmap="bwr")
ax.text(top_score[0], top_score[1], top_score[2], top_score[3], color="black")
cb = plt.colorbar(scat_plot, pad=0.2)
cb.ax.set_xlabel('F1 score')
plt.plot(top_score[0], top_score[1], top_score[2], marker="o", markersize=15, markerfacecolor="yellow")
path = Path(output_dir)
plt.savefig(str(path.absolute()) + '/grid_search_plot_' + model_name + ".pdf")
plt.show()
The graph I am getting looks like:
What I would like to do is to use a more granular color-bar. For example for my F1-score (colour-bar), show in:
color1 scores < 0.5
color2 scores 0.5 - 0.75
color3 scores 0.75 - 0.80
color4 scores 0.8 - 0.85
color5 scores 0.85-1
I was trying to re-use some code to create a custom cmap but nothing was working as expected.
One cheap/quick solution might be to create a "categorical color value", like this:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.colors import ListedColormap
import numpy as np
N = 40
x = np.random.uniform(0, 1, N)
y = np.random.uniform(0, 1, N)
z = np.random.uniform(0, 1, N)
# color values
c = np.random.uniform(0, 1, N)
# new color values
new_col = c.copy()
new_col[c < 0.5] = 0
new_col[(c >= 0.5) & (c < 0.75)] = 1
new_col[(c >= 0.75) & (c < 0.8)] = 2
new_col[(c >= 0.8) & (c < 0.85)] = 3
new_col[c >= 0.85] = 4
new_col = new_col / new_col.max()
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
scatter = ax.scatter(x, y, z, c=new_col, cmap=cm.get_cmap("tab10", 5))
cb = fig.colorbar(scatter)
cb.ax.set_yticklabels([0, 0.5, 0.75, 0.80, 0.85, 1])
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_zlim(0, 1)
EDIT to accommodate comments. The following should be able to deal with cases in which a category doesn't have any element:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.colors import ListedColormap
import numpy as np
N = 40
x = np.random.uniform(0, 1, N)
y = np.random.uniform(0, 1, N)
z = np.random.uniform(0, 1, N)
# color values
c = np.random.uniform(0, 1, N)
# number of categories
NC = 5
# new color values
new_col = c.copy()
new_col[c < 0.5] = 0
new_col[(c >= 0.5) & (c < 0.75)] = 1
new_col[(c >= 0.75) & (c < 0.8)] = 2
new_col[(c >= 0.8) & (c < 0.85)] = 3
new_col[c >= 0.85] = 4
new_col = new_col / NC
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
cmap = ListedColormap(["red", "green", "blue", "magenta", "cyan"])
scatter = ax.scatter(x, y, z, c=cmap(new_col))
cb = fig.colorbar(cm.ScalarMappable(cmap=cmap))
cb.ax.set_yticks(np.linspace(0, 1, NC+1), [0, 0.5, 0.75, 0.80, 0.85, 1])
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_zlim(0, 1)

Plot a model with multiple curve_fit parameters

I have a model that describes a sum of Gaussians distributions:
s1 = np.random.normal(2, 0.5, size = (1000, 1))
s2 = np.random.normal(5, 0.5, size = (1000, 1))
mb = (np.concatenate((s1, s2), axis=0)).max()
Xi = np.arange(0,mb,0.1) #bins
#histogram population 1
Y11, bins1 = np.histogram(s1, X)
Y1 = Y11/Y11.sum()
X1 = bins1[:-1]
#histogram population 2
Y22, bins2 = np.histogram(s2, X)
Y2 = Y22/Y22.sum()
X2 = bins2[:-1]
#universe, with all mixed populations
S = np.concatenate((s1, s2), axis=0)
Yi, bins = np.histogram(S, Xi)
Y = Yi/Yi.sum()
X = bins[:-1]
def gaussians(X, amp1, mean1, SD1, amp2, mean2, SD2):
A = amp1 * np.exp(-0.5*((X - mean1)/SD1)**2)
B = amp2 * np.exp(-0.5*((X - mean2)/SD2)**2)
return A + B
params, pcov = curve_fit(gaussians, X,Y, p0=(1,2,1,1,5,1), maxfev=4000)
j = numpy.arange(0.1, mb, 0.1)
plt.figure(figsize=(10, 6)) #size of graph
plt.plot(X, Y, 'o', linewidth=2)
plt.plot(X, gaussians(X ,params[0], params[1],params[2], params[3], params[4], params[5]),'b', linewidth=2)
plt.xlim([-.01, mb])
plt.ylim([0, 0.1])
plt.show()
This code plot a nice graph as follows:
I wonder how to plot each gaussian overlapped in the same graph from the parameters of my model function. I mean, something like this (made by hand):
For those worried to get the answer, I figured out how to do it. It's only matters to become zero all the parameters that you don't want to graph:
plt.plot(X, gaussians(X ,params[0], params[1],params[2], params[3], params[4], params[5]),'b', linewidth=8, alpha=0.1)
plt.plot(X, gaussians(X ,0, params[1],params[2], params[3], params[4], params[5]),'r', linewidth=1 )
plt.plot(X, gaussians(X ,params[0], params[1],params[2], 0, params[4], params[5]),'g', linewidth=1)
plt.xlim([-.01, mb])
plt.ylim([0, 0.1])

Integrals with "quad" and "args" - Young's double slit interferometer

I have to solve a problem "Fringes of Young" using integrals in Python with "quad" and "args"
Formula of the intensity on the screen for M(X,Y) for a source size R is the following :
A source point S have the coordinates (xs=0,ys) with -R/2<=ys<=R/2
I need to create a function to calculate the intensity I(X,Y,R) using "args" of "quad".
Then, plot I(0,Y,10e-6) for Y between -0.01 and 0.01, also, I(0,Y,0.002),I(0,Y,0.003),I(0,Y,0.004). Any idea where is my fault?
My code :
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
y_min = -0.01
y_max = +0.01
R = y_max-y_min
y = np.linspace(y_min, y_max, 100)
X = 0
Y = 0
d = 1
D = 10
s = 10
Lambda = 0.5e-3
delta_s = lambda ys,X,Y : np.sqrt(X**2+(Y-d/2)**2+D**2)+np.sqrt((ys-d/2)**2+s**2)- \
np.sqrt(X**2+(Y+d/2)**2+D**2)-np.sqrt((ys+d/2)**2+s**2)
def integrand(y_s,x,y):
value = 2*(1+np.cos(2*np.pi*delta_s(x,y,y_s)/Lambda))
return value
def calcul_XYR(X,Y,R):
compteur = 0
I_XYR = [] # array for I(X,Y,R)
while compteur < len(y-1):
Y = y[compteur]
print(Y)
I_XYR.append(1/R*quad(integrand, -R/2, R/2, args=(X,Y))[0])
compteur+=1
return I_XYR
plt.figure(figsize=(7, 5))
plt.title("Franges de Young - Figure 3")
plt.axis([y_min, 0.015, 0, 4])
plt.xlabel("Y (mm)")
plt.ylabel("Intensity (a.u.)")
plt.plot(y, calcul_XYR(0,Y,1e-6), '-', color="red", label=r'$R=10^{-6}$')
plt.plot(y, calcul_XYR(0,Y,0.002), '-', color="blue", label=r'$R=0.002$')
plt.plot(y, calcul_XYR(0,Y,0.003), '-', color="black", label=r'$R=0.003$')
plt.plot(y, calcul_XYR(0,Y,0.004), '-', color="green", label=r'$R=0.004$')
plt.legend(loc='right', bbox_to_anchor=(1.00, 0.3))
plt.savefig('question 3 figure.pdf', format='pdf')
plt.show()
Result :
Expected :
I'd also like to plot (using imshow with parameters : cmp(gray),vmin,vmax) a 2D image corresponding to I(X,Y,1e-06). (X between -10 to 10).
The main mistake is the order of the parameters to delta_s. It is defined as delta_s = lambda ys, X, Y, but called as delta_s(X, Y, ys).
Also, calcul_XYR doesn't use its parameter Y, so it's better removed. The loop can be written as for Y in y.
Here is the modified code to generate the desired plot:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
y_min = -0.01
y_max = +0.01
#R = y_max - y_min
y = np.linspace(y_min, y_max, 100)
X = 0
Y = 0
d = 1
D = 10
s = 10
Lambda = 0.5e-3
def delta_s(X, Y, ys):
return np.sqrt(X ** 2 + (Y - d / 2) ** 2 + D ** 2) + np.sqrt((ys - d / 2) ** 2 + s ** 2) - \
np.sqrt(X ** 2 + (Y + d / 2) ** 2 + D ** 2) - np.sqrt((ys + d / 2) ** 2 + s ** 2)
def integrand(y_s, x, y):
return 2 * (1 + np.cos(2 * np.pi * delta_s(x, y, y_s) / Lambda))
def calcul_XR(X, R):
I_XYR = [] # array for I(X,Y,R)
for Y in y:
I_XYR.append(1 / R * quad(integrand, -R / 2, R / 2, args=(X, Y))[0])
return I_XYR
plt.figure(figsize=(7, 5))
plt.title("Franges de Young - Figure 3")
plt.axis([y_min, 0.015, 0, 4])
plt.xlabel("Y (mm)")
plt.ylabel("Intensity (a.u.)")
plt.plot(y, calcul_XR(0, 1e-6), '-', color="red", label=r'$R=10^{-6}$')
plt.plot(y, calcul_XR(0, 0.002), '-', color="blue", label=r'$R=0.002$')
plt.plot(y, calcul_XR(0, 0.003), '-', color="black", label=r'$R=0.003$')
plt.plot(y, calcul_XR(0, 0.004), '-', color="green", label=r'$R=0.004$')
plt.legend(loc='right', bbox_to_anchor=(1.00, 0.3))
plt.savefig('question 3 figure.pdf', format='pdf')
plt.show()
The following code displays an image of the function:
x_min = -10
x_max = 10
x = np.linspace(x_min, x_max, 100)
R = 1e-6
plt.figure(figsize=(7, 5))
graphe1 = []
for xi in x:
graphe1.append(calcul_XYR(xi, R))
graphe1 = np.array(graphe1).T #convert to numpy array and transpose
# imshow normally starts displaying at the top `origin='lower'` reverses this;
# the extent is used to tell imshow what the x and y limits of the image are, to correctly put the ticks
# without `aspect='auto'` imshow seems to want to display x and y with the same scale
# interpolation='bilinear' tells to smooth out the pixels
plt.imshow(graphe1, cmap=plt.cm.gray, vmin=None, vmax=None,
extent=[x_min, x_max, y_min, y_max],
aspect='auto', origin='lower', interpolation='bilinear')
plt.xlabel('X')
plt.ylabel('Y')
plt.title(f'R={R}')
plt.show()

Matplotlib : display array values with imshow

I'm trying to create a grid using a matplotlib function like imshow.
From this array:
[[ 1 8 13 29 17 26 10 4],
[16 25 31 5 21 30 19 15]]
I would like to plot the value as a color AND the text value itself (1,2, ...) on the same grid. This is what I have for the moment (I can only plot the color associated to each value):
from matplotlib import pyplot
import numpy as np
grid = np.array([[1,8,13,29,17,26,10,4],[16,25,31,5,21,30,19,15]])
print 'Here is the array'
print grid
fig1, (ax1, ax2)= pyplot.subplots(2, sharex = True, sharey = False)
ax1.imshow(grid, interpolation ='none', aspect = 'auto')
ax2.imshow(grid, interpolation ='bicubic', aspect = 'auto')
pyplot.show()
You want to loop over the values in grid, and use ax.text to add the label to the plot.
Fortunately, for 2D arrays, numpy has ndenumerate, which makes this quite simple:
for (j,i),label in np.ndenumerate(grid):
ax1.text(i,j,label,ha='center',va='center')
ax2.text(i,j,label,ha='center',va='center')
If for any reason you have to use a different extent from the one that is provided naturally by imshow the following method (even if more contrived) does the job:
size = 4
data = np.arange(size * size).reshape((size, size))
# Limits for the extent
x_start = 3.0
x_end = 9.0
y_start = 6.0
y_end = 12.0
extent = [x_start, x_end, y_start, y_end]
# The normal figure
fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111)
im = ax.imshow(data, extent=extent, origin='lower', interpolation='None', cmap='viridis')
# Add the text
jump_x = (x_end - x_start) / (2.0 * size)
jump_y = (y_end - y_start) / (2.0 * size)
x_positions = np.linspace(start=x_start, stop=x_end, num=size, endpoint=False)
y_positions = np.linspace(start=y_start, stop=y_end, num=size, endpoint=False)
for y_index, y in enumerate(y_positions):
for x_index, x in enumerate(x_positions):
label = data[y_index, x_index]
text_x = x + jump_x
text_y = y + jump_y
ax.text(text_x, text_y, label, color='black', ha='center', va='center')
fig.colorbar(im)
plt.show()
If you want to put other type of data and not necessarily the values that you used for the image you can modify the script above in the following way (added values after data):
size = 4
data = np.arange(size * size).reshape((size, size))
values = np.random.rand(size, size)
# Limits for the extent
x_start = 3.0
x_end = 9.0
y_start = 6.0
y_end = 12.0
extent = [x_start, x_end, y_start, y_end]
# The normal figure
fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111)
im = ax.imshow(data, extent=extent, origin='lower', interpolation='None', cmap='viridis')
# Add the text
jump_x = (x_end - x_start) / (2.0 * size)
jump_y = (y_end - y_start) / (2.0 * size)
x_positions = np.linspace(start=x_start, stop=x_end, num=size, endpoint=False)
y_positions = np.linspace(start=y_start, stop=y_end, num=size, endpoint=False)
for y_index, y in enumerate(y_positions):
for x_index, x in enumerate(x_positions):
label = values[y_index, x_index]
text_x = x + jump_x
text_y = y + jump_y
ax.text(text_x, text_y, label, color='black', ha='center', va='center')
fig.colorbar(im)
plt.show()

Categories

Resources