Make the HighCharts HTML to plot the alignment rates
437439
def bowtie_alignment_plot (self):
        

        # Specify the order of the different possible categories
        keys = OrderedDict()
        keys['reads_aligned'] = { 'color': '#8bbc21', 'name': 'Aligned' }
        keys['multimapped'] =   { 'color': '#2f7ed8', 'name': 'Multimapped' }
        keys['not_aligned'] =   { 'color': '#0d233a', 'name': 'Not aligned' }

        # Config for the plot
        config = {
            'id': 'bowtie1_alignment',
            'title': 'Bowtie 1: Alignment Scores',
            'ylab': '# Reads',
            'cpswitch_counts_label': 'Number of Reads'
        }

        self.add_section(
            description = 'This plot shows the number of reads aligning to the reference in different ways.',
            helptext = '''
            There are 3 possible types of alignment:
            * **Aligned**: Read has only one occurence in the reference genome.
            * **Multimapped**: Read has multiple occurence.
            * **Not aligned**: Read has no occurence.
            ''',
            plot = bargraph.plot(self.bowtie_data, keys, config)
        )
93739
function showEmbedding(data) {
  const margin = {top: 20, right: 15, bottom: 60, left: 60};
  const width = 800 - margin.left - margin.right;
  const height = 800 - margin.top - margin.bottom;

  const x = d3.scaleLinear().domain([0, 1]).range([0, width]);
  const y = d3.scaleLinear().domain([0, 1]).range([height, 0]);

  const chart = d3.select('body')
                    .append('svg')
                    .attr('width', width + margin.right + margin.left)
                    .attr('height', height + margin.top + margin.bottom)
                    .attr('class', 'chart');

  const main =
      chart.append('g')
          .attr(
              'transform', 'translate(' + margin.left + ',' + margin.top + ')')
          .attr('width', width)
          .attr('height', height)
          .attr('class', 'main');

  const xAxis = d3.axisBottom(x);
  main.append('g')
      .attr('transform', 'translate(0,' + height + ')')
      .attr('class', 'main axis date')
      .call(xAxis);

  const yAxis = d3.axisLeft(y);
  main.append('g')
      .attr('transform', 'translate(0,0)')
      .attr('class', 'main axis date')
      .call(yAxis);

  const dots = main.append('g');

  dots.selectAll('scatter-dots')
      .data(data)
      .enter()
      .append('svg:circle')
      .attr('cx', (d) => x(d[0]))
      .attr('cy', (d) => y(d[1]))
      .attr('stroke-width', 0.25)
      .attr('stroke', '#1f77b4')
      .attr('fill', 'none')
      .attr('r', 5);
}
335095
function FormatYTickLabel($which_ylab) {
    switch ($this->y_grid_label_type) {
      case "data":
        $ylab = number_format($which_ylab,$this->y_precision,".",",") . "$this->si_units";
      break;
      case "none":
        $ylab = '';
      break;
      case "time":
        $ylab = strftime($this->y_time_format,$which_ylab);
      break;
      case "right":
        //Make it right aligned
        //$ylab = str_pad($which_ylab,$this->y_label_width," ",STR_PAD_LEFT); //PHP4 only
        $sstr = "%".strlen($this->plot_max_y)."s";
        $ylab = sprintf($sstr,$which_ylab);
      break;
      default:
        //Unchanged from whatever format is passed in
        $ylab = $which_ylab;
      break;
    }

    return($ylab);

  }
1271966
function () {
            var chart = this,
              axes = chart.axes,
              renderer = chart.renderer,
              options = chart.options;

            // Title
            chart.setTitle();


            // Legend
            chart.legend = new Legend(chart, options.legend);

            chart.getStacks(); // render stacks

            // Get margins by pre-rendering axes
            // set axes scales
            each(axes, function (axis) {
                axis.setScale();
            });

            chart.getMargins();

            chart.maxTicks = null; // reset for second pass
            each(axes, function (axis) {
                axis.setTickPositions(true); // update to reflect the new margins
                axis.setMaxTicks();
            });
            chart.adjustTickAmounts();
            chart.getMargins(); // second pass to check for new labels


            // Draw the borders and backgrounds
            chart.drawChartBox();


            // Axes
            if (chart.hasCartesianSeries) {
                each(axes, function (axis) {
                    axis.render();
                });
            }

            // The series
            if (!chart.seriesGroup) {
                chart.seriesGroup = renderer.g('series-group')
                  .attr({ zIndex: 3 })
                  .add();
            }
            chart.renderSeries();

            // Labels
            chart.renderLabels();

            // Credits
            chart.showCredits(options.credits);

            // Set flag
            chart.hasRendered = true;

        }
