SLIDE 12: Pie Charts: All 4 Legend Options ------------------------------------------
505643
function slide12() {
		var slide = pptx.addNewSlide();
		slide.addNotes('API Docs: https://gitbrent.github.io/PptxGenJS/docs/api-charts.html');
		slide.addTable( [ [{ text:'Chart Examples: Pie Charts: Legends', options:gOptsTextL },gOptsTextR] ], gOptsTabOpts );

		// INTERNAL USE: Not visible to user (its behind a chart): Used for ensuring ref counting works across obj types (eg: `rId` check/test)
		if (NODEJS) slide.addImage({ path:(NODEJS ? gPaths.ccCopyRemix.path.replace(/http.+\/examples/, '../examples') : gPaths.ccCopyRemix.path), x:0.5, y:1.0, w:1.2, h:1.2 });

		// TOP-LEFT
		slide.addText( '.', {x:0.5, y:0.5, w:4.2, h:3.2, fill:'F1F1F1', color:'F1F1F1'} );
		slide.addChart(
			pptx.charts.PIE, dataChartPieStat,
			{x:0.5, y:0.5, w:4.2, h:3.2, showLegend:true, legendPos:'l', legendFontFace:'Courier New'}
		);

		// TOP-RIGHT
		slide.addText( '.', {x:5.6, y:0.5, w:3.2, h:3.2, fill:'F1F1F1', color:'F1F1F1'} );
		slide.addChart( pptx.charts.PIE, dataChartPieStat, {x:5.6, y:0.5, w:3.2, h:3.2, showLegend:true, legendPos:'t'} );

		// BTM-LEFT
		slide.addText( '.', {x:0.5, y:4.0, w:4.2, h:3.2, fill:'F1F1F1', color:'F1F1F1'} );
		slide.addChart( pptx.charts.PIE, dataChartPieLocs, {x:0.5, y:4.0, w:4.2, h:3.2, showLegend:true, legendPos:'r'} );

		// BTM-RIGHT
		slide.addText( '.', {x:5.6, y:4.0, w:3.2, h:3.2, fill:'F1F1F1', color:'F1F1F1'} );
		slide.addChart( pptx.charts.PIE, dataChartPieLocs, {x:5.6, y:4.0, w:3.2, h:3.2, showLegend:true, legendPos:'b'} );

		// BOTH: TOP-RIGHT
		slide.addText( '.', {x:9.8, y:0.5, w:3.2, h:3.2, fill:'F1F1F1', color:'F1F1F1'} );
		// DEMO: `legendFontSize`, `titleAlign`, `titlePos`
		slide.addChart( pptx.charts.PIE, dataChartPieLocs,
		{
			x:9.8, y:0.5, w:3.2, h:3.2, dataBorder:{pt:'1',color:'F1F1F1'},
			showLegend: true,
			legendPos: 't',
			showTitle: true,
			title:'Left Title & Large Legend',

			legendFontSize: 14,
			titleAlign: 'left',
			titlePos: {x: 0, y: 0}
		});

		// BOTH: BTM-RIGHT
		slide.addText( '.', {x:9.8, y:4.0, w:3.2, h:3.2, fill:'F1F1F1', color:'F1F1F1'} );
		slide.addChart( pptx.charts.PIE, dataChartPieLocs, {x:9.8, y:4.0, w:3.2, h:3.2, dataBorder:{pt:'1',color:'F1F1F1'}, showLegend:true, legendPos:'b', showTitle:true, title:'Title & Legend'} );
	}
726182
function () {
		var series = this,
			chart = series.chart,
			renderer = chart.renderer,
			shapeArgs,
			tracker,
			trackerLabel = +new Date(),
			options = series.options,
			cursor = options.cursor,
			css = cursor && { cursor: cursor },
			rel;

		each(series.data, function (point) {
			tracker = point.tracker;
			shapeArgs = point.trackerArgs || point.shapeArgs;
			delete shapeArgs.strokeWidth;
			if (point.y !== null) {
				if (tracker) {// update
					tracker.attr(shapeArgs);

				} else {
					point.tracker =
						renderer[point.shapeType](shapeArgs)
						.attr({
							isTracker: trackerLabel,
							fill: TRACKER_FILL,
							visibility: series.visible ? VISIBLE : HIDDEN,
							zIndex: options.zIndex || 1
						})
						.on(hasTouch ? 'touchstart' : 'mouseover', function (event) {
							rel = event.relatedTarget || event.fromElement;
							if (chart.hoverSeries !== series && attr(rel, 'isTracker') !== trackerLabel) {
								series.onMouseOver();
							}
							point.onMouseOver();

						})
						.on('mouseout', function (event) {
							if (!options.stickyTracking) {
								rel = event.relatedTarget || event.toElement;
								if (attr(rel, 'isTracker') !== trackerLabel) {
									series.onMouseOut();
								}
							}
						})
						.css(css)
						.add(point.group || chart.trackerGroup); // pies have point group - see issue #118
				}
			}
		});
	}
134570
function (value, legend) {
            for (var i = 0; i < legend.slices.length; ++i) {
                if ((legend.slices[i].sliceValue !== undefined && value === legend.slices[i].sliceValue) ||
                    ((legend.slices[i].sliceValue === undefined) &&
                        (legend.slices[i].min === undefined || value >= legend.slices[i].min) &&
                        (legend.slices[i].max === undefined || value <= legend.slices[i].max))
                ) {
                    return legend.slices[i];
                }
            }
            return {};
        }
415249
private function _renderLegend() {
		$legend = $this->_chart->getLegend();
		if (!is_null($legend)) {
			$legendPosition = $legend->getPosition();
			$legendOverlay = $legend->getOverlay();
			switch ($legendPosition) {
				case 'r'	:
					$this->_graph->legend->SetPos(0.01,0.5,'right','center');	//	right
					$this->_graph->legend->SetColumns(1);
					break;
				case 'l'	:
					$this->_graph->legend->SetPos(0.01,0.5,'left','center');	//	left
					$this->_graph->legend->SetColumns(1);
					break;
				case 't'	:
					$this->_graph->legend->SetPos(0.5,0.01,'center','top');	//	top
					break;
				case 'b'	:
					$this->_graph->legend->SetPos(0.5,0.99,'center','bottom');	//	bottom
					break;
				default		:
					$this->_graph->legend->SetPos(0.01,0.01,'right','top');	//	top-right
					$this->_graph->legend->SetColumns(1);
					break;
			}
		} else {
			$this->_graph->legend->Hide();
		}
	}
975262
def add_legend(self):
        """"""
        cuts = [tag for tag in self.tags if tag is not self._new_cut]
        self.cuts_plot.ax.legend(cuts, loc='best',
                                 shadow=True, fancybox=True,
                                 prop={'size': 8}, labelspacing=0.2)
308310
def _draw_legend(self):
        
        legend_box = self.guides.build(self)
        if not legend_box:
            return

        figure = self.figure
        left = figure.subplotpars.left
        right = figure.subplotpars.right
        top = figure.subplotpars.top
        bottom = figure.subplotpars.bottom
        W, H = figure.get_size_inches()
        position = self.guides.position
        get_property = self.theme.themeables.property
        # defaults
        spacing = 0.1
        strip_margin_x = 0
        strip_margin_y = 0

        with suppress(KeyError):
            spacing = get_property('legend_box_spacing')
        with suppress(KeyError):
            strip_margin_x = get_property('strip_margin_x')
        with suppress(KeyError):
            strip_margin_y = get_property('strip_margin_y')

        right_strip_width = self.facet.strip_size('right')
        top_strip_height = self.facet.strip_size('top')

        # Other than when the legend is on the right the rest of
        # the computed x, y locations are not gauranteed not to
        # overlap with the axes or the labels. The user must then
        # use the legend_margin theme parameter to adjust the
        # location. This should get fixed when MPL has a better
        # layout manager.
        if position == 'right':
            loc = 6
            pad = right_strip_width*(1+strip_margin_x) + spacing
            x = right + pad/W
            y = 0.5
        elif position == 'left':
            loc = 7
            x = left - spacing/W
            y = 0.5
        elif position == 'top':
            loc = 8
            x = 0.5
            pad = top_strip_height*(1+strip_margin_y) + spacing
            y = top + pad/H
        elif position == 'bottom':
            loc = 9
            x = 0.5
            y = bottom - spacing/H
        else:
            loc = 10
            x, y = position

        anchored_box = AnchoredOffsetbox(
            loc=loc,
            child=legend_box,
            pad=0.,
            frameon=False,
            bbox_to_anchor=(x, y),
            bbox_transform=figure.transFigure,
            borderpad=0.)

        anchored_box.set_zorder(90.1)
        self.figure._themeable['legend_background'] = anchored_box
        ax = self.axs[0]
        ax.add_artist(anchored_box)
