clean up plot of tan(x) - plot

I want to visualize the roots of tan(xi) = tanh(xi), xi>0 and my plot
plot(tan(pi*xi), tanh(pi*xi), (xi, 0, 4), ylim=(-1, 2))
comes out like this
where one sees the actual roots, xi_i \approx pi*(n+1/4), n=1, ... but also
fake roots at pi*(n+1/2), the reason why being sympy plotting algorithm that draws a vertical line between plus and minus infinity.
I tried to avoid the adaptive sampling and using a low sampling rate to no avail. Other programs, eg gnuplot, give me a more reasonable plot, at least in view of my concerns, that is...
Eventually my question is, is it possible to avoid those vertical lines in sympy's plot() function?

Sympy uses matplotlib as a backend for plotting; the root cause is that matplotlib connects the dots even around a singularity. If one plots with numpy, the direct access to y-values being plotted allows one to replace overly large numbers with nan or infinity. If staying within sympy, such tight control over numerics does not appear to be available. The best I could do is to split the range into a list of smaller ranges that do not include singularities, using the knowledge of the specific function tan(pi*x):
import math
from sympy import *
xi = symbols('xi')
xmin = 0
xmax = 4
ranges = [(xi, n-0.499, n+0.499) for n in range(math.ceil(xmin+0.5), math.floor(xmax+0.5))]
ranges.insert(0, (xi, 0, 0.499))
ranges.append((xi, math.floor(xmax+0.5) - 0.499, xmax))
plot((tanh(pi*xi), (xi, xmin, xmax)), *[(tan(pi*xi), ran) for ran in ranges], ylim=(-1, 2))
Output:

When a curve has singularities, it can plotted by segments, excluding the singularities. A tiny interval around the each singularity is built with math.nextafter(a,b) which returns a plus the smallest possible increment for a float, in direction of b.
from sympy import init_printing, symbols, plot
from sympy import singularities, Interval, tan, pi
from math import nextafter
init_printing()
x = symbols('x')
# The function to plot
y = tan(pi*x)
# Split x range at x singularities
min_x = next_x = 0
max_x = 4 # 4*pi
segments = []
undefs = singularities(y, x, domain=Interval(min_x, max_x))
for u in undefs:
# Add a subrange up to singularity for singularities within x range
if (u >= min_x) and (u <= max_x):
segments.append((x, next_x, nextafter(u, u-1)))
next_x = nextafter(u, u+1)
# Add last segment
if u <= max_x: segments.append((x, next_x, max_x))
# Plot all segments
plots = plot(*[(y, segment) for segment in segments], ylim=(-2,2), show=False)
plots.aspect_ratio = (1,1)
plots.show()
Of course you can use the same color for each curve segment.

Related

Plotting Maxwellian Distribution in Julia

I have a list of positive and negative values and a single temperature. I am trying to plot the Maxwell-Boltzmann Distribution using the equation for particles moving in only one direction.
m_e = 9.11E-28 # electron mass [g]
k = 1.38E-16 # boltzmann constant [erg*K^-1]
v = range(1e10, -1e10, step=-1e8) # velocity [cm/s]
T_M = 1e6 # temperature of Maxwellian [K]
function Maxwellian(v_Max, T_Max)
normal = (m_e/(2*pi*k*T_Max))^1.5
exp_term = exp(-((m_e).*v_Max.*v_Max)/(3*k*T_Max))
return normal*exp_term
end
# Initially comparing chosen distribution f_s to Maxwellian F_s
plot(v, Maxwellian.(v, T_M), label= L"F_s" * " (Maxwellian)")
xlabel!("velocity (cm/s)")
ylabel!("probability density")
However, when, plotting this, my whole function is 0:
I tested out if I wrote my function correctly by replacing return normal*exp_term with return exp_term (i.e. ignoring any normalization constants) and this seems to produce the distinct of the bell curve:
Yet, without the normalization constant, this will not preserve the area under the curve. I was wondering what may I be doing incorrectly with setting up my Maxwellian function and the constant in front of the exponential.
If you print the normalization term on its own:
julia> (m_e/(2*pi*k*T_M))^1.5
1.0769341115495682e-27
you can see that it is 10 orders of magnitude smaller than the Y-axis scale used for the plot. You can set the Y-axis limits during the plots with ylims argument, or after the plot with:
julia> ylims!(-1e-28, 2e-27)
which changes the plot to:

How to draw a boundary line on a scatter plot for classifier in Julia?

