File size: 3,037 Bytes
79402cb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
from __future__ import annotations
import numpy as np
import plotly.express as px
import math
import plotly.graph_objects as go

class Derivative:
    def __init__(self, start_stop_num: List[int, int, int] = [-10, 10, 200], expression: str = "x", function_name: str = None):
        start, stop, num = start_stop_num
        
        self.x = np.linspace(start= start, stop= stop, num = num)
        self.function_name = function_name if function_name else expression
        self.expression = expression
        self.h = 0.0001
        self.y = None
        self.delta_y = None

    def _function(self):
        
        def _make_function(x):
            return eval(self.expression)
        
        self.y = _make_function(self.x)
        self.delta_y = _make_function(self.x + self.h)
    
    def _get_derivative(self):

        if self.delta_y is None or self.y is None:
            raise Exception("Define your y and delta_y first")
        
        self.derivative =  (self.delta_y - self.y) / self.h
        return self.derivative

    def _plot_f(self):

        fig = px.scatter(x = self.x, y = self.y, title = self.function_name)
        return fig

    def _plot_derivative(self):

        fig = px.scatter(x = self.x, y = self.derivative, title = f"Derivative of {self.function_name}")
        return fig

    def get_slope_one_point(self, x):
        # using x and y, obtain the slope
        # y = eval(self.expression)
        math_expression = self.expression.replace("np", "math")

        def _make_function(x): 
            return eval(math_expression)
        
        y = _make_function(x)
        delta_y = _make_function(x + self.h)
        slope = (delta_y - y) / self.h

        return slope, y

    def get_tangent_line_vals(self, x):
        slope, y = self.get_slope_one_point(x)
        tangent_line_y_vals = slope * (self.x - x) + y
        return y, tangent_line_y_vals

    def draw_tangent_line(self, x):
        y, tl_y_vals = self.get_tangent_line_vals(x)

        title = f"Tangent line at point({x},{round(y, 2)}) of {self.function_name}"

        if self.y is None:
            self._function()

        fig = go.Figure()
        fig.update_layout(title = title)
        fig.add_trace(go.Scatter(x = self.x, y = tl_y_vals, name = f"Tangent Line at ({x},{round(y, 2)})"))
        fig.add_trace(go.Scatter(x = self.x, y = self.y, name = self.function_name))

        return fig

    def get_plots(self): 
        return self._plot_f(), self._plot_derivative()

    def __call__(self):
        
        self._function()
        self._get_derivative()

def get_fn(input: str):
    dev_obj = Derivative(expression = input)
    dev_obj()
    fn_fig, _ = dev_obj.get_plots()
    return fn_fig

def get_dev(input: str):
    dev_obj = Derivative(expression = input)
    dev_obj()
    _, dev_fig = dev_obj.get_plots()
    return dev_fig

def get_tangent_line(input_1: str, input_2: str):
    dev_obj = Derivative(expression = input_1)
    tl_fig = dev_obj.draw_tangent_line(int(input_2))
    return tl_fig