835471
function (chart) {
			var series = this,
				valueDecimals = chart.options.legend.valueDecimals,
				legendItems = [],
				name,
				from,
				to,
				fromLabel,
				toLabel,
				colorRange,
				valueRanges,
				gradientColor,
				grad,
				tmpLabel,
				horizontal = chart.options.legend.layout === 'horizontal';

			
			Highcharts.Series.prototype.init.apply(this, arguments);
			colorRange = series.options.colorRange;
			valueRanges = series.options.valueRanges;

			if (valueRanges) {
				each(valueRanges, function (range) {
					from = range.from;
					to = range.to;
					
					// Assemble the default name. This can be overridden by legend.options.labelFormatter
					name = '';
					if (from === UNDEFINED) {
						name = '< ';
					} else if (to === UNDEFINED) {
						name = '> ';
					}
					if (from !== UNDEFINED) {
						name += numberFormat(from, valueDecimals);
					}
					if (from !== UNDEFINED && to !== UNDEFINED) {
						name += ' - ';
					}
					if (to !== UNDEFINED) {
						name += numberFormat(to, valueDecimals);
					}
					
					// Add a mock object to the legend items
					legendItems.push(Highcharts.extend({
						chart: series.chart,
						name: name,
						options: {},
						drawLegendSymbol: seriesTypes.area.prototype.drawLegendSymbol,
						visible: true,
						setState: function () {},
						setVisible: function () {}
					}, range));
				});
				series.legendItems = legendItems;

			} else if (colorRange) {

				from = colorRange.from;
				to = colorRange.to;
				fromLabel = colorRange.fromLabel;
				toLabel = colorRange.toLabel;

				// Flips linearGradient variables and label text.
				grad = horizontal ? [0, 0, 1, 0] : [0, 1, 0, 0]; 
				if (!horizontal) {
					tmpLabel = fromLabel;
					fromLabel = toLabel;
					toLabel = tmpLabel;
				} 

				// Creates color gradient.
				gradientColor = {
					linearGradient: { x1: grad[0], y1: grad[1], x2: grad[2], y2: grad[3] },
					stops: 
					[
						[0, from],
						[1, to]
					]
				};

				// Add a mock object to the legend items.
				legendItems = [{
					chart: series.chart,
					options: {},
					fromLabel: fromLabel,
					toLabel: toLabel,
					color: gradientColor,
					drawLegendSymbol: this.drawLegendSymbolGradient,
					visible: true,
					setState: function () {},
					setVisible: function () {}
				}];

				series.legendItems = legendItems;
			}
		}