118525
function drawAxis() {
            if (isHorizontal) {
                svg.select('.x-axis-group .axis.x')
                    .attr('transform', `translate( 0, ${chartHeight} )`)
                    .call(xAxis);

                svg.select('.y-axis-group.axis')
                    .attr('transform', `translate( ${-xAxisPadding.left}, 0)`)
                    .call(yAxis);
            } else {
                svg.select('.x-axis-group .axis.x')
                    .attr('transform', `translate( 0, ${chartHeight} )`)
                    .call(xAxis);

                svg.select('.y-axis-group.axis')
                    .attr('transform', `translate( ${-xAxisPadding.left}, 0)`)
                    .call(yAxis)
                    .call(adjustYTickLabels);
            }

            if (yAxisLabel) {
                if (yAxisLabelEl) {
                    svg.selectAll('.y-axis-label-text').remove();
                }

                yAxisLabelEl = svg.select('.y-axis-label')
                    .append('text')
                        .classed('y-axis-label-text', true)
                        .attr('x', -chartHeight / 2)
                        .attr('y', yAxisLabelOffset)
                        .attr('text-anchor', 'middle')
                        .attr('transform', 'rotate(270 0 0)')
                        .text(yAxisLabel)
            }
        }
1181350
function (str, x, y) {

		var defaultChartStyle = defaultOptions.chart.style;

		return this.createElement('span')
			.attr({
				text: str,
				x: mathRound(x),
				y: mathRound(y)
			})
			.css({
				whiteSpace: 'nowrap',
				fontFamily: defaultChartStyle.fontFamily,
				fontSize: defaultChartStyle.fontSize
			});
	}
1173
function () {
            var series = this,
              chart = series.chart,
              wasDirtyData = series.isDirtyData, // cache it here as it is set to false in render, but used after
              group = series.group,
              xAxis = series.xAxis,
              yAxis = series.yAxis;

            // reposition on resize
            if (group) {
                if (chart.inverted) {
                    group.attr({
                        width: chart.plotWidth,
                        height: chart.plotHeight
                    });
                }

                group.animate({
                    translateX: pick(xAxis && xAxis.left, chart.plotLeft),
                    translateY: pick(yAxis && yAxis.top, chart.plotTop)
                });
            }

            series.translate();
            if (series.setTooltipPoints) {
                series.setTooltipPoints(true);
            }
            series.render();

            if (wasDirtyData) {
                fireEvent(series, 'updatedData');
            }
        }
79073
function (e) {

            var chart = this.chart;

            hoverChartIndex = chart.index;

            e = this.normalize(e);
            e.returnValue = false; // #2251, #3224

            if (chart.mouseIsDown === 'mousedown') {
                this.drag(e);
            }

            // Show the tooltip and run mouse over events (#977)
            if ((this.inClass(e.target, 'highcharts-tracker') ||
              chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) && !chart.openMenu) {
                this.runPointActions(e);
            }
        }
487940
function () {
		var series = this,
			chart = series.chart,
			group = series.group;

		/*if (clipRect) {
			stop(clipRect);
			clipRect.animate({ // for chart resize
				width: chart.plotSizeX,
				height: chart.plotSizeY
			});
		}*/

		// reposition on resize
		if (group) {
			if (chart.inverted) {
				group.attr({
					width: chart.plotWidth,
					height: chart.plotHeight
				});
			}

			group.animate({
				translateX: chart.plotLeft,
				translateY: chart.plotTop
			});
		}

		series.translate();
		series.setTooltipPoints(true);
		series.render();
	}
