|
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] |
|
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] |
|
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) |
|
|
|
|
|
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>' |
|
|
|
|
|
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() |