Skip to content
Snippets Groups Projects
quickmap.py 3.18 KiB
Newer Older
Recolic Keghart's avatar
Recolic Keghart committed
#!/bin/env python3
# -*- coding: UTF-8 -*-
# Gereric: Draw line.
# Recolic Keghart, Apr 29, 2017.

import numpy
from scipy.optimize import leastsq
import matplotlib.pyplot as plt
from matplotlib import rcParams

def dotMultiply(vctA, vctB):
    if len(vctA) != len(vctB):
        print("Error: While vcta is ", vctA, " and vctb is ", vctB)
        raise ValueError("dotmulti needs lena == lenb.")
    ans = 0
    for a, b in zip(vctA, vctB):
        ans += a * b
    return ans

Recolic Keghart's avatar
Recolic Keghart committed
def GetMap(parrX, parrY, windowSizeX=12, windowSizeY=8, extendXRate=1, extendYRate=1, line=False, passO=False, maxXPower=1, inverseK=False):
    '''
    Arguments:
    parrX and parrY: array of coordinates of points. Ex: GetMap([1,2,3,4,5], [1,2,3,4,5]) -> y=x
    line: Should I draw a fitting line?
    passO: Should the fitting line pass (0,0)? That's saying, should k0 be zero?
    maxXPower: If I should draw a fitting line, what polynomial function should I use? Ex: GetMap([1,2,3,4,5], [1,4,9,16,25], line=True, maxXPower) -> y=x^2
    inverseK: Usually, I'm drawing the curl `y=KX`, while K=[k0,k1,k2,...], X=[x^0,x^1,x^2,...]. If this switch is set, I'll drawing the curl `KY=x`. Don't worry, this switch is transparent to you.
    Ex: GetMap([0,1,1,4,4,9,9], [0,1,-1,2,-2,3,-3], maxXPower=2, line=True, inverseK=True) -> y^2=x
    
    ReturnValue:
    void
    '''
Recolic Keghart's avatar
Recolic Keghart committed
    print('Generic-GetMap by Recolic.')
    arrX, arrY = parrX, parrY
Recolic Keghart's avatar
Recolic Keghart committed
    maxX, maxY = max(arrX) * extendXRate, max(arrY) * extendYRate
    minX, minY = min(arrX) * extendXRate, min(arrY) * extendYRate
Recolic Keghart's avatar
Recolic Keghart committed
    # Do calculate
    # y = [k0 k1 k2 ...] dot [x^0 x^1 x^2 ...]
Recolic Keghart's avatar
Recolic Keghart committed
    print('Your input: ', arrX, '|', arrY)
    print('Data collection done. Generating result...')
    X, Y = numpy.array(arrX), numpy.array(arrY)

    def lineFunc(k, x):
        vctX = [x ** power for power in range(maxXPower + 1)]
Recolic Keghart's avatar
Recolic Keghart committed
        if passO:
            vctX[0] = 0
        return dotMultiply(k, vctX)
Recolic Keghart's avatar
Recolic Keghart committed

Recolic Keghart's avatar
Recolic Keghart committed
    def lossFunc(k, x, y): return abs(lineFunc(k, x) - y)
Recolic Keghart's avatar
Recolic Keghart committed

    # Fire!
    if line:
        kInit = [1 for _ in range(maxXPower + 1)]
        kInit[0] = 0 # guarantee passO.
Recolic Keghart's avatar
Recolic Keghart committed
        if inverseK:
            kFinal, _ = leastsq(lossFunc, kInit, args=(Y, X))
            print('Fitting line done. k^-1=', kFinal)
Recolic Keghart's avatar
Recolic Keghart committed
        else:
            kFinal, _ = leastsq(lossFunc, kInit, args=(X, Y))
            print('Fitting line done. k=', kFinal)
Recolic Keghart's avatar
Recolic Keghart committed
    else:
        print('Drawing map without fitting a line...')

    # Draw function map.
    rcParams['grid.linestyle'] = '-'
Recolic Keghart's avatar
Recolic Keghart committed
    rcParams['grid.color'] = 'blue'
    rcParams['grid.linewidth'] = 0.2
    plt.figure(figsize=(windowSizeX, windowSizeY))
    plt.scatter(X, Y, color="red", label="Sample Point", linewidth=3)
Recolic Keghart's avatar
Recolic Keghart committed
    if line:
Recolic Keghart's avatar
Recolic Keghart committed
        if inverseK:
            py = numpy.linspace(minY, maxY, 1000)
            px = dotMultiply(kFinal, [py ** power for power in range(maxXPower + 1)])
        else:
            px = numpy.linspace(minX, maxX, 1000)
            py = dotMultiply(kFinal, [px ** power for power in range(maxXPower + 1)])
        plt.plot(px, py, color="orange", label="Fitting Line", linewidth=2)
Recolic Keghart's avatar
Recolic Keghart committed
    plt.legend()
    plt.grid()
    plt.show()

    def toFloat(sstr):
        if sstr == '':
            return 0.0
        else:
            return float(sstr)