If I want to draw a boundary line to separate two classes which is the result of my classifier. How to draw it?
The picture is the sample, the black line is the boundary I want to draw.
the green points is the boundary points. I want to draw a curve perfectly fit those points. But when I plot those curve, the result is the purple line which is not a curve.
Here is a reproducible example how to do it:
using Plots
x = rand(1000)
y = rand(1000)
color = [3 * (b-0.5)^2 < a - 0.1 ? "red" : "blue" for (a, b) in zip(x, y)]
y_bound = 0:0.01:1
x_bound = #. 3 * (y_bound - 0.5)^2 + 0.1
scatter(x, y, color=color, legend=false)
plot!(x_bound, y_bound, color="green")
and you should get a plot like:
The crucial thing here is to make your boundary points ordered (i.e. they must be ordered in the vectors properly so that when you plot a line you connect proper points). In my example I achieved it by varying the y-dimension and calculating the x dimension.
In more complex cases it will be better to use contour plot, e.g.:
x = 1:0.1:8
y = 1:0.1:7
f(x, y) = begin
(3x + y ^ 2) * abs(sin(x) + cos(y)) - 40
end
X = repeat(reshape(x, 1, :), length(y), 1)
Y = repeat(y, 1, length(x))
Z = map(f, X, Y)
contour(x, y, Z, levels=[0], color="green", width=3)
x_s = 7 .* rand(1000) .+ 1
y_s = 6 .* rand(1000) .+ 1
color = [f(a, b) > 0 ? "red" : "blue" for (a, b) in zip(x_s, y_s)]
scatter!(x_s, y_s, color=color, legend=false)
and you should get something like:
However, as you can see this time for the best results it is best to pass scores to contour and specify the classification threshold as level.
I guess your TA asked you to conduct a grid search for this question.
The meaning of grid search is not searching over the data point you have, but searching over whole coordinate. (I.e. From (0,0), (0,1), (0,2) to (0,100), then to (1,0), (1,1) and so on.) You may change the distance between each point when you conduct a grid search.
In your case, you need to solve the equation d_1(X) = d_2(X). So what you need to do is to simulate some points (like the above example), then put those points into |d_1(X) - d_2(X)|, and pick the points that bring you to a value that is smaller than epsilon (a self-given small number like 0.05 or 0.1). Then use Plot() to connect them.
This is not the most efficient way to create the boundary but this is what you learnt in your tutorial. You may also try contour().

How to plot Daubechies psi and phi wavelet functions in R?