126766
def build_html():
    """"""
    source = AjaxDataSource(data_url='./data',
                            polling_interval=INTERVAL,
                            method='GET')

    # OHLC plot
    p = figure(plot_height=400,
               title='OHLC',
               sizing_mode='scale_width',
               tools="xpan,xwheel_zoom,xbox_zoom,reset",
               x_axis_type=None,
               y_axis_location="right",
               y_axis_label="Price ($)")
    p.x_range.follow = "end"
    p.x_range.follow_interval = 100
    p.x_range.range_padding = 0
    p.line(x='time', y='average', alpha=0.25, line_width=3, color='black',
           source=source)
    p.line(x='time', y='ma', alpha=0.8, line_width=2, color='steelblue',
           source=source)
    p.segment(x0='time', y0='low', x1='time', y1='high', line_width=2,
              color='black', source=source)
    p.segment(x0='time', y0='open', x1='time', y1='close', line_width=8,
              color='color', source=source, alpha=0.8)

    # MACD plot
    p2 = figure(plot_height=200,
                title='MACD',
                sizing_mode='scale_width',
                x_range=p.x_range,
                x_axis_label='Time (s)',
                tools="xpan,xwheel_zoom,xbox_zoom,reset",
                y_axis_location="right")
    p2.line(x='time', y='macd', color='darkred', line_width=2, source=source)
    p2.line(x='time', y='macd9', color='navy', line_width=2, source=source)
    p2.segment(x0='time', y0=0, x1='time', y1='macdh', line_width=6, color='steelblue',
               alpha=0.5, source=source)

    # Combine plots together
    plot = gridplot([[p], [p2]], toolbar_location="left", plot_width=1000)

    # Compose html from plots and template
    script, div = components(plot, theme=theme)
    html = template.render(resources=CDN.render(), script=script, div=div)

    return html
988873
function () {
		if (this.options.chart.alignTicks !== false) {
			each(this.axes, function (axis) {
				axis.adjustTickAmount();
			});
		}
		this.maxTicks = null;
	}
1301679
def hicup_alignment_chart (self):
        

        # Specify the order of the different possible categories
        keys = OrderedDict()
        keys['Unique_Alignments_Read']   = { 'color': '#2f7ed8', 'name': 'Unique Alignments' }
        keys['Multiple_Alignments_Read'] = { 'color': '#492970', 'name': 'Multiple Alignments' }
        keys['Failed_To_Align_Read']     = { 'color': '#0d233a', 'name': 'Failed To Align' }
        keys['Too_Short_To_Map_Read']    = { 'color': '#f28f43', 'name': 'Too short to map' }

        # Construct a data structure for the plot - duplicate the samples for read 1 and read 2
        data = {}
        for s_name in self.hicup_data:
            data['{} Read 1'.format(s_name)] = {}
            data['{} Read 2'.format(s_name)] = {}
            data['{} Read 1'.format(s_name)]['Unique_Alignments_Read'] = self.hicup_data[s_name]['Unique_Alignments_Read_1']
            data['{} Read 2'.format(s_name)]['Unique_Alignments_Read'] = self.hicup_data[s_name]['Unique_Alignments_Read_2']
            data['{} Read 1'.format(s_name)]['Multiple_Alignments_Read'] = self.hicup_data[s_name]['Multiple_Alignments_Read_1']
            data['{} Read 2'.format(s_name)]['Multiple_Alignments_Read'] = self.hicup_data[s_name]['Multiple_Alignments_Read_2']
            data['{} Read 1'.format(s_name)]['Failed_To_Align_Read'] = self.hicup_data[s_name]['Failed_To_Align_Read_1']
            data['{} Read 2'.format(s_name)]['Failed_To_Align_Read'] = self.hicup_data[s_name]['Failed_To_Align_Read_2']
            data['{} Read 1'.format(s_name)]['Too_Short_To_Map_Read'] = self.hicup_data[s_name]['Too_Short_To_Map_Read_1']
            data['{} Read 2'.format(s_name)]['Too_Short_To_Map_Read'] = self.hicup_data[s_name]['Too_Short_To_Map_Read_2']

        # Config for the plot
        config = {
            'id': 'hicup_mapping_stats_plot',
            'title': 'HiCUP: Mapping Statistics',
            'ylab': '# Reads',
            'cpswitch_counts_label': 'Number of Reads'
        }

        return bargraph.plot(data, keys, config)
