Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
astrofrog committed Jul 6, 2023
1 parent b9bbfa0 commit 41b6928
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 10 deletions.
72 changes: 72 additions & 0 deletions glue_jupyter/bqplot/scatter/scatter_density_mark.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from bqplot_image_gl import ImageGL
from bqplot_image_gl.viewlistener import ViewListener

from mpl_scatter_density.fixed_data_density_helper import FixedDataDensityHelper

from ...utils import debounced

__all__ = ['GenericDensityMark']
Expand Down Expand Up @@ -147,3 +149,73 @@ def update(self, *args, **kwargs):

def invalidate_cache(self):
self.update()


class ScatterDensityMark(GenericDensityMark):
"""
Bqplot artist to make a density plot of (x, y) scatter data.
Parameters
----------
figure : bqplot.figure
The figure
x, y : iterable
The data to plot.
c : iterable
Values to use for color-encoding. This is meant to be the same as
the argument with the same name in :meth:`~matplotlib.axes.Axes.scatter`
although for now only 1D iterables of values are accepted. Note that
values are averaged inside each pixel of the density map *before*
applying the colormap, which in some cases will be different from what
the average color of markers would have been inside each pixel.
dpi : int or `None`
The number of dots per inch to include in the density map. To use
the native resolution of the drawing device, set this to None.
downres_factor : int
For interactive devices, when panning, the density map will
automatically be made at a lower resolution and including only a
subset of the points. The new dpi of the figure when panning will
then be dpi / downres_factor, and the number of elements in the
arrays will be reduced by downres_factor**2.
cmap : `matplotlib.colors.Colormap`
The colormap to use for the density map.
color : str or tuple
The color to use for the density map. This can be any valid
Matplotlib color. If specified, this takes precedence over the
colormap.
alpha : float
Overall transparency of the density map.
norm : `matplotlib.colors.Normalize`
The normalization class for the density map.
vmin, vmax : float or func
The lower and upper levels used for scaling the density map. These can
optionally be functions that take the density array and returns a single
value (e.g. a function that returns the 5% percentile, or the minimum).
This is useful since when zooming in/out, the optimal limits change.
update_while_panning : bool, optional
Whether to compute histograms on-the-fly while panning.
kwargs
Any additional keyword arguments are passed to AxesImage.
"""

def __init__(self, figure, x, y, downres_factor=4, c=None, **kwargs):
self.histogram2d_helper = FixedDataDensityHelper(figure, x, y, c=c,
downres_factor=downres_factor)
super().__init__(figure=figure, histogram2d_func=self.histogram2d_helper,
**kwargs)

def set_xy(self, x, y):
self.histogram2d_helper.set_xy(x, y)

def set_c(self, c):
self.histogram2d_helper.set_c(c)

# def on_press(self, event=None, force=False):
# if not force:
# if self._update_while_panning and self.histogram2d_helper._downres_factor == 1:
# return
# self.histogram2d_helper.downres()
# return super().on_press(force=force)

# def on_release(self, event=None):
# self.histogra).on_release()
38 changes: 28 additions & 10 deletions notebooks/Experimental/bqplot_scatter_density.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"source": [
"import numpy as np\n",
"from bqplot import Figure, LinearScale, Axis, ColorScale\n",
"from glue_jupyter.bqplot.scatter.scatter_density_mark import GenericDensityMark"
"from glue_jupyter.bqplot.scatter.scatter_density_mark import ScatterDensityMark"
]
},
{
Expand All @@ -19,15 +19,23 @@
"metadata": {},
"outputs": [],
"source": [
"from fast_histogram import histogram2d\n",
"\n",
"N = 1_000_000\n",
"x = np.random.normal(1, 0.1, N)\n",
"y = np.random.normal(0, 0.2, N)\n",
"\n",
"def density(*, bins, range):\n",
" print(bins, range)\n",
" return histogram2d(y, x, bins=bins, range=range)"
"y = np.random.normal(0, 0.2, N)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6af0f4b2",
"metadata": {},
"outputs": [],
"source": [
"class CustomFigure(Figure):\n",
" def get_xscale(self):\n",
" return 'linear'\n",
" def get_yscale(self):\n",
" return 'linear'"
]
},
{
Expand All @@ -44,19 +52,29 @@
"axis_x = Axis(scale=scale_x, label='x')\n",
"axis_y = Axis(scale=scale_y, label='y', orientation='vertical')\n",
"\n",
"figure = Figure(scales=scales, axes=[axis_x, axis_y])\n",
"figure = CustomFigure(scales=scales, axes=[axis_x, axis_y])\n",
"\n",
"scales_image = {'x': scale_x,\n",
" 'y': scale_y,\n",
" 'image': ColorScale(min=0, max=1)}\n",
"\n",
"image = GenericDensityMark(figure=figure, histogram2d_func=density)\n",
"image = ScatterDensityMark(figure=figure, x=x, y=y)\n",
"\n",
"figure.marks = (image,)\n",
"\n",
"figure"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cd8b0344",
"metadata": {},
"outputs": [],
"source": [
"# NOTE: FixedDataDensityHelper uses self._ax in one place, see if we can avoid that"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down

0 comments on commit 41b6928

Please sign in to comment.