Logarithmic scale in a negative domain in Plots.jl - plot

Consider this minimal example
julia> using Plots
julia> pyplot()
julia> x = -100:0.01:100
julia> y = x
julia> plot(x, y, xscale = :log10)
This raises the following error:
DomainError:
log10 will only return a complex result if called with a complex argument. Try log10(complex(x)).
Of course, this is because the logarithm of negative numbers is not well defined. However, in python you can overcome this problem using the command plt.xscale('symlog'). Is there an equivalent command for Plots.jl?

Related

Polar Plots in Julia

I came across a Rose plot obtained with Plots.jl package in Julia:
https://goropikari.github.io/PlotsGallery.jl/src/rose.html
Two things are not clear to me. The first one is what is Julia doing on the line:
θ = 0:2pi/n:2pi
It seems that the output is (lower limit):(bin size):(upper limit) but I haven't seen this type of arithmetics previously where two ranges are divided. The second thing is that I would like to obtain a histogram polar plot as it was done with R (Making a polar histogram in ggplot2), but I haven't found the documentation for line styles or how to do it in Plots.jl. Thanks.
Note that start:step:end is a common syntax in creating ranges. Let's dissect the line:
# `pi` is a reserved variable name in Julia
julia> pi
π = 3.1415926535897...
# A simple division
julia> 2pi/1
6.283185307179586
# Simple multiplication
julia> 2pi
6.283185307179586
So the 0:2pi/n:2pi creates an object of type StepRange that starts from 0 up to 2pi with steps of size 2pi/n.
In the case of desired plot, you can use the PlotlyJS.jl package. As they provided an example here. (Scroll down until you see "Polar Bar Chart")
I tested the code myself, and it's reproducible expectedly. Unfortunately, I don't know anything about the R language.
julia> using RDatasets, DataFrames, PlotlyJS
julia> df = RDatasets.dataset("datasets", "iris");
julia> sepal = df.SepalWidth;
julia> plot(
barpolar(
r=sepal
)
)
Results in:

What is the equivalent of Matlab's mesh function in Julia Plots.jl

In Matlab, we would first use [x, y] = meshgrid to generate the grid, then use mesh(x, y, z) to plot the 3D plot. I want to use the same funtionality in Julia Plots.jl, which API should I use? And how can I achieve that?
Thanks a lot in advance!!!
use surface
using Plots
xs = range(-2, stop=2, length=100)\
ys = range(-pi, stop=pi, length=100)
f(x,y) = x*sin(y)
surface(xs, ys, f)
In modern Julia, v1.17, the approach is to create x and y ranges. Julia has changed over the years, and used to have linspace - it doesn't anymore.
There are three ways to create a range:
x = start:step:end
x = range(start,end,step=step)
x = range(start,end,length=npts)
You will also need Plots. If you precompile it, it takes less time to load.
]
pkg > add Plots
pkg > precompile
pkg > Ctrl-C
You need to select your backend for Plots. Choices are:
pyplot() to select PyPlot (also requires Python's MatPlotLib)
plotly() to select Plotly (displays in web browser)
gr() to select GR, the default
Finally, you need to use surface to draw the surface. The function surface can take either a function or a matrix of z values. The function takes two parameters, x and y. Either the function is supplied directly, or it is applied to the ranges:
z = f.(x',y);
One of the ranges is transposed with ', and output suppressed with ;
Surface also takes optional parameters:
fill = :fillname
legend = true | false
size = (width,height)
clims = (lowlimit,highlimit)
An example:
using Plots
plotly()
x=range(-5,5,length=101)
y=range(-5,5,length=101)
function f(x,y)
r = sqrt(x^2+y^2)
sinc(r)
end
z = f.(x',y);
surface(x,y,z,size=(1600,1000),fill=:greens,legend=false)

How to plot complex numbers in Julia?

I was trying to plot complex numbers in Julia but I haven't found any good way to do it yet.
using PyPlot
nums = ComplexF64.([1,2,4],[2,2,-1])
polar.(Base.vect.(0.0,angle.(nums)),Base.vect.(0.0,abs.(nums)),marker="o")
One way is to plot the real and imaginary part as x and y
julia> using Plots
julia> d = [0.0000000+0.0000000im, 0.1111111+0.0000000im,
0.1666667+0.0962250im, 0.2222222+0.0000000im,
0.3333333+0.0000000im, 0.3888889+0.0962250im,
0.3333333+0.1924501im, 0.4444444+0.1924501im,
0.5000000+0.2886751im, 0.5555556+0.1924501im,
0.6666667+0.1924501im, 0.6111111+0.0962250im,
0.6666667+0.0000000im, 0.7777778+0.0000000im,
0.8333333+0.0962250im, 0.8888889+0.0000000im,
1.0000000+0.0000000im]
julia> plot(real(d),imag(d))
# or directly with plot(d)

plotting a line tangent to a function at a point

Heres a block of code that plots a function over a range, as well as the at a single input :
a = 1.0
f(x::Float64) = -x^2 - a
scatter(f, -3:.1:3)
scatter!([a], [f(a)])
i would like to plot the line, tangent to the point, like so:
Is there a pattern or simple tool for doing so?
That depends on what you mean by "pattern or simple tool" - the easiest way is to just derive the derivative by hand and then plot that as a function:
hand_gradient(x) = -2x
and then add plot!(hand_gradient, 0:0.01:3) to your plot.
Of course that can be a bit tedious with more complicated functions or when you want to plot lots of gradients, so another way would be to utilise Julia's excellent automatic differentiation capabilities. Comparing all the different options is a bit beyond the scope of this answer, but check out https://juliadiff.org/ if you're interested. Here, I will be using the widely used Zygote library:
julia> using Plots, Zygote
julia> a = 1.0;
julia> f(x) = -x^2 - a;
[NB I have slightly amended your f definition to be in line with the plot you posted, which is an inverted parabola]
note that here I am not restricting the type of input argument x to f - this is crucial for automatic differentiation to work, as it is implemented by runnning a different number type (a Dual) through your function. In general, restricting argument types in this way is an anti-pattern in Julia - it does not help performance, but makes your code less interoperable with other parts of the ecosystem, as you can see here if you try to automatically differentiate through f(x::Float64).
Now let's use Zygote to provide gradients for us:
julia> f'
#43 (generic function with 1 method)
as you can see, running f' now returns an anonymous function - this is the derivative of f, as you can verify by evaluating it at a specific point:
julia> f'(2)
-4.0
Now all we need to do is leverage this to construct a function that itself returns a function which traces out the line of the gradient:
julia> gradient_line(f, x₀) = (x -> f(x₀) + f'(x₀)*(x-x₀))
gradient_line (generic function with 1 method)
this function takes in a function f and a point x₀ for which we want to get the tangent, and then returns an anonymous function which returns the value of the tangent at each value of x. Putting this to use:
julia> default(markerstrokecolor = "white", linewidth = 2);
julia> scatter(f, -3:0.1:3, label = "f(x) = -x² - 1", xlabel = "x", ylabel = "f(x)");
julia> scatter!([1], [f(1)], label = "", markersize = 10);
julia> plot!(gradient_line(f, 1), 0:0.1:3, label = "f'(1)", color = 2);
julia> scatter!([-2], [f(-2)], label = "", markersize = 10, color = 3);
julia> plot!(gradient_line(f, -2), -3:0.1:0, label = "f'(-2)", color = 3)
It is overkill for this problem, but you could use the CalculusWithJulia package which wraps up a tangent operator (along with some other conveniences) similar to what is derived in the previous answers:
using CalculusWithJulia # ignore any warnings
using Plots
f(x) = sin(x)
a, b = 0, pi/2
c = pi/4
plot(f, a, b)
plot!(tangent(f,c), a, b)
Well, the tool is called high school math :)
You can simply calculate the slope (m) and intersect (b) of the tanget (mx + b) and then plot it. To determine the former, we need to compute the derivative of the function f in the point a, i.e. f'(a). The simplest possible estimator is the difference quotient (I assume that it would be cheating to just derive the parabola analytically):
m = (f(a+Δ) - f(a))/Δ
Having the slope, our tanget should better go through the point (a, f(a)). Hence we have to choose b accordingly as:
b = f(a) - m*a
Choosing a suitably small value for Δ, e.g. Δ = 0.01 we obtain:
Δ = 0.01
m = (f(a+Δ) - f(a))/Δ
b = f(a) - m*a
scatter(f, -3:.1:3)
scatter!([a], [f(a)])
plot!(x -> m*x + b, 0, 3)
Higher order estimators for the derivative can be found in FiniteDifferences.jl and FiniteDiff.jl for example. Alternatively, you could use automatic differentiation (AD) tools such as ForwardDiff.jl to obtain the local derivative (see Nils answer for an example).

Plot of function, DomainError. Exponentiation yielding a complex result requires a complex argument

Background
I read here that newton method fails on function x^(1/3) when it's inital step is 1. I am tring to test it in julia jupyter notebook.
I want to print a plot of function x^(1/3)
then I want to run code
f = x->x^(1/3)
D(f) = x->ForwardDiff.derivative(f, float(x))
x = find_zero((f, D(f)),1, Roots.Newton(),verbose=true)
Problem:
How to print chart of function x^(1/3) in range eg.(-1,1)
I tried
f = x->x^(1/3)
plot(f,-1,1)
I got
I changed code to
f = x->(x+0im)^(1/3)
plot(f,-1,1)
I got
I want my plot to look like a plot of x^(1/3) in google
However I can not print more than a half of it
That's because x^(1/3) does not always return a real (as in numbers) result or the real cube root of x. For negative numbers, the exponentiation function with some powers like (1/3 or 1.254 and I suppose all non-integers) will return a Complex. For type-stability requirements in Julia, this operation applied to a negative Real gives a DomainError. This behavior is also noted in Frequently Asked Questions section of Julia manual.
julia> (-1)^(1/3)
ERROR: DomainError with -1.0:
Exponentiation yielding a complex result requires a complex argument.
Replace x^y with (x+0im)^y, Complex(x)^y, or similar.
julia> Complex(-1)^(1/3)
0.5 + 0.8660254037844386im
Note that The behavior of returning a complex number for exponentiation of negative values is not really different than, say, MATLAB's behavior
>>> (-1)^(1/3)
ans =
0.5000 + 0.8660i
What you want, however, is to plot the real cube root.
You can go with
plot(x -> x < 0 ? -(-x)^(1//3) : x^(1//3), -1, 1)
to enforce real cube root or use the built-in cbrt function for that instead.
plot(cbrt, -1, 1)
It also has an alias ∛.
plot(∛, -1, 1)
F(x) is an odd function, you just use [0 1] as input variable.
The plot on [-1 0] is deducted as follow
The code is below
import numpy as np
import matplotlib.pyplot as plt
# Function f
f = lambda x: x**(1/3)
fig, ax = plt.subplots()
x1 = np.linspace(0, 1, num = 100)
x2 = np.linspace(-1, 0, num = 100)
ax.plot(x1, f(x1))
ax.plot(x2, -f(x1[::-1]))
ax.axhline(y=0, color='k')
ax.axvline(x=0, color='k')
plt.show()
Plot
That Google plot makes no sense to me. For x > 0 it's ok, but for negative values of x the correct result is complex, and the Google plot appears to be showing the negative of the absolute value, which is strange.
Below you can see the output from Matlab, which is less fussy about types than Julia. As you can see it does not agree with your plot.
From the plot you can see that positive x values give a real-valued answer, while negative x give a complex-valued answer. The reason Julia errors for negative inputs, is that they are very concerned with type stability. Having the output type of a function depend on the input value would cause a type instability, which harms performance. This is less of a concern for Matlab or Python, etc.
If you want a plot similar the above in Julia, you can define your function like this:
f = x -> sign(x) * abs(complex(x)^(1/3))
Edit: Actually, a better and faster version is
f = x -> sign(x) * abs(x)^(1/3)
Yeah, it looks awkward, but that's because you want a really strange plot, which imho makes no sense for the function x^(1/3).

Resources