35408
function slide18() {
		var slide = pptx.addNewSlide();
		slide.addNotes('API Docs: https://gitbrent.github.io/PptxGenJS/docs/api-charts.html');
		slide.addTable( [ [{ text:'Chart Options: Shadow, Transparent Colors', options:gOptsTextL },gOptsTextR] ], gOptsTabOpts );

		var arrDataRegions = [{
			name  : 'Region 2',
			labels: ['April', 'May', 'June', 'July', 'August'],
			values: [0, 30, 53, 10, 25]
		}, {
			name  : 'Region 3',
			labels: ['April', 'May', 'June', 'July', 'August'],
			values: [17, 26, 53, 100, 75]
		}, {
			name  : 'Region 4',
			labels: ['April', 'May', 'June', 'July', 'August'],
			values: [55, 43, 70, 90, 80]
		}, {
			name  : 'Region 5',
			labels: ['April', 'May', 'June', 'July', 'August'],
			values: [55, 43, 70, 90, 80]
		}];
		var arrDataHighVals = [
			{
				name  : 'California',
				labels: ['Apartment', 'Townhome', 'Duplex', 'House', 'Big House'],
				values: [2000, 2800, 3200, 4000, 5000]
			},
			{
				name  : 'Texas',
				labels: ['Apartment', 'Townhome', 'Duplex', 'House', 'Big House'],
				values: [1400, 2000, 2500, 3000, 3800]
			}
		];
		var single = [{
			name  : 'Texas',
			labels: ['Apartment', 'Townhome', 'Duplex', 'House', 'Big House'],
			values: [1400, 2000, 2500, 3000, 3800]
		}];

		// TOP-LEFT: H/bar
		var optsChartBar1 = { x:0.5, y:0.6, w:6.0, h:3.0,
			showTitle: true,
			title: 'Large blue shadow',
			barDir: 'bar',
			barGrouping: 'standard',
			dataLabelColor   : 'FFFFFF',
			showValue        : true,
			shadow: {
				type: 'outer',
				blur: 10,
				offset: 5,
				angle: 45,
				color: '0059B1',
				opacity: 1
			}
		};

		var pieOptions = { x:7.0, y:0.6, w:6.0, h:3.0,
			showTitle: true,
			title: 'Rotated cyan shadow',
			dataLabelColor   : 'FFFFFF',
			shadow: {
				type: 'outer',
				blur: 10,
				offset: 5,
				angle: 180,
				color: '00FFFF',
				opacity: 1
			}
		};

		// BTM-LEFT: H/bar - 100% layout without axis labels
		var optsChartBar3 = { x:0.5, y:3.8, w:6.0, h:3.5,
			showTitle: true,
			title: 'No shadow, transparent colors',
			barDir     : 'bar',
			barGrouping: 'stacked',
			chartColors: ['transparent', '5DA5DA', 'transparent', 'FAA43A'],
			shadow: 'none'
		};

		// BTM-RIGHT: V/col - TITLE and LEGEND
		var optsChartBar4 = { x:7.0, y:3.8, w:6.0, h:3.5,
			barDir: 'col',
			barGrouping: 'stacked',
			showTitle: true,
			title: 'Red glowing shadow',
			catAxisLabelColor   : '0000CC',
			catAxisLabelFontFace: 'Times',
			catAxisLabelFontSize: 12,
			catAxisOrientation  : 'minMax',
			chartColors: ['5DA5DA','FAA43A'],
			shadow: {
				type: 'outer',
				blur: 20,
				offset: 1,
				angle: 90,
				color: 'A70000',
				opacity: 1
			}
		};

		slide.addChart( pptx.charts.BAR, single, optsChartBar1 );
		slide.addChart( pptx.charts.PIE, dataChartPieStat, pieOptions );
		slide.addChart( pptx.charts.BAR, arrDataRegions, optsChartBar3 );
		slide.addChart( pptx.charts.BAR, arrDataHighVals, optsChartBar4 );
	}
688558
def map_with_slider(h3: HistogramND, *, show_zero: bool = True, show_values: bool = False, **kwargs) -> dict:
    
    vega = _create_figure(kwargs)

    values_arr = get_data(h3, kwargs.pop("density", None), kwargs.pop("cumulative", None))
    values = values_arr.tolist()
    value_format = get_value_format(kwargs.pop("value_format", None))

    _add_title(h3, vega, kwargs)
    _create_scales(h3, vega, kwargs)
    _create_axes(h3, vega, kwargs)
    _create_cmap_scale(values_arr, vega, kwargs)
    _create_colorbar(vega, kwargs)

    x = h3.get_bin_centers(0)
    y = h3.get_bin_centers(1)
    x1 = h3.get_bin_left_edges(0)
    x2 = h3.get_bin_right_edges(0)
    y1 = h3.get_bin_left_edges(1)
    y2 = h3.get_bin_right_edges(1)

    data = []
    for i in range(h3.shape[0]):
        for j in range(h3.shape[1]):
            for k in range(h3.shape[2]):
                if not show_zero and values[i][j][k] == 0:
                    continue
                item = {
                    "x": float(x[i]),
                    "x1": float(x1[i]),
                    "x2": float(x2[i]),
                    "y": float(y[j]),
                    "y1": float(y1[j]),
                    "y2": float(y2[j]),
                    "k": k,
                    "c": float(values[i][j][k]),
                }
                if show_values:
                    item["label"] = value_format(values[i][j][k])
                data.append(item)

    vega["signals"] = [
        {
            "name": "k", "value": h3.shape[2] // 2,
            "bind": {
                "input": "range", "min": 0, "max": h3.shape[2] - 1,
                "step": 1, "name": (h3.axis_names[2] or "axis2") + " [slice]"
            }
        }
    ]

    vega["data"] = [{
        "name": "table",
        "values": data,
        "transform": [
             {
                 "type": "filter",
                 "expr": "k == datum.k",
             }
        ]
    }]

    vega["marks"] = [
        {
            "type": "rect",
            "from": {"data": "table"},
            "encode": {
                "enter": {
                    "x": {"scale": "xscale", "field": "x1"},
                    "x2": {"scale": "xscale", "field": "x2"},
                    "y": {"scale": "yscale", "field": "y1"},
                    "y2": {"scale": "yscale", "field": "y2"},
                    "fill": {"scale": "color", "field": "c"},
                    "stroke": {"value": 0},
                    # "strokeWidth": {"value": 0},
                    # "fillColor": {"value": "#ffff00"}
                },
                # "update": {
                #     "fillOpacity": {"value": 0.6}
                # },
                # "hover": {
                #     "fillOpacity": {"value": 0.5}
                # }
            }
        }
    ]

    if show_values:
        vega["marks"].append(
            {
                "type": "text",
                "from": {"data": "table"},
                "encode": {
                    "enter": {
                        "align": {"value": "center"},
                        "baseline": {"value": "middle"},
                        "fontSize": {"value": 13},
                        "fontWeight": {"value": "bold"},
                        "text": {"field": "label"},
                        "x": {"scale": "xscale", "field": "x"},
                        "y": {"scale": "yscale", "field": "y"},
                    }
                }
            }
        )

    return vega
475561
def legend(args = {})
      config.data[:options][:legend] = {} unless config.data[:options][:legend]
      config.data[:options][:legend][:position]  = args[:position] if args [:position]
      config.data[:options][:legend][:display]   = true  if args[:display]
      config.data[:options][:legend][:display]   = false if args[:hidden]
      config.data[:options][:legend][:fullWidth] = true  if args[:full]
      config.data[:options][:legend][:reverse]   = true  if args[:reverse]
      # legend labels
      config.data[:options][:legend][:labels][:boxWidth]  = args[:width]   if args[:width]
      config.data[:options][:legend][:labels][:fontSize]  = args[:size]    if args[:size]
      config.data[:options][:legend][:labels][:fontStyle] = args[:style]   if args[:style]
      config.data[:options][:legend][:labels][:padding]   = args[:padding] if args[:padding]
    end
1358202
function () {
		var legend = this,
			chart = legend.chart,
			renderer = chart.renderer,
			legendGroup = legend.group,
			allItems,
			display,
			legendWidth,
			legendHeight,
			box = legend.box,
			options = legend.options,
			padding = legend.padding,
			legendBorderWidth = options.borderWidth,
			legendBackgroundColor = options.backgroundColor;

		legend.itemX = legend.initialItemX;
		legend.itemY = legend.initialItemY;
		legend.offsetWidth = 0;
		legend.lastItemY = 0;

		if (!legendGroup) {
			legend.group = legendGroup = renderer.g('legend')
				.attr({ zIndex: 7 }) 
				.add();
			legend.contentGroup = renderer.g()
				.attr({ zIndex: 1 }) // above background
				.add(legendGroup);
			legend.scrollGroup = renderer.g()
				.add(legend.contentGroup);
		}
		
		legend.renderTitle();

		// add each series or point
		allItems = [];
		each(chart.series, function (serie) {
			var seriesOptions = serie.options;

			if (!seriesOptions.showInLegend || defined(seriesOptions.linkedTo)) {
				return;
			}

			// use points or series for the legend item depending on legendType
			allItems = allItems.concat(
					serie.legendItems ||
					(seriesOptions.legendType === 'point' ?
							serie.data :
							serie)
			);
		});

		// sort by legendIndex
		stableSort(allItems, function (a, b) {
			return ((a.options && a.options.legendIndex) || 0) - ((b.options && b.options.legendIndex) || 0);
		});

		// reversed legend
		if (options.reversed) {
			allItems.reverse();
		}

		legend.allItems = allItems;
		legend.display = display = !!allItems.length;

		// render the items
		each(allItems, function (item) {
			legend.renderItem(item); 
		});

		// Draw the border
		legendWidth = options.width || legend.offsetWidth;
		legendHeight = legend.lastItemY + legend.lastLineHeight + legend.titleHeight;
		
		
		legendHeight = legend.handleOverflow(legendHeight);

		if (legendBorderWidth || legendBackgroundColor) {
			legendWidth += padding;
			legendHeight += padding;

			if (!box) {
				legend.box = box = renderer.rect(
					0,
					0,
					legendWidth,
					legendHeight,
					options.borderRadius,
					legendBorderWidth || 0
				).attr({
					stroke: options.borderColor,
					'stroke-width': legendBorderWidth || 0,
					fill: legendBackgroundColor || NONE
				})
				.add(legendGroup)
				.shadow(options.shadow);
				box.isNew = true;

			} else if (legendWidth > 0 && legendHeight > 0) {
				box[box.isNew ? 'attr' : 'animate'](
					box.crisp(null, null, null, legendWidth, legendHeight)
				);
				box.isNew = false;
			}

			// hide the border if no items
			box[display ? 'show' : 'hide']();
		}
		
		legend.legendWidth = legendWidth;
		legend.legendHeight = legendHeight;

		// Now that the legend width and height are established, put the items in the 
		// final position
		each(allItems, function (item) {
			legend.positionItem(item);
		});

		// 1.x compatibility: positioning based on style
		/*var props = ['left', 'right', 'top', 'bottom'],
			prop,
			i = 4;
		while (i--) {
			prop = props[i];
			if (options.style[prop] && options.style[prop] !== 'auto') {
				options[i < 2 ? 'align' : 'verticalAlign'] = prop;
				options[i < 2 ? 'x' : 'y'] = pInt(options.style[prop]) * (i % 2 ? -1 : 1);
			}
		}*/

		if (display) {
			legendGroup.align(extend({
				width: legendWidth,
				height: legendHeight
			}, options), true, 'spacingBox');
		}

		if (!chart.isResizing) {
			this.positionCheckboxes();
		}
	}
532742
def add_legends(self, xhists=True, yhists=False, scatter=True, **kwargs):
        
        axs = []
        if xhists:
            axs.extend(self.hxs)
        if yhists:
            axs.extend(self.hys)
        if scatter:
            axs.extend(self.ax)

        for ax in axs:
            ax.legend(**kwargs)
1346293
function () {
		var options = this.options,
			userOptions = this.userOptions,
			defaultColors = this.chart.options.colors,
			counters = this.chart.counters,
			color,
			colorIndex;

		color = options.color || defaultPlotOptions[this.type].color;

		if (!color && !options.colorByPoint) {
			if (defined(userOptions._colorIndex)) { // after Series.update()
				colorIndex = userOptions._colorIndex;
			} else {
				userOptions._colorIndex = counters.color;
				colorIndex = counters.color++;
			}
			color = defaultColors[colorIndex];
		}
		
		this.color = color;
		counters.wrapColor(defaultColors.length);
	}
