From 76322a6b82c11cfd40c30070e4af82266d394223 Mon Sep 17 00:00:00 2001 From: clewis7 Date: Tue, 18 Feb 2025 17:50:24 -0500 Subject: [PATCH 1/7] add kmeans clustering example --- examples/machine_learning/kmeans.py | 111 ++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 examples/machine_learning/kmeans.py diff --git a/examples/machine_learning/kmeans.py b/examples/machine_learning/kmeans.py new file mode 100644 index 000000000..f26133031 --- /dev/null +++ b/examples/machine_learning/kmeans.py @@ -0,0 +1,111 @@ +""" +K-Means Clustering of MNIST Dataset +=================================== + +Example showing how you can perform K-Means clustering on the MNIST dataset. +""" + +# test_example = false +# sphinx_gallery_pygfx_docs = 'screenshot' + +import fastplotlib as fpl +import numpy as np +import random +import time +from sklearn.datasets import load_digits +from sklearn.cluster import KMeans +from sklearn.decomposition import PCA + +# load the data +mnist = load_digits() + +# get the data and labels +data = mnist['data'] # (1797, 64) +labels = mnist['target'] # (1797,) + +# visualize the first 5 digits +# NOTE: this is just to give a sense of the dataset if you are unfamiliar, +# the more interesting visualization is below :D +fig_data = fpl.Figure(shape=(1, 5), size=(900, 300)) + +for i in range(5): + # reshape each image to (8, 8) + fig_data[0, i].add_image(data[i].reshape(8,8), cmap="gray") + # add the label as a title + fig_data[0, i].set_title(f"Label: {labels[i]}") + # turn off the axes and toolbar + fig_data[0, i].axes.visible = False + fig_data[0, i].toolbar = False + +fig_data.show() + +# project the data from 64 dimensions down to the number of unique digits +n_digits = len(np.unique(labels)) # 10 + +reduced_data = PCA(n_components=n_digits).fit_transform(data) # (1797, 10) + +# performs K-Means clustering, take the best of 4 runs +kmeans = KMeans(n_clusters=n_digits, n_init=4) +# fit the lower-dimension data +kmeans.fit(reduced_data) + +# get the centroids (center of the clusters) +centroids = kmeans.cluster_centers_ + +# plot the reduced and original data +figure = fpl.Figure(shape=(1,2), size=(700, 400)) + +# set the axes to False +figure[0, 0].axes.visible = False +figure[0, 1].axes.visible = False + + +figure[0, 0].set_title(f"K-means clustering of PCA-reduced data") + +# plot the centroids +figure[0, 0].add_scatter( + data=np.vstack((centroids[:, 0], centroids[:, 1])).T, + colors="white", + sizes=15 +) +# plot the down-projected data +digit_scatter = figure[0,0].add_scatter( + data=np.vstack((reduced_data[:, 0], reduced_data[:, 1])).T, + sizes=5, + cmap="tab10", # use a qualitative cmap + cmap_transform=kmeans.labels_, # color by the predicted cluster +) + +# initial index +ix = 0 + +# plot the initial image +digit_img = figure[0, 1].add_image(data[ix].reshape(8,8), cmap="gray", name="digit") + +# change the color and size of the initial selected data point +digit_scatter.colors[ix] = "magenta" +digit_scatter.sizes[ix] = 10 + +# define event handler to update the selected data point +@digit_scatter.add_event_handler("click") +def update(ev): + # reset colors and sizes + digit_scatter.cmap = "tab10" + digit_scatter.sizes = 5 + + # update with new seleciton + ix = ev.pick_info["vertex_index"] + + digit_scatter.colors[ix] = "magenta" + digit_scatter.sizes[ix] = 10 + + # update digit fig + figure[0, 1]["digit"].data = data[ix].reshape(8, 8) + +figure.show() + +# NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively +# please see our docs for using fastplotlib interactively in ipython and jupyter +if __name__ == "__main__": + print(__doc__) + fpl.loop.run() \ No newline at end of file From be9a31148ec4e04754f7a77e571f6de59a03593f Mon Sep 17 00:00:00 2001 From: clewis7 Date: Tue, 18 Feb 2025 18:29:04 -0500 Subject: [PATCH 2/7] update conf --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 66b3c9317..b8d3e36cb 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -88,7 +88,7 @@ templates_path = ["_templates"] exclude_patterns = [] -napoleon_custom_sections = ["Features"] +#napoleon_custom_sections = ("Features") # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output From 7c1305038a278c1fbd3568aa4a64e83bad1ce0ce Mon Sep 17 00:00:00 2001 From: clewis7 Date: Wed, 19 Feb 2025 08:54:07 -0500 Subject: [PATCH 3/7] switch to tool tip --- examples/machine_learning/kmeans.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/machine_learning/kmeans.py b/examples/machine_learning/kmeans.py index f26133031..913d33da4 100644 --- a/examples/machine_learning/kmeans.py +++ b/examples/machine_learning/kmeans.py @@ -28,14 +28,15 @@ # the more interesting visualization is below :D fig_data = fpl.Figure(shape=(1, 5), size=(900, 300)) -for i in range(5): +# iterate through each subplot +for i, subplot in enumerate(fig_data): # reshape each image to (8, 8) - fig_data[0, i].add_image(data[i].reshape(8,8), cmap="gray") + subplot.add_image(data[i].reshape(8,8), cmap="gray") # add the label as a title - fig_data[0, i].set_title(f"Label: {labels[i]}") + subplot.set_title(f"Label: {labels[i]}") # turn off the axes and toolbar - fig_data[0, i].axes.visible = False - fig_data[0, i].toolbar = False + subplot.axes.visible = False + subplot.toolbar = False fig_data.show() @@ -87,7 +88,7 @@ digit_scatter.sizes[ix] = 10 # define event handler to update the selected data point -@digit_scatter.add_event_handler("click") +@digit_scatter.add_event_handler("pointer_enter") def update(ev): # reset colors and sizes digit_scatter.cmap = "tab10" From 713f1022844886429edfb170c318410728ecebd6 Mon Sep 17 00:00:00 2001 From: clewis7 Date: Fri, 21 Feb 2025 10:07:56 -0500 Subject: [PATCH 4/7] switch to linear interp and 3D camera for kmeans --- examples/machine_learning/kmeans.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/machine_learning/kmeans.py b/examples/machine_learning/kmeans.py index 913d33da4..f6ab416c5 100644 --- a/examples/machine_learning/kmeans.py +++ b/examples/machine_learning/kmeans.py @@ -10,8 +10,6 @@ import fastplotlib as fpl import numpy as np -import random -import time from sklearn.datasets import load_digits from sklearn.cluster import KMeans from sklearn.decomposition import PCA @@ -31,7 +29,7 @@ # iterate through each subplot for i, subplot in enumerate(fig_data): # reshape each image to (8, 8) - subplot.add_image(data[i].reshape(8,8), cmap="gray") + subplot.add_image(data[i].reshape(8,8), cmap="gray", interpolation="linear") # add the label as a title subplot.set_title(f"Label: {labels[i]}") # turn off the axes and toolbar @@ -53,25 +51,29 @@ # get the centroids (center of the clusters) centroids = kmeans.cluster_centers_ -# plot the reduced and original data -figure = fpl.Figure(shape=(1,2), size=(700, 400)) +# plot the kmeans result and corresponding original image +figure = fpl.Figure( + shape=(1,2), + size=(700, 400), + cameras=["3d", "2d"], + controller_types=[["fly", "panzoom"]] +) # set the axes to False figure[0, 0].axes.visible = False figure[0, 1].axes.visible = False - figure[0, 0].set_title(f"K-means clustering of PCA-reduced data") # plot the centroids figure[0, 0].add_scatter( - data=np.vstack((centroids[:, 0], centroids[:, 1])).T, + data=np.vstack((centroids[:, 0], centroids[:, 1], centroids[:, 2])).T, colors="white", sizes=15 ) # plot the down-projected data digit_scatter = figure[0,0].add_scatter( - data=np.vstack((reduced_data[:, 0], reduced_data[:, 1])).T, + data=np.vstack((reduced_data[:, 0], reduced_data[:, 1], reduced_data[:, 2])).T, sizes=5, cmap="tab10", # use a qualitative cmap cmap_transform=kmeans.labels_, # color by the predicted cluster @@ -81,7 +83,7 @@ ix = 0 # plot the initial image -digit_img = figure[0, 1].add_image(data[ix].reshape(8,8), cmap="gray", name="digit") +digit_img = figure[0, 1].add_image(data[ix].reshape(8,8), cmap="gray", name="digit", interpolation="linear") # change the color and size of the initial selected data point digit_scatter.colors[ix] = "magenta" From d073c660db10cb6a098d0c60ae67b1187719666e Mon Sep 17 00:00:00 2001 From: Kushal Kolar Date: Fri, 21 Feb 2025 23:44:45 -0500 Subject: [PATCH 5/7] increase timeout for deploy docs connection --- .github/workflows/docs-deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index fe267291a..abd030296 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -98,6 +98,7 @@ jobs: server: ${{ secrets.DOCS_SERVER }} username: ${{ secrets.DOCS_USERNAME }} password: ${{ secrets.DOCS_PASSWORD }} + timeout: 190000 local-dir: docs/build/html/ server-dir: ./ # deploy to the root dir exclude: | # don't delete the /ver/ dir From e9481454b64eb77b38ed10b3cbda9993015b0029 Mon Sep 17 00:00:00 2001 From: Kushal Kolar Date: Sat, 22 Feb 2025 00:38:13 -0500 Subject: [PATCH 6/7] increase log level --- .github/workflows/docs-deploy.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index abd030296..f854ed70d 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -98,7 +98,8 @@ jobs: server: ${{ secrets.DOCS_SERVER }} username: ${{ secrets.DOCS_USERNAME }} password: ${{ secrets.DOCS_PASSWORD }} - timeout: 190000 + log-level: verbose + timeout: 60000 local-dir: docs/build/html/ server-dir: ./ # deploy to the root dir exclude: | # don't delete the /ver/ dir From dc2bb2cd101a7063a48b5f33946cf568a50dab1c Mon Sep 17 00:00:00 2001 From: clewis7 Date: Mon, 24 Feb 2025 11:15:47 -0500 Subject: [PATCH 7/7] requested changes --- docs/source/conf.py | 2 -- examples/machine_learning/kmeans.py | 11 ++++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index b8d3e36cb..76298d4ff 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -88,8 +88,6 @@ templates_path = ["_templates"] exclude_patterns = [] -#napoleon_custom_sections = ("Features") - # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output diff --git a/examples/machine_learning/kmeans.py b/examples/machine_learning/kmeans.py index f6ab416c5..620fa15fb 100644 --- a/examples/machine_learning/kmeans.py +++ b/examples/machine_learning/kmeans.py @@ -67,13 +67,13 @@ # plot the centroids figure[0, 0].add_scatter( - data=np.vstack((centroids[:, 0], centroids[:, 1], centroids[:, 2])).T, + data=np.vstack([centroids[:, 0], centroids[:, 1], centroids[:, 2]]).T, colors="white", sizes=15 ) # plot the down-projected data digit_scatter = figure[0,0].add_scatter( - data=np.vstack((reduced_data[:, 0], reduced_data[:, 1], reduced_data[:, 2])).T, + data=np.vstack([reduced_data[:, 0], reduced_data[:, 1], reduced_data[:, 2]]).T, sizes=5, cmap="tab10", # use a qualitative cmap cmap_transform=kmeans.labels_, # color by the predicted cluster @@ -83,7 +83,12 @@ ix = 0 # plot the initial image -digit_img = figure[0, 1].add_image(data[ix].reshape(8,8), cmap="gray", name="digit", interpolation="linear") +digit_img = figure[0, 1].add_image( + data=data[ix].reshape(8,8), + cmap="gray", + name="digit", + interpolation="linear" +) # change the color and size of the initial selected data point digit_scatter.colors[ix] = "magenta"