639729
function () {
		
		var 
			// Get positions - either an integer or a percentage string must be given
			getLength = function (length, relativeTo) {
				return (/%$/).test(length) ?
					relativeTo * parseInt(length, 10) / 100 :
					parseInt(length, 10);
			},
			
			sum = 0,
			series = this,
			chart = series.chart,
			options = series.options,
			reversed = options.reversed,
			plotWidth = chart.plotWidth,
			plotHeight = chart.plotHeight,
			cumulative = 0, // start at top
			center = options.center,
			centerX = getLength(center[0], plotWidth),
			centerY = getLength(center[1], plotHeight),
			width = getLength(options.width, plotWidth),
			tempWidth,
			getWidthAt,
			height = getLength(options.height, plotHeight),
			neckWidth = getLength(options.neckWidth, plotWidth),
			neckHeight = getLength(options.neckHeight, plotHeight),
			neckY = height - neckHeight,
			data = series.data,
			path,
			fraction,
			half = options.dataLabels.position === 'left' ? 1 : 0,

			x1, 
			y1, 
			x2, 
			x3, 
			y3, 
			x4, 
			y5;

		// Return the width at a specific y coordinate
		series.getWidthAt = getWidthAt = function (y) {
			return y > height - neckHeight || height === neckHeight ?
				neckWidth :
				neckWidth + (width - neckWidth) * ((height - neckHeight - y) / (height - neckHeight));
		};
		series.getX = function (y, half) {
					return centerX + (half ? -1 : 1) * ((getWidthAt(reversed ? plotHeight - y : y) / 2) + options.dataLabels.distance);
		};

		// Expose
		series.center = [centerX, centerY, height];
		series.centerX = centerX;

		/*
		 * Individual point coordinate naming:
		 *
		 * x1,y1 _________________ x2,y1
		 *  \                         /
		 *   \                       /
		 *    \                     /
		 *     \                   /
		 *      \                 /
		 *     x3,y3 _________ x4,y3
		 *
		 * Additional for the base of the neck:
		 *
		 *       |               |
		 *       |               |
		 *       |               |
		 *     x3,y5 _________ x4,y5
		 */




		// get the total sum
		each(data, function (point) {
			sum += point.y;
		});

		each(data, function (point) {
			// set start and end positions
			y5 = null;
			fraction = sum ? point.y / sum : 0;
			y1 = centerY - height / 2 + cumulative * height;
			y3 = y1 + fraction * height;
			//tempWidth = neckWidth + (width - neckWidth) * ((height - neckHeight - y1) / (height - neckHeight));
			tempWidth = getWidthAt(y1);
			x1 = centerX - tempWidth / 2;
			x2 = x1 + tempWidth;
			tempWidth = getWidthAt(y3);
			x3 = centerX - tempWidth / 2;
			x4 = x3 + tempWidth;

			// the entire point is within the neck
			if (y1 > neckY) {
				x1 = x3 = centerX - neckWidth / 2;
				x2 = x4 = centerX + neckWidth / 2;
			
			// the base of the neck
			} else if (y3 > neckY) {
				y5 = y3;

				tempWidth = getWidthAt(neckY);
				x3 = centerX - tempWidth / 2;
				x4 = x3 + tempWidth;

				y3 = neckY;
			}

			if (reversed) {
				y1 = height - y1;
				y3 = height - y3;
				y5 = (y5 ? height - y5 : null);
			}
			// save the path
			path = [
				'M',
				x1, y1,
				'L',
				x2, y1,
				x4, y3
			];
			if (y5) {
				path.push(x4, y5, x3, y5);
			}
			path.push(x3, y3, 'Z');

			// prepare for using shared dr
			point.shapeType = 'path';
			point.shapeArgs = { d: path };


			// for tooltips and data labels
			point.percentage = fraction * 100;
			point.plotX = centerX;
			point.plotY = (y1 + (y5 || y3)) / 2;

			// Placement of tooltips and data labels
			point.tooltipPos = [
				centerX,
				point.plotY
			];

			// Slice is a noop on funnel points
			point.slice = noop;
			
			// Mimicking pie data label placement logic
			point.half = half;

			cumulative += fraction;
		});		
	}
