File size: 7,829 Bytes
fb0e940
 
 
 
9f13c80
 
 
 
 
 
fb0e940
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
da45c29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9f13c80
 
 
 
 
 
fb0e940
 
9f13c80
 
 
 
 
 
fb0e940
 
 
da45c29
 
 
 
 
fb0e940
da45c29
 
 
 
fb0e940
da45c29
fb0e940
da45c29
 
 
 
 
 
 
 
 
 
 
 
 
fb0e940
 
 
9f13c80
 
 
 
da45c29
9f13c80
da45c29
9f13c80
da45c29
9f13c80
 
 
 
fb0e940
da45c29
9f13c80
fb0e940
 
 
 
 
 
da45c29
 
 
 
 
 
 
fb0e940
 
 
9f13c80
fb0e940
 
da45c29
fb0e940
 
 
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
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, x_predict=None, y_predict=None):
    fig, ax = plt.subplots(figsize=(10, 6))
    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):
    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)}."
                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, 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)
    return fig, None

iface = gr.Interface(
    fn=interpolate_and_plot,
    inputs=[
        gr.Textbox(label="X values (comma-separated)"),
        gr.Textbox(label="Y values (comma-separated)"),
        gr.Number(label="X value to predict (optional)", value=lambda: None),
        gr.Radio(["Linear", "Quadratic", "Lagrange", "Newton Forward", "Newton Backward"], label="Interpolation Method", value="Linear"),
        gr.Textbox(label="Plot Title", value="Interpolation Plot"),
        gr.Textbox(label="X-axis Label", value="x"),
        gr.Textbox(label="Y-axis Label", value="y"),
        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"),
        gr.Slider(minimum=8, maximum=24, step=1, label="Label Size", value=12)
    ],
    outputs=[
        gr.Plot(label="Interpolation Plot"),
        gr.HTML(label="Result or Error Message")
    ],
    title="Interpolation App",
    description="Enter x and y values to see the interpolation graph. Choose the interpolation method using the radio buttons. Optionally, enter an x value (between min and max of input x values) to predict its corresponding y value. Note: Newton Forward and Backward methods require uniform x spacing. You can also customize the plot labels, legend position, and label size."
)

iface.launch()