diff --git a/contrib_colormaps/plotting.py b/contrib_colormaps/plotting.py
index 039b5d5..3efe179 100644
--- a/contrib_colormaps/plotting.py
+++ b/contrib_colormaps/plotting.py
@@ -27,9 +27,10 @@ def swatch(name, bounds=None, array=array, **kwargs):
cmap=palette[name]))
if 'matplotlib' in backends:
aspect = kwargs.pop('aspect', 15)
- fig_size = kwargs.pop('fig_size', 350)
+ fig_size = kwargs.pop('fig_size',350)
plot.opts(opts.Image(backend='matplotlib', aspect=aspect, fig_size=fig_size,
cmap=cm[name]))
+
return plot.opts(opts.Image(xaxis=None, yaxis=None), opts.Image(**kwargs))
diff --git a/examples/colormaps/index.ipynb b/examples/colormaps/index.ipynb
index 9032633..0c88a38 100644
--- a/examples/colormaps/index.ipynb
+++ b/examples/colormaps/index.ipynb
@@ -4,16 +4,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Accessing the colormaps\n",
- "\n",
- "After importing `contrib_colormaps` as `cc`, all the colormaps will be available for use in different forms. It's a bit difficult to describe, but the idea is that this library should have at least one such form convenient for any particular application. There are two different basic versions for each colormap, each of which is fundamentally a list of colors: \n",
- "\n",
- "1. A Bokeh-style palette, i.e., a Python list of RGB colors as hex strings, like ``['#000000', ..., '#ffffff']``\n",
- "2. If matplotlib is installed and importable, a Matplotlib ``LinearSegmentedColormap`` using normalized magnitudes, like ``LinearSegmentedColormap.from_list(\"fire\",[ [0.0,0.0,0.0], ..., [1.0,1.0,1.0] ], 256)``\n",
- "\n",
- "The Bokeh-compatible palettes are provided as attributes in the ``contrib_colormaps`` namespace, with long names prefixed with ``b_``. E.g. ``rainforest`` can be accessed as ``cc.b_sample``. These names should tab complete once ``cc`` has been imported. Because Bokeh palettes are just Python lists, you can always reverse them using normal Python syntax, e.g. ``list(reversed(cc.b_sample))``, or use subsets of them with slice notation, e.g. ``cc.b_sample[25:]``. If you want to access the palettes by string name, they are also collected into a dictionary named ``palette``, so you can use ``cc.palette[\"sample\"]`` or ``cc.palette.sample``; whichever is more convenient.\n",
+ "## Documenting colormaps\n",
"\n",
- "The Matplotlib colormaps are also provided as tab-completable attributes, but consistently with a prefix ``m_``, e.g. ``cc.m_sample``. Already reversed versions are also available, as ``cc.m_sample_r``. The same colormaps are also registered with matplotlib's string-based dictionary with the prefix ``cc_``, making them available by name within various matplotlib functions (e.g. ``cc_sample``, ``cc_sample_r``). Finally, if you want to access the colormaps by string name without using Matplotlib's registry, they are also stored in the ``cc.cm`` dictionary, e.g. ``cc.cm[\"sample\"]`` or ``cc.cm[\"sample_r\"]``."
+ "For ease of use, we provide minimal plotting commands for use with contrib_colormaps. These depend on holoviews, which needs to be installed before they can be used. Once set up, these commands provide easy viewing capability of the colormaps."
]
},
{
@@ -22,113 +15,3388 @@
"source": [
"#### Example\n",
"\n",
- "Here we show importing sample and printing the first 5 colors. "
+ "Import `swatch` from `contrib_colormaps.plotting` and load your desired backend into holoviews. Then call `swatch` with the name of a colormap. "
]
},
{
"cell_type": "code",
- "execution_count": null,
- "metadata": {
- "scrolled": true
- },
+ "execution_count": 1,
+ "metadata": {},
"outputs": [],
"source": [
- "import contrib_colormaps as cc\n",
- "\n",
- "cc.b_sample[:5]"
+ "from contrib_colormaps.plotting import swatch, swatches\n",
+ "import holoviews as hv"
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": 3,
"metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "application/javascript": [
+ "function HoloViewsWidget() {\n",
+ "}\n",
+ "\n",
+ "HoloViewsWidget.prototype.init_slider = function(init_val){\n",
+ " if(this.load_json) {\n",
+ " this.from_json()\n",
+ " } else {\n",
+ " this.update_cache();\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "HoloViewsWidget.prototype.populate_cache = function(idx){\n",
+ " this.cache[idx].innerHTML = this.frames[idx];\n",
+ " if (this.embed) {\n",
+ " delete this.frames[idx];\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "HoloViewsWidget.prototype.process_error = function(msg){\n",
+ "}\n",
+ "\n",
+ "HoloViewsWidget.prototype.from_json = function() {\n",
+ " var data_url = this.json_path + this.id + '.json';\n",
+ " $.getJSON(data_url, $.proxy(function(json_data) {\n",
+ " this.frames = json_data;\n",
+ " this.update_cache();\n",
+ " this.update(0);\n",
+ " }, this));\n",
+ "}\n",
+ "\n",
+ "HoloViewsWidget.prototype.dynamic_update = function(current){\n",
+ " if (current === undefined) {\n",
+ " return\n",
+ " }\n",
+ " this.current = current;\n",
+ " if (this.comm) {\n",
+ " var msg = {comm_id: this.id+'_client', content: current}\n",
+ " this.comm.send(msg);\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "HoloViewsWidget.prototype.update_cache = function(force){\n",
+ " var frame_len = Object.keys(this.frames).length;\n",
+ " for (var i=0; i 0) {\n",
+ " that.time = Date.now();\n",
+ " that.dynamic_update(that.queue[that.queue.length-1]);\n",
+ " that.queue = [];\n",
+ " } else {\n",
+ " that.wait = false;\n",
+ " }\n",
+ " if ((msg.msg_type == \"Ready\") && msg.content) {\n",
+ " console.log(\"Python callback returned following output:\", msg.content);\n",
+ " } else if (msg.msg_type == \"Error\") {\n",
+ " console.log(\"Python failed with the following traceback:\", msg.traceback)\n",
+ " }\n",
+ " }\n",
+ " var comm = HoloViews.comm_manager.get_client_comm(this.plot_id, this.id+'_client', ack_callback);\n",
+ " return comm\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "HoloViewsWidget.prototype.msg_handler = function(msg) {\n",
+ " var metadata = msg.metadata;\n",
+ " if ((metadata.msg_type == \"Ready\")) {\n",
+ " if (metadata.content) {\n",
+ " console.log(\"Python callback returned following output:\", metadata.content);\n",
+ " }\n",
+ "\treturn;\n",
+ " } else if (metadata.msg_type == \"Error\") {\n",
+ " console.log(\"Python failed with the following traceback:\", metadata.traceback)\n",
+ " return\n",
+ " }\n",
+ " this.process_msg(msg)\n",
+ "}\n",
+ "\n",
+ "HoloViewsWidget.prototype.process_msg = function(msg) {\n",
+ "}\n",
+ "\n",
+ "function SelectionWidget(frames, id, slider_ids, keyMap, dim_vals, notFound, load_json, mode, cached, json_path, dynamic, plot_id){\n",
+ " this.frames = frames;\n",
+ " this.id = id;\n",
+ " this.plot_id = plot_id;\n",
+ " this.slider_ids = slider_ids;\n",
+ " this.keyMap = keyMap\n",
+ " this.current_frame = 0;\n",
+ " this.current_vals = dim_vals;\n",
+ " this.load_json = load_json;\n",
+ " this.mode = mode;\n",
+ " this.notFound = notFound;\n",
+ " this.cached = cached;\n",
+ " this.dynamic = dynamic;\n",
+ " this.cache = {};\n",
+ " this.json_path = json_path;\n",
+ " this.init_slider(this.current_vals[0]);\n",
+ " this.queue = [];\n",
+ " this.wait = false;\n",
+ " if (!this.cached || this.dynamic) {\n",
+ " this.comm = this.init_comms();\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "SelectionWidget.prototype = new HoloViewsWidget;\n",
+ "\n",
+ "\n",
+ "SelectionWidget.prototype.get_key = function(current_vals) {\n",
+ " var key = \"(\";\n",
+ " for (var i=0; i Date.now()))) {\n",
+ " this.queue.push(key);\n",
+ " return\n",
+ " }\n",
+ " this.queue = [];\n",
+ " this.time = Date.now();\n",
+ " this.current_frame = key;\n",
+ " this.wait = true;\n",
+ " this.dynamic_update(key)\n",
+ " } else if (key !== undefined) {\n",
+ " this.update(key)\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "\n",
+ "/* Define the ScrubberWidget class */\n",
+ "function ScrubberWidget(frames, num_frames, id, interval, load_json, mode, cached, json_path, dynamic, plot_id){\n",
+ " this.slider_id = \"_anim_slider\" + id;\n",
+ " this.loop_select_id = \"_anim_loop_select\" + id;\n",
+ " this.id = id;\n",
+ " this.plot_id = plot_id;\n",
+ " this.interval = interval;\n",
+ " this.current_frame = 0;\n",
+ " this.direction = 0;\n",
+ " this.dynamic = dynamic;\n",
+ " this.timer = null;\n",
+ " this.load_json = load_json;\n",
+ " this.mode = mode;\n",
+ " this.cached = cached;\n",
+ " this.frames = frames;\n",
+ " this.cache = {};\n",
+ " this.length = num_frames;\n",
+ " this.json_path = json_path;\n",
+ " document.getElementById(this.slider_id).max = this.length - 1;\n",
+ " this.init_slider(0);\n",
+ " this.wait = false;\n",
+ " this.queue = [];\n",
+ " if (!this.cached || this.dynamic) {\n",
+ " this.comm = this.init_comms()\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype = new HoloViewsWidget;\n",
+ "\n",
+ "ScrubberWidget.prototype.set_frame = function(frame){\n",
+ " this.current_frame = frame;\n",
+ " var widget = document.getElementById(this.slider_id);\n",
+ " if (widget === null) {\n",
+ " this.pause_animation();\n",
+ " return\n",
+ " }\n",
+ " widget.value = this.current_frame;\n",
+ " if (this.dynamic || !this.cached) {\n",
+ " if ((this.time !== undefined) && ((this.wait) && ((this.time + 10000) > Date.now()))) {\n",
+ " this.queue.push(frame);\n",
+ " return\n",
+ " }\n",
+ " this.queue = [];\n",
+ " this.time = Date.now();\n",
+ " this.wait = true;\n",
+ " this.dynamic_update(frame)\n",
+ " } else {\n",
+ " this.update(frame)\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.get_loop_state = function(){\n",
+ " var button_group = document[this.loop_select_id].state;\n",
+ " for (var i = 0; i < button_group.length; i++) {\n",
+ " var button = button_group[i];\n",
+ " if (button.checked) {\n",
+ " return button.value;\n",
+ " }\n",
+ " }\n",
+ " return undefined;\n",
+ "}\n",
+ "\n",
+ "\n",
+ "ScrubberWidget.prototype.next_frame = function() {\n",
+ " this.set_frame(Math.min(this.length - 1, this.current_frame + 1));\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.previous_frame = function() {\n",
+ " this.set_frame(Math.max(0, this.current_frame - 1));\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.first_frame = function() {\n",
+ " this.set_frame(0);\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.last_frame = function() {\n",
+ " this.set_frame(this.length - 1);\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.slower = function() {\n",
+ " this.interval /= 0.7;\n",
+ " if(this.direction > 0){this.play_animation();}\n",
+ " else if(this.direction < 0){this.reverse_animation();}\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.faster = function() {\n",
+ " this.interval *= 0.7;\n",
+ " if(this.direction > 0){this.play_animation();}\n",
+ " else if(this.direction < 0){this.reverse_animation();}\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.anim_step_forward = function() {\n",
+ " if(this.current_frame < this.length - 1){\n",
+ " this.next_frame();\n",
+ " }else{\n",
+ " var loop_state = this.get_loop_state();\n",
+ " if(loop_state == \"loop\"){\n",
+ " this.first_frame();\n",
+ " }else if(loop_state == \"reflect\"){\n",
+ " this.last_frame();\n",
+ " this.reverse_animation();\n",
+ " }else{\n",
+ " this.pause_animation();\n",
+ " this.last_frame();\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.anim_step_reverse = function() {\n",
+ " if(this.current_frame > 0){\n",
+ " this.previous_frame();\n",
+ " } else {\n",
+ " var loop_state = this.get_loop_state();\n",
+ " if(loop_state == \"loop\"){\n",
+ " this.last_frame();\n",
+ " }else if(loop_state == \"reflect\"){\n",
+ " this.first_frame();\n",
+ " this.play_animation();\n",
+ " }else{\n",
+ " this.pause_animation();\n",
+ " this.first_frame();\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.pause_animation = function() {\n",
+ " this.direction = 0;\n",
+ " if (this.timer){\n",
+ " clearInterval(this.timer);\n",
+ " this.timer = null;\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.play_animation = function() {\n",
+ " this.pause_animation();\n",
+ " this.direction = 1;\n",
+ " var t = this;\n",
+ " if (!this.timer) this.timer = setInterval(function(){t.anim_step_forward();}, this.interval);\n",
+ "}\n",
+ "\n",
+ "ScrubberWidget.prototype.reverse_animation = function() {\n",
+ " this.pause_animation();\n",
+ " this.direction = -1;\n",
+ " var t = this;\n",
+ " if (!this.timer) this.timer = setInterval(function(){t.anim_step_reverse();}, this.interval);\n",
+ "}\n",
+ "\n",
+ "function extend(destination, source) {\n",
+ " for (var k in source) {\n",
+ " if (source.hasOwnProperty(k)) {\n",
+ " destination[k] = source[k];\n",
+ " }\n",
+ " }\n",
+ " return destination;\n",
+ "}\n",
+ "\n",
+ "function update_widget(widget, values) {\n",
+ " if (widget.hasClass(\"ui-slider\")) {\n",
+ " widget.slider('option', {\n",
+ " min: 0,\n",
+ " max: values.length-1,\n",
+ " dim_vals: values,\n",
+ " value: 0,\n",
+ " dim_labels: values\n",
+ " })\n",
+ " widget.slider('option', 'slide').call(widget, event, {value: 0})\n",
+ " } else {\n",
+ " widget.empty();\n",
+ " for (var i=0; i\", {\n",
+ " value: i,\n",
+ " text: values[i]\n",
+ " }))\n",
+ " };\n",
+ " widget.data('values', values);\n",
+ " widget.data('value', 0);\n",
+ " widget.trigger(\"change\");\n",
+ " };\n",
+ "}\n",
+ "\n",
+ "function init_slider(id, plot_id, dim, values, next_vals, labels, dynamic, step, value, next_dim,\n",
+ " dim_idx, delay, jQueryUI_CDN, UNDERSCORE_CDN) {\n",
+ " // Slider JS Block START\n",
+ " function loadcssfile(filename){\n",
+ " var fileref=document.createElement(\"link\")\n",
+ " fileref.setAttribute(\"rel\", \"stylesheet\")\n",
+ " fileref.setAttribute(\"type\", \"text/css\")\n",
+ " fileref.setAttribute(\"href\", filename)\n",
+ " document.getElementsByTagName(\"head\")[0].appendChild(fileref)\n",
+ " }\n",
+ " loadcssfile(\"https://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css\");\n",
+ " /* Check if jQuery and jQueryUI have been loaded\n",
+ " otherwise load with require.js */\n",
+ " var jQuery = window.jQuery,\n",
+ " // check for old versions of jQuery\n",
+ " oldjQuery = jQuery && !!jQuery.fn.jquery.match(/^1\\.[0-4](\\.|$)/),\n",
+ " jquery_path = '',\n",
+ " paths = {},\n",
+ " noConflict;\n",
+ " var jQueryUI = jQuery.ui;\n",
+ " // check for jQuery\n",
+ " if (!jQuery || oldjQuery) {\n",
+ " // load if it's not available or doesn't meet min standards\n",
+ " paths.jQuery = jQuery;\n",
+ " noConflict = !!oldjQuery;\n",
+ " } else {\n",
+ " // register the current jQuery\n",
+ " define('jquery', [], function() { return jQuery; });\n",
+ " }\n",
+ " if (!jQueryUI) {\n",
+ " paths.jQueryUI = jQueryUI_CDN.slice(null, -3);\n",
+ " } else {\n",
+ " define('jQueryUI', [], function() { return jQuery.ui; });\n",
+ " }\n",
+ " paths.underscore = UNDERSCORE_CDN.slice(null, -3);\n",
+ " var jquery_require = {\n",
+ " paths: paths,\n",
+ " shim: {\n",
+ " \"jQueryUI\": {\n",
+ " exports:\"$\",\n",
+ " deps: ['jquery']\n",
+ " },\n",
+ " \"underscore\": {\n",
+ " exports: '_'\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " require.config(jquery_require);\n",
+ " require([\"jQueryUI\", \"underscore\"], function(jUI, _){\n",
+ " if (noConflict) $.noConflict(true);\n",
+ " var vals = values;\n",
+ " if (dynamic && vals.constructor === Array) {\n",
+ " var default_value = parseFloat(value);\n",
+ " var min = parseFloat(vals[0]);\n",
+ " var max = parseFloat(vals[vals.length-1]);\n",
+ " var wstep = step;\n",
+ " var wlabels = [default_value];\n",
+ " var init_label = default_value;\n",
+ " } else {\n",
+ " var min = 0;\n",
+ " if (dynamic) {\n",
+ " var max = Object.keys(vals).length - 1;\n",
+ " var init_label = labels[value];\n",
+ " var default_value = values[value];\n",
+ " } else {\n",
+ " var max = vals.length - 1;\n",
+ " var init_label = labels[value];\n",
+ " var default_value = value;\n",
+ " }\n",
+ " var wstep = 1;\n",
+ " var wlabels = labels;\n",
+ " }\n",
+ " function adjustFontSize(text) {\n",
+ " var width_ratio = (text.parent().width()/8)/text.val().length;\n",
+ " var size = Math.min(0.9, Math.max(0.6, width_ratio))+'em';\n",
+ " text.css('font-size', size);\n",
+ " }\n",
+ " var slider = $('#_anim_widget'+id+'_'+dim);\n",
+ " slider.slider({\n",
+ " animate: \"fast\",\n",
+ " min: min,\n",
+ " max: max,\n",
+ " step: wstep,\n",
+ " value: default_value,\n",
+ " dim_vals: vals,\n",
+ " dim_labels: wlabels,\n",
+ " next_vals: next_vals,\n",
+ " slide: function(event, ui) {\n",
+ " var vals = slider.slider(\"option\", \"dim_vals\");\n",
+ " var next_vals = slider.slider(\"option\", \"next_vals\");\n",
+ " var dlabels = slider.slider(\"option\", \"dim_labels\");\n",
+ " if (dynamic) {\n",
+ " var dim_val = ui.value;\n",
+ " if (vals.constructor === Array) {\n",
+ " var label = ui.value;\n",
+ " } else {\n",
+ " var label = dlabels[ui.value];\n",
+ " }\n",
+ " } else {\n",
+ " var dim_val = vals[ui.value];\n",
+ " var label = dlabels[ui.value];\n",
+ " }\n",
+ " var text = $('#textInput'+id+'_'+dim);\n",
+ " text.val(label);\n",
+ " adjustFontSize(text);\n",
+ " HoloViews.index[plot_id].set_frame(dim_val, dim_idx);\n",
+ " if (Object.keys(next_vals).length > 0) {\n",
+ " var new_vals = next_vals[dim_val];\n",
+ " var next_widget = $('#_anim_widget'+id+'_'+next_dim);\n",
+ " update_widget(next_widget, new_vals);\n",
+ " }\n",
+ " }\n",
+ " });\n",
+ " slider.keypress(function(event) {\n",
+ " if (event.which == 80 || event.which == 112) {\n",
+ " var start = slider.slider(\"option\", \"value\");\n",
+ " var stop = slider.slider(\"option\", \"max\");\n",
+ " for (var i=start; i<=stop; i++) {\n",
+ " var delay = i*delay;\n",
+ " $.proxy(function doSetTimeout(i) { setTimeout($.proxy(function() {\n",
+ " var val = {value:i};\n",
+ " slider.slider('value',i);\n",
+ " slider.slider(\"option\", \"slide\")(null, val);\n",
+ " }, slider), delay);}, slider)(i);\n",
+ " }\n",
+ " }\n",
+ " if (event.which == 82 || event.which == 114) {\n",
+ " var start = slider.slider(\"option\", \"value\");\n",
+ " var stop = slider.slider(\"option\", \"min\");\n",
+ " var count = 0;\n",
+ " for (var i=start; i>=stop; i--) {\n",
+ " var delay = count*delay;\n",
+ " count = count + 1;\n",
+ " $.proxy(function doSetTimeout(i) { setTimeout($.proxy(function() {\n",
+ " var val = {value:i};\n",
+ " slider.slider('value',i);\n",
+ " slider.slider(\"option\", \"slide\")(null, val);\n",
+ " }, slider), delay);}, slider)(i);\n",
+ " }\n",
+ " }\n",
+ " });\n",
+ " var textInput = $('#textInput'+id+'_'+dim)\n",
+ " textInput.val(init_label);\n",
+ " adjustFontSize(textInput);\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "function init_dropdown(id, plot_id, dim, vals, value, next_vals, labels, next_dim, dim_idx, dynamic) {\n",
+ " var widget = $(\"#_anim_widget\"+id+'_'+dim);\n",
+ " widget.data('values', vals)\n",
+ " for (var i=0; i\", {\n",
+ " value: val,\n",
+ " text: labels[i]\n",
+ " }));\n",
+ " };\n",
+ " widget.data(\"next_vals\", next_vals);\n",
+ " widget.val(value);\n",
+ " widget.on('change', function(event, ui) {\n",
+ " if (dynamic) {\n",
+ " var dim_val = parseInt(this.value);\n",
+ " } else {\n",
+ " var dim_val = $.data(this, 'values')[this.value];\n",
+ " }\n",
+ " var next_vals = $.data(this, \"next_vals\");\n",
+ " if (Object.keys(next_vals).length > 0) {\n",
+ " var new_vals = next_vals[dim_val];\n",
+ " var next_widget = $('#_anim_widget'+id+'_'+next_dim);\n",
+ " update_widget(next_widget, new_vals);\n",
+ " }\n",
+ " var widgets = HoloViews.index[plot_id]\n",
+ " if (widgets) {\n",
+ " widgets.set_frame(dim_val, dim_idx);\n",
+ " }\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "\n",
+ "if (window.HoloViews === undefined) {\n",
+ " window.HoloViews = {}\n",
+ " window.PyViz = window.HoloViews\n",
+ "} else if (window.PyViz === undefined) {\n",
+ " window.PyViz = window.HoloViews\n",
+ "}\n",
+ "\n",
+ "\n",
+ "var _namespace = {\n",
+ " init_slider: init_slider,\n",
+ " init_dropdown: init_dropdown,\n",
+ " comms: {},\n",
+ " comm_status: {},\n",
+ " index: {},\n",
+ " plot_index: {},\n",
+ " kernels: {},\n",
+ " receivers: {}\n",
+ "}\n",
+ "\n",
+ "for (var k in _namespace) {\n",
+ " if (!(k in window.HoloViews)) {\n",
+ " window.HoloViews[k] = _namespace[k];\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Define Bokeh specific subclasses\n",
+ "function BokehSelectionWidget() {\n",
+ " SelectionWidget.apply(this, arguments);\n",
+ "}\n",
+ "\n",
+ "function BokehScrubberWidget() {\n",
+ " ScrubberWidget.apply(this, arguments);\n",
+ "}\n",
+ "\n",
+ "// Let them inherit from the baseclasses\n",
+ "BokehSelectionWidget.prototype = Object.create(SelectionWidget.prototype);\n",
+ "BokehScrubberWidget.prototype = Object.create(ScrubberWidget.prototype);\n",
+ "\n",
+ "// Define methods to override on widgets\n",
+ "var BokehMethods = {\n",
+ " update_cache : function(){\n",
+ " for (var index in this.frames) {\n",
+ " this.frames[index] = JSON.parse(this.frames[index]);\n",
+ " }\n",
+ " },\n",
+ " update : function(current){\n",
+ " if (current === undefined) {\n",
+ " return;\n",
+ " }\n",
+ " var data = this.frames[current];\n",
+ " if (data !== undefined) {\n",
+ " if (data.root in HoloViews.plot_index) {\n",
+ " var doc = HoloViews.plot_index[data.root].model.document;\n",
+ " } else {\n",
+ " var doc = Bokeh.index[data.root].model.document;\n",
+ " }\n",
+ " doc.apply_json_patch(data.content);\n",
+ " }\n",
+ " },\n",
+ " init_comms: function() {\n",
+ " if (Bokeh.protocol !== undefined) {\n",
+ " this.receiver = new Bokeh.protocol.Receiver()\n",
+ " } else {\n",
+ " this.receiver = null;\n",
+ " }\n",
+ " return HoloViewsWidget.prototype.init_comms.call(this);\n",
+ " },\n",
+ " process_msg : function(msg) {\n",
+ " if (this.plot_id in HoloViews.plot_index) {\n",
+ " var doc = HoloViews.plot_index[this.plot_id].model.document;\n",
+ " } else {\n",
+ " var doc = Bokeh.index[this.plot_id].model.document;\n",
+ " }\n",
+ " if (this.receiver === null) { return }\n",
+ " var receiver = this.receiver;\n",
+ " if (msg.buffers.length > 0) {\n",
+ " receiver.consume(msg.buffers[0].buffer)\n",
+ " } else {\n",
+ " receiver.consume(msg.content.data)\n",
+ " }\n",
+ " const comm_msg = receiver.message;\n",
+ " if ((comm_msg != null) && (doc != null)) {\n",
+ " doc.apply_json_patch(comm_msg.content, comm_msg.buffers)\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "// Extend Bokeh widgets with backend specific methods\n",
+ "extend(BokehSelectionWidget.prototype, BokehMethods);\n",
+ "extend(BokehScrubberWidget.prototype, BokehMethods);\n",
+ "\n",
+ "window.HoloViews.BokehSelectionWidget = BokehSelectionWidget\n",
+ "window.HoloViews.BokehScrubberWidget = BokehScrubberWidget\n",
+ "\n",
+ "// Define MPL specific subclasses\n",
+ "function MPLSelectionWidget() {\n",
+ " SelectionWidget.apply(this, arguments);\n",
+ "}\n",
+ "\n",
+ "function MPLScrubberWidget() {\n",
+ " ScrubberWidget.apply(this, arguments);\n",
+ "}\n",
+ "\n",
+ "// Let them inherit from the baseclasses\n",
+ "MPLSelectionWidget.prototype = Object.create(SelectionWidget.prototype);\n",
+ "MPLScrubberWidget.prototype = Object.create(ScrubberWidget.prototype);\n",
+ "\n",
+ "// Define methods to override on widgets\n",
+ "var MPLMethods = {\n",
+ " init_slider : function(init_val){\n",
+ " if(this.load_json) {\n",
+ " this.from_json()\n",
+ " } else {\n",
+ " this.update_cache();\n",
+ " }\n",
+ " if (this.dynamic | !this.cached | (this.current_vals === undefined)) {\n",
+ " this.update(0)\n",
+ " } else {\n",
+ " this.set_frame(this.current_vals[0], 0)\n",
+ " }\n",
+ " },\n",
+ " process_msg : function(msg) {\n",
+ " var data = msg.content.data;\n",
+ " this.frames[this.current] = data;\n",
+ " this.update_cache(true);\n",
+ " this.update(this.current);\n",
+ " }\n",
+ "}\n",
+ "// Extend MPL widgets with backend specific methods\n",
+ "extend(MPLSelectionWidget.prototype, MPLMethods);\n",
+ "extend(MPLScrubberWidget.prototype, MPLMethods);\n",
+ "\n",
+ "window.HoloViews.MPLSelectionWidget = MPLSelectionWidget\n",
+ "window.HoloViews.MPLScrubberWidget = MPLScrubberWidget\n",
+ "\n",
+ " function JupyterCommManager() {\n",
+ " }\n",
+ "\n",
+ " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n",
+ " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n",
+ " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n",
+ " comm_manager.register_target(comm_id, function(comm) {\n",
+ " comm.on_msg(msg_handler);\n",
+ " });\n",
+ " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n",
+ " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n",
+ " comm.onMsg = msg_handler;\n",
+ " });\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n",
+ " if (comm_id in window.PyViz.comms) {\n",
+ " return window.PyViz.comms[comm_id];\n",
+ " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n",
+ " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n",
+ " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n",
+ " if (msg_handler) {\n",
+ " comm.on_msg(msg_handler);\n",
+ " }\n",
+ " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n",
+ " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n",
+ " comm.open();\n",
+ " if (msg_handler) {\n",
+ " comm.onMsg = msg_handler;\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " window.PyViz.comms[comm_id] = comm;\n",
+ " return comm;\n",
+ " }\n",
+ "\n",
+ " window.PyViz.comm_manager = new JupyterCommManager();\n",
+ " \n",
+ "\n",
+ "var JS_MIME_TYPE = 'application/javascript';\n",
+ "var HTML_MIME_TYPE = 'text/html';\n",
+ "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n",
+ "var CLASS_NAME = 'output';\n",
+ "\n",
+ "/**\n",
+ " * Render data to the DOM node\n",
+ " */\n",
+ "function render(props, node) {\n",
+ " var div = document.createElement(\"div\");\n",
+ " var script = document.createElement(\"script\");\n",
+ " node.appendChild(div);\n",
+ " node.appendChild(script);\n",
+ "}\n",
+ "\n",
+ "/**\n",
+ " * Handle when a new output is added\n",
+ " */\n",
+ "function handle_add_output(event, handle) {\n",
+ " var output_area = handle.output_area;\n",
+ " var output = handle.output;\n",
+ " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n",
+ " return\n",
+ " }\n",
+ " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n",
+ " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n",
+ " if (id !== undefined) {\n",
+ " var nchildren = toinsert.length;\n",
+ " var html_node = toinsert[nchildren-1].children[0];\n",
+ " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n",
+ " var scripts = [];\n",
+ " var nodelist = html_node.querySelectorAll(\"script\");\n",
+ " for (var i in nodelist) {\n",
+ " if (nodelist.hasOwnProperty(i)) {\n",
+ " scripts.push(nodelist[i])\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " scripts.forEach( function (oldScript) {\n",
+ " var newScript = document.createElement(\"script\");\n",
+ " var attrs = [];\n",
+ " var nodemap = oldScript.attributes;\n",
+ " for (var j in nodemap) {\n",
+ " if (nodemap.hasOwnProperty(j)) {\n",
+ " attrs.push(nodemap[j])\n",
+ " }\n",
+ " }\n",
+ " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n",
+ " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n",
+ " oldScript.parentNode.replaceChild(newScript, oldScript);\n",
+ " });\n",
+ " if (JS_MIME_TYPE in output.data) {\n",
+ " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n",
+ " }\n",
+ " output_area._hv_plot_id = id;\n",
+ " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n",
+ " window.PyViz.plot_index[id] = Bokeh.index[id];\n",
+ " } else {\n",
+ " window.PyViz.plot_index[id] = null;\n",
+ " }\n",
+ " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n",
+ " var bk_div = document.createElement(\"div\");\n",
+ " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n",
+ " var script_attrs = bk_div.children[0].attributes;\n",
+ " for (var i = 0; i < script_attrs.length; i++) {\n",
+ " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n",
+ " }\n",
+ " // store reference to server id on output_area\n",
+ " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "/**\n",
+ " * Handle when an output is cleared or removed\n",
+ " */\n",
+ "function handle_clear_output(event, handle) {\n",
+ " var id = handle.cell.output_area._hv_plot_id;\n",
+ " var server_id = handle.cell.output_area._bokeh_server_id;\n",
+ " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n",
+ " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n",
+ " if (server_id !== null) {\n",
+ " comm.send({event_type: 'server_delete', 'id': server_id});\n",
+ " return;\n",
+ " } else if (comm !== null) {\n",
+ " comm.send({event_type: 'delete', 'id': id});\n",
+ " }\n",
+ " delete PyViz.plot_index[id];\n",
+ " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n",
+ " var doc = window.Bokeh.index[id].model.document\n",
+ " doc.clear();\n",
+ " const i = window.Bokeh.documents.indexOf(doc);\n",
+ " if (i > -1) {\n",
+ " window.Bokeh.documents.splice(i, 1);\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "/**\n",
+ " * Handle kernel restart event\n",
+ " */\n",
+ "function handle_kernel_cleanup(event, handle) {\n",
+ " delete PyViz.comms[\"hv-extension-comm\"];\n",
+ " window.PyViz.plot_index = {}\n",
+ "}\n",
+ "\n",
+ "/**\n",
+ " * Handle update_display_data messages\n",
+ " */\n",
+ "function handle_update_output(event, handle) {\n",
+ " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n",
+ " handle_add_output(event, handle)\n",
+ "}\n",
+ "\n",
+ "function register_renderer(events, OutputArea) {\n",
+ " function append_mime(data, metadata, element) {\n",
+ " // create a DOM node to render to\n",
+ " var toinsert = this.create_output_subarea(\n",
+ " metadata,\n",
+ " CLASS_NAME,\n",
+ " EXEC_MIME_TYPE\n",
+ " );\n",
+ " this.keyboard_manager.register_events(toinsert);\n",
+ " // Render to node\n",
+ " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n",
+ " render(props, toinsert[0]);\n",
+ " element.append(toinsert);\n",
+ " return toinsert\n",
+ " }\n",
+ "\n",
+ " events.on('output_added.OutputArea', handle_add_output);\n",
+ " events.on('output_updated.OutputArea', handle_update_output);\n",
+ " events.on('clear_output.CodeCell', handle_clear_output);\n",
+ " events.on('delete.Cell', handle_clear_output);\n",
+ " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n",
+ "\n",
+ " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n",
+ " safe: true,\n",
+ " index: 0\n",
+ " });\n",
+ "}\n",
+ "\n",
+ "if (window.Jupyter !== undefined) {\n",
+ " try {\n",
+ " var events = require('base/js/events');\n",
+ " var OutputArea = require('notebook/js/outputarea').OutputArea;\n",
+ " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n",
+ " register_renderer(events, OutputArea);\n",
+ " }\n",
+ " } catch(err) {\n",
+ " }\n",
+ "}\n"
+ ],
+ "application/vnd.holoviews_load.v0+json": "function HoloViewsWidget() {\n}\n\nHoloViewsWidget.prototype.init_slider = function(init_val){\n if(this.load_json) {\n this.from_json()\n } else {\n this.update_cache();\n }\n}\n\nHoloViewsWidget.prototype.populate_cache = function(idx){\n this.cache[idx].innerHTML = this.frames[idx];\n if (this.embed) {\n delete this.frames[idx];\n }\n}\n\nHoloViewsWidget.prototype.process_error = function(msg){\n}\n\nHoloViewsWidget.prototype.from_json = function() {\n var data_url = this.json_path + this.id + '.json';\n $.getJSON(data_url, $.proxy(function(json_data) {\n this.frames = json_data;\n this.update_cache();\n this.update(0);\n }, this));\n}\n\nHoloViewsWidget.prototype.dynamic_update = function(current){\n if (current === undefined) {\n return\n }\n this.current = current;\n if (this.comm) {\n var msg = {comm_id: this.id+'_client', content: current}\n this.comm.send(msg);\n }\n}\n\nHoloViewsWidget.prototype.update_cache = function(force){\n var frame_len = Object.keys(this.frames).length;\n for (var i=0; i 0) {\n that.time = Date.now();\n that.dynamic_update(that.queue[that.queue.length-1]);\n that.queue = [];\n } else {\n that.wait = false;\n }\n if ((msg.msg_type == \"Ready\") && msg.content) {\n console.log(\"Python callback returned following output:\", msg.content);\n } else if (msg.msg_type == \"Error\") {\n console.log(\"Python failed with the following traceback:\", msg.traceback)\n }\n }\n var comm = HoloViews.comm_manager.get_client_comm(this.plot_id, this.id+'_client', ack_callback);\n return comm\n }\n}\n\nHoloViewsWidget.prototype.msg_handler = function(msg) {\n var metadata = msg.metadata;\n if ((metadata.msg_type == \"Ready\")) {\n if (metadata.content) {\n console.log(\"Python callback returned following output:\", metadata.content);\n }\n\treturn;\n } else if (metadata.msg_type == \"Error\") {\n console.log(\"Python failed with the following traceback:\", metadata.traceback)\n return\n }\n this.process_msg(msg)\n}\n\nHoloViewsWidget.prototype.process_msg = function(msg) {\n}\n\nfunction SelectionWidget(frames, id, slider_ids, keyMap, dim_vals, notFound, load_json, mode, cached, json_path, dynamic, plot_id){\n this.frames = frames;\n this.id = id;\n this.plot_id = plot_id;\n this.slider_ids = slider_ids;\n this.keyMap = keyMap\n this.current_frame = 0;\n this.current_vals = dim_vals;\n this.load_json = load_json;\n this.mode = mode;\n this.notFound = notFound;\n this.cached = cached;\n this.dynamic = dynamic;\n this.cache = {};\n this.json_path = json_path;\n this.init_slider(this.current_vals[0]);\n this.queue = [];\n this.wait = false;\n if (!this.cached || this.dynamic) {\n this.comm = this.init_comms();\n }\n}\n\nSelectionWidget.prototype = new HoloViewsWidget;\n\n\nSelectionWidget.prototype.get_key = function(current_vals) {\n var key = \"(\";\n for (var i=0; i Date.now()))) {\n this.queue.push(key);\n return\n }\n this.queue = [];\n this.time = Date.now();\n this.current_frame = key;\n this.wait = true;\n this.dynamic_update(key)\n } else if (key !== undefined) {\n this.update(key)\n }\n}\n\n\n/* Define the ScrubberWidget class */\nfunction ScrubberWidget(frames, num_frames, id, interval, load_json, mode, cached, json_path, dynamic, plot_id){\n this.slider_id = \"_anim_slider\" + id;\n this.loop_select_id = \"_anim_loop_select\" + id;\n this.id = id;\n this.plot_id = plot_id;\n this.interval = interval;\n this.current_frame = 0;\n this.direction = 0;\n this.dynamic = dynamic;\n this.timer = null;\n this.load_json = load_json;\n this.mode = mode;\n this.cached = cached;\n this.frames = frames;\n this.cache = {};\n this.length = num_frames;\n this.json_path = json_path;\n document.getElementById(this.slider_id).max = this.length - 1;\n this.init_slider(0);\n this.wait = false;\n this.queue = [];\n if (!this.cached || this.dynamic) {\n this.comm = this.init_comms()\n }\n}\n\nScrubberWidget.prototype = new HoloViewsWidget;\n\nScrubberWidget.prototype.set_frame = function(frame){\n this.current_frame = frame;\n var widget = document.getElementById(this.slider_id);\n if (widget === null) {\n this.pause_animation();\n return\n }\n widget.value = this.current_frame;\n if (this.dynamic || !this.cached) {\n if ((this.time !== undefined) && ((this.wait) && ((this.time + 10000) > Date.now()))) {\n this.queue.push(frame);\n return\n }\n this.queue = [];\n this.time = Date.now();\n this.wait = true;\n this.dynamic_update(frame)\n } else {\n this.update(frame)\n }\n}\n\nScrubberWidget.prototype.get_loop_state = function(){\n var button_group = document[this.loop_select_id].state;\n for (var i = 0; i < button_group.length; i++) {\n var button = button_group[i];\n if (button.checked) {\n return button.value;\n }\n }\n return undefined;\n}\n\n\nScrubberWidget.prototype.next_frame = function() {\n this.set_frame(Math.min(this.length - 1, this.current_frame + 1));\n}\n\nScrubberWidget.prototype.previous_frame = function() {\n this.set_frame(Math.max(0, this.current_frame - 1));\n}\n\nScrubberWidget.prototype.first_frame = function() {\n this.set_frame(0);\n}\n\nScrubberWidget.prototype.last_frame = function() {\n this.set_frame(this.length - 1);\n}\n\nScrubberWidget.prototype.slower = function() {\n this.interval /= 0.7;\n if(this.direction > 0){this.play_animation();}\n else if(this.direction < 0){this.reverse_animation();}\n}\n\nScrubberWidget.prototype.faster = function() {\n this.interval *= 0.7;\n if(this.direction > 0){this.play_animation();}\n else if(this.direction < 0){this.reverse_animation();}\n}\n\nScrubberWidget.prototype.anim_step_forward = function() {\n if(this.current_frame < this.length - 1){\n this.next_frame();\n }else{\n var loop_state = this.get_loop_state();\n if(loop_state == \"loop\"){\n this.first_frame();\n }else if(loop_state == \"reflect\"){\n this.last_frame();\n this.reverse_animation();\n }else{\n this.pause_animation();\n this.last_frame();\n }\n }\n}\n\nScrubberWidget.prototype.anim_step_reverse = function() {\n if(this.current_frame > 0){\n this.previous_frame();\n } else {\n var loop_state = this.get_loop_state();\n if(loop_state == \"loop\"){\n this.last_frame();\n }else if(loop_state == \"reflect\"){\n this.first_frame();\n this.play_animation();\n }else{\n this.pause_animation();\n this.first_frame();\n }\n }\n}\n\nScrubberWidget.prototype.pause_animation = function() {\n this.direction = 0;\n if (this.timer){\n clearInterval(this.timer);\n this.timer = null;\n }\n}\n\nScrubberWidget.prototype.play_animation = function() {\n this.pause_animation();\n this.direction = 1;\n var t = this;\n if (!this.timer) this.timer = setInterval(function(){t.anim_step_forward();}, this.interval);\n}\n\nScrubberWidget.prototype.reverse_animation = function() {\n this.pause_animation();\n this.direction = -1;\n var t = this;\n if (!this.timer) this.timer = setInterval(function(){t.anim_step_reverse();}, this.interval);\n}\n\nfunction extend(destination, source) {\n for (var k in source) {\n if (source.hasOwnProperty(k)) {\n destination[k] = source[k];\n }\n }\n return destination;\n}\n\nfunction update_widget(widget, values) {\n if (widget.hasClass(\"ui-slider\")) {\n widget.slider('option', {\n min: 0,\n max: values.length-1,\n dim_vals: values,\n value: 0,\n dim_labels: values\n })\n widget.slider('option', 'slide').call(widget, event, {value: 0})\n } else {\n widget.empty();\n for (var i=0; i\", {\n value: i,\n text: values[i]\n }))\n };\n widget.data('values', values);\n widget.data('value', 0);\n widget.trigger(\"change\");\n };\n}\n\nfunction init_slider(id, plot_id, dim, values, next_vals, labels, dynamic, step, value, next_dim,\n dim_idx, delay, jQueryUI_CDN, UNDERSCORE_CDN) {\n // Slider JS Block START\n function loadcssfile(filename){\n var fileref=document.createElement(\"link\")\n fileref.setAttribute(\"rel\", \"stylesheet\")\n fileref.setAttribute(\"type\", \"text/css\")\n fileref.setAttribute(\"href\", filename)\n document.getElementsByTagName(\"head\")[0].appendChild(fileref)\n }\n loadcssfile(\"https://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css\");\n /* Check if jQuery and jQueryUI have been loaded\n otherwise load with require.js */\n var jQuery = window.jQuery,\n // check for old versions of jQuery\n oldjQuery = jQuery && !!jQuery.fn.jquery.match(/^1\\.[0-4](\\.|$)/),\n jquery_path = '',\n paths = {},\n noConflict;\n var jQueryUI = jQuery.ui;\n // check for jQuery\n if (!jQuery || oldjQuery) {\n // load if it's not available or doesn't meet min standards\n paths.jQuery = jQuery;\n noConflict = !!oldjQuery;\n } else {\n // register the current jQuery\n define('jquery', [], function() { return jQuery; });\n }\n if (!jQueryUI) {\n paths.jQueryUI = jQueryUI_CDN.slice(null, -3);\n } else {\n define('jQueryUI', [], function() { return jQuery.ui; });\n }\n paths.underscore = UNDERSCORE_CDN.slice(null, -3);\n var jquery_require = {\n paths: paths,\n shim: {\n \"jQueryUI\": {\n exports:\"$\",\n deps: ['jquery']\n },\n \"underscore\": {\n exports: '_'\n }\n }\n }\n require.config(jquery_require);\n require([\"jQueryUI\", \"underscore\"], function(jUI, _){\n if (noConflict) $.noConflict(true);\n var vals = values;\n if (dynamic && vals.constructor === Array) {\n var default_value = parseFloat(value);\n var min = parseFloat(vals[0]);\n var max = parseFloat(vals[vals.length-1]);\n var wstep = step;\n var wlabels = [default_value];\n var init_label = default_value;\n } else {\n var min = 0;\n if (dynamic) {\n var max = Object.keys(vals).length - 1;\n var init_label = labels[value];\n var default_value = values[value];\n } else {\n var max = vals.length - 1;\n var init_label = labels[value];\n var default_value = value;\n }\n var wstep = 1;\n var wlabels = labels;\n }\n function adjustFontSize(text) {\n var width_ratio = (text.parent().width()/8)/text.val().length;\n var size = Math.min(0.9, Math.max(0.6, width_ratio))+'em';\n text.css('font-size', size);\n }\n var slider = $('#_anim_widget'+id+'_'+dim);\n slider.slider({\n animate: \"fast\",\n min: min,\n max: max,\n step: wstep,\n value: default_value,\n dim_vals: vals,\n dim_labels: wlabels,\n next_vals: next_vals,\n slide: function(event, ui) {\n var vals = slider.slider(\"option\", \"dim_vals\");\n var next_vals = slider.slider(\"option\", \"next_vals\");\n var dlabels = slider.slider(\"option\", \"dim_labels\");\n if (dynamic) {\n var dim_val = ui.value;\n if (vals.constructor === Array) {\n var label = ui.value;\n } else {\n var label = dlabels[ui.value];\n }\n } else {\n var dim_val = vals[ui.value];\n var label = dlabels[ui.value];\n }\n var text = $('#textInput'+id+'_'+dim);\n text.val(label);\n adjustFontSize(text);\n HoloViews.index[plot_id].set_frame(dim_val, dim_idx);\n if (Object.keys(next_vals).length > 0) {\n var new_vals = next_vals[dim_val];\n var next_widget = $('#_anim_widget'+id+'_'+next_dim);\n update_widget(next_widget, new_vals);\n }\n }\n });\n slider.keypress(function(event) {\n if (event.which == 80 || event.which == 112) {\n var start = slider.slider(\"option\", \"value\");\n var stop = slider.slider(\"option\", \"max\");\n for (var i=start; i<=stop; i++) {\n var delay = i*delay;\n $.proxy(function doSetTimeout(i) { setTimeout($.proxy(function() {\n var val = {value:i};\n slider.slider('value',i);\n slider.slider(\"option\", \"slide\")(null, val);\n }, slider), delay);}, slider)(i);\n }\n }\n if (event.which == 82 || event.which == 114) {\n var start = slider.slider(\"option\", \"value\");\n var stop = slider.slider(\"option\", \"min\");\n var count = 0;\n for (var i=start; i>=stop; i--) {\n var delay = count*delay;\n count = count + 1;\n $.proxy(function doSetTimeout(i) { setTimeout($.proxy(function() {\n var val = {value:i};\n slider.slider('value',i);\n slider.slider(\"option\", \"slide\")(null, val);\n }, slider), delay);}, slider)(i);\n }\n }\n });\n var textInput = $('#textInput'+id+'_'+dim)\n textInput.val(init_label);\n adjustFontSize(textInput);\n });\n}\n\nfunction init_dropdown(id, plot_id, dim, vals, value, next_vals, labels, next_dim, dim_idx, dynamic) {\n var widget = $(\"#_anim_widget\"+id+'_'+dim);\n widget.data('values', vals)\n for (var i=0; i\", {\n value: val,\n text: labels[i]\n }));\n };\n widget.data(\"next_vals\", next_vals);\n widget.val(value);\n widget.on('change', function(event, ui) {\n if (dynamic) {\n var dim_val = parseInt(this.value);\n } else {\n var dim_val = $.data(this, 'values')[this.value];\n }\n var next_vals = $.data(this, \"next_vals\");\n if (Object.keys(next_vals).length > 0) {\n var new_vals = next_vals[dim_val];\n var next_widget = $('#_anim_widget'+id+'_'+next_dim);\n update_widget(next_widget, new_vals);\n }\n var widgets = HoloViews.index[plot_id]\n if (widgets) {\n widgets.set_frame(dim_val, dim_idx);\n }\n });\n}\n\n\nif (window.HoloViews === undefined) {\n window.HoloViews = {}\n window.PyViz = window.HoloViews\n} else if (window.PyViz === undefined) {\n window.PyViz = window.HoloViews\n}\n\n\nvar _namespace = {\n init_slider: init_slider,\n init_dropdown: init_dropdown,\n comms: {},\n comm_status: {},\n index: {},\n plot_index: {},\n kernels: {},\n receivers: {}\n}\n\nfor (var k in _namespace) {\n if (!(k in window.HoloViews)) {\n window.HoloViews[k] = _namespace[k];\n }\n}\n\n// Define Bokeh specific subclasses\nfunction BokehSelectionWidget() {\n SelectionWidget.apply(this, arguments);\n}\n\nfunction BokehScrubberWidget() {\n ScrubberWidget.apply(this, arguments);\n}\n\n// Let them inherit from the baseclasses\nBokehSelectionWidget.prototype = Object.create(SelectionWidget.prototype);\nBokehScrubberWidget.prototype = Object.create(ScrubberWidget.prototype);\n\n// Define methods to override on widgets\nvar BokehMethods = {\n update_cache : function(){\n for (var index in this.frames) {\n this.frames[index] = JSON.parse(this.frames[index]);\n }\n },\n update : function(current){\n if (current === undefined) {\n return;\n }\n var data = this.frames[current];\n if (data !== undefined) {\n if (data.root in HoloViews.plot_index) {\n var doc = HoloViews.plot_index[data.root].model.document;\n } else {\n var doc = Bokeh.index[data.root].model.document;\n }\n doc.apply_json_patch(data.content);\n }\n },\n init_comms: function() {\n if (Bokeh.protocol !== undefined) {\n this.receiver = new Bokeh.protocol.Receiver()\n } else {\n this.receiver = null;\n }\n return HoloViewsWidget.prototype.init_comms.call(this);\n },\n process_msg : function(msg) {\n if (this.plot_id in HoloViews.plot_index) {\n var doc = HoloViews.plot_index[this.plot_id].model.document;\n } else {\n var doc = Bokeh.index[this.plot_id].model.document;\n }\n if (this.receiver === null) { return }\n var receiver = this.receiver;\n if (msg.buffers.length > 0) {\n receiver.consume(msg.buffers[0].buffer)\n } else {\n receiver.consume(msg.content.data)\n }\n const comm_msg = receiver.message;\n if ((comm_msg != null) && (doc != null)) {\n doc.apply_json_patch(comm_msg.content, comm_msg.buffers)\n }\n }\n}\n\n// Extend Bokeh widgets with backend specific methods\nextend(BokehSelectionWidget.prototype, BokehMethods);\nextend(BokehScrubberWidget.prototype, BokehMethods);\n\nwindow.HoloViews.BokehSelectionWidget = BokehSelectionWidget\nwindow.HoloViews.BokehScrubberWidget = BokehScrubberWidget\n\n// Define MPL specific subclasses\nfunction MPLSelectionWidget() {\n SelectionWidget.apply(this, arguments);\n}\n\nfunction MPLScrubberWidget() {\n ScrubberWidget.apply(this, arguments);\n}\n\n// Let them inherit from the baseclasses\nMPLSelectionWidget.prototype = Object.create(SelectionWidget.prototype);\nMPLScrubberWidget.prototype = Object.create(ScrubberWidget.prototype);\n\n// Define methods to override on widgets\nvar MPLMethods = {\n init_slider : function(init_val){\n if(this.load_json) {\n this.from_json()\n } else {\n this.update_cache();\n }\n if (this.dynamic | !this.cached | (this.current_vals === undefined)) {\n this.update(0)\n } else {\n this.set_frame(this.current_vals[0], 0)\n }\n },\n process_msg : function(msg) {\n var data = msg.content.data;\n this.frames[this.current] = data;\n this.update_cache(true);\n this.update(this.current);\n }\n}\n// Extend MPL widgets with backend specific methods\nextend(MPLSelectionWidget.prototype, MPLMethods);\nextend(MPLScrubberWidget.prototype, MPLMethods);\n\nwindow.HoloViews.MPLSelectionWidget = MPLSelectionWidget\nwindow.HoloViews.MPLScrubberWidget = MPLScrubberWidget\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n }\n\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n"
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ":Image [x,y] (z)"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {
+ "application/vnd.holoviews_exec.v0+json": {}
+ },
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "## Plotting\n",
- "\n",
- "For ease of use, we also provide minimal plotting commands for use with contrib_colormaps. These depend on holoviews, which needs to be installed before they can be used. Once set up, these commands provide easy viewing capability of the colormaps.\n",
- "\n",
- "#### Example\n",
- "\n",
- "Import `swatch` from `contrib_colormaps.plotting` and load your desired backend into holoviews. Then call `swatch` with the name of a colormap. "
+ "hv.extension('matplotlib', logo=False)\n",
+ "swatch('sample')"
]
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 2,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "application/javascript": [
+ "\n",
+ "(function(root) {\n",
+ " function now() {\n",
+ " return new Date();\n",
+ " }\n",
+ "\n",
+ " var force = true;\n",
+ "\n",
+ " if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n",
+ " root._bokeh_onload_callbacks = [];\n",
+ " root._bokeh_is_loading = undefined;\n",
+ " }\n",
+ "\n",
+ " var JS_MIME_TYPE = 'application/javascript';\n",
+ " var HTML_MIME_TYPE = 'text/html';\n",
+ " var EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n",
+ " var CLASS_NAME = 'output_bokeh rendered_html';\n",
+ "\n",
+ " /**\n",
+ " * Render data to the DOM node\n",
+ " */\n",
+ " function render(props, node) {\n",
+ " var script = document.createElement(\"script\");\n",
+ " node.appendChild(script);\n",
+ " }\n",
+ "\n",
+ " /**\n",
+ " * Handle when an output is cleared or removed\n",
+ " */\n",
+ " function handleClearOutput(event, handle) {\n",
+ " var cell = handle.cell;\n",
+ "\n",
+ " var id = cell.output_area._bokeh_element_id;\n",
+ " var server_id = cell.output_area._bokeh_server_id;\n",
+ " // Clean up Bokeh references\n",
+ " if (id != null && id in Bokeh.index) {\n",
+ " Bokeh.index[id].model.document.clear();\n",
+ " delete Bokeh.index[id];\n",
+ " }\n",
+ "\n",
+ " if (server_id !== undefined) {\n",
+ " // Clean up Bokeh references\n",
+ " var cmd = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n",
+ " cell.notebook.kernel.execute(cmd, {\n",
+ " iopub: {\n",
+ " output: function(msg) {\n",
+ " var id = msg.content.text.trim();\n",
+ " if (id in Bokeh.index) {\n",
+ " Bokeh.index[id].model.document.clear();\n",
+ " delete Bokeh.index[id];\n",
+ " }\n",
+ " }\n",
+ " }\n",
+ " });\n",
+ " // Destroy server and session\n",
+ " var cmd = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n",
+ " cell.notebook.kernel.execute(cmd);\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " /**\n",
+ " * Handle when a new output is added\n",
+ " */\n",
+ " function handleAddOutput(event, handle) {\n",
+ " var output_area = handle.output_area;\n",
+ " var output = handle.output;\n",
+ "\n",
+ " // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n",
+ " if ((output.output_type != \"display_data\") || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n",
+ " return\n",
+ " }\n",
+ "\n",
+ " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n",
+ "\n",
+ " if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n",
+ " toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n",
+ " // store reference to embed id on output_area\n",
+ " output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n",
+ " }\n",
+ " if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n",
+ " var bk_div = document.createElement(\"div\");\n",
+ " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n",
+ " var script_attrs = bk_div.children[0].attributes;\n",
+ " for (var i = 0; i < script_attrs.length; i++) {\n",
+ " toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n",
+ " }\n",
+ " // store reference to server id on output_area\n",
+ " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " function register_renderer(events, OutputArea) {\n",
+ "\n",
+ " function append_mime(data, metadata, element) {\n",
+ " // create a DOM node to render to\n",
+ " var toinsert = this.create_output_subarea(\n",
+ " metadata,\n",
+ " CLASS_NAME,\n",
+ " EXEC_MIME_TYPE\n",
+ " );\n",
+ " this.keyboard_manager.register_events(toinsert);\n",
+ " // Render to node\n",
+ " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n",
+ " render(props, toinsert[toinsert.length - 1]);\n",
+ " element.append(toinsert);\n",
+ " return toinsert\n",
+ " }\n",
+ "\n",
+ " /* Handle when an output is cleared or removed */\n",
+ " events.on('clear_output.CodeCell', handleClearOutput);\n",
+ " events.on('delete.Cell', handleClearOutput);\n",
+ "\n",
+ " /* Handle when a new output is added */\n",
+ " events.on('output_added.OutputArea', handleAddOutput);\n",
+ "\n",
+ " /**\n",
+ " * Register the mime type and append_mime function with output_area\n",
+ " */\n",
+ " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n",
+ " /* Is output safe? */\n",
+ " safe: true,\n",
+ " /* Index of renderer in `output_area.display_order` */\n",
+ " index: 0\n",
+ " });\n",
+ " }\n",
+ "\n",
+ " // register the mime type if in Jupyter Notebook environment and previously unregistered\n",
+ " if (root.Jupyter !== undefined) {\n",
+ " var events = require('base/js/events');\n",
+ " var OutputArea = require('notebook/js/outputarea').OutputArea;\n",
+ "\n",
+ " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n",
+ " register_renderer(events, OutputArea);\n",
+ " }\n",
+ " }\n",
+ "\n",
+ " \n",
+ " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n",
+ " root._bokeh_timeout = Date.now() + 5000;\n",
+ " root._bokeh_failed_load = false;\n",
+ " }\n",
+ "\n",
+ " var NB_LOAD_WARNING = {'data': {'text/html':\n",
+ " \"
\\n\"+\n",
+ " \"
\\n\"+\n",
+ " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n",
+ " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n",
+ " \"
\\n\"+\n",
+ " \"
\\n\"+\n",
+ " \"
re-rerun `output_notebook()` to attempt to load from CDN again, or
\"],_default:[0,\"\",\"\"]};function ve(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):void 0!==e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&N(e,t)?b.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),\"script\"),l&&ye(a),n)for(c=0;o=a[c++];)he.test(o.type||\"\")&&n.push(o);return f}me=r.createDocumentFragment().appendChild(r.createElement(\"div\")),(xe=r.createElement(\"input\")).setAttribute(\"type\",\"radio\"),xe.setAttribute(\"checked\",\"checked\"),xe.setAttribute(\"name\",\"t\"),me.appendChild(xe),h.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML=\"\",h.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return r.activeElement}catch(e){}}()==(\"focus\"===t)}function Ae(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return b().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=b.guid++)),e.each(function(){b.event.add(this,t,i,r,n)})}function De(e,t,n){n?(Y.set(e,t,!1),b.event.add(e,t,{namespace:!1,handler:function(e){var r,i,a=Y.get(this,t);if(1&e.isTrigger&&this[t]){if(a.length)(b.event.special[t]||{}).delegateType&&e.stopPropagation();else if(a=o.call(arguments),Y.set(this,t,a),r=n(this,t),this[t](),a!==(i=Y.get(this,t))||r?Y.set(this,t,!1):i={},a!==i)return e.stopImmediatePropagation(),e.preventDefault(),i.value}else a.length&&(Y.set(this,t,{value:b.event.trigger(b.extend(a[0],b.Event.prototype),a.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,t)&&b.event.add(e,t,ke)}b.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(e);if(v)for(n.handler&&(n=(o=n).handler,i=o.selector),i&&b.find.matchesSelector(re,i),n.guid||(n.guid=b.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(t){return void 0!==b&&b.event.triggered!==t.type?b.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||\"\").match(P)||[\"\"]).length;l--;)d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=b.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=b.event.special[d]||{},c=b.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&b.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),b.event.global[d]=!0)},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){for(l=(t=(t||\"\").match(P)||[\"\"]).length;l--;)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){for(f=b.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||b.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(u)&&Y.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=b.event.fix(e),u=new Array(arguments.length),l=(Y.get(this,\"events\")||{})[s.type]||[],c=b.event.special[s.type]||{};for(u[0]=s,t=1;t=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:b.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,qe=/"
+ ],
+ "text/plain": [
+ ":Image [x,y] (z)"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {
+ "application/vnd.holoviews_exec.v0+json": {
+ "id": "1003"
+ }
+ },
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "from contrib_colormaps.plotting import swatch, swatches\n",
- "import holoviews as hv\n",
- "hv.extension('bokeh', 'matplotlib', logo=False)"
+ "hv.extension('bokeh', logo=False)\n",
+ "swatch('sample')"
]
},
{
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
+ "cell_type": "markdown",
+ "metadata": {},
"source": [
- "swatch('sample')"
+ "## Accessing the colormaps\n",
+ "\n",
+ "After importing `contrib_colormaps` as `cc`, all the colormaps will be available for use in different forms. It's a bit difficult to describe, but the idea is that this library should have at least one such form convenient for any particular application. There are two different basic versions for each colormap, each of which is fundamentally a list of colors: \n",
+ "\n",
+ "1. A Bokeh-style palette, i.e., a Python list of RGB colors as hex strings, like ``['#000000', ..., '#ffffff']``\n",
+ "2. If matplotlib is installed and importable, a Matplotlib ``LinearSegmentedColormap`` using normalized magnitudes, like ``LinearSegmentedColormap.from_list(\"fire\",[ [0.0,0.0,0.0], ..., [1.0,1.0,1.0] ], 256)``"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Usage\n",
- "\n",
- "All of the colormaps can be used directly in plotting libraries such as matplotlib or bokeh.\n",
+ "#### Example\n",
"\n",
- "#### Matplotlib"
+ "Here we show importing sample and printing the first 5 colors. "
]
},
{
"cell_type": "code",
- "execution_count": null,
- "metadata": {
- "scrolled": true
- },
- "outputs": [],
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['#0034f8', '#0038f5', '#003bf1', '#003eee', '#0041ea']"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "import numpy as np\n",
"import contrib_colormaps as cc\n",
- "import matplotlib.pyplot as plt\n",
"\n",
- "xs, _ = np.meshgrid(np.linspace(0, 1, 80), np.linspace(0, 1, 10))\n",
- "plt.imshow(xs, cmap=cc.cm.sample); # use tab completion to choose"
+ "cc.b_sample[:5]"
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": 36,
"metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[(0.0, 0.20755, 0.97632, 1.0),\n",
+ " (0.0, 0.22113, 0.96201, 1.0),\n",
+ " (0.0, 0.23397, 0.94773, 1.0),\n",
+ " (0.0, 0.24623, 0.93346, 1.0),\n",
+ " (0.0, 0.25798, 0.91922, 1.0)]"
+ ]
+ },
+ "execution_count": 36,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "#### Bokeh"
+ "[cc.m_sample(i) for i in range(5)]"
]
},
{
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"metadata": {},
- "outputs": [],
"source": [
- "import numpy as np\n",
- "import contrib_colormaps as cc\n",
- "from bokeh.plotting import figure, show\n",
- "\n",
- "xs, _ = np.meshgrid(np.linspace(0, 1, 80), np.linspace(0, 1, 10))\n",
- "p = figure(x_range=(0, 80), y_range=(0, 10), height=100, width=400)\n",
+ "The Bokeh-compatible palettes are provided as attributes in the ``contrib_colormaps`` namespace, with long names prefixed with ``b_``. E.g. ``rainforest`` can be accessed as ``cc.b_sample``. These names should tab complete once ``cc`` has been imported. Because Bokeh palettes are just Python lists, you can always reverse them using normal Python syntax, e.g. ``list(reversed(cc.b_sample))``, or use subsets of them with slice notation, e.g. ``cc.b_sample[25:]``. If you want to access the palettes by string name, they are also collected into a dictionary named ``palette``, so you can use ``cc.palette[\"sample\"]`` or ``cc.palette.sample``; whichever is more convenient.\n",
"\n",
- "p.image(image=[xs], x=0, y=0, dw=80, dh=10, palette=cc.palette.sample) # use tab completion to choose\n",
- "show(p)"
+ "The Matplotlib colormaps are also provided as tab-completable attributes, but consistently with a prefix ``m_``, e.g. ``cc.m_sample``. Already reversed versions are also available, as ``cc.m_sample_r``. The same colormaps are also registered with matplotlib's string-based dictionary with the prefix ``cc_``, making them available by name within various matplotlib functions (e.g. ``cc_sample``, ``cc_sample_r``). Finally, if you want to access the colormaps by string name without using Matplotlib's registry, they are also stored in the ``cc.cm`` dictionary, e.g. ``cc.cm[\"sample\"]`` or ``cc.cm[\"sample_r\"]``."
]
}
],
"metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
"language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
"name": "python",
- "pygments_lexer": "ipython3"
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.7.4"
}
},
"nbformat": 4,
diff --git a/examples/index.ipynb b/examples/index.ipynb
index 027072d..bee78ab 100644
--- a/examples/index.ipynb
+++ b/examples/index.ipynb
@@ -4,15 +4,94 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Collection of user-contributed colormaps\n",
+ "# Collection of user-contributed colormaps\n",
"\n",
"[contrib_colormaps](https://github.com/pyviz/contrib_colormaps) is a collection of \n",
"user-contributed colormaps for use with Python plotting programs like\n",
"[Bokeh](http://bokeh.pydata.org),\n",
"[Matplotlib](http://matplotlib.org),\n",
"[HoloViews](http://holoviews.org), and\n",
- "[Datashader](https://github.com/pyviz/datashader). \n",
+ "[Datashader](https://github.com/pyviz/datashader). "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "All of the colormaps can be used directly in plotting libraries such as matplotlib or bokeh."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Using contrib_colormaps"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Matplotlib"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ "