Julia Community

Cover image for Plotting smooth graphs with Julia
Yuto Horikawa
Yuto Horikawa

Posted on

Plotting smooth graphs with Julia

Abstract

  • The graphs (curves) output by Plots.jl are polygonal lines, so they look a bit like sharp edges.
  • If we use the BasicBSpline.jl package to plot the curve, they will be approximated by Bézier curves, and we'll be happy!

The package used in this article can be installed from Julia's REPL with the following command:

]add Plots
add StaticArrays
add BasicBSpline
add https://github.com/hyrodium/BasicBSplineExporter.jl
Enter fullscreen mode Exit fullscreen mode

Smooth case

Plotting with Plots.jl

Let's begin by plotting with the Plots.jl package!

using Plots

plot(sin,-8,8)  # plot sin curve from -8 to 8
savefig("sin_Plots.svg")  # save with SVG format
savefig("sin_Plots.png")  # save with PNG format
Enter fullscreen mode Exit fullscreen mode

sin plot

Zoom in on the SVG image near the maxima.

sin plot zoom 1

sin plot zoom 2

It seems non-smooth curve with sharp edges.

This is because the curve is approximated by a polyline. The following image shows an SVG image opened in Inkscape.

sin plot in inkscape

How can we get a smooth graph?
SVG supports Bézier curves, so it should be possible as the file format...
→ Use the BasicBSpline.jl package!

Plotting with BasicBSplineExporter.jl

using BasicBSpline
using BasicBSplineExporter
using StaticArrays

f(t) = SVector(t,sin(t)) # pamametrized sine curve
t0,t1 = -8,8             # endpoints

p = 3                                     # Polynomial degree; SVG allows Bézier curves up to 3rd degree.
k = KnotVector(t0:t1)+p*KnotVector(t0,t1) # Knot vector
P = BSplineSpace{p}(k)                    # B-spline space (piecewise polynomial space)

a = fittingcontrolpoints(f,(P,))  # Calculate control points of B-spline curve
M = BSplineManifold(a,(P,)) # Define B-spline curve
save_svg("sin_BasicBSpline.svg", M, xlims=(-10,10), ylims=(-2,2)) # Save in SVG format
save_png("sin_BasicBSpline.png", M, xlims=(-10,10), ylims=(-2,2)) # Save in PNG format
Enter fullscreen mode Exit fullscreen mode

sin plot with BasicBSpline.jl

Checking with Inkscape, you can see that the curve is smoothly represented by the Bézier curve as shown below.

sin plot with BasicBSpline.jl inkscape

sin plot with BasicBSpline.jl inkscape zoom

The B-spline curve defined above is connected at the knots so that the entire curve is C2C^2 class smooth. Since the curve is polynomial in each section, the curve is represented as a piecewise polynomial.

Non-smooth case

Plotting with Plots.jl

Let's plot a graph of f(x)=sin(x)f(x) = |\sin(x)| with Plots.jl

plot(abs∘sin,-8,8)
savefig("abssin_Plots.svg")
savefig("abssin_Plots.png")
Enter fullscreen mode Exit fullscreen mode

abssin plot

Since this is a polyline approximation, the graph appears to capture the characteristics even at discontinuities in the derivatives.

Plotting with BasicBSplineExporter.jl

As before, graphs can be output by doing the following.

f(t) = SVector(t,abs(sin(t)))
t0,t1 = -8,8
p = 3
k = KnotVector(range(t0,t1,length=50))+p*KnotVector(t0,t1)
P = BSplineSpace{p}(k)

a = fittingcontrolpoints(f,(P,))
M = BSplineManifold(a,(P,))
save_svg("abssin_BasicBSpline![](https://storage.googleapis.com/zenn-user-upload/555b66bd3bac-20211229.png).svg", M, xlims=(-10,10), ylims=(-2,2))
save_png("abssin_BasicBSpline.png", M, xlims=(-10,10), ylims=(-2,2))
Enter fullscreen mode Exit fullscreen mode

The exported graph↓
abs sin with BasicBSpline

Zoom in on the singularity↓
singularity point zoom

Even if the number of knots (the number of segmented polynomial divisions) is increased, the approximation accuracy will not improve much because of the "smoothly connected" constraint.

In B-spline theory, it is necessary to place more than one knot at the root of sin because the smoothness of the curve decreases as the knots overlap.

k = KnotVector(range(t0,t1,length=12))+p*KnotVector(t0,t1)
k += p*KnotVector(-2π:π:2π)  # Duplicate knots at points where we want to reduce smoothness
P = BSplineSpace{p}(k)

a = fittingcontrolpoints(f,(P,))
M = BSplineManifold(a,(P,))
save_svg("abssin_BasicBSpline_modified.svg", M, xlims=(-10,10), ylims=(-2,2))
save_png("abssin_BasicBSpline_modified.png", M, xlims=(-10,10), ylims=(-2,2))
Enter fullscreen mode Exit fullscreen mode

The exported graph↓
abssin with BasicBSpline

Beautiful even when zoomed in!
abssin with BasicBSpline zoom

Conclusion

  • With BasicBSpline.jl package, it's convenient to output smooth graphs!
  • B-spline allows you to change the smoothness depending on the overlap of knot vector!
  • Plots.jl is a really great package for plotting!

Note: this post is a English translation of this article in zenn.dev.

Discussion (0)