import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.cluster import KMeans import gradio as gr from gradio.components import Slider, Number, Image, Dataframe import matplotlib matplotlib.use('Agg') import numpy as np def generate_random_points_in_circle(center_x, center_y, radius, num_points): angles = np.random.uniform(0, 2 * np.pi, num_points) radii = np.sqrt(np.random.uniform(0, radius**2, num_points)) x_values = center_x + radii * np.cos(angles) y_values = center_y + radii * np.sin(angles) points = np.column_stack((x_values, y_values)) return points def compute_line_parameters(slope, intercept, mean, std, num_points, x_min, x_max, num_iterations): line_parameters = np.zeros((num_iterations, 2)) all_points = [] for i in range(num_iterations): x_values, y_values_with_noise = predict_line_with_noise(slope, intercept, mean, std, num_points, x_min, x_max) all_points.append(np.column_stack((x_values, y_values_with_noise))) idx = np.random.choice(num_points, 2, replace=False) x1, y1 = x_values[idx[0]], y_values_with_noise[idx[0]] x2, y2 = x_values[idx[1]], y_values_with_noise[idx[1]] line_slope = (y2 - y1) / (x2 - x1) line_intercept = y1 - line_slope * x1 line_parameters[i, 0] = line_slope line_parameters[i, 1] = line_intercept return line_parameters, all_points def create_points_plot(all_points, circle_points): fig, ax = plt.subplots() for points in all_points: x_values = points[:, 0] y_values = points[:, 1] ax.scatter(x_values, y_values, alpha=0.2, color="blue") ax.scatter(circle_points[:, 0], circle_points[:, 1], alpha=0.2, color='red') fig.canvas.draw() img = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,)) plt.close(fig) return img def create_points_lines_plot(all_points, line_parameters): fig, ax = plt.subplots() for points, (slope, intercept) in zip(all_points, line_parameters): x_values = points[:, 0] y_values = points[:, 1] ax.scatter(x_values, y_values, alpha=0.2) ax.plot(x_values, slope * x_values + intercept, alpha=0.5) fig.canvas.draw() img = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,)) plt.close(fig) return img def create_cluster_plot(line_parameters, labels, centroids): fig, ax = plt.subplots() ax.scatter(line_parameters[:, 0], line_parameters[:, 1], c=labels, cmap='viridis') ax.set_xlabel('Slope') ax.set_ylabel('Intercept') fig.canvas.draw() img = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,)) plt.close(fig) return img def cluster_line_parameters(line_parameters, num_clusters, all_points, circle_points): kmeans = KMeans(n_clusters=num_clusters) kmeans.fit(line_parameters) labels = kmeans.labels_ centroids = kmeans.cluster_centers_ counts = np.bincount(labels) points_img = create_points_plot(all_points, circle_points) points_lines_img = create_points_lines_plot(all_points, line_parameters) cluster_img = create_cluster_plot(line_parameters, labels, centroids) return labels, centroids, counts, points_img, points_lines_img, cluster_img def predict_line_with_noise(slope, intercept, mean, std, num_points, x_min, x_max): x_values = np.linspace(x_min, x_max, num_points) noise = np.random.normal(mean, std, num_points) y_values = slope * x_values + intercept + noise return x_values, y_values def cluster_line_params(slope, intercept, mean, std, num_points, x_min, x_max, num_iterations, num_clusters, center_x, center_y, radius, circle_points, random_seed): np.random.seed(random_seed) num_points = int(num_points) num_iterations = int(num_iterations) num_clusters = int(num_clusters) points_in_circle = generate_random_points_in_circle(center_x, center_y, radius, circle_points) line_parameters, all_points = compute_line_parameters(slope, intercept, mean, std, num_points, x_min, x_max, num_iterations) labels, centroids, counts, points_img, points_lines_img, cluster_img = cluster_line_parameters(line_parameters, num_clusters, all_points, points_in_circle) # return labels, centroids, img # put counts as the third column of centroids centroids = np.c_[centroids, counts] df = pd.DataFrame(centroids, columns=["Slope", "Intercept", "Count"]) # return img, centroids, df return points_img, points_lines_img, cluster_img, df # Define input and output components inputs = [ Slider(minimum=-5.0, maximum=5.0, value=1.0, label="Line Slope"), Slider(minimum=-10.0, maximum=10.0, value=0.0, label="Line Intercept"), Slider(minimum=0.0, maximum=5.0, value=1.0, label="Line Error Mean"), Slider(minimum=0.0, maximum=5.0, value=1.0, label="Line Error Standard Deviation"), Number(value=100, label="Number of Points Sampled from the Line"), Number(value=-5, label="Minimum Value of x for Sampling"), Number(value=5, label="Maximum Value of x for Sampling"), Number(value=100, label="Number of Iterations for RANSAC-like Line Parameter Estimation"), Number(value=3, label="Number of Clusters of Line Parameters"), Number(value=0, label="X Value Center of the Circle"), Number(value=0, label="Y Value Center of the Circle"), Number(value=1, label="Radius of the Circle"), Number(value=100, precision=0, label="Number of Points Sampled from the Circle"), Number(value=0, precision=0, label="Random Seed") ] outputs = [ Image(label="Points", type="pil"), Image(label="Points and Lines", type="pil"), Image(label="Clustering of the line parameters", type="pil"), Dataframe(label="Centroids and Counts", type="pandas") ] # Create the Gradio interface interface = gr.Interface( fn=cluster_line_params, inputs=inputs, # outputs=["numpy", "numpy", "image"], outputs=outputs, title="Line Parameter Clustering", description="Cluster line parameters with Gaussian noise", allow_flagging="never" ) # Launch the interface interface.launch()