1345281
function () {
		var options = this.options,
			chart = this.chart,
			group = this.group,
			title = this.title,
			shape = this.shape,
			linkedTo = this.linkedObject,
			xAxis = chart.xAxis[options.xAxis],
			yAxis = chart.yAxis[options.yAxis],
			width = options.width,
			height = options.height,
			anchorY = ALIGN_FACTOR[options.anchorY],
			anchorX = ALIGN_FACTOR[options.anchorX],
			resetBBox = false,
			shapeParams,
			linkType,
			series,
			param,
			bbox,
			x,
			y;

		if (linkedTo) {
			linkType = (linkedTo instanceof Highcharts.Point) ? 'point' :
						(linkedTo instanceof Highcharts.Series) ? 'series' : null;

			if (linkType === 'point') {
				options.xValue = linkedTo.x;
				options.yValue = linkedTo.y;
				series = linkedTo.series;
			} else if (linkType === 'series') {
				series = linkedTo;
			}

			if (group.visibility !== series.group.visibility) {
				group.attr({
					visibility: series.group.visibility
				});
			}
		}


		// Based on given options find annotation pixel position
		x = (defined(options.xValue) ? xAxis.toPixels(options.xValue + xAxis.minPointOffset) - xAxis.minPixelPadding : options.x);
		y = defined(options.yValue) ? yAxis.toPixels(options.yValue) : options.y;

		if (isNaN(x) || isNaN(y) || !isNumber(x) || !isNumber(y)) {
			return;
		}


		if (title) {
			title.attr(options.title);
			title.css(options.title.style);
			resetBBox = true;
		}

		if (shape) {
			shapeParams = extend({}, options.shape.params);

			if (options.units === 'values') {
				for (param in shapeParams) {
					if (inArray(param, ['width', 'x']) > -1) {
						shapeParams[param] = xAxis.translate(shapeParams[param]);
					} else if (inArray(param, ['height', 'y']) > -1) {
						shapeParams[param] = yAxis.translate(shapeParams[param]);
					}
				}

				if (shapeParams.width) {
					shapeParams.width -= xAxis.toPixels(0) - xAxis.left;
				}

				if (shapeParams.x) {
					shapeParams.x += xAxis.minPixelPadding;
				}

				if (options.shape.type === 'path') {
					translatePath(shapeParams.d, xAxis, yAxis, x, y);
				}
			}

			// move the center of the circle to shape x/y
			if (options.shape.type === 'circle') {
				shapeParams.x += shapeParams.r;
				shapeParams.y += shapeParams.r;
			}

			resetBBox = true;
			shape.attr(shapeParams);
		}

		group.bBox = null;

		// If annotation width or height is not defined in options use bounding box size
		if (!isNumber(width)) {
			bbox = group.getBBox();
			width = bbox.width;
		}

		if (!isNumber(height)) {
			// get bbox only if it wasn't set before
			if (!bbox) {
				bbox = group.getBBox();
			}

			height = bbox.height;
		}

		// Calculate anchor point
		if (!isNumber(anchorX)) {
			anchorX = ALIGN_FACTOR.center;
		}

		if (!isNumber(anchorY)) {
			anchorY = ALIGN_FACTOR.center;
		}

		// Translate group according to its dimension and anchor point
		x = x - width * anchorX;
		y = y - height * anchorY;

		if (chart.animation && defined(group.translateX) && defined(group.translateY)) {
			group.animate({
				translateX: x,
				translateY: y
			});
		} else {
			group.translate(x, y);
		}
	}
170626
function () {
		var chart = this,
			options = this.options,
			xAxisOptions = options.xAxis = splat(options.xAxis || {}),
			yAxisOptions = options.yAxis = splat(options.yAxis || {}),
			optionsArray,
			axis;

		// make sure the options are arrays and add some members
		each(xAxisOptions, function (axis, i) {
			axis.index = i;
			axis.isX = true;
		});

		each(yAxisOptions, function (axis, i) {
			axis.index = i;
		});

		// concatenate all axis options into one array
		optionsArray = xAxisOptions.concat(yAxisOptions);

		each(optionsArray, function (axisOptions) {
			axis = new Axis(chart, axisOptions);
		});

		chart.adjustTickAmounts();
	}