The analysis with wavelets seems to be carried out as a discrete transform via matrix multiplication. So it is not surprising, I guess, that when plotting, for example, D4, the R package wmtsa returns the plot:
require(wmtsa)
filters <- wavDaubechies("d4")
plot(filters)
The question is how to go from this discretized plot to the plot in the Wikipedia entry:
Please note that I'm not interested in generating these curves precisely with wmtsa. Any other package will do - I don't have Matlab or Mathematica. But I wonder if the way to go is to start with translating this Mathematica chunk of code in this paper into R, rather than using built-in functions:
Wave1etTransform.m
c[k-1 := c[k] = Daubechies[4][[k+l]];
phi[l] = (l+Sqrt[3])/2 // N;
phi[2] = (l-Sqrt[3])/2 // N;
phi[xJ; xc=0 II x>=3] : = 0
phi[x-?NumberQ] := phi[x] =
N[Sqrt[2]] Sum[c[k] phi[2x-k],{k,0,3}];
In order to plot the wavelet and scaling function all you need are the four numbers shown in the first two plots. I'll focus on plotting the scaling function.
Integer shifts of the scaling function, 𝜑, form an orthonormal basis of the subspace V0 of the multiresolution analysis. We also have that V-1 ⊆ V0 and that 𝜑(x/2) ∈ V-1. Using this gives us the identity
𝜑(x/2) = ∑k ∈ ℤ hk𝜑(x-k)
Now we just need the values of hk. For the Daubechies wavelet these are the values show in the discrete plot you gave (and zero for every other value of k). For an exact value of the hk, first let 𝜇 = (1+sqrt(3))/2. Then we have that
h0 = 𝜇/4
h1 = (1+𝜇)/4
h2 = (2-𝜇)/4
h3 = (1-𝜇)/4
and hk = 0 otherwise.
Using these two things we are able to plot the function using what is known as the cascade algorithm. First notice that 𝜑(0) = 𝜑(0/2) = h0𝜑(0) + h1𝜑(0-1) + h2𝜑(0-2) + h3𝜑(0-3). The only way this equation can hold is if 𝜑(0) = 𝜑(-1) = 𝜑(-2) = 𝜑(-3) = 0. Extending this will show that for x ≦ 0 we have that 𝜑(x) = 0. Furthermore, a similar argument can show that 𝜑(x) = 0 for x ≥ 3.
Thus, we only need to worry about x = 1 and x = 2 to find non-zero values of 𝜑 for integer values of x. If we put x = 2 into the identity for 𝜑(x/2) we get that 𝜑(1) = h0𝜑(2) + h1𝜑(1). Putting x = 4 into the identity gives us that 𝜑(2) = h2𝜑(2) + h3𝜑(1).
We can rewrite the above two equations as a matrix multiplied by a vector equals a vector. In fact, it will be in the form v = Av (v is the same vector on both sides). This means that v is an eigenvector of the matrix A with eigenvalue 1. But v = (𝜑(1), 𝜑(2)) and so by finding this eigenvector using the standard methods we will be able to find the values of 𝜑(1) and 𝜑(2).
In fact, this gives us that 𝜑(1) = (1+sqrt(3))/2 and 𝜑(2) = (1-sqrt(3))/2 (this is where those values in the Mathematica code sample come from). Also note that we need to specifically chose the eigenvector of magnitude 2 for this algorithm to work so you must use those values for 𝜑(1) and 𝜑(2) even though you could rescale the eigenvector.
Now we can find the values of 𝜑(1/2), 𝜑(3/2), and 𝜑(5/2). For example, 𝜑(1/2) = h0𝜑(1) and 𝜑(3/2) = h1𝜑(2) + h2𝜑(1).
With these values, you can then find the values of 𝜑(1/4), 𝜑(3/4), and so on. Continuing this process will give you the value of 𝜑 for all dyadic rationals (rational numbers in the form k/2j.
The same process can be used to find the wavelet function. You only need to use the four different values shown in the first plot rather than the four shown in the second plot.
I recently implemented this Python. An R implementation will be fairly similar.
import numpy as np
import matplotlib.pyplot as plt
def cascade_algorithm(j: int):
mu = (1 + np.sqrt(3))/2
h_k = np.array([mu/4, (1+mu)/4, (2-mu)/4, (1-mu)/4])
# Array to store all the value of phi.
phi_vals = np.zeros((2, 3*2**j+1), dtype=np.float64)
for i in range(3*2**j+1):
phi_vals[0][i] = i/(2**j)
calced_vals = np.zeros((3*2**j+1), dtype=np.bool)
# Input values for 1 and 2.
phi_vals[1][1*2**j] = (1+np.sqrt(3))/2
phi_vals[1][2*2**j] = (1-np.sqrt(3))/2
# We now know the values for 0, 1, 2, and 3.
calced_vals[0] = True
calced_vals[1*2**j] = True
calced_vals[2*2**j] = True
calced_vals[3*2**j] = True
# Now calculate for all the dyadic rationals.
for k in range(1, j+1):
for l in range(1, 3*2**k):
x = l/(2**k)
if calced_vals[int(x*2**j)] != True:
calced_vals[int(x*2**j)] = True
two_x = 2*x
which_k = np.array([0, 1, 2, 3], dtype=np.int)
which_k = ((two_x - which_k > 0) & (two_x - which_k < 3))
phi = 0
for n, _ in enumerate(which_k):
if which_k[n] == True:
phi += h_k[n]*phi_vals[1][int((two_x-n)*2**j)]
phi_vals[1][int(x*2**j)] = 2*phi
return phi_vals
phi_vals = cascade_algorithm(10)
plt.plot(phi_vals[0], phi_vals[1])
plt.show()
If you just want to plot the graphs, then you can use the package "wavethresh" to plot for example the D4 with the following commands:
draw.default(filter.number=4, family="DaubExPhase", enhance=FALSE, main="D4 Mother", scaling.function = F) # mother wavelet
draw.default(filter.number=4, family="DaubExPhase", enhance=FALSE, main="D4 Father", scaling.function = T) # father wavelet
Notice that the mother wavelet and the father wavelets will be plotted depending on the variable "scaling.function". If true, then it plots the father wavelet (scaling), else it plots the mother wavelet.
If you want to generate it by yourself, without packages, I'd suggest you follow Daubechies-Lagarias algorithm, in this paper. It is not hard to implement.

Weighted random coordinates

This may be more of a search for a term, but solutions are also welcome. I'm looking to create n amount of random x,y coordinates. The issue I am having is that I would like the coordinates to be "weighted" or have more of a chance of falling closer to a specific point. I've created something close by using this pseudo code:
x = rand(100) //random integer between 0 and 100
x = rand(x) //random number between 0 and the previous rand value
//randomize x to positive or negative
//repeat for y
This works to pull objects toward 0,0 - however if you create enough points, you can see a pattern of the x and y axis. This is because the even if x manages to get to 100, the chances are high that y will then be closer to.
I'm looking to avoid the formation of this x,y line. Bonus points if there is a way to throw in multiple "weighted coordinates" that the random coordinates would sort of gravitate to, instead of statically to 0,0.
This is easier in polar coordinates. All you have to do is to generate a uniform random angle and a power distributed distance. Here's an example in Python:
import math
from random import random
def randomPoint(aroundX, aroundY, scale, density):
angle = random()*2*math.pi
x = random()
if x == 0:
x = 0.0000001
distance = scale * (pow(x, -1.0/density) - 1)
return (aroundX + distance * math.sin(angle),
aroundY + distance * math.cos(angle))
Here's the distribution of randomPoint(0, 0, 1, 1):
We can shift it to center around another point like 1,2 with randomPoint(1, 2, 1, 1):
We can spread across a larger area by increasing the scale. Here's randomPoint(0, 0, 3, 1):
And we can change the shape, that is the tendency to flock together, by changing the density. randomPoint(0, 0, 1, 3):

Graphing a polar curve with uniform speed

I would like to draw an animation of a polar curve (a spiral) being graphed. I am using javascript and canvas. Currently, I am using setInterval to call a draw function, which graphs an x and y coordinate found from a parametric representation of the polar curve (x and y in terms of theta). I am incrementing theta by 0.01, from 0 to 2*pi, once for every call to draw(). The problem is that I wish for the animation to draw the same amount of the curve for each call to draw, so that the drawing appears to progress with uniform speed. It doesn't matter if the time between each call to draw is different; I just need the speed (in terms of pixels drawn / # of calls to draw) to be constant for the entire awing. In other words, I need the arc length of the segment of the polar graph drawn for each call to draw to be the same. I have no idea how to go about this. Any help/sugestions would be greatly appreciated. Thanks
Let f(z) be the theta variable you are referring to in your question. Here are two parametric equations that should be very similar to what you have:
x(f(z)) = f(z)cos(f(z))
y(f(z)) = f(z)sin(f(z))
We can define the position p(f(z)) at f(z) as
p(f(z)) = [x(f(z)), y(f(z))]
The speed s(f(z)) at f(z) is the length of the derivative of p at f(z).
x'(f(z)) = f'(z)cos(f(z)) - f(z)f'(z)sin(f(z))
y'(f(z)) = f'(z)sin(f(z)) + f(z)f'(z)cos(f(z))
s(f(z)) = length(p'(f(z))) = length([x'(f(z)), y'(f(z))])
= length([f'(z)cos(f(z)) - f(z)f'(z)sin(f(z)), f'(z)sin(f(z)) + f(z)f'(z)cos(f(z))])
= sqrt([f'(z)cos(f(z))]2 + [f(z)f'(z)sin(f(z))]2 + [f'(z)sin(f(z))]2 + [f(z)f'(z)cos(f(z))]2)
= sqrt(f'(z) + [f(z)f'(z)]2)
If you want the speed s(f(z)) to be constant at C as z increases at a constant rate of 1, you need to solve this first-order nonlinear ordinary differential equation:
s(f(z)) = sqrt(f'(z) + [f(z)f'(z)]2) = C
http://www.wolframalpha.com/input/?i=sqrt%28f%27%28z%29+%2B+%5Bf%28z%29f%27%28z%29%5D%5E2%29+%3D+C
Solving this would give you a function theta = f(z) that you could use to compute theta as you keep increasing z. However, this differential equation has no closed form solution.
In other words, you'll have to make guesses at how much you should increase theta at each step, doing binary search on the delta to add to theta and line integrals over p(t) to evaluate how far each guess moves.
Easier method - change the parameter to setInterval proportional to the step arc length. That way you don't have to try to invert the arc length equation. If the interval starts getting too large, you can adjust the step size, but you can do so approximately.

Resources