File size: 9,274 Bytes
fb0e940
 
 
 
9d41ddd
9f13c80
 
 
 
 
 
fb0e940
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
da45c29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5f50a36
da45c29
5f50a36
 
 
 
 
 
 
 
da45c29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5f50a36
9f13c80
 
 
 
 
 
fb0e940
 
9f13c80
 
 
 
 
 
fb0e940
 
 
da45c29
 
 
 
 
fb0e940
da45c29
 
 
 
fb0e940
da45c29
fb0e940
da45c29
 
 
 
 
 
 
 
 
 
 
 
 
fb0e940
 
 
9f13c80
 
 
 
cdd703d
 
e8edd35
9f13c80
da45c29
9f13c80
5f50a36
9f13c80
 
 
 
fb0e940
5f50a36
9f13c80
fb0e940
5f50a36
 
 
567a44d
4ee8a04
83c0e71
caef810
5f50a36
 
 
 
 
ebbf7a2
 
5f50a36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28f0030
5f50a36
 
 
 
 
 
 
 
 
 
 
 
fb0e940
5f50a36
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt


def create_error_plot(error_message):
    fig, ax = plt.subplots(figsize=(10, 6))
    ax.text(0.5, 0.5, error_message, color='red', fontsize=16, ha='center', va='center', wrap=True)
    ax.axis('off')
    return fig

def linear_interpolation(x, y, x_interp):
    return np.interp(x_interp, x, y)

def quadratic_interpolation(x, y, x_interp):
    coeffs = np.polyfit(x, y, 2)
    return np.polyval(coeffs, x_interp)

def lagrange_interpolation(x, y, x_interp):
    n = len(x)
    y_interp = np.zeros_like(x_interp, dtype=float)
    
    for i in range(n):
        p = y[i]
        for j in range(n):
            if i != j:
                p = p * (x_interp - x[j]) / (x[i] - x[j])
        y_interp += p
    
    return y_interp

def newton_forward_interpolation(x, y, x_interp):
    n = len(x)
    h = x[1] - x[0]  # Assuming uniform spacing for simplicity
    F = [[0 for _ in range(n)] for _ in range(n)]
    for i in range(n):
        F[i][0] = y[i]
    
    for j in range(1, n):
        for i in range(n - j):
            F[i][j] = F[i+1][j-1] - F[i][j-1]
    
    def newton_forward(x_val):
        u = (x_val - x[0]) / h
        result = y[0]
        term = 1
        for i in range(1, n):
            term *= (u - i + 1) / i
            result += term * F[0][i]
        return result
    
    return np.array([newton_forward(xi) for xi in x_interp])

def newton_backward_interpolation(x, y, x_interp):
    n = len(x)
    h = x[1] - x[0]  # Assuming uniform spacing for simplicity
    F = [[0 for _ in range(n)] for _ in range(n)]
    for i in range(n):
        F[i][0] = y[i]
    
    for j in range(1, n):
        for i in range(n - 1, j - 1, -1):
            F[i][j] = F[i][j-1] - F[i-1][j-1]
    
    def newton_backward(x_val):
        u = (x_val - x[-1]) / h
        result = y[-1]
        term = 1
        for i in range(1, n):
            term *= (u + i - 1) / i
            result += term * F[n-1][i]
        return result
    
    return np.array([newton_backward(xi) for xi in x_interp])

def create_and_edit_plot(x, y, x_interp, y_interp, method, plot_title, x_label, y_label, legend_position, label_size, log_x, x_predict=None, y_predict=None):
    fig, ax = plt.subplots(figsize=(10, 6))
    
    if log_x:
        # Ensure all x-values are positive before setting log scale
        if np.any(np.array(x) <= 0):
            return create_error_plot("Error: All x values must be positive for logarithmic scale."), \
                   '<p style="color: red;">Error: All x values must be positive for logarithmic scale.</p>'
        ax.set_xscale('log')

    ax.scatter(x, y, color='red', label='Input points')
    ax.plot(x_interp, y_interp, label=f'{method} interpolant')
    ax.set_xlabel(x_label, fontsize=label_size)
    ax.set_ylabel(y_label, fontsize=label_size)
    ax.set_title(plot_title, fontsize=label_size + 2)
    ax.legend(loc=legend_position, fontsize=label_size - 2)
    ax.tick_params(axis='both', which='major', labelsize=label_size - 2)
    ax.grid(True)

    if x_predict is not None and y_predict is not None:
        ax.scatter([x_predict], [y_predict], color='green', s=100, label='Predicted point')
        ax.legend(loc=legend_position, fontsize=label_size - 2)

    return fig

