diff --git a/README.md b/README.md index 9ec6c50ce..943fb7ae7 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ or with pip: pip install datashader For the best performance, we recommend using conda so that you are sure -to get numerical libraries optimized for your platform. The lastest +to get numerical libraries optimized for your platform. The latest releases are avalailable on the pyviz channel `conda install -c pyviz datashader` and the latest pre-release versions are avalailable on the dev-labelled channel `conda install -c pyviz/label/dev datashader`. diff --git a/examples/dashboard.ipynb b/examples/dashboard.ipynb index 70a66192b..844b6f62f 100644 --- a/examples/dashboard.ipynb +++ b/examples/dashboard.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This notebook contains the code for an interactive dashboard for making [Datashader](http://datashader.org) plots from any dataset that has latitude and longitude (geographic) values. Apart from Datashader itself, the code relies on other Python packages from the [PyViz](http://pyviz.org) project that are each designed to make it simple to:\n", + "This notebook contains the code for an interactive dashboard for making [Datashader](http://datashader.org) plots from any dataset that has latitude and longitude (geographic) values. Apart from Datashader itself, the code relies on other Python packages from the [HoloViz](http://holoviz.org) project that are each designed to make it simple to:\n", "\n", "- lay out plots and widgets into an app or dashboard, in a notebook or for serving separately ([Panel](http://panel.pyviz.org))\n", "- build interactive web-based plots without writing JavaScript ([Bokeh](http://bokeh.pydata.org))\n", @@ -19,8 +19,8 @@ "metadata": {}, "outputs": [], "source": [ - "import os, colorcet, param as pm, holoviews as hv, panel as pn, datashader as ds\n", - "import intake, geoviews.tile_sources as gts\n", + "import os, colorcet, param as pm, holoviews as hv, panel as pn, datashader as ds, intake\n", + "from holoviews.element import tiles\n", "from holoviews.operation.datashader import rasterize, shade, spread\n", "from collections import OrderedDict as odict\n", "\n", @@ -72,8 +72,8 @@ "cmaps = odict([(n,colorcet.palette[n]) for n in ['fire', 'bgy', 'bgyw', 'bmy', 'gray', 'kbc']])\n", "\n", "maps = ['EsriImagery', 'EsriUSATopo', 'EsriTerrain', 'CartoMidnight', 'StamenWatercolor', 'StamenTonerBackground']\n", - "bases = odict([(name, gts.tile_sources[name].relabel(name)) for name in maps])\n", - "gopts = hv.opts.WMTS(responsive=True, xaxis=None, yaxis=None, bgcolor='black', show_grid=False)\n", + "bases = odict([(name, tiles.tile_sources[name]().relabel(name)) for name in maps])\n", + "gopts = hv.opts.Tiles(responsive=True, xaxis=None, yaxis=None, bgcolor='black', show_grid=False)\n", "\n", "class Explorer(pm.Parameterized):\n", " plot = pm.Selector(plots)\n", @@ -99,12 +99,12 @@ " return self.agg_fn(field)\n", "\n", " @pm.depends('map_opacity', 'basemap')\n", - " def tiles(self):\n", + " def base(self):\n", " return self.basemap.opts(gopts).opts(alpha=self.map_opacity)\n", "\n", " @pm.depends('show_labels')\n", " def labels(self):\n", - " return gts.StamenLabels.options(level='annotation', alpha=1 if self.show_labels else 0)\n", + " return tiles.StamenLabels().opts(level='annotation', alpha=1 if self.show_labels else 0)\n", "\n", " def viewable(self,**kwargs):\n", " rasterized = rasterize(hv.DynamicMap(self.elem), aggregator=self.aggregator, width=800, height=400)\n", @@ -112,7 +112,7 @@ " spreaded = spread(shaded, px=self.param.spreading, how=\"add\")\n", " dataplot = spreaded.apply.opts(alpha=self.param.data_opacity, show_legend=False)\n", " \n", - " return hv.DynamicMap(self.tiles) * dataplot * hv.DynamicMap(self.labels)\n", + " return hv.DynamicMap(self.base) * dataplot * hv.DynamicMap(self.labels)\n", " \n", "explorer = Explorer(name=\"\")" ] @@ -210,6 +210,8 @@ " show_labels = pm.Boolean(True)\n", "\n", " def view(self,**kwargs):\n", + " base = self.basemap.opts(gopts).opts(alpha=self.map_opacity)\n", + "\n", " field = None if self.field == \"counts\" else self.field\n", " rasterized = rasterize(hv.DynamicMap(getattr(source.plot, self.plot)), \n", " aggregator=self.agg_fn(field), width=800, height=400)\n", @@ -217,10 +219,9 @@ " spreaded = spread(shaded, px=self.spreading, how=\"add\")\n", " dataplot = spreaded.opts(alpha=self.data_opacity, show_legend=False)\n", " \n", - " tiles = self.basemap.opts(gopts).opts(alpha=self.map_opacity)\n", - " labels = gts.StamenLabels.options(level='annotation', alpha=1 if self.show_labels else 0)\n", - " \n", - " return tiles * dataplot * labels\n", + " labels = tiles.StamenLabels().opts(level='annotation', alpha=1 if self.show_labels else 0)\n", + "\n", + " return base * dataplot * labels\n", " \n", "explorer2 = Explorer2(name=\"\")" ] @@ -319,7 +320,7 @@ "\n", "These sources of dynamic behavior make the `dataplot` chain of DynamicMaps be richly interactive. The interactive `dataplot` is then overlaid with `hv.DynamicMap(self.tiles)` (which itself is updated when the `map_opacity` and `basemap` parameters change), and with `hv.DynamicMap(self.labels)` (which itself is updated when the `show_labels` parameter changes). Now, each part of the plot updates only if the relevant parameters have changed, and otherwise is left as it was, avoiding flicker and providing snappy performance.\n", "\n", - "As you can see, if we want to be very careful to tie each bit of computation to the values that affect it, then we can precisely determine which code to re-run interactively, providing maximal responsiveness where possible (try dragging the opacity sliders or selecting colormaps), while re-running everything when needed (when aggregation-related parameters change). In your own Panel dashboards and apps, you can often use the simplest approach (which can be as simple as a one-line call to [interact](https://panel.pyviz.org/user_guide/Introduction.html)), but it is important to know that fine-grained control is available when you need it, and is still typically vastly more concise and explicitly expressed than with other dashboarding approaches." + "As you can see, if we want to be very careful to tie each bit of computation to the values that affect it, then we can precisely determine which code to re-run interactively, providing maximal responsiveness where possible (try dragging the opacity sliders or selecting colormaps), while re-running everything when needed (when aggregation-related parameters change). In your own Panel dashboards and apps, you can often use the simplest approach (which can be as simple as a one-line call to [interact](https://panel.pyviz.org/user_guide/Interact.html)), but it is important to know that fine-grained control is available when you need it, and is still typically vastly more concise and explicitly expressed than with other dashboarding approaches." ] } ], diff --git a/examples/dashboard.yml b/examples/dashboard.yml index 9aa5e488f..b383b69ac 100644 --- a/examples/dashboard.yml +++ b/examples/dashboard.yml @@ -10,8 +10,8 @@ sources: counts: label: GPS coordinates plot: - xlim: !!python/tuple [-8240227, -8231284] - ylim: !!python/tuple [ 4974203, 4979238] + xlim: [-8240227, -8231284] + ylim: [ 4974203, 4979238] kind: points persist: true plots: @@ -38,8 +38,8 @@ sources: pickup_hour: label: Pick-up Hour plot: - xlim: !!python/tuple [-8240227.037, -8231283.905] - ylim: !!python/tuple [4974203.152, 4979238.441] + xlim: [-8240227.037, -8231283.905] + ylim: [4974203.152, 4979238.441] kind: points hover_cols: ['dropoff_hour', 'pickup_hour', 'passenger_count'] persist: true @@ -71,8 +71,8 @@ sources: pickup_hour: label: Pick-up Hour plot: - xlim: !!python/tuple [-8240227.037, -8231283.905] - ylim: !!python/tuple [4974203.152, 4979238.441] + xlim: [-8240227.037, -8231283.905] + ylim: [4974203.152, 4979238.441] kind: points hover_cols: ['dropoff_hour', 'pickup_hour', 'passenger_count'] persist: true @@ -100,8 +100,8 @@ sources: plot: x: easting y: northing - xlim: !!python/tuple [-13914936, -7235767] - ylim: !!python/tuple [2632019, 6446276] + xlim: [-13914936, -7235767] + ylim: [2632019, 6446276] kind: points persist: true plots: @@ -136,8 +136,8 @@ sources: True: Ascending False: Descending plot: - xlim: !!python/tuple [-2000000, 2500000] - ylim: !!python/tuple [4100000, 7800000] + xlim: [-2000000, 2500000] + ylim: [4100000, 7800000] kind: points x: longitude y: latitude