from __future__ import unicode_literals
from collections import defaultdict
import traceback
import numpy as np
import param
from ..core import (HoloMap, DynamicMap, CompositeOverlay, Layout,
Overlay, GridSpace, NdLayout, Store)
from ..core.spaces import get_nested_streams
from ..core.util import (match_spec, is_number, wrap_tuple, basestring,
get_overlay_spec, unique_iterator)
from ..element import Area, Polygons
from ..operation.stats import univariate_kde, bivariate_kde, Operation
from ..streams import LinkedStream
[docs]def displayable(obj):
"""
Predicate that returns whether the object is displayable or not
(i.e whether the object obeys the nesting hierarchy
"""
if isinstance(obj, Overlay) and any(isinstance(o, (HoloMap, GridSpace))
for o in obj):
return False
if isinstance(obj, HoloMap):
return not (obj.type in [Layout, GridSpace, NdLayout])
if isinstance(obj, (GridSpace, Layout, NdLayout)):
for el in obj.values():
if not displayable(el):
return False
return True
return True
class Warning(param.Parameterized): pass
display_warning = Warning(name='Warning')
def collate(obj):
if isinstance(obj, Overlay):
nested_type = [type(o).__name__ for o in obj
if isinstance(o, (HoloMap, GridSpace))][0]
display_warning.warning("Nesting %ss within an Overlay makes it difficult "
"to access your data or control how it appears; "
"we recommend calling .collate() on the Overlay "
"in order to follow the recommended nesting "
"structure shown in the Composing Data tutorial"
"(http://goo.gl/2YS8LJ)" % nested_type)
return obj.collate()
if isinstance(obj, DynamicMap):
return obj.collate()
if isinstance(obj, HoloMap):
display_warning.warning("Nesting {0}s within a {1} makes it difficult "
"to access your data or control how it appears; "
"we recommend calling .collate() on the {1} "
"in order to follow the recommended nesting "
"structure shown in the Composing Data tutorial"
"(https://goo.gl/2YS8LJ)".format(obj.type.__name__, type(obj).__name__))
return obj.collate()
elif isinstance(obj, (Layout, NdLayout)):
try:
display_warning.warning(
"Layout contains HoloMaps which are not nested in the "
"recommended format for accessing your data; calling "
".collate() on these objects will resolve any violations "
"of the recommended nesting presented in the Composing Data "
"tutorial (https://goo.gl/2YS8LJ)")
expanded = []
for el in obj.values():
if isinstance(el, HoloMap) and not displayable(el):
collated_layout = Layout.from_values(el.collate())
expanded.extend(collated_layout.values())
return Layout(expanded)
except:
raise Exception(undisplayable_info(obj))
else:
raise Exception(undisplayable_info(obj))
[docs]def isoverlay_fn(obj):
"""
Determines whether object is a DynamicMap returning (Nd)Overlay types.
"""
return isinstance(obj, DynamicMap) and (isinstance(obj.last, CompositeOverlay))
[docs]def overlay_depth(obj):
"""
Computes the depth of a DynamicMap overlay if it can be determined
otherwise return None.
"""
if isinstance(obj, DynamicMap):
if isinstance(obj.last, CompositeOverlay):
return len(obj.last)
elif obj.last is None:
return None
return 1
else:
return 1
[docs]def compute_overlayable_zorders(obj, path=[]):
"""
Traverses an overlayable composite container to determine which
objects are associated with specific (Nd)Overlay layers by
z-order, making sure to take DynamicMap Callables into
account. Returns a mapping between the zorders of each layer and a
corresponding lists of objects.
Used to determine which overlaid subplots should be linked with
Stream callbacks.
"""
path = path+[obj]
zorder_map = defaultdict(list)
# Process non-dynamic layers
if not isinstance(obj, DynamicMap):
if isinstance(obj, CompositeOverlay):
for z, o in enumerate(obj):
zorder_map[z] = [o, obj]
else:
if obj not in zorder_map[0]:
zorder_map[0].append(obj)
return zorder_map
isoverlay = isinstance(obj.last, CompositeOverlay)
isdynoverlay = obj.callback._is_overlay
if obj not in zorder_map[0] and not isoverlay:
zorder_map[0].append(obj)
depth = overlay_depth(obj)
# Process the inputs of the DynamicMap callback
dmap_inputs = obj.callback.inputs if obj.callback.link_inputs else []
for z, inp in enumerate(dmap_inputs):
no_zorder_increment = False
if any(not (isoverlay_fn(p) or p.last is None) for p in path) and isoverlay_fn(inp):
# If overlay has been collapsed do not increment zorder
no_zorder_increment = True
input_depth = overlay_depth(inp)
if depth is not None and input_depth is not None and depth < input_depth:
# Skips branch of graph where the number of elements in an
# overlay has been reduced but still contains more than one layer
if depth > 1:
continue
else:
no_zorder_increment = True
# Recurse into DynamicMap.callback.inputs and update zorder_map
z = z if isdynoverlay else 0
deep_zorders = compute_overlayable_zorders(inp, path=path)
offset = max(zorder_map.keys())
for dz, objs in deep_zorders.items():
global_z = offset+z if no_zorder_increment else offset+dz+z
zorder_map[global_z] = list(unique_iterator(zorder_map[global_z]+objs))
# If object branches but does not declare inputs (e.g. user defined
# DynamicMaps returning (Nd)Overlay) add the items on the DynamicMap.last
found = any(isinstance(p, DynamicMap) and p.callback._is_overlay for p in path)
linked = any(isinstance(s, LinkedStream) and s.linked for s in obj.streams)
if (found or linked) and isoverlay and not isdynoverlay:
offset = max(zorder_map.keys())
for z, o in enumerate(obj.last):
if isoverlay and linked:
zorder_map[offset+z].append(obj)
if o not in zorder_map[offset+z]:
zorder_map[offset+z].append(o)
return zorder_map
[docs]def initialize_dynamic(obj):
"""
Initializes all DynamicMap objects contained by the object
"""
dmaps = obj.traverse(lambda x: x, specs=[DynamicMap])
for dmap in dmaps:
if dmap.unbounded:
# Skip initialization until plotting code
continue
if not len(dmap):
dmap[dmap._initial_key()]
[docs]def get_plot_frame(map_obj, key_map, cached=False):
"""
Returns an item in a HoloMap or DynamicMap given a mapping key
dimensions and their values.
"""
if map_obj.kdims and len(map_obj.kdims) == 1 and map_obj.kdims[0] == 'Frame':
# Special handling for static plots
return map_obj.last
key = tuple(key_map[kd.name] for kd in map_obj.kdims)
if key in map_obj.data and cached:
return map_obj.data[key]
else:
try:
return map_obj[key]
except KeyError:
return None
except StopIteration as e:
raise e
except Exception:
print(traceback.format_exc())
return None
[docs]def undisplayable_info(obj, html=False):
"Generate helpful message regarding an undisplayable object"
collate = '<tt>collate</tt>' if html else 'collate'
info = "For more information, please consult the Composing Data tutorial (http://git.io/vtIQh)"
if isinstance(obj, HoloMap):
error = "HoloMap of %s objects cannot be displayed." % obj.type.__name__
remedy = "Please call the %s method to generate a displayable object" % collate
elif isinstance(obj, Layout):
error = "Layout containing HoloMaps of Layout or GridSpace objects cannot be displayed."
remedy = "Please call the %s method on the appropriate elements." % collate
elif isinstance(obj, GridSpace):
error = "GridSpace containing HoloMaps of Layouts cannot be displayed."
remedy = "Please call the %s method on the appropriate elements." % collate
if not html:
return '\n'.join([error, remedy, info])
else:
return "<center>{msg}</center>".format(msg=('<br>'.join(
['<b>%s</b>' % error, remedy, '<i>%s</i>' % info])))
[docs]def compute_sizes(sizes, size_fn, scaling_factor, scaling_method, base_size):
"""
Scales point sizes according to a scaling factor,
base size and size_fn, which will be applied before
scaling.
"""
if sizes.dtype.kind not in ('i', 'f'):
return None
if scaling_method == 'area':
pass
elif scaling_method == 'width':
scaling_factor = scaling_factor**2
else:
raise ValueError(
'Invalid value for argument "scaling_method": "{}". '
'Valid values are: "width", "area".'.format(scaling_method))
sizes = size_fn(sizes)
return (base_size*scaling_factor*sizes)
[docs]def get_sideplot_ranges(plot, element, main, ranges):
"""
Utility to find the range for an adjoined
plot given the plot, the element, the
Element the plot is adjoined to and the
dictionary of ranges.
"""
key = plot.current_key
dims = element.dimensions()
dim = dims[0] if 'frequency' in dims[1].name else dims[1]
range_item = main
if isinstance(main, HoloMap):
if issubclass(main.type, CompositeOverlay):
range_item = [hm for hm in main.split_overlays()[1]
if dim in hm.dimensions('all')][0]
else:
range_item = HoloMap({0: main}, kdims=['Frame'])
ranges = match_spec(range_item.last, ranges)
if dim.name in ranges:
main_range = ranges[dim.name]
else:
framewise = plot.lookup_options(range_item.last, 'norm').options.get('framewise')
if framewise and range_item.get(key, False):
main_range = range_item[key].range(dim)
else:
main_range = range_item.range(dim)
# If .main is an NdOverlay or a HoloMap of Overlays get the correct style
if isinstance(range_item, HoloMap):
range_item = range_item.last
if isinstance(range_item, CompositeOverlay):
range_item = [ov for ov in range_item
if dim in ov.dimensions('all')][0]
return range_item, main_range, dim
[docs]def within_range(range1, range2):
"""Checks whether range1 is within the range specified by range2."""
range1 = [r if np.isfinite(r) else None for r in range1]
range2 = [r if np.isfinite(r) else None for r in range2]
return ((range1[0] is None or range2[0] is None or range1[0] >= range2[0]) and
(range1[1] is None or range2[1] is None or range1[1] <= range2[1]))
def validate_unbounded_mode(holomaps, dynmaps):
composite = HoloMap(enumerate(holomaps), kdims=['testing_kdim'])
holomap_kdims = set(unique_iterator([kd.name for dm in holomaps for kd in dm.kdims]))
hmranges = {d: composite.range(d) for d in holomap_kdims}
if any(not set(d.name for d in dm.kdims) <= holomap_kdims
for dm in dynmaps):
raise Exception('DynamicMap that are unbounded must have key dimensions that are a '
'subset of dimensions of the HoloMap(s) defining the keys.')
elif not all(within_range(hmrange, dm.range(d)) for dm in dynmaps
for d, hmrange in hmranges.items() if d in dm.kdims):
raise Exception('HoloMap(s) have keys outside the ranges specified on '
'the DynamicMap(s).')
[docs]def get_dynamic_mode(composite):
"Returns the common mode of the dynamic maps in given composite object"
dynmaps = composite.traverse(lambda x: x, [DynamicMap])
holomaps = composite.traverse(lambda x: x, ['HoloMap'])
dynamic_unbounded = any(m.unbounded for m in dynmaps)
if holomaps:
validate_unbounded_mode(holomaps, dynmaps)
elif dynamic_unbounded and not holomaps:
raise Exception("DynamicMaps in unbounded mode must be displayed alongside "
"a HoloMap to define the sampling.")
return dynmaps and not holomaps, dynamic_unbounded
[docs]def initialize_unbounded(obj, dimensions, key):
"""
Initializes any DynamicMaps in unbounded mode.
"""
select = dict(zip([d.name for d in dimensions], key))
try:
obj.select([DynamicMap], **select)
except KeyError:
pass
[docs]def save_frames(obj, filename, fmt=None, backend=None, options=None):
"""
Utility to export object to files frame by frame, numbered individually.
Will use default backend and figure format by default.
"""
backend = Store.current_backend if backend is None else backend
renderer = Store.renderers[backend]
fmt = renderer.params('fig').objects[0] if fmt is None else fmt
plot = renderer.get_plot(obj)
for i in range(len(plot)):
plot.update(i)
renderer.save(plot, '%s_%s' % (filename, i), fmt=fmt, options=options)
[docs]def dynamic_update(plot, subplot, key, overlay, items):
"""
Given a plot, subplot and dynamically generated (Nd)Overlay
find the closest matching Element for that plot.
"""
match_spec = get_overlay_spec(overlay,
wrap_tuple(key),
subplot.current_frame)
specs = [(i, get_overlay_spec(overlay, wrap_tuple(k), el))
for i, (k, el) in enumerate(items)]
return closest_match(match_spec, specs)
[docs]def closest_match(match, specs, depth=0):
"""
Recursively iterates over type, group, label and overlay key,
finding the closest matching spec.
"""
new_specs = []
match_lengths = []
for i, spec in specs:
if spec[0] == match[0]:
new_specs.append((i, spec[1:]))
else:
if is_number(match[0]) and is_number(spec[0]):
match_length = -abs(match[0]-spec[0])
elif all(isinstance(s[0], basestring) for s in [spec, match]):
match_length = max(i for i in range(len(match[0]))
if match[0].startswith(spec[0][:i]))
else:
match_length = 0
match_lengths.append((i, match_length, spec[0]))
if len(new_specs) == 1:
return new_specs[0][0]
elif new_specs:
depth = depth+1
return closest_match(match[1:], new_specs, depth)
else:
if depth == 0 or not match_lengths:
return None
else:
return sorted(match_lengths, key=lambda x: -x[1])[0][0]
[docs]def map_colors(arr, crange, cmap, hex=True):
"""
Maps an array of values to RGB hex strings, given
a color range and colormap.
"""
if isinstance(crange, np.ndarray):
xsorted = np.argsort(crange)
ypos = np.searchsorted(crange[xsorted], arr)
arr = xsorted[ypos]
else:
if isinstance(crange, tuple):
cmin, cmax = crange
else:
cmin, cmax = np.nanmin(arr), np.nanmax(arr)
arr = (arr - cmin) / (cmax-cmin)
arr = np.ma.array(arr, mask=np.logical_not(np.isfinite(arr)))
arr = cmap(arr)
if hex:
arr *= 255
return ["#{0:02x}{1:02x}{2:02x}".format(*(int(v) for v in c[:-1]))
for c in arr]
else:
return arr
[docs]def dim_axis_label(dimensions, separator=', '):
"""
Returns an axis label for one or more dimensions.
"""
if not isinstance(dimensions, list): dimensions = [dimensions]
return separator.join([d.pprint_label for d in dimensions])
[docs]def attach_streams(plot, obj, precedence=1.1):
"""
Attaches plot refresh to all streams on the object.
"""
def append_refresh(dmap):
for stream in get_nested_streams(dmap):
if plot.refresh not in stream._subscribers:
stream.add_subscriber(plot.refresh, precedence)
return obj.traverse(append_refresh, [DynamicMap])
[docs]def traverse_setter(obj, attribute, value):
"""
Traverses the object and sets the supplied attribute on the
object. Supports Dimensioned and DimensionedPlot types.
"""
obj.traverse(lambda x: setattr(x, attribute, value))
[docs]def get_min_distance(element):
"""
Gets the minimum sampling distance of the x- and y-coordinates
in a grid.
"""
xys = element.array([0, 1]).astype('float64').view(dtype=np.complex128)
m, n = np.meshgrid(xys, xys)
distances = np.abs(m-n)
np.fill_diagonal(distances, np.inf)
distances = distances[distances>0]
if len(distances):
return distances.min()
return 0
[docs]def rgb2hex(rgb):
"""
Convert RGB(A) tuple to hex.
"""
if len(rgb) > 3:
rgb = rgb[:-1]
return "#{0:02x}{1:02x}{2:02x}".format(*(int(v*255) for v in rgb))
# linear_kryw_0_100_c71 (aka "fire"):
# A perceptually uniform equivalent of matplotlib's "hot" colormap, from
# http://peterkovesi.com/projects/colourmaps
fire_colors = linear_kryw_0_100_c71 = [\
[0, 0, 0 ], [0.027065, 2.143e-05, 0 ],
[0.052054, 7.4728e-05, 0 ], [0.071511, 0.00013914, 0 ],
[0.08742, 0.0002088, 0 ], [0.10109, 0.00028141, 0 ],
[0.11337, 0.000356, 2.4266e-17], [0.12439, 0.00043134, 3.3615e-17],
[0.13463, 0.00050796, 2.1604e-17], [0.14411, 0.0005856, 0 ],
[0.15292, 0.00070304, 0 ], [0.16073, 0.0013432, 0 ],
[0.16871, 0.0014516, 0 ], [0.17657, 0.0012408, 0 ],
[0.18364, 0.0015336, 0 ], [0.19052, 0.0017515, 0 ],
[0.19751, 0.0015146, 0 ], [0.20401, 0.0015249, 0 ],
[0.20994, 0.0019639, 0 ], [0.21605, 0.002031, 0 ],
[0.22215, 0.0017559, 0 ], [0.22808, 0.001546, 1.8755e-05],
[0.23378, 0.0016315, 3.5012e-05], [0.23955, 0.0017194, 3.3352e-05],
[0.24531, 0.0018097, 1.8559e-05], [0.25113, 0.0019038, 1.9139e-05],
[0.25694, 0.0020015, 3.5308e-05], [0.26278, 0.0021017, 3.2613e-05],
[0.26864, 0.0022048, 2.0338e-05], [0.27451, 0.0023119, 2.2453e-05],
[0.28041, 0.0024227, 3.6003e-05], [0.28633, 0.0025363, 2.9817e-05],
[0.29229, 0.0026532, 1.9559e-05], [0.29824, 0.0027747, 2.7666e-05],
[0.30423, 0.0028999, 3.5752e-05], [0.31026, 0.0030279, 2.3231e-05],
[0.31628, 0.0031599, 1.2902e-05], [0.32232, 0.0032974, 3.2915e-05],
[0.32838, 0.0034379, 3.2803e-05], [0.33447, 0.0035819, 2.0757e-05],
[0.34057, 0.003731, 2.3831e-05], [0.34668, 0.0038848, 3.502e-05 ],
[0.35283, 0.0040418, 2.4468e-05], [0.35897, 0.0042032, 1.1444e-05],
[0.36515, 0.0043708, 3.2793e-05], [0.37134, 0.0045418, 3.012e-05 ],
[0.37756, 0.0047169, 1.4846e-05], [0.38379, 0.0048986, 2.796e-05 ],
[0.39003, 0.0050848, 3.2782e-05], [0.3963, 0.0052751, 1.9244e-05],
[0.40258, 0.0054715, 2.2667e-05], [0.40888, 0.0056736, 3.3223e-05],
[0.41519, 0.0058798, 2.159e-05 ], [0.42152, 0.0060922, 1.8214e-05],
[0.42788, 0.0063116, 3.2525e-05], [0.43424, 0.0065353, 2.2247e-05],
[0.44062, 0.006765, 1.5852e-05], [0.44702, 0.0070024, 3.1769e-05],
[0.45344, 0.0072442, 2.1245e-05], [0.45987, 0.0074929, 1.5726e-05],
[0.46631, 0.0077499, 3.0976e-05], [0.47277, 0.0080108, 1.8722e-05],
[0.47926, 0.0082789, 1.9285e-05], [0.48574, 0.0085553, 3.0063e-05],
[0.49225, 0.0088392, 1.4313e-05], [0.49878, 0.0091356, 2.3404e-05],
[0.50531, 0.0094374, 2.8099e-05], [0.51187, 0.0097365, 6.4695e-06],
[0.51844, 0.010039, 2.5791e-05], [0.52501, 0.010354, 2.4393e-05],
[0.53162, 0.010689, 1.6037e-05], [0.53825, 0.011031, 2.7295e-05],
[0.54489, 0.011393, 1.5848e-05], [0.55154, 0.011789, 2.3111e-05],
[0.55818, 0.012159, 2.5416e-05], [0.56485, 0.012508, 1.5064e-05],
[0.57154, 0.012881, 2.541e-05 ], [0.57823, 0.013283, 1.6166e-05],
[0.58494, 0.013701, 2.263e-05 ], [0.59166, 0.014122, 2.3316e-05],
[0.59839, 0.014551, 1.9432e-05], [0.60514, 0.014994, 2.4323e-05],
[0.6119, 0.01545, 1.3929e-05], [0.61868, 0.01592, 2.1615e-05],
[0.62546, 0.016401, 1.5846e-05], [0.63226, 0.016897, 2.0838e-05],
[0.63907, 0.017407, 1.9549e-05], [0.64589, 0.017931, 2.0961e-05],
[0.65273, 0.018471, 2.0737e-05], [0.65958, 0.019026, 2.0621e-05],
[0.66644, 0.019598, 2.0675e-05], [0.67332, 0.020187, 2.0301e-05],
[0.68019, 0.020793, 2.0029e-05], [0.68709, 0.021418, 2.0088e-05],
[0.69399, 0.022062, 1.9102e-05], [0.70092, 0.022727, 1.9662e-05],
[0.70784, 0.023412, 1.7757e-05], [0.71478, 0.024121, 1.8236e-05],
[0.72173, 0.024852, 1.4944e-05], [0.7287, 0.025608, 2.0245e-06],
[0.73567, 0.02639, 1.5013e-07], [0.74266, 0.027199, 0 ],
[0.74964, 0.028038, 0 ], [0.75665, 0.028906, 0 ],
[0.76365, 0.029806, 0 ], [0.77068, 0.030743, 0 ],
[0.77771, 0.031711, 0 ], [0.78474, 0.032732, 0 ],
[0.79179, 0.033741, 0 ], [0.79886, 0.034936, 0 ],
[0.80593, 0.036031, 0 ], [0.81299, 0.03723, 0 ],
[0.82007, 0.038493, 0 ], [0.82715, 0.039819, 0 ],
[0.83423, 0.041236, 0 ], [0.84131, 0.042647, 0 ],
[0.84838, 0.044235, 0 ], [0.85545, 0.045857, 0 ],
[0.86252, 0.047645, 0 ], [0.86958, 0.049578, 0 ],
[0.87661, 0.051541, 0 ], [0.88365, 0.053735, 0 ],
[0.89064, 0.056168, 0 ], [0.89761, 0.058852, 0 ],
[0.90451, 0.061777, 0 ], [0.91131, 0.065281, 0 ],
[0.91796, 0.069448, 0 ], [0.92445, 0.074684, 0 ],
[0.93061, 0.08131, 0 ], [0.93648, 0.088878, 0 ],
[0.94205, 0.097336, 0 ], [0.9473, 0.10665, 0 ],
[0.9522, 0.1166, 0 ], [0.95674, 0.12716, 0 ],
[0.96094, 0.13824, 0 ], [0.96479, 0.14963, 0 ],
[0.96829, 0.16128, 0 ], [0.97147, 0.17303, 0 ],
[0.97436, 0.18489, 0 ], [0.97698, 0.19672, 0 ],
[0.97934, 0.20846, 0 ], [0.98148, 0.22013, 0 ],
[0.9834, 0.23167, 0 ], [0.98515, 0.24301, 0 ],
[0.98672, 0.25425, 0 ], [0.98815, 0.26525, 0 ],
[0.98944, 0.27614, 0 ], [0.99061, 0.28679, 0 ],
[0.99167, 0.29731, 0 ], [0.99263, 0.30764, 0 ],
[0.9935, 0.31781, 0 ], [0.99428, 0.3278, 0 ],
[0.995, 0.33764, 0 ], [0.99564, 0.34735, 0 ],
[0.99623, 0.35689, 0 ], [0.99675, 0.3663, 0 ],
[0.99722, 0.37556, 0 ], [0.99765, 0.38471, 0 ],
[0.99803, 0.39374, 0 ], [0.99836, 0.40265, 0 ],
[0.99866, 0.41145, 0 ], [0.99892, 0.42015, 0 ],
[0.99915, 0.42874, 0 ], [0.99935, 0.43724, 0 ],
[0.99952, 0.44563, 0 ], [0.99966, 0.45395, 0 ],
[0.99977, 0.46217, 0 ], [0.99986, 0.47032, 0 ],
[0.99993, 0.47838, 0 ], [0.99997, 0.48638, 0 ],
[1, 0.4943, 0 ], [1, 0.50214, 0 ],
[1, 0.50991, 1.2756e-05], [1, 0.51761, 4.5388e-05],
[1, 0.52523, 9.6977e-05], [1, 0.5328, 0.00016858],
[1, 0.54028, 0.0002582 ], [1, 0.54771, 0.00036528],
[1, 0.55508, 0.00049276], [1, 0.5624, 0.00063955],
[1, 0.56965, 0.00080443], [1, 0.57687, 0.00098902],
[1, 0.58402, 0.0011943 ], [1, 0.59113, 0.0014189 ],
[1, 0.59819, 0.0016626 ], [1, 0.60521, 0.0019281 ],
[1, 0.61219, 0.0022145 ], [1, 0.61914, 0.0025213 ],
[1, 0.62603, 0.0028496 ], [1, 0.6329, 0.0032006 ],
[1, 0.63972, 0.0035741 ], [1, 0.64651, 0.0039701 ],
[1, 0.65327, 0.0043898 ], [1, 0.66, 0.0048341 ],
[1, 0.66669, 0.005303 ], [1, 0.67336, 0.0057969 ],
[1, 0.67999, 0.006317 ], [1, 0.68661, 0.0068648 ],
[1, 0.69319, 0.0074406 ], [1, 0.69974, 0.0080433 ],
[1, 0.70628, 0.0086756 ], [1, 0.71278, 0.0093486 ],
[1, 0.71927, 0.010023 ], [1, 0.72573, 0.010724 ],
[1, 0.73217, 0.011565 ], [1, 0.73859, 0.012339 ],
[1, 0.74499, 0.01316 ], [1, 0.75137, 0.014042 ],
[1, 0.75772, 0.014955 ], [1, 0.76406, 0.015913 ],
[1, 0.77039, 0.016915 ], [1, 0.77669, 0.017964 ],
[1, 0.78298, 0.019062 ], [1, 0.78925, 0.020212 ],
[1, 0.7955, 0.021417 ], [1, 0.80174, 0.02268 ],
[1, 0.80797, 0.024005 ], [1, 0.81418, 0.025396 ],
[1, 0.82038, 0.026858 ], [1, 0.82656, 0.028394 ],
[1, 0.83273, 0.030013 ], [1, 0.83889, 0.031717 ],
[1, 0.84503, 0.03348 ], [1, 0.85116, 0.035488 ],
[1, 0.85728, 0.037452 ], [1, 0.8634, 0.039592 ],
[1, 0.86949, 0.041898 ], [1, 0.87557, 0.044392 ],
[1, 0.88165, 0.046958 ], [1, 0.88771, 0.04977 ],
[1, 0.89376, 0.052828 ], [1, 0.8998, 0.056209 ],
[1, 0.90584, 0.059919 ], [1, 0.91185, 0.063925 ],
[1, 0.91783, 0.068579 ], [1, 0.92384, 0.073948 ],
[1, 0.92981, 0.080899 ], [1, 0.93576, 0.090648 ],
[1, 0.94166, 0.10377 ], [1, 0.94752, 0.12051 ],
[1, 0.9533, 0.14149 ], [1, 0.959, 0.1672 ],
[1, 0.96456, 0.19823 ], [1, 0.96995, 0.23514 ],
[1, 0.9751, 0.2786 ], [1, 0.97992, 0.32883 ],
[1, 0.98432, 0.38571 ], [1, 0.9882, 0.44866 ],
[1, 0.9915, 0.51653 ], [1, 0.99417, 0.58754 ],
[1, 0.99625, 0.65985 ], [1, 0.99778, 0.73194 ],
[1, 0.99885, 0.80259 ], [1, 0.99953, 0.87115 ],
[1, 0.99989, 0.93683 ], [1, 1, 1 ]]
# Bokeh palette
fire = [str('#{0:02x}{1:02x}{2:02x}'.format(int(r*255),int(g*255),int(b*255)))
for r,g,b in fire_colors]
# Matplotlib colormap
try:
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.cm import register_cmap
fire_cmap = LinearSegmentedColormap.from_list("fire", fire_colors, N=len(fire_colors))
fire_r_cmap = LinearSegmentedColormap.from_list("fire_r", list(reversed(fire_colors)), N=len(fire_colors))
register_cmap("fire", cmap=fire_cmap)
register_cmap("fire_r", cmap=fire_r_cmap)
except ImportError:
pass