jupyter-scatter


Namejupyter-scatter JSON
Version 0.19.1 PyPI version JSON
download
home_pageNone
SummaryAn interactive scatter plot widget for Jupyter Notebook, Lab, and Google Colab that can handle millions of points and supports view linking
upload_time2024-09-30 01:08:13
maintainerNone
docs_urlNone
authorNone
requires_pythonNone
licenseApache-2.0
keywords ipython ipywidgets jupyter jupyterlab jupyterlab-extension scatter scatter plot widgets
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <h1 align="center">
  <img src="https://jupyter-scatter.dev/images/logo-dark.svg" height="24"></img> Jupyter Scatter
</h1>

<div align="center">
  
  [![pypi version](https://img.shields.io/pypi/v/jupyter-scatter.svg?color=1a8cff&style=flat-square)](https://pypi.org/project/jupyter-scatter/)
  [![build status](https://img.shields.io/github/actions/workflow/status/flekschas/jupyter-scatter/ci.yml?branch=main&color=1a8cff&style=flat-square)](https://github.com/flekschas/jupyter-scatter/actions/workflows/ci.yml)
  [![API docs](https://img.shields.io/badge/API-docs-1a8cff.svg?style=flat-square)](https://jupyter-scatter.dev/api)
  [![notebook examples](https://img.shields.io/badge/notebook-examples-1a8cff.svg?style=flat-square)](notebooks/get-started.ipynb)
  [![tutorial](https://img.shields.io/badge/SciPy_'23-tutorial-1a8cff.svg?style=flat-square)](https://github.com/flekschas/jupyter-scatter-tutorial)
  [![DOI](https://img.shields.io/badge/JOSS-10.21105/joss.07059-1a8cff.svg?style=flat-square)](https://doi.org/10.21105/joss.07059)
  
</div>

<div align="center">
  
  <strong>An interactive scatter plot widget for Jupyter Notebook, Lab, and Google Colab</strong><br/>that can handle [millions of points](#visualize-millions-of-data-points) and supports [view linking](#linking-scatter-plots).
  
</div>

<br/>

<div align="center">
  
  ![Demo](https://user-images.githubusercontent.com/932103/223292112-c9ca18b9-bc6b-4c3b-94ac-984960e8f717.gif)
  
</div>

**Features?**

- ๐Ÿ–ฑ๏ธ **Interactive**: Pan, zoom, and select data points interactively with your mouse or through the Python API.
- ๐Ÿš€ **Scalable**: Plot up to several millions data points smoothly thanks to WebGL rendering.
- ๐Ÿ”— **Interlinked**: Synchronize the view, hover, and selection across multiple scatter plot instances.
- โœจ **Effective Defaults**: Rely on Jupyter Scatter to choose perceptually effective point colors and opacity by default.
- ๐Ÿ“š **Friendly API:** Enjoy a readable API that integrates deeply with Pandas DataFrames.
- ๐Ÿ› ๏ธ **Integratable**: Use Jupyter Scatter in your own widgets by observing its traitlets.

**Why?**

Imagine trying to explore a dataset of millions of data points as a 2D scatter. Besides plotting, the exploration typically involves three things: First, we want to interactively adjust the view (e.g., via panning & zooming) and the visual point encoding (e.g., the point color, opacity, or size). Second, we want to be able to select and highlight data points. And third, we want to compare multiple datasets or views of the same dataset (e.g., via synchronized interactions). The goal of jupyter-scatter is to support all three requirements and scale to millions of points.

**How?**

Internally, Jupyter Scatter uses [regl-scatterplot](https://github.com/flekschas/regl-scatterplot/) for WebGL rendering, [traitlets](https://traitlets.readthedocs.io/en/stable/) for two-way communication between the JS and iPython kernels, and [anywidget](https://anywidget.dev/) for composing the widget.

**Docs**

Visit [https://jupyter-scatter.dev](https://jupyter-scatter.dev) for detailed documentation including examples and a complete API description.

---

**Index**

1. [Install](#install)
2. [Get Started](#get-started)
   1. [Simplest Example](#simplest-example)
   2. [Pandas DataFrame Example](#pandas-dataframe-example)
   3. [Advanced Example](#advanced-example)
   4. [Functional API Example](#functional-api-example)
   5. [Linking Scatter Plots](#linking-scatter-plots)
   6. [Visualize Millions of Data Points](#visualize-millions-of-data-points)
   7. [Google Colab](#google-colab)
4. [Development](#development)
5. [Citation](#citation)

## Install

```bash
pip install jupyter-scatter
```

If you want to use Jupyter Scatter in JupyterLab <=2 you need to manually
install it as an extension as follows:

```bash
jupyter labextension install @jupyter-widgets/jupyterlab-manager jupyter-scatter
```

If you want to instal Jupyter Scatter from source, make sure to have [Node](https://nodejs.org) installed. While several version might work, we're primarily testing against the [Active LTS and Maintenance LTS releases](https://nodejs.org/en/about/previous-releases).

For a minimal working example, take a look at [test-environments](test-environments).

## Get Started

> [!TIP]
> Visit [jupyter-scatter.dev](https://jupyter-scatter.dev) for details on all essential features of Jupyter Scatter and check out our [full-blown tutorial](https://github.com/flekschas/jupyter-scatter-tutorial) from SciPy '23.

### Simplest Example

In the simplest case, you can pass the x/y coordinates to the plot function as follows:

```python
import jscatter
import numpy as np

x = np.random.rand(500)
y = np.random.rand(500)

jscatter.plot(x, y)
```

<img width="448" alt="Simplest scatter plotexample" src="https://user-images.githubusercontent.com/932103/116143120-bc5f2280-a6a8-11eb-8614-51def74d692e.png">

### Pandas DataFrame Example

Say your data is stored in a Pandas dataframe like the following:

```python
import pandas as pd

# Just some random float and int values
data = np.random.rand(500, 4)
df = pd.DataFrame(data, columns=['mass', 'speed', 'pval', 'group'])
# We'll convert the `group` column to strings to ensure it's recognized as
# categorical data. This will come in handy in the advanced example.
df['group'] = df['group'].map(lambda c: chr(65 + round(c)), na_action=None)
```

|   | x    | y    | value | group |
|---|------|------|-------|-------|
| 0 |	0.13 | 0.27 | 0.51  | G     |
| 1 |	0.87 | 0.93 | 0.80  | B     |
| 2 |	0.10 | 0.25 | 0.25  | F     |
| 3 |	0.03 | 0.90 | 0.01  | G     |
| 4 |	0.19 | 0.78 | 0.65  | D     |

You can then visualize this data by referencing column names:

```python
jscatter.plot(data=df, x='mass', y='speed')
```

<details><summary>Show the resulting scatter plot</summary>
<img width="448" alt="Pandas scatter plot example" src="https://user-images.githubusercontent.com/932103/116143383-1364f780-a6a9-11eb-974c-4facec249974.png">
</details>

### Advanced Example

Often you want to customize the visual encoding, such as the point color, size, and opacity.

```python
jscatter.plot(
  data=df,
  x='mass',
  y='speed',
  size=8, # static encoding
  color_by='group', # data-driven encoding
  opacity_by='density', # view-driven encoding
)
```

<img width="448" alt="Advanced scatter plot example" src="https://user-images.githubusercontent.com/932103/116143470-2f689900-a6a9-11eb-861f-fcd8c563fde4.png">

In the above example, we chose a static point size of `8`. In contrast, the point color is data-driven and assigned based on the categorical `group` value. The point opacity is view-driven and defined dynamically by the number of points currently visible in the view.

Also notice how jscatter uses an appropriate color map by default based on the data type used for color encoding. In this examples, jscatter uses the color blindness safe color map from [Okabe and Ito](https://jfly.uni-koeln.de/color/#pallet) as the data type is `categorical` and the number of categories is less than `9`.

**Important:** in order for jscatter to recognize categorical data, the `dtype` of the corresponding column needs to be `category`!

You can, of course, customize the color map and many other parameters of the visual encoding as shown next.

### Functional API Example

The [flat API](#advanced-example) can get overwhelming when you want to customize a lot of properties. Therefore, jscatter provides a functional API that groups properties by type and exposes them via meaningfully-named methods.

```python
scatter = jscatter.Scatter(data=df, x='mass', y='speed')
scatter.selection(df.query('mass < 0.5').index)
scatter.color(by='mass', map='plasma', order='reverse')
scatter.opacity(by='density')
scatter.size(by='pval', map=[2, 4, 6, 8, 10])
scatter.height(480)
scatter.background('black')
scatter.show()
```

<img width="448" alt="Functional API scatter plot example" src="https://user-images.githubusercontent.com/932103/116155554-3945c880-a6b8-11eb-9033-4d0c07f01590.png">

When you update properties dynamically, i.e., after having called `scatter.show()`, the plot will update automatically. For instance, try calling `scatter.xy('speed', 'mass')`and you will see how the points are mirrored along the diagonal.

Moreover, all arguments are optional. If you specify arguments, the methods will act as setters and change the properties. If you call a method without any arguments it will act as a getter and return the property (or properties). For example, `scatter.selection()` will return the _currently_ selected points.

Finally, the scatter plot is interactive and supports two-way communication. Hence, if you select some point with the lasso tool and then call `scatter.selection()` you will get the current selection.

### Linking Scatter Plots

To explore multiple scatter plots and have their view, selection, and hover interactions link, use `jscatter.link()`.

```python
jscatter.link([
  jscatter.Scatter(data=embeddings, x='pcaX', y='pcaY', **config),
  jscatter.Scatter(data=embeddings, x='tsneX', y='tsneY', **config),
  jscatter.Scatter(data=embeddings, x='umapX', y='umapY', **config),
  jscatter.Scatter(data=embeddings, x='caeX', y='caeY', **config)
], rows=2)
```

https://user-images.githubusercontent.com/932103/162584133-85789d40-04f5-428d-b12c-7718f324fb39.mp4

See [notebooks/linking.ipynb](notebooks/linking.ipynb) for more details.

### Visualize Millions of Data Points

With `jupyter-scatter` you can easily visualize and interactively explore datasets with millions of points.

In the following we're visualizing 5 million points generated with the [Rรถssler attractor](https://en.wikipedia.org/wiki/R%C3%B6ssler_attractor).

```python
points = np.asarray(roesslerAttractor(5000000))
jscatter.plot(points[:,0], points[:,1], height=640)
```

https://user-images.githubusercontent.com/932103/162586987-0b5313b0-befd-4bd1-8ef5-13332d8b15d1.mp4

See [notebooks/examples.ipynb](notebooks/examples.ipynb) for more details.

### Google Colab

While jscatter is primarily developed for Jupyter Lab and Notebook, it also runs just fine in Google Colab. See [jupyter-scatter-colab-test.ipynb](https://colab.research.google.com/drive/195z6h6LsYpC25IIB3fSZIVUbqVlhtnQo?usp=sharing) for an example.

## Development

<details><summary>Setting up a development environment</summary>
<p>

**Requirements:**

- [Hatch](https://hatch.pypa.io/latest/) >= v1.7.0
- [Node](https://nodejs.org) [Active LTS or Maintenance LTS release](https://nodejs.org/en/about/previous-releases)

**Installation:**

```bash
git clone https://github.com/flekschas/jupyter-scatter/ jscatter && cd jscatter
hatch shell
pip install -e ".[dev]"
```

**After Changing Python code:** restart the kernel.

Alternatively, you can enable auto reloading by enabling the `autoreload`
extension. To do so, run the following code at the beginning of a notebook:

```py
%load_ext autoreload
%autoreload 2
```

**After Changing JavaScript code:** do `cd js && npm run build`.

Alternatively, you can enable anywidgets hot-module-reloading (HMR) as follows
and run `npm run watch` to rebundle the JS code on the fly.

```py
%env ANYWIDGET_HMR=1
```

</p>
</details>

<details><summary>Setting up a test environment</summary>
<p>

Go to [test-environments](test-environments) and follow the instructions.

</p>
</details>

<details><summary>Running tests</summary>
<p>

Run `pytest` after activating `hatch shell`.

</p>
</details>

## Citation

If you use Jupyter Scatter in your research, please cite the following preprint:

```bibtex
@article{lekschas2024jupyter,
  title = {{Jupyter Scatter}: Interactive Exploration of Large-Scale Datasets},
  author = {Fritz Lekschas and Trevor Manz},
  journal = {Journal of Open Source Software},
  publisher = {The Open Journal},
  year = {2024},
  volume = {9},
  number = {101},
  pages = {7059},
  doi = {10.21105/joss.07059},
  url = {https://doi.org/10.21105/joss.07059},
} 
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "jupyter-scatter",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "ipython, ipywidgets, jupyter, jupyterlab, jupyterlab-extension, scatter, scatter plot, widgets",
    "author": null,
    "author_email": "Fritz Lekschas <code@lekschas.de>",
    "download_url": "https://files.pythonhosted.org/packages/d7/04/4ab4fe631bde661ba6c06d18dd036968a22c0fac6862be1627206c4aa7bc/jupyter_scatter-0.19.1.tar.gz",
    "platform": null,
    "description": "<h1 align=\"center\">\n  <img src=\"https://jupyter-scatter.dev/images/logo-dark.svg\" height=\"24\"></img> Jupyter Scatter\n</h1>\n\n<div align=\"center\">\n  \n  [![pypi version](https://img.shields.io/pypi/v/jupyter-scatter.svg?color=1a8cff&style=flat-square)](https://pypi.org/project/jupyter-scatter/)\n  [![build status](https://img.shields.io/github/actions/workflow/status/flekschas/jupyter-scatter/ci.yml?branch=main&color=1a8cff&style=flat-square)](https://github.com/flekschas/jupyter-scatter/actions/workflows/ci.yml)\n  [![API docs](https://img.shields.io/badge/API-docs-1a8cff.svg?style=flat-square)](https://jupyter-scatter.dev/api)\n  [![notebook examples](https://img.shields.io/badge/notebook-examples-1a8cff.svg?style=flat-square)](notebooks/get-started.ipynb)\n  [![tutorial](https://img.shields.io/badge/SciPy_'23-tutorial-1a8cff.svg?style=flat-square)](https://github.com/flekschas/jupyter-scatter-tutorial)\n  [![DOI](https://img.shields.io/badge/JOSS-10.21105/joss.07059-1a8cff.svg?style=flat-square)](https://doi.org/10.21105/joss.07059)\n  \n</div>\n\n<div align=\"center\">\n  \n  <strong>An interactive scatter plot widget for Jupyter Notebook, Lab, and Google Colab</strong><br/>that can handle [millions of points](#visualize-millions-of-data-points) and supports [view linking](#linking-scatter-plots).\n  \n</div>\n\n<br/>\n\n<div align=\"center\">\n  \n  ![Demo](https://user-images.githubusercontent.com/932103/223292112-c9ca18b9-bc6b-4c3b-94ac-984960e8f717.gif)\n  \n</div>\n\n**Features?**\n\n- \ud83d\uddb1\ufe0f **Interactive**: Pan, zoom, and select data points interactively with your mouse or through the Python API.\n- \ud83d\ude80 **Scalable**: Plot up to several millions data points smoothly thanks to WebGL rendering.\n- \ud83d\udd17 **Interlinked**: Synchronize the view, hover, and selection across multiple scatter plot instances.\n- \u2728 **Effective Defaults**: Rely on Jupyter Scatter to choose perceptually effective point colors and opacity by default.\n- \ud83d\udcda **Friendly API:** Enjoy a readable API that integrates deeply with Pandas DataFrames.\n- \ud83d\udee0\ufe0f **Integratable**: Use Jupyter Scatter in your own widgets by observing its traitlets.\n\n**Why?**\n\nImagine trying to explore a dataset of millions of data points as a 2D scatter. Besides plotting, the exploration typically involves three things: First, we want to interactively adjust the view (e.g., via panning & zooming) and the visual point encoding (e.g., the point color, opacity, or size). Second, we want to be able to select and highlight data points. And third, we want to compare multiple datasets or views of the same dataset (e.g., via synchronized interactions). The goal of jupyter-scatter is to support all three requirements and scale to millions of points.\n\n**How?**\n\nInternally, Jupyter Scatter uses [regl-scatterplot](https://github.com/flekschas/regl-scatterplot/) for WebGL rendering, [traitlets](https://traitlets.readthedocs.io/en/stable/) for two-way communication between the JS and iPython kernels, and [anywidget](https://anywidget.dev/) for composing the widget.\n\n**Docs**\n\nVisit [https://jupyter-scatter.dev](https://jupyter-scatter.dev) for detailed documentation including examples and a complete API description.\n\n---\n\n**Index**\n\n1. [Install](#install)\n2. [Get Started](#get-started)\n   1. [Simplest Example](#simplest-example)\n   2. [Pandas DataFrame Example](#pandas-dataframe-example)\n   3. [Advanced Example](#advanced-example)\n   4. [Functional API Example](#functional-api-example)\n   5. [Linking Scatter Plots](#linking-scatter-plots)\n   6. [Visualize Millions of Data Points](#visualize-millions-of-data-points)\n   7. [Google Colab](#google-colab)\n4. [Development](#development)\n5. [Citation](#citation)\n\n## Install\n\n```bash\npip install jupyter-scatter\n```\n\nIf you want to use Jupyter Scatter in JupyterLab <=2 you need to manually\ninstall it as an extension as follows:\n\n```bash\njupyter labextension install @jupyter-widgets/jupyterlab-manager jupyter-scatter\n```\n\nIf you want to instal Jupyter Scatter from source, make sure to have [Node](https://nodejs.org) installed. While several version might work, we're primarily testing against the [Active LTS and Maintenance LTS releases](https://nodejs.org/en/about/previous-releases).\n\nFor a minimal working example, take a look at [test-environments](test-environments).\n\n## Get Started\n\n> [!TIP]\n> Visit [jupyter-scatter.dev](https://jupyter-scatter.dev) for details on all essential features of Jupyter Scatter and check out our [full-blown tutorial](https://github.com/flekschas/jupyter-scatter-tutorial) from SciPy '23.\n\n### Simplest Example\n\nIn the simplest case, you can pass the x/y coordinates to the plot function as follows:\n\n```python\nimport jscatter\nimport numpy as np\n\nx = np.random.rand(500)\ny = np.random.rand(500)\n\njscatter.plot(x, y)\n```\n\n<img width=\"448\" alt=\"Simplest scatter plotexample\" src=\"https://user-images.githubusercontent.com/932103/116143120-bc5f2280-a6a8-11eb-8614-51def74d692e.png\">\n\n### Pandas DataFrame Example\n\nSay your data is stored in a Pandas dataframe like the following:\n\n```python\nimport pandas as pd\n\n# Just some random float and int values\ndata = np.random.rand(500, 4)\ndf = pd.DataFrame(data, columns=['mass', 'speed', 'pval', 'group'])\n# We'll convert the `group` column to strings to ensure it's recognized as\n# categorical data. This will come in handy in the advanced example.\ndf['group'] = df['group'].map(lambda c: chr(65 + round(c)), na_action=None)\n```\n\n|   | x    | y    | value | group |\n|---|------|------|-------|-------|\n| 0 |\t0.13 | 0.27 | 0.51  | G     |\n| 1 |\t0.87 | 0.93 | 0.80  | B     |\n| 2 |\t0.10 | 0.25 | 0.25  | F     |\n| 3 |\t0.03 | 0.90 | 0.01  | G     |\n| 4 |\t0.19 | 0.78 | 0.65  | D     |\n\nYou can then visualize this data by referencing column names:\n\n```python\njscatter.plot(data=df, x='mass', y='speed')\n```\n\n<details><summary>Show the resulting scatter plot</summary>\n<img width=\"448\" alt=\"Pandas scatter plot example\" src=\"https://user-images.githubusercontent.com/932103/116143383-1364f780-a6a9-11eb-974c-4facec249974.png\">\n</details>\n\n### Advanced Example\n\nOften you want to customize the visual encoding, such as the point color, size, and opacity.\n\n```python\njscatter.plot(\n  data=df,\n  x='mass',\n  y='speed',\n  size=8, # static encoding\n  color_by='group', # data-driven encoding\n  opacity_by='density', # view-driven encoding\n)\n```\n\n<img width=\"448\" alt=\"Advanced scatter plot example\" src=\"https://user-images.githubusercontent.com/932103/116143470-2f689900-a6a9-11eb-861f-fcd8c563fde4.png\">\n\nIn the above example, we chose a static point size of `8`. In contrast, the point color is data-driven and assigned based on the categorical `group` value. The point opacity is view-driven and defined dynamically by the number of points currently visible in the view.\n\nAlso notice how jscatter uses an appropriate color map by default based on the data type used for color encoding. In this examples, jscatter uses the color blindness safe color map from [Okabe and Ito](https://jfly.uni-koeln.de/color/#pallet) as the data type is `categorical` and the number of categories is less than `9`.\n\n**Important:** in order for jscatter to recognize categorical data, the `dtype` of the corresponding column needs to be `category`!\n\nYou can, of course, customize the color map and many other parameters of the visual encoding as shown next.\n\n### Functional API Example\n\nThe [flat API](#advanced-example) can get overwhelming when you want to customize a lot of properties. Therefore, jscatter provides a functional API that groups properties by type and exposes them via meaningfully-named methods.\n\n```python\nscatter = jscatter.Scatter(data=df, x='mass', y='speed')\nscatter.selection(df.query('mass < 0.5').index)\nscatter.color(by='mass', map='plasma', order='reverse')\nscatter.opacity(by='density')\nscatter.size(by='pval', map=[2, 4, 6, 8, 10])\nscatter.height(480)\nscatter.background('black')\nscatter.show()\n```\n\n<img width=\"448\" alt=\"Functional API scatter plot example\" src=\"https://user-images.githubusercontent.com/932103/116155554-3945c880-a6b8-11eb-9033-4d0c07f01590.png\">\n\nWhen you update properties dynamically, i.e., after having called `scatter.show()`, the plot will update automatically. For instance, try calling `scatter.xy('speed', 'mass')`and you will see how the points are mirrored along the diagonal.\n\nMoreover, all arguments are optional. If you specify arguments, the methods will act as setters and change the properties. If you call a method without any arguments it will act as a getter and return the property (or properties). For example, `scatter.selection()` will return the _currently_ selected points.\n\nFinally, the scatter plot is interactive and supports two-way communication. Hence, if you select some point with the lasso tool and then call `scatter.selection()` you will get the current selection.\n\n### Linking Scatter Plots\n\nTo explore multiple scatter plots and have their view, selection, and hover interactions link, use `jscatter.link()`.\n\n```python\njscatter.link([\n  jscatter.Scatter(data=embeddings, x='pcaX', y='pcaY', **config),\n  jscatter.Scatter(data=embeddings, x='tsneX', y='tsneY', **config),\n  jscatter.Scatter(data=embeddings, x='umapX', y='umapY', **config),\n  jscatter.Scatter(data=embeddings, x='caeX', y='caeY', **config)\n], rows=2)\n```\n\nhttps://user-images.githubusercontent.com/932103/162584133-85789d40-04f5-428d-b12c-7718f324fb39.mp4\n\nSee [notebooks/linking.ipynb](notebooks/linking.ipynb) for more details.\n\n### Visualize Millions of Data Points\n\nWith `jupyter-scatter` you can easily visualize and interactively explore datasets with millions of points.\n\nIn the following we're visualizing 5 million points generated with the [R\u00f6ssler attractor](https://en.wikipedia.org/wiki/R%C3%B6ssler_attractor).\n\n```python\npoints = np.asarray(roesslerAttractor(5000000))\njscatter.plot(points[:,0], points[:,1], height=640)\n```\n\nhttps://user-images.githubusercontent.com/932103/162586987-0b5313b0-befd-4bd1-8ef5-13332d8b15d1.mp4\n\nSee [notebooks/examples.ipynb](notebooks/examples.ipynb) for more details.\n\n### Google Colab\n\nWhile jscatter is primarily developed for Jupyter Lab and Notebook, it also runs just fine in Google Colab. See [jupyter-scatter-colab-test.ipynb](https://colab.research.google.com/drive/195z6h6LsYpC25IIB3fSZIVUbqVlhtnQo?usp=sharing) for an example.\n\n## Development\n\n<details><summary>Setting up a development environment</summary>\n<p>\n\n**Requirements:**\n\n- [Hatch](https://hatch.pypa.io/latest/) >= v1.7.0\n- [Node](https://nodejs.org) [Active LTS or Maintenance LTS release](https://nodejs.org/en/about/previous-releases)\n\n**Installation:**\n\n```bash\ngit clone https://github.com/flekschas/jupyter-scatter/ jscatter && cd jscatter\nhatch shell\npip install -e \".[dev]\"\n```\n\n**After Changing Python code:** restart the kernel.\n\nAlternatively, you can enable auto reloading by enabling the `autoreload`\nextension. To do so, run the following code at the beginning of a notebook:\n\n```py\n%load_ext autoreload\n%autoreload 2\n```\n\n**After Changing JavaScript code:** do `cd js && npm run build`.\n\nAlternatively, you can enable anywidgets hot-module-reloading (HMR) as follows\nand run `npm run watch` to rebundle the JS code on the fly.\n\n```py\n%env ANYWIDGET_HMR=1\n```\n\n</p>\n</details>\n\n<details><summary>Setting up a test environment</summary>\n<p>\n\nGo to [test-environments](test-environments) and follow the instructions.\n\n</p>\n</details>\n\n<details><summary>Running tests</summary>\n<p>\n\nRun `pytest` after activating `hatch shell`.\n\n</p>\n</details>\n\n## Citation\n\nIf you use Jupyter Scatter in your research, please cite the following preprint:\n\n```bibtex\n@article{lekschas2024jupyter,\n  title = {{Jupyter Scatter}: Interactive Exploration of Large-Scale Datasets},\n  author = {Fritz Lekschas and Trevor Manz},\n  journal = {Journal of Open Source Software},\n  publisher = {The Open Journal},\n  year = {2024},\n  volume = {9},\n  number = {101},\n  pages = {7059},\n  doi = {10.21105/joss.07059},\n  url = {https://doi.org/10.21105/joss.07059},\n} \n```\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "An interactive scatter plot widget for Jupyter Notebook, Lab, and Google Colab that can handle millions of points and supports view linking",
    "version": "0.19.1",
    "project_urls": {
        "changelog": "https://github.com/flekschas/jupyter-scatter/blob/main/CHANGELOG.md",
        "documentation": "https://jupyter-scatter.dev/api",
        "homepage": "https://jupyter-scatter.dev",
        "repository": "https://github.com/flekschas/jupyter-scatter"
    },
    "split_keywords": [
        "ipython",
        " ipywidgets",
        " jupyter",
        " jupyterlab",
        " jupyterlab-extension",
        " scatter",
        " scatter plot",
        " widgets"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "11b3a760978949909043f5ba51854d299914ab2c90e8e3d4a1ba128501352642",
                "md5": "07c7fc828ecfd873437d3e775d9661c0",
                "sha256": "7ef514ce4be322c814f3a96c41734f726c18d4fa1069b74c88a7aca80bfb30d6"
            },
            "downloads": -1,
            "filename": "jupyter_scatter-0.19.1-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "07c7fc828ecfd873437d3e775d9661c0",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": null,
            "size": 205109,
            "upload_time": "2024-09-30T01:08:11",
            "upload_time_iso_8601": "2024-09-30T01:08:11.759757Z",
            "url": "https://files.pythonhosted.org/packages/11/b3/a760978949909043f5ba51854d299914ab2c90e8e3d4a1ba128501352642/jupyter_scatter-0.19.1-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d7044ab4fe631bde661ba6c06d18dd036968a22c0fac6862be1627206c4aa7bc",
                "md5": "c057d059ff94f38e7f0ca343793d6778",
                "sha256": "67c4b8c66723933010c1a4508c5ef8bd17d16212761879acb64eef7af77468dc"
            },
            "downloads": -1,
            "filename": "jupyter_scatter-0.19.1.tar.gz",
            "has_sig": false,
            "md5_digest": "c057d059ff94f38e7f0ca343793d6778",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 222101,
            "upload_time": "2024-09-30T01:08:13",
            "upload_time_iso_8601": "2024-09-30T01:08:13.796612Z",
            "url": "https://files.pythonhosted.org/packages/d7/04/4ab4fe631bde661ba6c06d18dd036968a22c0fac6862be1627206c4aa7bc/jupyter_scatter-0.19.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-09-30 01:08:13",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "flekschas",
    "github_project": "jupyter-scatter",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "jupyter-scatter"
}
        
Elapsed time: 4.88453s