Created
May 6, 2017 02:06
-
-
Save 9999years/9d19a4c87cfc145a1c160281fa8c7b0b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math | |
import re | |
def get_float(prompt): | |
return float(input(prompt)) | |
# ok, this one is kinda complicated to describe | |
# scales a number val (assumed to be in the range of valmin to valmax) | |
# to the equivalent fractional distance from min to max | |
# eg if you have a percent value and you want it to be a byte val | |
# you could call scale(val, 0.0, 1.0, 0.0, 255.0) | |
def scale(val, valmin, valmax, outmin, outmax): | |
return ( | |
(val - valmin) / (valmax - valmin) | |
* (outmax - outmin) + outmin | |
) | |
print("enter a formula to graph in terms of x") | |
print("functions like sin, tan, ln, floor, and sqrt are allowed") | |
print("as are pi and e. exponentiation is allowed (e.g. x^2) but for non-") | |
print("integer exponents e.g. pow(x, 2.2) should be used instead") | |
print("EXAMPLE: y(x) = 2sin(x)") | |
print("EXAMPLE: y(x) = ln(0.5x^2)") | |
print("EXAMPLE: y(x) = pow(x, 3.3)") | |
fn = input("y(x) = ") | |
if len(fn) is 0: | |
fn = "2sin(x)" | |
# replace stuff like 2tan(4x) with 2*tan(4*x) | |
fn = re.sub(r"(\d+)([a-zA-Z]+)", r"\1 * \2", fn) | |
# ln = log | |
fn = re.sub(r"ln", r"log", fn) | |
# replace stuff like tan(x) with math.tan(x), which python can evaluate | |
# sorry this is so long, please ignore, it's literally every math method | |
fn = re.sub(r"""\b(ceil|copysign|fabs|factorial|floor|fmod|frexp|fsum|isinf| | |
isnan|ldexp|modf|trunc|exp|expm1|log|log1p|log10|pow|sqrt|acos|asin|atan| | |
atan2|cos|hypot|sin|tan|degrees|radians|acosh|asinh|atanh|cosh|sinh|tanh|erf| | |
erfc|gamma|lgamma|pi|e)\b""", r"math.\1", fn) | |
#replace ^ with ** | |
fn = re.sub(r"\^", r"**", fn) | |
coords = [] | |
# window info for console output | |
win_w = 79 | |
win_h = 23 | |
win_cx = math.floor(win_w / 2) | |
win_cy = math.floor(win_h / 2) | |
# graph data | |
domain_min = -5 | |
domain_max = 5 | |
range_min = -5 | |
range_max = 5 | |
for i in range(0, win_w): | |
x = scale(i, 0, win_w, domain_min, domain_max) | |
try: | |
coords.append(eval(fn)) | |
except ValueError: | |
# negative number in a log or root probably | |
coords.append(float("nan")) | |
# create win_h-element 2d array | |
graph = [] | |
for i in range(0, win_h): | |
graph.append([]) | |
for i in range(0, win_w): | |
# make sure we have space to work with | |
for j in range(0, win_h): | |
graph[j].append(" ") | |
# line for x axis | |
graph[win_cy][i] = "-" | |
# if we have a number to plot, plot it | |
if not math.isnan(coords[i]): | |
height = math.floor(scale(coords[i], range_min, range_max, 0, win_h)) | |
if height > 0 and height < win_h: | |
graph[height][i] = "#" | |
for i in range(0, win_h): | |
graph[i][win_cx] = "|" | |
for i in range(domain_min, domain_max): | |
x_tick = math.floor(scale(i, domain_min, domain_max, 0, win_w)) | |
graph[win_cy][x_tick] = "+" | |
graph[win_cy + 1][x_tick] = str(abs(i)) | |
if i < 0 and x_tick > 0: | |
graph[win_cy + 1][x_tick - 1] = "-" | |
for i in range(range_min, range_max): | |
y_tick = math.floor(scale(i, range_min, range_max, 0, win_h)) | |
graph[y_tick][win_cx] = "+" | |
graph[y_tick][win_cx + 3] = str(abs(i)) | |
if i < 0 and y_tick > 0: | |
graph[y_tick][win_cx + 2] = "-" | |
# origin | |
graph[win_cy][win_cx] = "+" | |
for j in range(win_h - 1, -1, -1): | |
for i in range(0, win_w): | |
print(graph[j][i], end="") | |
print("\n", end="") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment