{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "7f459b95-7bd3-4053-8e98-196bae61b14e", "metadata": {}, "outputs": [], "source": [ ":dep ndarray = \"0.15.6\"" ] }, { "cell_type": "code", "execution_count": 2, "id": "0309c3d7-c00f-4283-9208-44bcd92e9465", "metadata": {}, "outputs": [], "source": [ ":dep linfa = { version = \"0.6.1\" }\n", "// clustering is a separate crate\n", ":dep linfa-clustering = { version = \"0.6.1\" }" ] }, { "cell_type": "code", "execution_count": 4, "id": "00bd5c64-87b9-429f-85d0-8e4b8482d835", "metadata": {}, "outputs": [], "source": [ "// apt install libfontconfig-dev on Ubuntu 22.04 LTS\n", ":dep plotters = { version = \"^0.3.4\", default_features = false, features = [\"evcxr\", \"all_series\"] }\n", "extern crate plotters;\n", "// Import all the plotters prelude functions\n", "use plotters::prelude::*;" ] }, { "cell_type": "code", "execution_count": 5, "id": "8b9ff0e5-7af6-4b89-b9b6-cf4ab2d3219c", "metadata": {}, "outputs": [], "source": [ ":dep rand = \"0.8.5\"" ] }, { "cell_type": "code", "execution_count": 6, "id": "64dba201-38f7-4c40-95fc-fc958a66f499", "metadata": {}, "outputs": [], "source": [ "// Import the linfa prelude and KMeans algorithm\n", "use linfa::prelude::*;\n", "use linfa_clustering::Dbscan;\n", "// We'll build our dataset on our own using ndarray and rand\n", "use ndarray::prelude::*;\n", "// Import the plotters crate to create the scatter plot\n", "use plotters::prelude::*;" ] }, { "cell_type": "code", "execution_count": 7, "id": "a0ee40ad-529a-4d2b-accd-7d5209456dec", "metadata": {}, "outputs": [], "source": [ "use rand::prelude::*;\n", "use std::f32;" ] }, { "cell_type": "code", "execution_count": 8, "id": "df831b7b-b5e7-4dea-8573-ba47172e858b", "metadata": {}, "outputs": [], "source": [ "// Creates random points contained in an approximately square area\n", "pub fn create_square(center_point: [f32; 2], edge_length: f32, num_points: usize) -> Array2 {\n", " // We\n", " let mut data: Array2 = Array2::zeros((num_points, 2));\n", " let mut rng = rand::thread_rng();\n", " for i in 0..num_points {\n", " let x = rng.gen_range(-edge_length * 0.5..edge_length * 0.5); // generates a float between 0 and 1\n", " let y = rng.gen_range(-edge_length * 0.5..edge_length * 0.5);\n", " data[[i, 0]] = center_point[0] + x;\n", " data[[i, 1]] = center_point[1] + y;\n", " }\n", "\n", " data\n", "}" ] }, { "cell_type": "code", "execution_count": 9, "id": "47387ec3-8cea-4be4-bfe8-94a8691af51a", "metadata": {}, "outputs": [], "source": [ "// Creates a circle of random points\n", "pub fn create_circle(center_point: [f32; 2], radius: f32, num_points: usize) -> Array2 {\n", " let mut data: Array2 = Array2::zeros((num_points, 2));\n", " let mut rng = rand::thread_rng();\n", " for i in 0..num_points {\n", " let theta = rng.gen_range(0.0..2.0 * f32::consts::PI);\n", " let r = rng.gen_range(0.0..radius);\n", " let x = r * f32::cos(theta);\n", " let y = r * f32::sin(theta);\n", "\n", " data[[i, 0]] = center_point[0] + x;\n", " data[[i, 1]] = center_point[1] + y;\n", " }\n", "\n", " data\n", "}" ] }, { "cell_type": "code", "execution_count": 10, "id": "5a5662b4-861d-482a-b2dc-2717a58506f5", "metadata": {}, "outputs": [], "source": [ "// Creates a line y = m*x + b with some noise\n", "pub fn create_line(m: f64, b: f64, num_points: usize, min_max: [f64; 2]) -> Array2 {\n", " let mut data: Array2 = Array2::zeros((num_points, 2));\n", "\n", " let mut rng = rand::thread_rng();\n", " for i in 0..num_points {\n", " let var_y = rng.gen_range(-0.5..0.5f64);\n", " data[[i, 0]] = rng.gen_range(min_max[0]..min_max[1]);\n", " data[[i, 1]] = (m * data[[i, 0]]) + b + var_y;\n", " }\n", "\n", " data\n", "}" ] }, { "cell_type": "code", "execution_count": 11, "id": "6e4c6c49-dbfc-40a4-b40f-cf011592d329", "metadata": {}, "outputs": [], "source": [ "// Creates a quadratic y = m*x^2 + b with some noise\n", "pub fn create_curve(m: f64, pow: f64, b: f64, num_points: usize, min_max: [f64; 2]) -> Array2 {\n", " let mut data: Array2 = Array2::zeros((num_points, 2));\n", "\n", " let mut rng = rand::thread_rng();\n", " for i in 0..num_points {\n", " let var_y = rng.gen_range(-0.5..0.5f64);\n", " data[[i, 0]] = rng.gen_range(min_max[0]..min_max[1]);\n", " data[[i, 1]] = (m * data[[i, 0]].powf(pow)) + b + var_y;\n", " }\n", "\n", " data\n", "}" ] }, { "cell_type": "code", "execution_count": 12, "id": "5fa62785-1de1-4569-9f1f-86c69f020f92", "metadata": {}, "outputs": [], "source": [ "// Creates a hollow circle of random points with a specified inner and outer diameter\n", "pub fn create_hollow_circle(\n", " center_point: [f32; 2],\n", " radius: [f32; 2],\n", " num_points: usize,\n", ") -> Array2 {\n", " assert!(radius[0] < radius[1]);\n", " let mut data: Array2 = Array2::zeros((num_points, 2));\n", " let mut rng = rand::thread_rng();\n", " for i in 0..num_points {\n", " let theta = rng.gen_range(0.0..2.0 * f32::consts::PI);\n", " let r = rng.gen_range(radius[0]..radius[1]);\n", " let x = r * f32::cos(theta);\n", " let y = r * f32::sin(theta);\n", "\n", " data[[i, 0]] = center_point[0] + x;\n", " data[[i, 1]] = center_point[1] + y;\n", " }\n", "\n", " data\n", "}" ] }, { "cell_type": "code", "execution_count": 13, "id": "fe246cc7-374c-43a0-88cb-16fe6731d57b", "metadata": {}, "outputs": [], "source": [ "// Check the array has the correct shape for plotting (Two-dimensional, with 2 columns)\n", "pub fn check_array_for_plotting(arr: &Array2) -> bool {\n", " if (arr.shape().len() != 2) || (arr.shape()[1] != 2) {\n", " panic!(\n", " \"Array shape of {:?} is incorrect for 2D plotting!\",\n", " arr.shape()\n", " );\n", " // false\n", " } else {\n", " true\n", " }\n", "}" ] }, { "cell_type": "code", "execution_count": 14, "id": "3398338c-2b27-49f4-9d46-4cdeab07d879", "metadata": {}, "outputs": [], "source": [ " // The goal is to be able to find each of these as distinct, and exclude some of the noise\n", "let circle: Array2 = create_circle([5.0, 5.0], 1.0, 100); // Cluster 0\n", "let donut_1: Array2 = create_hollow_circle([5.0, 5.0], [2.0, 3.0], 400); // Cluster 1\n", "let donut_2: Array2 = create_hollow_circle([5.0, 5.0], [4.5, 4.75], 1000); // Cluster 2\n", "let noise: Array2 = create_square([5.0, 5.0], 10.0, 100); // Random noise\n", "\n", "\n", "let data = ndarray::concatenate(\n", " Axis(0),\n", " &[circle.view(), donut_1.view(), donut_2.view(), noise.view()],\n", " )\n", " .expect(\"An error occurred while stacking the dataset\");\n", "\n" ] }, { "cell_type": "code", "execution_count": 19, "id": "1fbebfd2-7c5f-4b24-88bc-06b850a5e4ac", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "DBSCAN\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "0.0\n", "\n", "\n", "\n", "1.0\n", "\n", "\n", "\n", "2.0\n", "\n", "\n", "\n", "3.0\n", "\n", "\n", "\n", "4.0\n", "\n", "\n", "\n", "5.0\n", "\n", "\n", "\n", "6.0\n", "\n", "\n", "\n", "7.0\n", "\n", "\n", "\n", "8.0\n", "\n", "\n", "\n", "9.0\n", "\n", "\n", "\n", "10.0\n", "\n", "\n", "\n", "\n", "0.0\n", "\n", "\n", "\n", "1.0\n", "\n", "\n", "\n", "2.0\n", "\n", "\n", "\n", "3.0\n", "\n", "\n", "\n", "4.0\n", "\n", "\n", "\n", "5.0\n", "\n", "\n", "\n", "6.0\n", "\n", "\n", "\n", "7.0\n", "\n", "\n", "\n", "8.0\n", "\n", "\n", "\n", "9.0\n", "\n", "\n", "\n", "10.0\n", "\n", "\n", "\n", "\n", "0.0\n", "\n", "\n", "\n", "1.0\n", "\n", "\n", "\n", "2.0\n", "\n", "\n", "\n", "3.0\n", "\n", "\n", "\n", "4.0\n", "\n", "\n", "\n", "5.0\n", "\n", "\n", "\n", "6.0\n", "\n", "\n", "\n", "7.0\n", "\n", "\n", "\n", "8.0\n", "\n", "\n", "\n", "9.0\n", "\n", "\n", "\n", "10.0\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "evcxr_figure((640, 240), |root| {\n", " \n", " root.fill(&WHITE).unwrap();\n", "\n", " let x_lim = 0.0..10.0f32;\n", " let y_lim = 0.0..10.0f32;\n", "\n", " let mut ctx = ChartBuilder::on(&root)\n", " .set_label_area_size(LabelAreaPosition::Left, 40) // Put in some margins\n", " .set_label_area_size(LabelAreaPosition::Right, 40)\n", " .set_label_area_size(LabelAreaPosition::Bottom, 40)\n", " .caption(\"DBSCAN\", (\"sans-serif\", 25)) // Set a caption and font\n", " .build_cartesian_2d(x_lim, y_lim)\n", " .expect(\"Couldn't build our ChartBuilder\");\n", " \n", " let circle: Array2 = create_circle([5.0, 5.0], 1.0, 100); // Cluster 0\n", " let donut_1: Array2 = create_hollow_circle([5.0, 5.0], [2.0, 3.0], 400); // Cluster 1\n", " let donut_2: Array2 = create_hollow_circle([5.0, 5.0], [4.5, 4.75], 1000); // Cluster 2\n", " let noise: Array2 = create_square([5.0, 5.0], 10.0, 100); // Random noise\n", "\n", " let data = ndarray::concatenate(\n", " Axis(0),\n", " &[circle.view(), donut_1.view(), donut_2.view(), noise.view()],\n", " )\n", " .expect(\"An error occurred while stacking the dataset\");\n", "\n", " // Compared to linfa's KMeans algorithm, the DBSCAN implementation can operate\n", " // directly on an ndarray `Array2` data structure, so there's no need to convert it\n", " // into the linfa-native `Dataset` first.\n", " let min_points = 20;\n", " let clusters = Dbscan::params(min_points)\n", " .tolerance(0.6)\n", " .transform(&data)\n", " .unwrap();\n", " // println!(\"{:#?}\", clusters);\n", "\n", "\n", " let x_lim = 0.0..10.0f32;\n", " let y_lim = 0.0..10.0f32;\n", " \n", "\n", " ctx.configure_mesh().draw().unwrap();\n", " let root_area = ctx.plotting_area();\n", " // ANCHOR_END: configure_chart\n", "\n", " // ANCHOR: run_check_for_plotting;\n", " // check_array_for_plotting(dataset: &Array2) -> bool {}\n", " check_array_for_plotting(&circle); // Panics if that's not true\n", " // ANCHOR_END: run_check_for_plotting\n", "\n", " // ANCHOR: plot_points\n", " for i in 0..data.shape()[0] {\n", " let coordinates = data.slice(s![i, 0..2]);\n", "\n", " let point = match clusters[i] {\n", " Some(0) => Circle::new(\n", " (coordinates[0], coordinates[1]),\n", " 3,\n", " ShapeStyle::from(&RED).filled(),\n", " ),\n", " Some(1) => Circle::new(\n", " (coordinates[0], coordinates[1]),\n", " 3,\n", " ShapeStyle::from(&GREEN).filled(),\n", " ),\n", " Some(2) => Circle::new(\n", " (coordinates[0], coordinates[1]),\n", " 3,\n", " ShapeStyle::from(&BLUE).filled(),\n", " ),\n", " // Making sure our pattern-matching is exhaustive\n", " // Note that we can define a custom color using RGB\n", " _ => Circle::new(\n", " (coordinates[0], coordinates[1]),\n", " 3,\n", " ShapeStyle::from(&RGBColor(255, 255, 255)).filled(),\n", " ),\n", " };\n", "\n", " root_area\n", " .draw(&point)\n", " .expect(\"An error occurred while drawing the point!\");\n", " }\n", " \n", " Ok(())\n", "}).style(\"width:90%\")" ] }, { "cell_type": "code", "execution_count": 16, "id": "a757a5d6-4105-4c76-a5bb-6ba1af81f3a6", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "Hello Plotters Chart Context!\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "extern crate plotters;\n", "use plotters::prelude::*;\n", "evcxr_figure((640, 240), |root| {\n", " // The following code will create a chart context\n", " let mut chart = ChartBuilder::on(&root)\n", " .caption(\"Hello Plotters Chart Context!\", (\"Arial\", 20).into_font())\n", " .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;\n", " // Then we can draw a series on it!\n", " chart.draw_series((1..10).map(|x|{\n", " let x = x as f32/10.0;\n", " Circle::new((x,x), 5, &RED)\n", " }))?;\n", " Ok(())\n", "}).style(\"width:60%\")" ] }, { "cell_type": "code", "execution_count": null, "id": "0ec6a01e-6c06-4d0d-b738-f46a7fe42fce", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Rust", "language": "rust", "name": "rust" }, "language_info": { "codemirror_mode": "rust", "file_extension": ".rs", "mimetype": "text/rust", "name": "Rust", "pygment_lexer": "rust", "version": "" } }, "nbformat": 4, "nbformat_minor": 5 }