Plotting program for functions

As hashed out in class. Also, compare with the streamlined version.

# -*- coding: utf-8 -*-
"""
Created on Mon Apr  5 11:14:01 2021

@author: rmontant
"""
import math
import shutil

# This is a GLOBAL variable!
# It gets its value in main(),
# while myftn() and expftn() use its value.
scale = None

# Lots of interpolation between the range and domain
# (x- and y- values) of the functions, and the number
# of rows and columns of the display.
# This function does all those interpolations:
def interpolate(xmid, xa, xb, ya, yb):
    return ya + (yb - ya) * (xmid - xa)/(xb - xa)
#--------


# Two example functions to plot:

def myftn(x):
    return (math.sin(x) * math.cos(scale * x))
#--------

def expftn(x):
    return (x**2 * math.exp(-scale * (x**0.8)))
#--------


# Make a horizontal plot of two lists of x- and y- values.
# The number of columns "n_cols" is actually equal to the
# length of the lists, so isn't really necessary.
# Similarly, "ymin" and "ymax" could be found from the
# yvals list, so they aren't necessary either.
def plot_xy(xvals, yvals, n_cols, n_rows, ymin, ymax):
    for r in range(n_rows-1, -1, -1):
        y_r = interpolate(r, 0, n_rows, ymin, ymax)
        for c in range(n_cols):
            #x_c = xvals[c]
            y_c = yvals[c]
            if y_c >= y_r >= 0  or  y_c <= y_r  <= 0:
                print('*', end='')
            else:
                print(' ', end='')
        print()
#--------

# Given an arbitrary function and the size of
# the display space, build the list of x-values
# for each column and the list of corresponding y-values.
# Then call "plot_xy()" to display them.

# Also, show how to use list comprehensions in place of loops.
#
def draw_function(xmin, xmax, n_cols, n_rows, y_ftn):
    #xvals = []
    #for c in range(n_cols):
    #    xvals.append( interpolate(c, 0, n_cols, xmin, xmax))
    xvals = [ interpolate(c, 0,n_cols, xmin,xmax) for c in range(n_cols) ]

    #yvals = []
    #for x in xvals:
    #    yvals.append( y_ftn(x) )
    yvals = [ y_ftn(x) for x in xvals ]

    ymin, ymax = min(yvals), max(yvals)

    plot_xy(xvals, yvals, n_cols, n_rows, ymin, ymax)
#--------


def main(argv=[__name__]):
    global scale

    n_cols = shutil.get_terminal_size()[0] - 6
    n_rows = shutil.get_terminal_size()[1] - 4
    if len(argv) == 3:
        xrange = float(argv[1])
        scale = float(argv[2])
    else:
        xrange = float(input('x_range? '))
        scale = float(input('Scale? '))

    x = 1e-99
    xmax = xrange * math.pi
#    nsteps = 200
#    xstep = (xmax - x) / nsteps

#    xvalues, yvalues = [], []
#    while x < xmax:
#        xvalues.append(x)
#        yvalues.append(myftn(x, scale))
#        x += xstep

    #plot_function(xvalues, yvalues, width, fill='*')    
    draw_function(x, xmax, n_cols, n_rows, expftn )
#--------

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))
#--------