# Python (Pyodide) on Observable running Clustergrammer2

**URL:** <https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363>\
**Category:** Show and tell\
**Created:** [July 23, 2021, 3:11am UTC](https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363 "2021-07-23T03:11:14Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![cornhundred](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cornhundred/32/1705_2.png) [@cornhundred](https://talk.observablehq.com/u/cornhundred)\
**Post date:** [July 23, 2021, 3:11am UTC](https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363/1 "2021-07-23T03:11:14Z")

</div>

Hi, I wanted to share a notebook I recently made using [Pyodide](https://observablehq.com/@gnestor/pyodide-demo) to run Python on ObservableHQ. The notebook allows users to upload their own high-dimensional data (three datasets are provided as examples), normalize their data (Z-score), perform hierarchical clustering on the rows and columns using clustergrammer2\_core (built upon scipy etc), and visualize the results as an interactive WebGL heatmap using [clustergrammer-gl](https://github.com/ismms-himc/clustergrammer-gl)

> **[Clustergrammer2 Pyodide](https://observablehq.com/@cornhundred/clustergrammer2-pyodide)**
>
> This notebook runs the Python library clustergrammer2\_core to perform unbiased hierarchical clustering of a dataset and output the data for visualization with clustergrammer-gl. Load Data from File Attachment You can upload your own data for...

 ![Screen Shot 2021-07-22 at 11.04.19 PM](https://canada1.discourse-cdn.com/flex030/uploads/observablehq/original/2X/0/0f2ff63b7df7bc6c687c0ed84c1f9cc9be713879.jpeg)

Currently, users have to upload their data using the file attachment tool in Observable and change the path to the file in the appropriate cell in order to have their data load - I’m wondering if that process can be streamlined. Also, the load time can be kind of long, but this appears to be caused by the necessary micropip installation step.

There seems to be a lot of potential for running Python code on Observable. I recently heard of Pyodide from the [Jupyter-Lite project](https://jupyterlite.readthedocs.io/en/latest/_static/lab/index.html).

---

<div class="post-metadata">

**Author:** ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)\
**Post date:** [July 23, 2021, 7:30am UTC](https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363/2 "2021-07-23T07:30:39Z")

</div>

This is amazing! thank you for sharing. Now I want to see how to load umap-learn 🙂

---

<div class="post-metadata">

**Author:** ![cornhundred](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cornhundred/32/1705_2.png) [@cornhundred](https://talk.observablehq.com/u/cornhundred)\
**Post date:** [July 23, 2021, 2:52pm UTC](https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363/3 "2021-07-23T14:52:52Z")

</div>

So far I haven’t been able to import umap from umap-learn

> **[Pyodide - UMAP](https://observablehq.com/@cornhundred/pyodide-umap)**
>
> Imports

One issue is that numba is not supported in Pyodide

> <https://github.com/pyodide/pyodide/issues/1739>
>
> Hi, I am having trouble installing and importing umap-learn in Pyodide. The link… is to an ObservableHQ notebook 
> 
> https://observablehq.com/@cornhundred/pyodide-umap
> 
> The code in the notebook is:
> 
> \`\`\`
> umap = {
>   
> // install umap-learn
> py\`
> import micropip
> micropip.install(\['umap-learn==0.5.1'\])
> import umap
> \`
>   
> var umap = py\`
> import umap
> umap\`
> 
> 
> return umap
> }
> \`\`\`
> 
> and the error is 
> 
> \`\`\`
> umap = PythonError: Traceback (most recent call last):
> File "/lib/python3.8/asyncio/futures.py", line 178, in result
> raise self.\_exception
> File "/lib/python3.8/asyncio/tasks.py", line 280, in \_\_step
> result = coro.send(None)
> File "/lib/python3.8/site-packages/pyodide/\_base.py", line 419, in eval\_code\_async
> return await CodeRunner(
> File "/lib/python3.8/site-packages/pyodide/\_base.py", line 270, in run\_async
> coro = eval(mod, self.globals, self.locals)
> File "\<exec\>", line 2, in \<module\>
> ModuleNotFoundError: No module named 'umap'
> \`\`\`

---

<div class="post-metadata">

**Author:** ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)\
**Post date:** [July 23, 2021, 7:09pm UTC](https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363/4 "2021-07-23T19:09:18Z")

</div>

Thanks! I was blocked by the same error but I didn’t know what was causing it

---

<div class="post-metadata">

**Author:** ![cornhundred](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cornhundred/32/1705_2.png) [@cornhundred](https://talk.observablehq.com/u/cornhundred)\
**Post date:** [July 23, 2021, 7:33pm UTC](https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363/5 "2021-07-23T19:33:00Z")

</div>

I wonder if there’s an older umap-learn version that does not use numba?

---

<div class="post-metadata">

**Author:** ![cornhundred](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cornhundred/32/1705_2.png) [@cornhundred](https://talk.observablehq.com/u/cornhundred)\
**Post date:** [July 26, 2021, 3:13pm UTC](https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363/6 "2021-07-26T15:13:43Z")

</div>

t-SNE (via sklearn) works on Pyodide 😀

[https://observablehq.com/d/6eb6e4c492b7d2a4](https://observablehq.com/d/6eb6e4c492b7d2a4)

I’ll update with a t-SNE/heatmap linked view later (something similar to this [https://observablehq.com/d/6eb6e4c492b7d2a4](https://observablehq.com/d/6eb6e4c492b7d2a4))

I might try this web worker UMAP.js approach later too [UMAP playground / John Alexis Guerra Gómez / Observable](https://observablehq.com/@john-guerra/umap-playground)

---

<div class="post-metadata">

**Author:** ![radames](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/radames/32/1699_2.png) [@radames](https://talk.observablehq.com/u/radames)\
**Post date:** [July 26, 2021, 7:55pm UTC](https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363/7 "2021-07-26T19:55:47Z")

</div>

hi @cornhundred, I’d be curious to see your notebook, could you please enable access? thanks

---

<div class="post-metadata">

**Author:** ![cornhundred](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cornhundred/32/1705_2.png) [@cornhundred](https://talk.observablehq.com/u/cornhundred)\
**Post date:** [July 26, 2021, 8:06pm UTC](https://talk.observablehq.com/t/python-pyodide-on-observable-running-clustergrammer2/5363/8 "2021-07-26T20:06:38Z")

</div>

> [@cornhundred](#):
>
> [Clustergrammer2 Pyodide - tSNE / Nicolas Fernandez | Observable](https://observablehq.com/d/6eb6e4c492b7d2a4)

@radames forgot to hit publish 😃
