Plotting Taylor Series

Previous posts have included an SVG library, memoization of factorials and Taylor Polynomials. In this post I will bring these all together to plot various sine waves created using Taylor Polynomials.

Taylor Polynomials are used to approximate functions, in this case sine, to any level of accuracy. We can plot these levels to show how they become increasingly accurate, which is the subject of this post.

A couple of examples are shown below. The dark blue circles show the sines calculated by Python's math.sin function; this can be taken as a definitive set of values. The other colours are sines calculated using Taylor Polynomials to various degrees, ie levels of accuracy. (Note that the degree of a Taylor Polynomial is not related to the degree as a unit of angle.) As you can see, the higher the degree the better the accuracy, the light blue degree 11 being the best. There is no theoretical limit to the degree, although the higher the degree the longer the calculation takes.

taylor series sine wave
taylor series sine wave

The three previous posts were:

Creating SVG Drawings

Memoization of Factorials

Calculating Sines with Taylor Polynomials

I won't go over these topics again in this post, but you might like to either read these posts before this one, or just regard them as black boxes which provide the necessary functionality for this project.

All the files needed for this project are included in the download from the Downloads page and the Github repository, but the new files are:

  • taylorseriesplot.py
  • main.py

This is the listing for taylorseriesplot.py. Enter or copy/paste it into the file using your favourite editor.

taylorseriesplot.py

import math

import taylorseries
import svg

def taylor_sin_plot(maxsin, maxdegrees, step, width, height, filename):

    """
    Plots a sine wave using Python's math.sin and then plots sine waves using
    the taylorseries module to various degrees to illustrate increasing accurancy.
    Plots are generated and saved using the svg module.
    """

    topmargin = 64
    bottommargin = 32
    leftmargin = 32
    rightmargin = 128

    graph_height = height - topmargin - bottommargin
    graph_width = width - leftmargin - rightmargin
    pixels_per_unit_x = graph_width / maxdegrees
    pixels_per_unit_y = graph_height / (maxsin * 2.0)
    yzero = topmargin + (graph_height / 2)

    colours = ("blue", "red", "orange", "purple", "green", "cyan")

    # Create svg object
    s = svg.SVG()
    s.create(width, height)
    s.fill("#FFFFFF")

    # header text and border lines
    s.text(leftmargin, 38, "sans-serif", 16, "#000000", "#000000", "start", "Sines calculated with Taylor Polynomials to degree 3, 5, 7, 9 and 11")
    s.line("#808080", 2, leftmargin, topmargin, leftmargin, height - bottommargin)
    s.line("#808080", 2, leftmargin, height - bottommargin, width - rightmargin, height - bottommargin)

    # y axis indexes and values
    y = topmargin
    for i in range(maxsin, (maxsin * -1) - 1, -1):
         s.line("#808080", 1, leftmargin - 8, y, width - rightmargin, y)
         s.text(20, y + 4, "sans-serif", 12, "#000000", "#000000", "end", str(i))
         y += pixels_per_unit_y

    # x axis indexes and values
    x = leftmargin
    for d in range(0, maxdegrees + 1, 90):
         s.line("#808080", 1, x, topmargin, x, height - bottommargin + 8)
         s.text(x, height - bottommargin + 24, "sans-serif", 12, "#000000", "#000000", "middle", str(d))
         x += (pixels_per_unit_x * 90)

    # key
    x = width - rightmargin + 16
    y = topmargin + 16
    currdegree = 3
    for colourindex in range(0, 6):

         s.circle(colours[colourindex], 0, colours[colourindex], 6, x, y)

         if(colourindex == 0):
             s.text( x + 16, y + 4, "sans-serif", 12, "#000000", "#000000", "start", "math.sin")
         else:
             s.text( x + 16, y + 4, "sans-serif", 12, "#000000", "#000000", "start", str(currdegree));
             currdegree += 2

         y+= 24

    # Taylor Series plots
    x = leftmargin

    for degree in range(0, maxdegrees + 1, step):

        radians = math.radians(degree)
        sine = math.sin(radians)
        y = yzero - (sine * pixels_per_unit_y)
        colourindex = 0

        s.circle(colours[colourindex], 0, colours[colourindex], 3, x, y)

        for poly_degree in range(3, 12, 2):

            colourindex += 1

            sine = taylorseries.sine_of_radians(radians, poly_degree)

            if(sine <= maxsin and sine >= (maxsin * -1)):
                y = yzero - (sine * pixels_per_unit_y)
                s.circle(colours[colourindex], 0, colours[colourindex], 3, x, y)

        x += pixels_per_unit_x * step

    s.finalize()

    s.save(filename)

    print("File saved")