def interpolate_and_plot(x_input, y_input, x_predict, method, plot_title, x_label, y_label, legend_position, label_size, log_x):
    try:
        x = np.array([float(val.strip()) for val in x_input.split(',')])
        y = np.array([float(val.strip()) for val in y_input.split(',')])
    except ValueError:
        error_msg = "Error: Invalid input. Please enter comma-separated numbers."
        return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
    
    if len(x) != len(y):
        error_msg = "Error: Number of x and y values must be the same."
        return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
    
    if len(x) < 2:
        error_msg = "Error: At least two points are required for interpolation."
        return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
    
    x_interp = np.linspace(min(x), max(x), 100)
    
    # Interpolation method selection
    if method == "Linear":
        if len(x) < 2:
            error_msg = "Error: At least two points are required for linear interpolation."
            return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
        y_interp = linear_interpolation(x, y, x_interp)
    elif method == "Quadratic":
        if len(x) < 3:
            error_msg = "Error: At least three points are required for quadratic interpolation."
            return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
        y_interp = quadratic_interpolation(x, y, x_interp)
    elif method == "Lagrange":
        y_interp = lagrange_interpolation(x, y, x_interp)
    elif method == "Newton Forward":
        if not np.allclose(np.diff(x), x[1] - x[0]):
            error_msg = "Error: Newton Forward method requires uniform x spacing."
            return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
        y_interp = newton_forward_interpolation(x, y, x_interp)
    elif method == "Newton Backward":
        if not np.allclose(np.diff(x), x[1] - x[0]):
            error_msg = "Error: Newton Backward method requires uniform x spacing."
            return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
        y_interp = newton_backward_interpolation(x, y, x_interp)
    else:
        error_msg = "Error: Invalid interpolation method selected."
        return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
    
    # Predict y value for given x
    if x_predict is not None:
        try:
            x_predict = float(x_predict)
            if x_predict < min(x) or x_predict > max(x):
                error_msg = f"Error: Prediction x value must be between {min(x)} and {max(x)}."
                fig = create_and_edit_plot(x, y, x_interp, y_interp, method, plot_title, x_label, y_label, legend_position, label_size, log_x)
                return fig, f'<p style="color: red;">{error_msg}</p>'
                #return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
            
            y_predict = np.interp(x_predict, x_interp, y_interp)
            
            fig = create_and_edit_plot(x, y, x_interp, y_interp, method, plot_title, x_label, y_label, legend_position, label_size, log_x, x_predict, y_predict)
            return fig, f"Predicted y value for x = {x_predict}: {y_predict:.4f}"
        except ValueError:
            error_msg = "Error: Invalid input for x prediction. Please enter a number."
            return create_error_plot(error_msg), f'<p style="color: red;">{error_msg}</p>'
    
    fig = create_and_edit_plot(x, y, x_interp, y_interp, method, plot_title, x_label, y_label, legend_position, label_size, log_x)
    return fig, None

def toggle_plot_options(show_options):
    return not show_options, gr.update(visible=not show_options)

with gr.Blocks(theme=gr.themes.Base()) as iface:
    #gr.Markdown("# Interpolation App")
    gr.Markdown('<h1 style="text-align:center;">Interpolation App</h1>')
    gr.Markdown("Enter x and y values to see the interpolation graph")
    
    show_options = gr.State(False)
    
    with gr.Row():
        with gr.Column():
            x_input = gr.Textbox(label="X values (comma-separated)", value="1,2,3")
            y_input = gr.Textbox(label="Y values (comma-separated)", value="1,8,27")
            x_predict = gr.Number(label="X value to predict (optional)", value=lambda: None)
            method = gr.Radio(["Linear", "Quadratic", "Lagrange", "Newton Forward", "Newton Backward"], label="Interpolation Method", value="Linear")
            submit_btn = gr.Button("Generate Plot", variant="primary", elem_id="submit-btn")
            edit_plot_btn = gr.Button("Edit Plot", variant="secondary")
        
        with gr.Column():
            plot_output = gr.Plot(label="Interpolation Plot")
            result_output = gr.HTML(label="Result or Error Message")
    
    plot_options = gr.Column(visible=False)
    with plot_options:
        plot_title = gr.Textbox(label="Plot Title", value="Interpolation Plot")
        x_label = gr.Textbox(label="X-axis Label", value="x")
        y_label = gr.Textbox(label="Y-axis Label", value="y")
        legend_position = gr.Dropdown(["best", "upper right", "upper left", "lower left", "lower right", "right", "center left", "center right", "lower center", "upper center", "center"], label="Legend Position", value="best")
        label_size = gr.Slider(minimum=8, maximum=24, step=1, label="Label Size", value=16)
        log_x = gr.Checkbox(label="Log scale for X-axis", value=False)
    
    edit_plot_btn.click(
        toggle_plot_options,
        inputs=[show_options],
        outputs=[show_options, plot_options]
    )
    
    inputs = [x_input, y_input, x_predict, method, plot_title, x_label, y_label, legend_position, label_size, log_x]
    outputs = [plot_output, result_output]
    
    submit_btn.click(interpolate_and_plot, inputs=inputs, outputs=outputs)

iface.launch()