769509
function (e, shape, chart, series) {

            // The margin between the text and the box
            var textMargin = 5,
                // The margin between the ring and the popup
                popupMargin = 10,
                // The popup animation duration in ms
                animDuration = 750,
                // Collect some facts about the highlighted bubble
                selectedShape = d3.select(shape),
                cx = parseFloat(selectedShape.attr("cx")),
                cy = parseFloat(selectedShape.attr("cy")),
                r = parseFloat(selectedShape.attr("r")),
                opacity = dimple._helpers.opacity(e, chart, series),
                fill = selectedShape.attr("stroke"),
                dropDest = series._dropLineOrigin(),
                // Fade the popup stroke mixing the shape fill with 60% white
                popupStrokeColor = d3.rgb(
                    d3.rgb(fill).r + 0.6 * (255 - d3.rgb(fill).r),
                    d3.rgb(fill).g + 0.6 * (255 - d3.rgb(fill).g),
                    d3.rgb(fill).b + 0.6 * (255 - d3.rgb(fill).b)
                ),
                // Fade the popup fill mixing the shape fill with 80% white
                popupFillColor = d3.rgb(
                    d3.rgb(fill).r + 0.8 * (255 - d3.rgb(fill).r),
                    d3.rgb(fill).g + 0.8 * (255 - d3.rgb(fill).g),
                    d3.rgb(fill).b + 0.8 * (255 - d3.rgb(fill).b)
                ),
                // The running y value for the text elements
                y = 0,
                // The maximum bounds of the text elements
                w = 0,
                h = 0,
                t,
                box,
                rows = [],
                overlap;

            if (chart._tooltipGroup !== null && chart._tooltipGroup !== undefined) {
                chart._tooltipGroup.remove();
            }
            chart._tooltipGroup = chart.svg.append("g");

            // On hover make the line marker visible immediately
            selectedShape.style("opacity", 1);

            // Add a ring around the data point
            chart._tooltipGroup.append("circle")
                .attr("cx", cx)
                .attr("cy", cy)
                .attr("r", r)
                .attr("opacity", 0)
                .style("fill", "none")
                .style("stroke", fill)
                .style("stroke-width", 1)
                .transition()
                    .duration(animDuration / 2)
                    .ease("linear")
                        .attr("opacity", 1)
                        .attr("r", r + series.lineWeight + 2)
                        .style("stroke-width", 2);

            // Add a drop line to the x axis
            if (dropDest.y !== null) {
                chart._tooltipGroup.append("line")
                    .attr("x1", cx)
                    .attr("y1", (cy < dropDest.y ? cy + r + series.lineWeight + 2 : cy - r - series.lineWeight - 2))
                    .attr("x2", cx)
                    .attr("y2", (cy < dropDest.y ? cy + r + series.lineWeight + 2 : cy - r - series.lineWeight - 2))
                    .style("fill", "none")
                    .style("stroke", fill)
                    .style("stroke-width", 2)
                    .style("stroke-dasharray", ("3, 3"))
                    .style("opacity", opacity)
                    .transition()
                        .delay(animDuration / 2)
                        .duration(animDuration / 2)
                        .ease("linear")
                            // Added 1px offset to cater for svg issue where a transparent
                            // group overlapping a line can sometimes hide it in some browsers
                            // Issue #10
                            .attr("y2", (cy < dropDest.y ? dropDest.y - 1 : dropDest.y + 1));
            }

            // Add a drop line to the y axis
            if (dropDest.x !== null) {
                chart._tooltipGroup.append("line")
                    .attr("x1", (cx < dropDest.x ? cx + r + series.lineWeight + 2 : cx - r - series.lineWeight - 2))
                    .attr("y1", cy)
                    .attr("x2", (cx < dropDest.x ? cx + r + series.lineWeight + 2 : cx - r - series.lineWeight - 2))
                    .attr("y2", cy)
                    .style("fill", "none")
                    .style("stroke", fill)
                    .style("stroke-width", 2)
                    .style("stroke-dasharray", ("3, 3"))
                    .style("opacity", opacity)
                    .transition()
                        .delay(animDuration / 2)
                        .duration(animDuration / 2)
                        .ease("linear")
                            // Added 1px offset to cater for svg issue where a transparent
                            // group overlapping a line can sometimes hide it in some browsers
                            // Issue #10
                            .attr("x2", (cx < dropDest.x ? dropDest.x - 1 : dropDest.x + 1));
            }

            // Add a group for text
            t = chart._tooltipGroup.append("g");
            // Create a box for the popup in the text group
            box = t.append("rect");

            // Add the series categories
            if (series.categoryFields !== null && series.categoryFields !== undefined && series.categoryFields.length > 0) {
                series.categoryFields.forEach(function (c, i) {
                    // If the category name and value match don't display the category name
                    rows.push(c + (e.aggField[i] !== c ? ": " + e.aggField[i] : ""));
                }, this);
            }

            if (series.x._hasTimeField()) {
                rows.push(series.x.timeField + ": " + series.x._getFormat()(e.xField[0]));
            } else if (series.x._hasCategories()) {
                // Add the x axis categories
                series.x.categoryFields.forEach(function (c, i) {
                    // If the category name and value match don't display the category name
                    rows.push(c + (e.xField[i] !== c ? ": " + e.xField[i] : ""));
                }, this);
            } else if (series.x.useLog) {
                // Add the y axis log
                rows.push(series.x.measure + ": " + e.cx);
            } else {
                // Add the axis measure value
                rows.push(series.x.measure + ": " + series.x._getFormat()(e.cx));
            }

            if (series.y._hasTimeField()) {
                rows.push(series.y.timeField + ": " + series.y._getFormat()(e.yField[0]));
            } else if (series.y._hasCategories()) {
                // Add the y axis categories
                series.y.categoryFields.forEach(function (c, i) {
                    rows.push(c + (e.yField[i] !== c ? ": " + e.yField[i] : ""));
                }, this);
            } else if (series.y.useLog) {
                // Add the y axis log
                rows.push(series.y.measure + ": " + e.cy);
            } else {
                // Add the axis measure value
                rows.push(series.y.measure + ": " + series.y._getFormat()(e.cy));
            }

            if (series.z !== null && series.z !== undefined) {
                // Add the axis measure value
                rows.push(series.z.measure + ": " + series.z._getFormat()(e.zValue));
            }

            if (series.c !== null && series.c !== undefined) {
                // Add the axis measure value
                rows.push(series.c.measure + ": " + series.c._getFormat()(e.cValue));
            }

            // Get distinct text rows to deal with cases where 2 axes have the same dimensionality
            rows = rows.filter(function(elem, pos) {
                return rows.indexOf(elem) === pos;
            });

            // Create a text object for every row in the popup
            t.selectAll(".textHoverShapes").data(rows).enter()
                .append("text")
                    .text(function (d) { return d; })
                    .style("font-family", "sans-serif")
                    .style("font-size", "10px");

            // Get the max height and width of the text items
            t.each(function () {
                w = (this.getBBox().width > w ? this.getBBox().width : w);
                h = (this.getBBox().width > h ? this.getBBox().height : h);
            });

            // Position the text relatve to the bubble, the absolute positioning
            // will be done by translating the group
            t.selectAll("text")
                .attr("x", 0)
                .attr("y", function () {
                    // Increment the y position
                    y += this.getBBox().height;
                    // Position the text at the centre point
                    return y - (this.getBBox().height / 2);
                });

            // Draw the box with a margin around the text
            box.attr("x", -textMargin)
                .attr("y", -textMargin)
                .attr("height", Math.floor(y + textMargin) - 0.5)
                .attr("width", w + 2 * textMargin)
                .attr("rx", 5)
                .attr("ry", 5)
                .style("fill", popupFillColor)
                .style("stroke", popupStrokeColor)
                .style("stroke-width", 2)
                .style("opacity", 0.95);

            // Shift the ring margin left or right depending on whether it will overlap the edge
            overlap = cx + r + textMargin + popupMargin + w > parseFloat(chart.svg.attr("width"));

            // Translate the shapes to the x position of the bubble (the x position of the shapes is handled)
            t.attr("transform", "translate(" +
                   (overlap ? cx - (r + textMargin + popupMargin + w) : cx + r + textMargin + popupMargin) + " , " +
                   (cy - ((y - (h - textMargin)) / 2)) +
                ")");
        }