This file contains a single function, albeit one which is significantly longer than average. This is because I have put all the code for producing the graph illustrated above in one function. Much of the code is boilerplate from the point of view of drawing graphs (axes, headings, keys etc.) and in a later post I will write some general purpose functions to draw this sort of stuff for any type of graph. In the meantime I'll leave them in a single function.

The code to draw the various parts of the graph are easily distinguishable as I have used comments as headings, so lets look at them all in turn.

Variables

Drawing a graph requires a large number of variables to keep track of positions, and these are created and initialised at the beginning. Most are self-explanatory but pixels_per_unit_x and pixels_per_unit_y perhaps need an explanation: they are scaling factors for stretching or squashing data values into the number of pixels available.

The SVG Class Instance

Here we create an SVG object and call its create method with the function's width and height arguments. We also call the fill method to set the background to white.

Header Text and Axis Lines

These lines of code use the text and line methods to draw the heading text and axis lines. I won't go into details here of how the SVG class works but if you might want to read the full article here, or you might prefer to treat the class as a "black box".

The y-axis

The y axis consists of a line which was drawn above as well as values and index marks (short lines) which are drawn here. This uses a for loop from the maximum down to minimum sines so the third argument to range() is -1. Within the loop we draw a line and the current sine value before incrementing the y position. (Of course I could have for-looped forwards starting at the bottom and decremented y; it's an arbitrary decision.)

The x-axis and Values

Another for loop from 0 to maxdegrees, this time with an interval of 90. Within the loop we again draw the values and index marks before incrementing the y position.

The Key

This is the stack of circles in the top right corner showing the colours for each degree of the polynomial. It loops through the list of six colours declared earlier, drawing a small circle and the relevant text. For the first colour "math.sin" is printed, and for subsequent colours the actual polynomial degree is printed. Note that this is initialised to 3 and then incremented by 2 each time.

Plotting Values

This section consists of a for loop from 0 to maxdegrees, incremented by the value of the step argument. For each angle we plot the sine as calculated by Python's math module as well as the values calculated using Taylor Polynomials with degrees 3 to 11.

Both math.sin and my Taylor Polynomial function take radians so we set a variable using math.radians. (Thank you Python People for having the sense to provide this function; the implementors of some languages don't bother.) The sine is then calculated using math.sin, the y cooridinate is calculated and the colour index reset to 0. Next we plot the sine with a small circle.

Next we have an inner loop from 3 to 11, representing the polynomial degrees. The sine variable is set using taylorseries.sine_of_radians and then plotted with another small circle after first checking it within the minimum and maximum. As you can see from the plots above the values returned by the Taylor Polynomial can veer off wildly for larger angles and lower degrees.

Finishing Off

Now all we need to do is call finalize() to add a closing SVG tag and then save the file before printing a message.

We can now write the main function which as you can see is very simple, just a few calls to the taylor_sin_plot function.

main.py

import taylorseriesplot

#-----------------------------------------------------

def main():

    print("--------------------------\n| code-in-python.com     |\n| Plotting Taylor Series |\n--------------------------\n")

    taylorseriesplot.taylor_sin_plot(2, 360, 8, 1440, 800, "tsp1.svg")
    taylorseriesplot.taylor_sin_plot(2, 360, 4, 720, 400, "tsp2.svg")
    taylorseriesplot.taylor_sin_plot(4, 720, 8, 720, 400, "tsp3.svg")

#-----------------------------------------------------

main()

Running the program

That's the coding finished so we can run the program with the following terminal command.

Running the program

python3.6 main.py

The output is pretty boring but if you open the folder where your code is you'll find three .svg files have been created, including the two shown at the top of the page. If you double click them they should open with your default image viewer.

Program Output

--------------------------
| code-in-python.com     |
| Plotting Taylor Series |
--------------------------

File saved
File saved
File saved

You might want to play around with the arguments to "zoom in" or "zoom out" or to create larger images.

Please follow Code in Python on Twitter to keep up to date with new posts.