From d5b7fe1bd64cbfbc27bb2d18eb247cdbc9bf327c Mon Sep 17 00:00:00 2001 From: Marius Date: Thu, 11 May 2023 15:10:46 +0000 Subject: [PATCH] DBSCAN code adaption --- DBSCAN.html | 15525 +++++++++++++++++++++++++++++++++++++++++++++++++ DBSCAN.ipynb | 2386 ++++++++ 2 files changed, 17911 insertions(+) create mode 100644 DBSCAN.html create mode 100644 DBSCAN.ipynb diff --git a/DBSCAN.html b/DBSCAN.html new file mode 100644 index 0000000..fd1acb4 --- /dev/null +++ b/DBSCAN.html @@ -0,0 +1,15525 @@ +None + + + + +DBSCAN + + + + + + + + + + + + + +
+
+ +
+
+
In [ ]:
+
+
+
:dep ndarray = "0.15.6"
+
+ +
+
+
+ +
+
+
+
In [2]:
+
+
+
:dep linfa = { version = "0.6.1" }
+// clustering is a separate crate
+:dep linfa-clustering = { version = "0.6.1" }
+
+ +
+
+
+ +
+
+
+
In [4]:
+
+
+
// apt install libfontconfig-dev on Ubuntu 22.04 LTS
+:dep plotters = { version = "^0.3.4", default_features = false, features = ["evcxr", "all_series"] }
+extern crate plotters;
+// Import all the plotters prelude functions
+use plotters::prelude::*;
+
+ +
+
+
+ +
+
+
+
In [5]:
+
+
+
:dep rand = "0.8.5"
+
+ +
+
+
+ +
+
+
+
In [6]:
+
+
+
// Import the linfa prelude and KMeans algorithm
+use linfa::prelude::*;
+use linfa_clustering::Dbscan;
+// We'll build our dataset on our own using ndarray and rand
+use ndarray::prelude::*;
+// Import the plotters crate to create the scatter plot
+use plotters::prelude::*;
+
+ +
+
+
+ +
+
+
+
In [7]:
+
+
+
use rand::prelude::*;
+use std::f32;
+
+ +
+
+
+ +
+
+
+
In [8]:
+
+
+
// Creates random points contained in an approximately square area
+pub fn create_square(center_point: [f32; 2], edge_length: f32, num_points: usize) -> Array2<f32> {
+    // We
+    let mut data: Array2<f32> = Array2::zeros((num_points, 2));
+    let mut rng = rand::thread_rng();
+    for i in 0..num_points {
+        let x = rng.gen_range(-edge_length * 0.5..edge_length * 0.5); // generates a float between 0 and 1
+        let y = rng.gen_range(-edge_length * 0.5..edge_length * 0.5);
+        data[[i, 0]] = center_point[0] + x;
+        data[[i, 1]] = center_point[1] + y;
+    }
+
+    data
+}
+
+ +
+
+
+ +
+
+
+
In [9]:
+
+
+
// Creates a circle of random points
+pub fn create_circle(center_point: [f32; 2], radius: f32, num_points: usize) -> Array2<f32> {
+    let mut data: Array2<f32> = Array2::zeros((num_points, 2));
+    let mut rng = rand::thread_rng();
+    for i in 0..num_points {
+        let theta = rng.gen_range(0.0..2.0 * f32::consts::PI);
+        let r = rng.gen_range(0.0..radius);
+        let x = r * f32::cos(theta);
+        let y = r * f32::sin(theta);
+
+        data[[i, 0]] = center_point[0] + x;
+        data[[i, 1]] = center_point[1] + y;
+    }
+
+    data
+}
+
+ +
+
+
+ +
+
+
+
In [10]:
+
+
+
// Creates a line y = m*x + b with some noise
+pub fn create_line(m: f64, b: f64, num_points: usize, min_max: [f64; 2]) -> Array2<f64> {
+    let mut data: Array2<f64> = Array2::zeros((num_points, 2));
+
+    let mut rng = rand::thread_rng();
+    for i in 0..num_points {
+        let var_y = rng.gen_range(-0.5..0.5f64);
+        data[[i, 0]] = rng.gen_range(min_max[0]..min_max[1]);
+        data[[i, 1]] = (m * data[[i, 0]]) + b + var_y;
+    }
+
+    data
+}
+
+ +
+
+
+ +
+
+
+
In [11]:
+
+
+
// Creates a quadratic y = m*x^2 + b with some noise
+pub fn create_curve(m: f64, pow: f64, b: f64, num_points: usize, min_max: [f64; 2]) -> Array2<f64> {
+    let mut data: Array2<f64> = Array2::zeros((num_points, 2));
+
+    let mut rng = rand::thread_rng();
+    for i in 0..num_points {
+        let var_y = rng.gen_range(-0.5..0.5f64);
+        data[[i, 0]] = rng.gen_range(min_max[0]..min_max[1]);
+        data[[i, 1]] = (m * data[[i, 0]].powf(pow)) + b + var_y;
+    }
+
+    data
+}
+
+ +
+
+
+ +
+
+
+
In [12]:
+
+
+
// Creates a hollow circle of random points with a specified inner and outer diameter
+pub fn create_hollow_circle(
+    center_point: [f32; 2],
+    radius: [f32; 2],
+    num_points: usize,
+) -> Array2<f32> {
+    assert!(radius[0] < radius[1]);
+    let mut data: Array2<f32> = Array2::zeros((num_points, 2));
+    let mut rng = rand::thread_rng();
+    for i in 0..num_points {
+        let theta = rng.gen_range(0.0..2.0 * f32::consts::PI);
+        let r = rng.gen_range(radius[0]..radius[1]);
+        let x = r * f32::cos(theta);
+        let y = r * f32::sin(theta);
+
+        data[[i, 0]] = center_point[0] + x;
+        data[[i, 1]] = center_point[1] + y;
+    }
+
+    data
+}
+
+ +
+
+
+ +
+
+
+
In [13]:
+
+
+
// Check the array has the correct shape for plotting (Two-dimensional, with 2 columns)
+pub fn check_array_for_plotting(arr: &Array2<f32>) -> bool {
+    if (arr.shape().len() != 2) || (arr.shape()[1] != 2) {
+        panic!(
+            "Array shape of {:?} is incorrect for 2D plotting!",
+            arr.shape()
+        );
+        // false
+    } else {
+        true
+    }
+}
+
+ +
+
+
+ +
+
+
+
In [14]:
+
+
+
// The goal is to be able to find each of these as distinct, and exclude some of the noise
+let circle: Array2<f32> = create_circle([5.0, 5.0], 1.0, 100); // Cluster 0
+let donut_1: Array2<f32> = create_hollow_circle([5.0, 5.0], [2.0, 3.0], 400); // Cluster 1
+let donut_2: Array2<f32> = create_hollow_circle([5.0, 5.0], [4.5, 4.75], 1000); // Cluster 2
+let noise: Array2<f32> = create_square([5.0, 5.0], 10.0, 100); // Random noise
+
+
+let data = ndarray::concatenate(
+        Axis(0),
+        &[circle.view(), donut_1.view(), donut_2.view(), noise.view()],
+    )
+    .expect("An error occurred while stacking the dataset");
+
+ +
+
+
+ +
+
+
+
In [19]:
+
+
+
evcxr_figure((640, 240), |root| {
+    
+    root.fill(&WHITE).unwrap();
+
+    let x_lim = 0.0..10.0f32;
+    let y_lim = 0.0..10.0f32;
+
+    let mut ctx = ChartBuilder::on(&root)
+        .set_label_area_size(LabelAreaPosition::Left, 40) // Put in some margins
+        .set_label_area_size(LabelAreaPosition::Right, 40)
+        .set_label_area_size(LabelAreaPosition::Bottom, 40)
+        .caption("DBSCAN", ("sans-serif", 25)) // Set a caption and font
+        .build_cartesian_2d(x_lim, y_lim)
+        .expect("Couldn't build our ChartBuilder");
+    
+    let circle: Array2<f32> = create_circle([5.0, 5.0], 1.0, 100); // Cluster 0
+    let donut_1: Array2<f32> = create_hollow_circle([5.0, 5.0], [2.0, 3.0], 400); // Cluster 1
+    let donut_2: Array2<f32> = create_hollow_circle([5.0, 5.0], [4.5, 4.75], 1000); // Cluster 2
+    let noise: Array2<f32> = create_square([5.0, 5.0], 10.0, 100); // Random noise
+
+    let data = ndarray::concatenate(
+        Axis(0),
+        &[circle.view(), donut_1.view(), donut_2.view(), noise.view()],
+    )
+    .expect("An error occurred while stacking the dataset");
+
+    // Compared to linfa's KMeans algorithm, the DBSCAN implementation can operate
+    // directly on an ndarray `Array2` data structure, so there's no need to convert it
+    // into the linfa-native `Dataset` first.
+    let min_points = 20;
+    let clusters = Dbscan::params(min_points)
+        .tolerance(0.6)
+        .transform(&data)
+        .unwrap();
+    // println!("{:#?}", clusters);
+
+
+    let x_lim = 0.0..10.0f32;
+    let y_lim = 0.0..10.0f32;
+    
+
+    ctx.configure_mesh().draw().unwrap();
+    let root_area = ctx.plotting_area();
+    // ANCHOR_END: configure_chart
+
+    // ANCHOR: run_check_for_plotting;
+    // check_array_for_plotting(dataset: &Array2<f32>) -> bool {}
+    check_array_for_plotting(&circle); // Panics if that's not true
+                                       // ANCHOR_END: run_check_for_plotting
+
+    // ANCHOR: plot_points
+    for i in 0..data.shape()[0] {
+        let coordinates = data.slice(s![i, 0..2]);
+
+        let point = match clusters[i] {
+            Some(0) => Circle::new(
+                (coordinates[0], coordinates[1]),
+                3,
+                ShapeStyle::from(&RED).filled(),
+            ),
+            Some(1) => Circle::new(
+                (coordinates[0], coordinates[1]),
+                3,
+                ShapeStyle::from(&GREEN).filled(),
+            ),
+            Some(2) => Circle::new(
+                (coordinates[0], coordinates[1]),
+                3,
+                ShapeStyle::from(&BLUE).filled(),
+            ),
+            // Making sure our pattern-matching is exhaustive
+            // Note that we can define a custom color using RGB
+            _ => Circle::new(
+                (coordinates[0], coordinates[1]),
+                3,
+                ShapeStyle::from(&RGBColor(255, 255, 255)).filled(),
+            ),
+        };
+
+        root_area
+            .draw(&point)
+            .expect("An error occurred while drawing the point!");
+    }
+    
+    Ok(())
+}).style("width:90%")
+
+ +
+
+
+ +
+
+ + +
+ +
Out[19]:
+ + + +
+ + +DBSCAN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0.0 + + + +1.0 + + + +2.0 + + + +3.0 + + + +4.0 + + + +5.0 + + + +6.0 + + + +7.0 + + + +8.0 + + + +9.0 + + + +10.0 + + + + +0.0 + + + +1.0 + + + +2.0 + + + +3.0 + + + +4.0 + + + +5.0 + + + +6.0 + + + +7.0 + + + +8.0 + + + +9.0 + + + +10.0 + + + + +0.0 + + + +1.0 + + + +2.0 + + + +3.0 + + + +4.0 + + + +5.0 + + + +6.0 + + + +7.0 + + + +8.0 + + + +9.0 + + + +10.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
In [16]:
+
+
+
extern crate plotters;
+use plotters::prelude::*;
+evcxr_figure((640, 240), |root| {
+    // The following code will create a chart context
+    let mut chart = ChartBuilder::on(&root)
+        .caption("Hello Plotters Chart Context!", ("Arial", 20).into_font())
+        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;
+    // Then we can draw a series on it!
+    chart.draw_series((1..10).map(|x|{
+        let x = x as f32/10.0;
+        Circle::new((x,x), 5, &RED)
+    }))?;
+    Ok(())
+}).style("width:60%")
+
+ +
+
+
+ +
+
+ + +
+ +
Out[16]:
+ + + +
+ +Hello Plotters Chart Context! + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+
+
In [ ]:
+
+
+

+
+ +
+
+
+ +
+
+
+ + + + + + + + + diff --git a/DBSCAN.ipynb b/DBSCAN.ipynb new file mode 100644 index 0000000..07e3c64 --- /dev/null +++ b/DBSCAN.ipynb @@ -0,0 +1,2386 @@ +{ + "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 +}