diff --git a/bqplot_image_gl/imagegl.py b/bqplot_image_gl/imagegl.py index 5b58c7b..18132fb 100644 --- a/bqplot_image_gl/imagegl.py +++ b/bqplot_image_gl/imagegl.py @@ -70,7 +70,9 @@ class Contour(bqplot.Mark): contour_lines = (List(List(Array(None, allow_none=True))) .tag(sync=True, **double_list_array_serialization)) level = (Float() | List(Float())).tag(sync=True) - color = widgets.Color(None, allow_none=True).tag(sync=True) + label = (Unicode(None, allow_none=True) | List(Unicode())).tag(sync=True) + color = (widgets.Color(None, allow_none=True) | + List(widgets.Color(None, allow_none=True))).tag(sync=True) scales_metadata = Dict({ 'x': {'orientation': 'horizontal', 'dimension': 'x'}, 'y': {'orientation': 'vertical', 'dimension': 'y'}, diff --git a/examples/contour.ipynb b/examples/contour.ipynb index feea3c8..a9a3090 100644 --- a/examples/contour.ipynb +++ b/examples/contour.ipynb @@ -98,7 +98,7 @@ "outputs": [], "source": [ "cp = widgets.ColorPicker(value='purple')\n", - "widgets.jslink((cp, 'value'), (contour, 'color'))\n", + "widgets.jsdlink((cp, 'value'), (contour, 'color'))\n", "cp" ] }, @@ -137,6 +137,16 @@ "contour.level = [150, 180]" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# but also color\n", + "contour.color = ['red', 'green']" + ] + }, { "cell_type": "code", "execution_count": null, @@ -234,7 +244,7 @@ "metadata": {}, "outputs": [], "source": [ - "x, y = np.ogrid[-np.pi:np.pi:1000j, -np.pi:np.pi:1000j]\n", + "x, y = np.ogrid[-np.pi:np.pi:256j, -np.pi:np.pi:256j]\n", "values = np.sin(np.exp((np.sin(x)**3 + np.cos(y)**2)))" ] }, @@ -287,7 +297,9 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "contour_precomputed.label = ['min', 'max']" + ] } ], "metadata": { diff --git a/js/lib/contour.js b/js/lib/contour.js index 06d9ec5..ef5458c 100644 --- a/js/lib/contour.js +++ b/js/lib/contour.js @@ -74,7 +74,7 @@ class ContourModel extends bqplot.MarkModel { class ContourView extends bqplot.Mark { create_listeners() { super.create_listeners(); - this.listenTo(this.model, "change:label_steps", () => { + this.listenTo(this.model, "change:label_steps change:label", () => { this.updateLabels() }) this.listenTo(this.parent, "margin_updated", () => { @@ -114,8 +114,11 @@ class ContourView extends bqplot.Mark { this.d3label_group.selectAll("text").attr("fill", color) } getColor(threshold, index) { - if(this.model.get('color')) - return this.model.get('color'); + let color = this.model.get('color') + if(color) { + const color_array = Array.isArray(color) ? color : [color]; + return color_array[index % color_array.length]; + } const model = this.model; var colors = this.scales.image.model.color_range; var color_scale = d3.scaleLinear() @@ -126,7 +129,7 @@ class ContourView extends bqplot.Mark { const delta = max - min; // a good default color is one that is 50% off from the value of the colormap const level_plus_50_percent = ((threshold - min) + delta / 2) % delta + min; - const color = color_scale(level_plus_50_percent); + color = color_scale(level_plus_50_percent); return color; } createPath(index) { @@ -196,8 +199,14 @@ class ContourView extends bqplot.Mark { this.model.contours.forEach((contour, index) => { const color = this.getColor(model.thresholds[index], index); - const label = String(model.thresholds[index]); - // http://wiki.geojson.org/GeoJSON_draft_version_6#MultiPolygon + let label = this.model.get('label') + if(label) { + const label_array = Array.isArray(label) ? label : [label]; + label = label_array[index % label_array.length]; + } else { + label = String(model.thresholds[index]); + } + // http://wiki.geojson.org/GeoJSON_draft_version_6#MultiPolygon const is_polygon = contour.type == 'MultiPolygon'; contour.coordinates.forEach(polygon => { // a MultiPolygon is a list of rings