330460
function () {
        
        // PATCH by Simon Fishel
        //
        // execute plotRenderHook hook to pre-process the plotting options
        //
        // + if(series.options.hooks && series.options.hooks.plotRenderHook) {
        // +    series.options.hooks.plotRenderHook(series);
        // + }
        
        if(this.options.hooks && this.options.hooks.plotRenderHook) {
            this.options.hooks.plotRenderHook(this);
        }
        
		var total = 0,
			series = this,
			cumulative = -0.25, // start at top
			precision = 1000, // issue #172
			options = series.options,
			slicedOffset = options.slicedOffset,
			connectorOffset = slicedOffset + options.borderWidth,
			positions = options.center.concat([options.size, options.innerSize || 0]),
			chart = series.chart,
			plotWidth = chart.plotWidth,
			plotHeight = chart.plotHeight,
			start,
			end,
			angle,
			data = series.data,
			circ = 2 * mathPI,
			fraction,
			smallestSize = mathMin(plotWidth, plotHeight),
			isPercent,
			radiusX, // the x component of the radius vector for a given point
			radiusY,
			labelDistance = options.dataLabels.distance;

		// get positions - either an integer or a percentage string must be given
		positions = map(positions, function (length, i) {

			isPercent = /%$/.test(length);
			return isPercent ?
				// i == 0: centerX, relative to width
				// i == 1: centerY, relative to height
				// i == 2: size, relative to smallestSize
				// i == 4: innerSize, relative to smallestSize
				[plotWidth, plotHeight, smallestSize, smallestSize][i] *
					pInt(length) / 100 :
				length;
		});

		// utility for getting the x value from a given y, used for anticollision logic in data labels
		series.getX = function (y, left) {

			angle = math.asin((y - positions[1]) / (positions[2] / 2 + labelDistance));

			return positions[0] +
				(left ? -1 : 1) *
				(mathCos(angle) * (positions[2] / 2 + labelDistance));
		};

		// set center for later use
		series.center = positions;

		// get the total sum
		each(data, function (point) {
			total += point.y;
		});

		each(data, function (point) {
			// set start and end angle
			fraction = total ? point.y / total : 0;
			start = mathRound(cumulative * circ * precision) / precision;
			cumulative += fraction;
			end = mathRound(cumulative * circ * precision) / precision;

			// set the shape
			point.shapeType = 'arc';
			point.shapeArgs = {
				x: positions[0],
				y: positions[1],
				r: positions[2] / 2,
				innerR: positions[3] / 2,
				start: start,
				end: end
			};

			// center for the sliced out slice
			angle = (end + start) / 2;
			point.slicedTranslation = map([
				mathCos(angle) * slicedOffset + chart.plotLeft,
				mathSin(angle) * slicedOffset + chart.plotTop
			], mathRound);

			// set the anchor point for tooltips
			radiusX = mathCos(angle) * positions[2] / 2;
			radiusY = mathSin(angle) * positions[2] / 2;
			point.tooltipPos = [
				positions[0] + radiusX * 0.7,
				positions[1] + radiusY * 0.7
			];

			// set the anchor point for data labels
			point.labelPos = [
				positions[0] + radiusX + mathCos(angle) * labelDistance, // first break of connector
				positions[1] + radiusY + mathSin(angle) * labelDistance, // a/a
				positions[0] + radiusX + mathCos(angle) * connectorOffset, // second break, right outside pie
				positions[1] + radiusY + mathSin(angle) * connectorOffset, // a/a
				positions[0] + radiusX, // landing point for connector
				positions[1] + radiusY, // a/a
				labelDistance < 0 ? // alignment
					'center' :
					angle < circ / 4 ? 'left' : 'right', // alignment
				angle // center angle
			];

			// API properties
			point.percentage = fraction * 100;
			point.total = total;

		});


		this.setTooltipPoints();
	}