1226072
function getSeriesForPieChart () {

    var series = {
            type: 'pie',
            name: $("#tipInput").val(),
            data: []
        },
        tableData = getTableData();


    for ( var j = 1, jlen = tableData[ 0 ].length; j < jlen; j++ ) {

        var title = tableData[ 0 ][ j ],
            val = tableData[ 1 ][ j ];

        series.data.push( [ title, val ] );

    }

    return {
        series: [ series ]
    };

}
326565
function drawGradient(legend, barGroup, y) {
  var id = "terriajs-legend-gradient" + ++gradientCount;
  var defs = addSvgElement(legend, "defs", {}); // apparently it's ok to have the defs anywhere in the doc
  var linearGradient = svgElement(legend, "linearGradient", {
    x1: "0",
    x2: "0",
    y1: "1",
    y2: "0",
    id: id
  });
  legend.gradientColorMap.forEach(function(c, i) {
    linearGradient.appendChild(
      svgElement(legend, "stop", {
        offset: c.offset,
        "stop-color": c.color
      })
    );
  });
  defs.appendChild(linearGradient);

  var gradientItems = legend.items.filter(function(item) {
    return !defined(item.color);
  });

  var totalSpacingAbove = gradientItems.reduce(function(prev, item) {
    return prev + (item.spacingAbove || 0);
  }, 0);
  var barHeight = Math.max(
    (legend.computedItemHeight + legend.itemSpacing) * gradientItems.length +
      totalSpacingAbove,
    legend.barHeightMin
  );

  addSvgElement(
    legend,
    "rect",
    {
      x: legend.barLeft,
      y: y,
      width: legend.itemWidth,
      height: barHeight,
      fill: "url(#" + id + ")"
    },
    "gradient-bar"
  );

  return barHeight;
}
465235
function Chart(options) {

	this.__proto__ = new Control();

	this.init = function(options) {
		this.type = options.type = 'Chart';
		this.parent = options.parent;
		this.defaults = {
			x:48, y:48, w:288, h:144,
			text: '',
			script: undefined,
			onload: undefined,
			fill: this.parent.fill,
			fill_highlight: this.parent.lighter(this.parent.stroke), 	// ??
			stroke: this.parent.stroke,
			'stroke-width': this.parent.control_stroke,
			fontsize: this.parent.fontsize,
			repeat: 0,
			running: 0,
			corner: this.parent.button_corner,
			subtype: undefined,
			r: this.w/2,		//?? chart??
			autorun: undefined,
			interpolate: 'step-after',	// vs. 'basis'
			ticks: 5,
			target: undefined,
			refresh: 0,
			ymax: undefined,
			ymin: undefined
		};
		//console.log('Chart defaults:', this.defaults);
		this.setoptions(options);
		this.render();		// render D3 chart
		var self = this;
		if (this.refresh) setInterval(function() { self.redraw.call(self); }, this.refresh);
		return this;
	};

	this.attr = function(attrs) {
		this.__proto__.attr.call(this);
		this.svg.attr(attrs);
	};

	this.render = function() {

		var margin = {top: 0, right: 0, bottom: 0, left: 0};
		var width = this.w - margin.left - margin.right;
		var height = this.h - margin.top - margin.bottom;

		var x = d3.scale.linear().range([0, width]);
		var y = d3.scale.linear().range([height, 0]);
		var color = d3.scale.category10();
		var xAxis = d3.svg.axis().scale(x).ticks(this.ticks).orient('bottom');
		var yAxis = d3.svg.axis().scale(y).ticks(this.ticks).orient('left');

		var line = d3.svg.line().interpolate(this.interpolate)
				.x(function(d) { return x(d.time); })
				.y(function(d) { return y(d.value); });

		var self = this;
		this.outerrect = this.parent.paper.rect(this.x, this.y, this.w, this.h, this.parent.button_corner)
			.attr({fill: this.fill, stroke: this.stroke, 'stroke-width':this.parent.control_stroke});
		this.elts.push(this.outerrect);

		this.label = this.parent.paper.text(this.x + (this.w/2), this.y + this.h + this.fontsize*2, this.text)
			.attr({fill:this.stroke, stroke:this.stroke, 'font-size': this.fontsize});
		this.textelts.push(this.label);

		this.sethandlers();

		this.svg = d3.select(this.parent.paper.canvas).append('g')
				.attr('width', width + margin.left + margin.right)
				.attr('height', height + margin.top + margin.bottom)
			.append('g')
				//.attr('transform', 'translate(' + (this.x+margin.left) + ',' + (this.y+margin.top) + ')');
				.attr('transform', 'translate(' + (this.x) + ',' + (this.y) + ')');

		d3.json('/d3/' + this.target, function(data) {

			// console.log('d3:', typeof data, data);

			color.domain(d3.keys(data[0]).filter(function(key) { return key !== 'time'; }));
			var values = color.domain().map(function(name) {
				return {
					name: name,
					values: data.map(function(d) {
						return {time: d.time, value: +d[name]};
					})
				};
			});

			x.domain(d3.extent(data, function(d) { return d.time; }));
			if (self.ymax !== undefined) y.domain([self.ymin, self.ymax]);
			else y.domain([
				d3.min(values, function(c) { return d3.min(c.values, function(v) { return v.value; }); }),
				d3.max(values, function(c) { return d3.max(c.values, function(v) { return v.value; }); })
			]);

			self.svgx = self.svg.append('g')
					.attr('class', 'x axis')
					.attr('transform', 'translate(0,' + height + ')')
					.attr('stroke', self.stroke)
					.attr('fill', self.stroke)
					.call(xAxis);

			self.svgy = self.svg.append('g')
					.attr('class', 'y axis')
					.attr('stroke', self.stroke)
					.attr('fill', self.stroke)
					.call(yAxis);
/* y axis label
				.append('text')
					.attr('transform', 'rotate(-90)')
					.attr('y', 6)
					.attr('dy', '.71em')
					.style('text-anchor', 'end')
					.attr('stroke', self.stroke)
					.attr('fill', self.stroke)
					.text(' ');
*/
			self.svgvalue = self.svg.selectAll('.value')
					.data(values)
				.enter().append('g')
					.attr('class', 'value');

			self.svgvalue.append('path')
					.attr('class', 'line')
					.attr('d', function(d) { return line(d.values); })
					.style('stroke', function(d) { return color(d.name); })
					.style('fill', self.fill)
					.style('stroke-width', self['stroke-width']);

			self.svgvalue.append('text')
					.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
					.attr('transform', function(d) { return 'translate(' + x(d.value.time) + ',' + y(d.value.value) + ')'; })
					.attr('x', 3)
					.attr('dy', '.35em')
					.attr('stroke', self.stroke)
					.attr('fill', self.stroke)
					.text(function(d) { return d.name; });
		});
	};

	this.redraw = function() {
		if (this.svg) {
			var doomed_svg = this.svg;
			delete this.svg;
			this.render();
			doomed_svg.remove();
		}
	};

	this.remove = function() {
		this.__proto__.remove.call(this);
		this.svg.remove();
	};

	this.move = function(x, y) {
		this.x = x;
		this.y = y;
		this.outerrect.attr({x:this.x, y:this.y, width:this.w, height:this.h});
		this.label.attr({x:this.x + this.w/2, y:this.y + this.h + this.fontsize*2});

		var translation = ['translate(', this.x, ',', this.y,')'].join('');
		//console.log('translation:', translation)
		this.svg.attr('transform', translation);
	};

	this.handleClick = function(e) {
		if (this.repeat) {
			if (this.running) {
				this.running = false;
				clearInterval(this.intervalid);
				delete this.intervalid;
			} else {
				this.running = true;
				this.exec();
			}
		}
		else this.redraw();

		if (e) {
			e.preventDefault();
			e.stopPropagation();
		}
		return false;
	};

	this.setValue = function(value) {
		this.value = value;
		//this.label.attr({text: this.text + ': ' + this.value});
		var update = {id: this.id, value: this.value};
		this.fire('update', update);
	};

	return this.init(options || {});
}
943351
def legend(self, *args, **kwargs):
        
        if "fancybox" not in kwargs.keys():
            kwargs["fancybox"] = False
        if "framealpha" not in kwargs.keys():
            kwargs["framealpha"] = 1.
        return super().legend(*args, **kwargs)