function drawOddsRatioGraphic(dvc) {
    maxweek = d3.max(graphic_data, function (d) { return d.date })

    var threshold_md = dvc.optional.middleBreakpoint;
    var threshold_sm = dvc.optional.mobileBreakpoint;

    if (parseInt(graphic.style("width")) < threshold_sm) {
        size = "sm";
    } else if (parseInt(graphic.style("width")) < threshold_md) {
        size = "md";
    } else {
        size = "lg";
    }

    categorySort = {}
    if (Array.isArray(dvc.essential.categorySort)) {
        for (i = 0; i < dvc.essential.categorySort.length; i++) {
            categorySort[dvc.essential.categorySort[i]] = i;
        }

        graphic_data.sort(function (a, b) {
            return categorySort[a.category] - categorySort[b.category]
        })

        categories = Object.keys(categorySort)
    } else if (dvc.essential.categorySort == "descending") {
        //auto sort the array by biggest value
        graphic_data.filter(function (d) {
            return d.date == maxweek
        }).sort(function (a, b) { return +b.chiffre - (+a.chiffre) }).forEach(function (item, i) {
            categorySort[item.category] = i
        });

        graphic_data.sort(function (a, b) {
            return categorySort[a.category] - categorySort[b.category]
        })

        categories = Object.keys(categorySort)
    } else if (dvc.essential.categorySort == "ascending") {
        graphic_data.filter(function (d) {
            return d.date == maxweek
        }).sort(function (a, b) { return +a.chiffre - (+b.chiffre) }).forEach(function (item, i) {
            categorySort[item.category] = i
        });

        graphic_data.sort(function (a, b) {
            return categorySort[a.category] - categorySort[b.category]
        })

        categories = Object.keys(categorySort)

    }

    var margin = dvc.optional.margin[size]
    var chart_width = (parseInt(graphic.style("width")) - dvc.optional.margin_special_left) / dvc.optional.chart_every[size] - margin.left - margin.right;
    //var height = Math.ceil((chart_width * dvc.optional.aspectRatio[size][1]) / dvc.optional.aspectRatio[size][0]);
    var height = Math.ceil(dvc.essential.barHeight_sm_md_lg[size] * graphic_data.length / 4);

    // clear out existing graphics
    graphic.selectAll("*").remove();
    legend.selectAll("*").remove();

    //draw legend
    var legendSvg = legend
        .append('svg')
        .attr("width", dvc.optional.chart_every[size] * (chart_width + margin.left + margin.right) + dvc.optional.margin_special_left)

    var legendRowCount = createLegend();

    legendSvg.attr("height", dvc.optional.legendHeight[size] * legendRowCount);

    function createLegend() {
        var prevX = 0;
        var prevY = 0;
        lineNo = 0;
        var lineNoOld = 0;

        dvc.essential.colour_palette.map(function (d) {
            return d.key
        }).forEach(function (d, i) {

            // draw legend text based on content of var legendLabels ...
            var_group = d3.select("#legend").select('svg').append("g")

            var_group.append("rect")
                .attr("class", "rect" + i)
                .attr("fill", dvc.essential.colour_palette[i].colour)
                .attr("x", 0)
                .attr("y", 0)
                .attr("width", 20)
                .attr("height", 20)

            var_group.append("text")
                .text(dvc.essential.colour_palette[i].key)
                .attr("class", "legend" + i)
                .attr("text-anchor", "start")
                .style("font-size", parseInt(graphic.style("width")) < 400 ? "14px" : "16px")
                .style("fill", "#666")
                .attr('y', 20)
                .attr('x', 0);


            d3.selectAll(".legend" + (i))
                .each(calcPosition);

            function calcPosition() {


                var BBox = this.getBBox()


                //prevY =BBox.width
                d3.select(".legend" + (i))
                    .attr("y", function (d) {
                        if ((prevX + BBox.width + 50) > parseInt(graphic.style("width"))) {
                            lineNoOld = lineNo;
                            lineNo = lineNo + 1;
                            prevX = 0;
                        }
                        return eval((lineNo * 30) + 25);
                    })
                    .attr("x", function (d) {
                        return prevX + 25;
                    })


                d3.select(".rect" + (i))
                    .attr("y", function (d) {

                        if ((prevX + BBox.width + 50) > parseInt(graphic.style("width"))) {
                            lineNoOld = lineNo;
                            lineNo = lineNo + 1;
                            prevX = 0;
                        }

                        if (dvc.essential.legendStyle == "rect") {
                            return eval((lineNo * 20) + 5);
                        } else {
                            return eval((lineNo * 30) + 12);

                        }
                    })
                    .attr("x", function (d) {
                        return prevX;
                    })

                prevX = prevX + BBox.width + 50
            }; // end function calcPosition()
        }); // end foreach
        return lineNo + 1;
    } // end function createLegend()

    x = (function(domain, range) {
        // A special x scale that is linear in the value's reciprocal for values
        // less than 1. This doesn't implement the full D3 scale API.
        // It is assumed that all values are > 0.
        if (domain[0] >= 1) {
            return d3.scaleLinear()
                .domain(domain)
                .range(range);
        } else if (domain[1] <= 1) {
            var scale = d3.scaleLinear()
                .domain([1/domain[0], 1/domain[1]])
                .range(range);
            return function(x) {return scale(1/x)};
        } else {
            var scale = d3.scaleLinear()
                .domain([2 - 1/domain[0], domain[1]])
                .range(range);
            return function(x) {
                if (x >= 1) {
                    return scale(x);
                } else {
                    return scale(2 - 1/x);
                }
            };
        }
    }([
        Math.min(dvc.essential.xRangeSuggestion[0], d3.min(graphic_data, function (d) { return d.lower })),
        Math.max(dvc.essential.xRangeSuggestion[1], d3.max(graphic_data, function (d) { return d.upper }))
    ], [0, chart_width]));

    xCat = d3.scaleOrdinal()
        .range(dvc.essential.xTicks.map(function (d) { return x(d.val); }))
        .domain(dvc.essential.xTicks.map(function (d) { return d.label; }));

    colour = d3.scaleOrdinal()
        .range(dvc.essential.colour_palette.map(function (d) { return d.colour }))
        .domain(dvc.essential.colour_palette.map(function (d) { return d.key }))

    var xAxis = d3.axisBottom(xCat)
        .tickSize(-height)
        .tickValues(xCat.domain().map(function (d, i) { if (i % dvc.optional.x_ticks_every[size] == 0) { return d } }))

    nested = d3.nest()
        .key(function (d) {
            return d.category
        })
        .key(function (d) {
            return d.series
        })
        .sortValues(function (a, b) { return a.date - b.date; })
        .entries(graphic_data)

    y0 = d3.scaleBand().rangeRound([0, height]).paddingInner(0.1).paddingOuter(0.05);


    y0.domain(d3.map(graphic_data, function (d) {
        return d.date;
    }).keys());

    y1 = d3.scaleBand();
    y1.domain(d3.map(graphic_data, function (d) { return d.series }).keys()).range([0, y0.bandwidth()]);

    for (i = 0; i < nested.length; i++) {
        if (i % dvc.optional.chart_every[size] == 0) {
            drawLeftAxis()
            drawchart(nested[i].key, nested[i].values, i)
        } else {
            drawchart(nested[i].key, nested[i].values, i)
        }
    }

    function drawchart(key, data, i) {
        var chart = d3.select("#graphic")
            .append('svg')
            .attr("width", chart_width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)

        chart.append('text')
            .attr("x", margin.left)
            .attr("y", 12)
            .text(function () {
                return key
            })
            .attr('font-weight', 700)
            .attr('font-size', "14px")

        svg = chart
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

        svg
            .append('g')
            .attr('class', 'x axis')
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis)
            .selectAll("text")
            .attr('x', 0)
            .call(wrap, (x(dvc.essential.xTicks[1].val) - x(dvc.essential.xTicks[0].val))*1.05, .9)

        svg.selectAll('g.x.axis')
            .each(function () {
                if (i % dvc.optional.chart_every[size] == dvc.optional.chart_every[size] - 1 || i == nested.length - 1) {
                    d3.select(this).append("text")
                        .text("Odds ratio (OR)")
                        .attr("transform", "translate(" + (chart_width + margin.right / 2) + "," + margin.bottom / 2 + ")")
                        .attr('text-anchor', 'end')
                        .attr('fill', "#000")
                        .attr('x', 0)
                        .attr('y', 0)
                        .call(wrap, chart_width * .8, 0.5)
                }
            })

        series = svg.selectAll("g.series")
            .data(data)
            .enter()
            .append('g')

        series.selectAll("rect")
            .data(function (d) { return d.values })
            .enter()
            .append('rect')
            .attr('x', function (d) { return x(Math.min(1, d.chiffre)) })
            .attr('y', function (d) { return y0(d.date) + y1(d.series) })
            .attr('height', y1.bandwidth())
            .attr('width', function (d) { return Math.abs(x(d.chiffre) - x(1)) })
            .attr('fill', function (d) { return colour(d.series) })
            .append('title')
                .text(function(d) { return d.chiffre })

        // Dark line for "same rate"
        chart
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
            .append("line")
            .attr("x1", x(1))
            .attr("x2", x(1))
            .attr("y1", 0)
            .attr("y2", height)
            .attr("stroke", "#000")
            .attr("stroke-width", "1px");

        /*series.selectAll('line.between')
            .data(function (d) { return d.values })
            .enter()
            .append('line')
            .attr('class', "between")
            .attr('x1', function (d) { return x(d.lower) })
            .attr('x2', function (d) { return x(d.upper) })
            .attr('y1', function (d) { return y0(d.date) + y1(d.series) + y1.bandwidth() / 2 })
            .attr('y2', function (d) { return y0(d.date) + y1(d.series) + y1.bandwidth() / 2 })
            .attr('stroke', "#414042")
            .attr('stroke-width', "1.5px")

        series.selectAll('line.lower')
            .data(function (d) { return d.values })
            .enter()
            .append('line')
            .attr('class', "lower")
            .attr('x1', function (d) { return x(d.lower) })
            .attr('x2', function (d) { return x(d.lower) })
            .attr('y1', function (d) { return y0(d.date) + y1(d.series) + y1.bandwidth() * 0.25 })
            .attr('y2', function (d) { return y0(d.date) + y1(d.series) + y1.bandwidth() * 0.75 })
            .attr('stroke', "#414042")
            .attr('stroke-width', "1.5px")

        series.selectAll('line.upper')
            .data(function (d) { return d.values })
            .enter()
            .append('line')
            .attr('class', "upper")
            .attr('x1', function (d) { return x(d.upper) })
            .attr('x2', function (d) { return x(d.upper) })
            .attr('y1', function (d) { return y0(d.date) + y1(d.series) + y1.bandwidth() * 0.25 })
            .attr('y2', function (d) { return y0(d.date) + y1(d.series) + y1.bandwidth() * 0.75 })
            .attr('stroke', "#414042")
            .attr('stroke-width', "1.5px")*/
    }

    function drawLeftAxis() {
        var svg = d3.select("#graphic")
            .append('svg')
            .attr("width", dvc.optional.margin_special_left)
            .attr("height", height + margin.top + margin.bottom)
            .append('g')
            .attr("transform", "translate(" + dvc.optional.margin_special_left + "," + margin.top + ")")
            .append('g')
            .attr('class', 'y axis')
            .call(d3.axisLeft(y0))
            .selectAll(".tick text")
            .attr('y', 0)
            .call(wrap, dvc.optional.margin_special_left - 18, 0.35, 1, 1, true, true);
    }

    function wrap(
        text,
        width,
        dyAdjust,
        lineHeightEms,
        lineHeightSquishFactor,
        splitOnHyphen,
        centreVertically
    ) {
        if (dyAdjust == null) dyAdjust = 0;
        if (!lineHeightEms) lineHeightEms = 1.05;
        if (!lineHeightSquishFactor) lineHeightSquishFactor = 1;
        if (splitOnHyphen == null) splitOnHyphen = true;
        if (centreVertically == null) centreVertically = false;

        text.each(function () {
            var text = d3.select(this),
                x = text.attr("x"),
                y = text.attr("y");

            var words = [];
            text
                .text()
                .split(/\s+/)
                .forEach(function (w) {
                    if (splitOnHyphen) {
                        var subWords = w.split("-");
                        for (var i = 0; i < subWords.length - 1; i++)
                            words.push(subWords[i] + "-");
                        words.push(subWords[subWords.length - 1] + " ");
                    } else {
                        words.push(w + " ");
                    }
                });

            text.text(null); // Empty the text element

            // `tspan` is the tspan element that is currently being added to
            var tspan = text.append("tspan");

            var line = ""; // The current value of the line
            var prevLine = ""; // The value of the line before the last word (or sub-word) was added
            var nWordsInLine = 0; // Number of words in the line
            for (var i = 0; i < words.length; i++) {
                var word = words[i];
                prevLine = line;
                line = line + word;
                ++nWordsInLine;
                tspan.text(line.trim());
                if (tspan.node().getComputedTextLength() > width && nWordsInLine > 1) {
                    // The tspan is too long, and it contains more than one word.
                    // Remove the last word and add it to a new tspan.
                    tspan.text(prevLine.trim());
                    prevLine = "";
                    line = word;
                    nWordsInLine = 1;
                    tspan = text.append("tspan").text(word.trim());
                }
            }

            var tspans = text.selectAll("tspan");

            var h = lineHeightEms;
            // Reduce the line height a bit if there are more than 2 lines.
            if (tspans.size() > 2)
                for (var i = 0; i < tspans.size(); i++) h *= lineHeightSquishFactor;

            tspans.each(function (d, i) {
                // Calculate the y offset (dy) for each tspan so that the vertical centre
                // of the tspans roughly aligns with the text element's y position.
                var dy = dyAdjust + i * h + (centreVertically ? (-(tspans.size() - 1) * h) / 2 : 0);
                d3.select(this)
                    .attr("y", y)
                    .attr("x", x)
                    .attr("dy", dy + "em");
            });
        });
    }

    //use pym to calculate chart dimensions
    if (pymChild) {
        pymChild.sendHeight();
    }
}

function drawLineGraphic(dvc) {
    var threshold_md = 550;
    var threshold_sm = dvc.optional.mobileBreakpoint;

    //Replace default alt text for screenreader
    if (dvc.essential.screenreadertext != "") {
        d3.select("#screenreadertext").text(dvc.essential.screenreadertext);
    }

    legendLabels = graphic_data_.map(function (d) { return d.key });

    //set variables for chart dimensions dependent on width of #graphic
    if (parseInt(graphic.style("width")) < threshold_sm) {
        var margin = {
            top: dvc.optional.margin_sm[0],
            right: dvc.optional.margin_sm[1],
            bottom: dvc.optional.margin_sm[2],
            left: dvc.optional.margin_sm[3]
        };
        var size = 0;	// used for margin_centre and x_ticks
        var chart_width = parseInt(graphic.style("width")) - margin.left - margin.right;
        var height = Math.ceil((chart_width * dvc.optional.aspectRatio_sm[1]) / dvc.optional.aspectRatio_sm[0]) - margin.top - margin.bottom;
    }

    else if (parseInt(graphic.style("width")) < threshold_md) {
        var margin = {
            top: dvc.optional.margin_md[0],
            right: dvc.optional.margin_md[1],
            bottom: dvc.optional.margin_md[2],
            left: dvc.optional.margin_md[3]
        };
        var size = 1;
        var chart_width = parseInt(graphic.style("width")) - margin.left - margin.right;
        var height = Math.ceil((chart_width * dvc.optional.aspectRatio_md[1]) / dvc.optional.aspectRatio_md[0]) - margin.top - margin.bottom;
    }

    else {
        var margin = {
            top: dvc.optional.margin_lg[0],
            right: dvc.optional.margin_lg[1],
            bottom: dvc.optional.margin_lg[2],
            left: dvc.optional.margin_lg[3]
        };
        var size = 2;
        var chart_width = parseInt(graphic.style("width")) - margin.left - margin.right;
        var height = Math.ceil((chart_width * dvc.optional.aspectRatio_lg[1]) / dvc.optional.aspectRatio_lg[0]) - margin.top - margin.bottom;
    }


    // clear out existing graphics
    graphic.selectAll("*").remove();
    keypoints.selectAll("*").remove();

    var x = d3.scaleTime()
        .range([0, chart_width]);

    var y = d3.scaleLinear()
        .range([height, 0]);

    x.domain(d3.extent(flat_graphic_data, function (d) { return d.date; }));

    var chartSize = 2;
    if (parseInt(graphic.style("width")) < threshold_sm) {
        chartSize = 0;
    } else if (parseInt(graphic.style("width")) <= threshold_md) {
        chartSize = 1;
    }
    var ticksEvery = dvc.optional.x_ticks_every[chartSize];
    var allDates = graphic_data_[0].values.map(function (d) { return d.date });
    var xAxis = d3.axisBottom(x)
        .tickFormat(function (d, i) {
            //specify date format for x axis depending on #graphic width
            if (parseInt(graphic.style("width")) <= threshold_sm) {
                var fmt = d3.timeFormat(dvc.optional.xAxisTextFormat_sm_md_lg[0]);
                return fmt(d);
            } else if (parseInt(graphic.style("width")) <= threshold_md) {
                var fmt = d3.timeFormat(dvc.optional.xAxisTextFormat_sm_md_lg[1]);
                return fmt(d);
            } else {
                var fmt = d3.timeFormat(dvc.optional.xAxisTextFormat_sm_md_lg[2]);
                return fmt(d);
            }
        })
        .tickPadding(5)
        .tickValues(allDates.filter(function (d, i) {
            return i % ticksEvery === 0 && i < allDates.length - ticksEvery || i == allDates.length - 1;
        }));

    var yAxis = d3.axisLeft(y);


    //specify number or ticks on y axis
    if (parseInt(graphic.style("width")) <= threshold_sm) {
        yAxis.ticks(dvc.optional.y_num_ticks_sm_md_lg[0])
    } else if (parseInt(graphic.style("width")) <= threshold_md) {
        yAxis.ticks(dvc.optional.y_num_ticks_sm_md_lg[1])
    } else {
        yAxis.ticks(dvc.optional.y_num_ticks_sm_md_lg[2])
    }

    //gridlines
    var y_axis_grid = function () { return yAxis; }

    var counter;


    var line = d3.line()
        .defined(function (d) { return d.amt != null; }) // Right you scallywags, I'm going to tell you what this line does. This means that the line will not be drawn between any points a data point is NaN, or whatever function you want
        .curve(d3.curveLinear)
        .x(function (d) { return x(d.date); })
        .y(function (d) { return y(d.amt); });

    var errorBand = d3.area()
        .defined(function (d) { return d.amt != null; }) // Right you scallywags, I'm going to tell you what this line does. This means that the line will not be drawn between any points a data point is NaN, or whatever function you want
        .x(function (d) { return x(d.date); })
        .y0(function (d) { return y(d.upper); })
        .y1(function (d) { return y(d.lower); });

    // parse data into columns
    var flatData = [];
    var linesArr = graphic_data_.map(function (group) {
        return {
            key: group.key,
            values: group.values.map(function (d) {
                var datum = {
                    date: d.date,
                    amt: +d.asmr_per_100000_person_weeks,
                    lower: +d.asmr_lower,
                    upper: +d.asmr_upper
                };
                flatData.push(datum);
                return datum;
            })
        };
    });

    //y domain calculations	: zero to intelligent max choice, or intelligent min and max choice,  or interval chosen manually
    if (dvc.essential.yAxisScale == "auto_zero_max") {
        var yDomain = [
            0,
            d3.max(flatData, function (d) { return Math.ceil(d.amt); })
        ];
    } else if (dvc.essential.yAxisScale == "auto_min_max") {
        var yDomain = [
            d3.min(flatData, function (d) { return Math.floor(d.amt); }),
            d3.max(flatData, function (d) { return Math.ceil(d.amt); })
        ];
    } else {
        var yDomain = dvc.essential.yAxisScale;
    }

    y.domain(yDomain);

    //create svg for chart
    // var legend = d3.select('#graphic').append('svg')
    // 			//.attr("width", chart_width + margin.left + margin.right)
    // 			//.attr("height", margin.bottom +330) //height + margin.top + margin.bottom +30)
    // 			// .append("g")
    // 			// .attr("id", "legend");


    //var svg = d3.select('#graphic').append('svg')
    var svg = d3.select('#graphic').append('svg')
        .attr("id", "chart")
        .style("background-color", "#fff")
        .attr("width", chart_width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)  //+30)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    svg.append("rect")
        .style("fill", "#fff")
        .attr("width", chart_width)
        .attr("height", height);

    svg.append('g')
        .attr('class', 'y axis')
        .call(yAxis);

    svg.append('g')
        .attr('class', 'y grid')
        .call(y_axis_grid()
            .tickSize(-chart_width, 0, 0)
            .tickFormat('')
        );

    //y axis label
    svg.append("text")
        //.attr('class', 'unit')
        .attr('transform', 'translate(' + -margin.left + ',-10)') // " + eval(-margin.top + (lineNo+1)*20) + "
        .attr("font-size", "14px")
        .attr("fill", "#000")
        .text(function (d, i) { return dvc.essential.yAxisLabel });

    //x axis label
    svg.append("text")
        .attr('transform', 'translate(' + (chart_width + margin.right/3) + ',' + (height + margin.bottom - 5) + ')')
        .attr("font-size", "14px")
        .attr("fill", "#000")
        .attr("text-anchor", "end")
        .text(function (d, i) { return dvc.essential.xAxisLabel });

    //create x axis, if y axis doesn't start at 0 drop x axis accordingly
    svg.append('g')
        .attr('class', 'x axis')
        .attr('transform', function (d) {
            if (yDomain[0] != 0) {
                return 'translate(0,' + (height + 30) + ')'
            } else {
                return 'translate(0,' + height + ')'
            }
        })
        .call(xAxis);

    //create icon to symbolise break in y axis if required
    if (yDomain[0] > 0 && dvc.essential.yAxisBreak == true) {
        var paths = svg.append("defs")
            .append("g")
            .attr("id", "icon")
            .append("g");

        paths.append("polyline")
            .attr("points", "2.881,9.54 7.94,5.061 12.341,9.54 17.77,5.061")
            .attr("stroke", "#666")
            .attr("fill", "none")
        paths.append("polyline")
            .attr("points", "2.881,14.54 7.94,10.061 12.341,14.54 17.77,10.061")
            .attr("stroke", "#666")
            .attr("fill", "none");

        //specify position of icon
        svg.append("g").attr("id", "iconpath")
            .attr("transform", "translate(-10,3)")
            .append("use")
            .attr("xlink:href", "#icon")
            .attr("x", x(x.domain()[0]))
            .attr("y", function () {
                if (parseInt(graphic.style("width")) < threshold_sm) {
                    return y(dvc.essential.yAxisBreak_sm_md_lg[0])
                } else if (parseInt(graphic.style("width")) < threshold_md) {
                    return y(dvc.essential.yAxisBreak_sm_md_lg[1])
                } else {
                    return y(dvc.essential.yAxisBreak_sm_md_lg[2])
                }
            });
    }

    //create centre line if required
    if (dvc.optional.centre_line == true) {
        svg.append("line")
            //.attr("id","centreline")
            .attr("stroke", "#CCC")
            .attr("stroke-width", 3)
            .attr('y1', y(dvc.optional.centre_line_value))
            .attr('y2', y(dvc.optional.centre_line_value))
            .attr('x1', 0)
            .attr('x2', chart_width);
    } else if (yDomain[0] < 0) {
        svg.append("line")
            //.attr("id","centreline")
            .attr("stroke", "#CCC")
            .attr("stroke-width", 3)
            .attr('y1', y(0))
            .attr('y2', y(0))
            .attr('x1', 0)
            .attr('x2', chart_width);
    }


    //create vertical line if required
    if (dvc.optional.vertical_line == true) {

        dvc.optional.annotateLineX1_Y1_X2_Y2.forEach(function (d, i) {

            svg.append("line")
                .attr('x1', x(d3.timeParse(dvc.essential.dateFormat)(dvc.optional.annotateLineX1_Y1_X2_Y2[i][0][0])))
                .attr('x2', x(d3.timeParse(dvc.essential.dateFormat)(dvc.optional.annotateLineX1_Y1_X2_Y2[i][1][0])))
                .attr('y1', y(dvc.optional.annotateLineX1_Y1_X2_Y2[i][0][1]))
                .attr('y2', y(dvc.optional.annotateLineX1_Y1_X2_Y2[i][1][1]))
                .style('stroke', '#888')
                .style('stroke-width', 2);
            //.style('stroke-dasharray', '5 5');   ,dash px,space px


        })
    }

    //create rectangle
    if (dvc.optional.annotateRect == true) {

        dvc.optional.annotateRectX_Y.forEach(function (d, i) {

            svg.append("rect")
                .attr('x', x(d3.timeParse(dvc.essential.dateFormat)(dvc.optional.annotateRectX_Y[i][0][0])))
                .attr('y', y(dvc.optional.annotateRectX_Y[i][0][1]))
                .attr('height', y(dvc.optional.annotateRectX_Y[i][1][1]) - y(dvc.optional.annotateRectX_Y[i][0][1]))
                .attr('width', x(d3.timeParse(dvc.essential.dateFormat)(dvc.optional.annotateRectX_Y[i][1][0])) - x(d3.timeParse(dvc.essential.dateFormat)(dvc.optional.annotateRectX_Y[i][0][0])))
                .style('fill', dvc.optional.lineColor_opcty[i][0])
                .style('stroke-width', 2)
                .style('opacity', dvc.optional.lineColor_opcty[i][1]);

        })
    }

    //create error bands
    if (windowLocationHash[1]) {
        svg.append('g').selectAll('path')
            .data(linesArr)
            .enter()
            .append('path')
            //.attr('class', 'line')
            .style("fill", function (d, i) { return dvc.essential.colour_palette[i]; })
            .style("stroke", 'none')
            .style("opacity", 0.3)
            .style("stroke-linecap", 'round')
            .style("stroke-linejoin", 'round')
            .attr('d', function (d) {
                return errorBand(d.values);
            });
    }

    //create lines
    svg.append('g').selectAll('path')
        .data(linesArr)
        .enter()
        .append('path')
        .style("stroke", function (d, i) { return dvc.essential.colour_palette[i] || "red"; })
        .style("fill", 'none')
        .style("stroke-width", dvc.optional.stroke_width)
        .style("stroke-linecap", 'round')
        .style("stroke-linejoin", 'round')
        .attr('d', function (d) {
            return line(d.values);
        });



    // add markers
    if (parseInt(graphic.style("width")) > threshold_sm && dvc.optional.lineMarkers == true) {

        /*for (var i=0; i<graphic_data_.length; i++) {
            var column = graphic_data_[i].key;
            svg.append("g")
            .selectAll("circles")
            .data(lines[column]) // raw data
            .enter()
            .append('circle')
            .style('fill', function(d){ return dvc.essential.colour_palette[i]; })
            .style('stroke', function(d){ return dvc.essential.colour_palette[i]; })
            .style('stroke-width', 1)
            .attr("cx", function(d){
                                        return x(d.date);
                                    })
            .attr("cy", function(d){
                                        return y(d.amt);
                                    })
            .attr("r", function(d){if(d[column]!=0){return 3}else{return 0}});
        }*/

    } // ends if

    // circle annotations
    if (dvc.essential.circles == true) {
        dvc.essential.annotationCXCY.forEach(function (d, i) {
            svg.append("circle")
                .attr("cx", x(d3.timeParse(dvc.essential.dateFormat)(dvc.essential.annotationCXCY[i][0])))
                .attr("cy", y(dvc.essential.annotationCXCY[i][1]))
                .attr("r", 6)
                .attr("fill", dvc.essential.annotationColour)

            svg.append("text")
                .attr("x", x(d3.timeParse(dvc.essential.dateFormat)(dvc.essential.annotationCXCY[i][0])) - 20)
                .attr("y", y(dvc.essential.annotationCXCY[i][1]) - 15)
                .text(dvc.essential.annotationCXCY[i][0])
        })
    } // ends if

    writeAnnotation();

    function writeAnnotation() {

        if (parseInt(graphic.style("width")) < threshold_sm) {

            dvc.essential.annotationBullet.forEach(function (d, i) {

                d3.select("#keypoints").append("svg")
                    .attr("width", "15px")
                    .attr("height", "15px")
                    .attr("class", "circles")
                    .append("circle")
                    .attr("class", "annocirc" + (i))
                    .attr("r", "2")
                    .attr('cy', "9px")
                    .attr("cx", "10px");

                d3.select("#keypoints")
                    .append("p")
                    .style("font-size", "14px")
                    .style("font-weight", 400)
                    .text(dvc.essential.annotationBullet[i]);

            })// end foreach

        }
        else {

            annotations = dvc.essential.annotationsChart;

            // For elements with time series
            for (i = 0; i < annotations.length; i++) {
                annotations[i].xVal = new Date(annotations[i].xVal);
            }

            var swoopy = d3.swoopyDrag()
                .x(function (d) { return x(d.xVal) })
                .y(function (d) { return y(d.yVal) })
                .draggable(dvc.essential.draggable)
                .annotations(annotations);


            var swoopySel = svg.append('g').attr("class", "annotations").call(swoopy); // Expected number, "translate()". error for each annotation

            svg.append('marker')
                .attr('id', 'arrow')
                .attr('viewBox', '-10 -10 20 20')
                .attr('markerWidth', 20)
                .attr('markerHeight', 20)
                .attr('orient', 'auto')
                .append('path')
                .attr('d', 'M-6.75,-6.75 L 0,0 L -6.75,6.75')
                .attr('fill', '#808080');

            swoopySel.selectAll('path').attr('marker-end', 'url(#arrow)');


            d3.selectAll(".annotations path")
                .style("stroke", "#808080")
                .attr("fill", "none");

            swoopySel.selectAll('text')
                .attr('font-size', '13px')
                .attr('font-size', '13px')
                .attr("font-size", "13px")
                .attr("font-weight", 500)
                .each(function (d, i) {
                    d3.select(this)
                        .text('')                        //clear existing text
                        .tspans(d3.wordwrap(d.text, dvc.essential.wordwrap[i])) //wrap after xx char
                });


            swoopySel.selectAll('text')
                .each(function (d, i) {
                    d3.select(this).selectAll('tspan')
                        .attr("text-anchor", dvc.essential.annoAlign[i]);
                });
        } // end else ...

        return;

    }// end function writeAnnotation()

    // always create a legend on mobile. when not on mobile, only create a legend if not using direct line labeling.
    var onMobile = parseInt(graphic.style("width")) < dvc.optional.mobileBreakpoint;
    if (!dvc.essential.directLabeling || onMobile) {
        createLegend();
    }
    else {
        createLineLabels();
    }

    function createLegend() {


        legenditems = d3.select("#graphic")
            .insert("div", "#chart")
            .attr("id", "legend");

        legendLabels.forEach(function (d, i) {

            legenditem = legenditems.append("div")
                .attr("class", "legenditem");


            legenditem.append("div").attr("class", "legendline").style("width", "20px").style("height", "2.5px").style("background-color", dvc.essential.colour_palette[i]);
            legenditem.append("p").attr("class", "legendtext").text(d);


        });

    }// end function createLegend()


    function createLineLabels() {
        for (var i = 0; i < graphic_data_.length; i++) {
            var group = graphic_data_[i];
            var vals = group.values;
            svg.append("text")
                // place the line labels to the right of the lines and add label adjustment from config
                .attr("transform", function (d) {
                    var xcoord = x(vals[vals.length - 1].date) + dvc.essential.directLabelingAdjust[i]['x']
                    var ycoord = y(vals[vals.length - 1].asmr_per_100000_person_weeks) + dvc.essential.directLabelingAdjust[i]['y'];
                    return "translate(" + xcoord + "," + ycoord + ")";
                })
                .attr("x", 10)
                .attr("dy", ".35em")
                .attr("class", "label")
                .style("fill", dvc.essential.colour_palette_labels[i])
                .text(group.key)
                .call(wrap, margin.right)
        } // end for loop running through data columns
    } // end function createLineLabels()

    function wrap(text, width) {
        text.each(function () {
            var text = d3.select(this),
                words = text.text().split(/\s+/).reverse(),
                word,
                line = [],
                lineHeight = 1.0, // ems
                y = text.attr("y") + 5,
                tspan = text.text(null).append("tspan").attr("x", 5).attr("y", y),
                tspans = [tspan];
            while (word = words.pop()) {
                line.push(word);
                tspan.text(line.join(" "));
                if (tspan.node().getComputedTextLength() > width - 5) {
                    line.pop();
                    tspan.text(line.join(" "));
                    line = [word];
                    tspan = text.append("tspan").attr("x", 5).attr("y", y).text(word);
                    tspans.push(tspan);
                }
            }
            var dy = -(tspans.length - 1) * lineHeight / 2;
            tspans.forEach(function (tspan) {
                tspan.attr("dy", dy + "em");
                dy += lineHeight;
            });
        });
    }

    // css fix
    d3.selectAll("path").attr("fill", "none");

    d3.selectAll("text").attr("font-family", "'Open Sans', sans-serif");

    d3.selectAll(".x text").attr("font-size", "14px").attr("fill", "#000");
    d3.selectAll(".y text").attr("font-size", "14px").attr("fill", "#000");

    d3.selectAll(".y line")
        .attr("stroke", "#CCC")
        .attr("stroke-width", "1px")
        .style("shape-rendering", "crispEdges");

    d3.selectAll(".x line")
        .attr("stroke", "#CCC")
        .attr("stroke-width", "1px")
        .style("shape-rendering", "crispEdges");


    // save SVG
    d3.select("#buttonid").on("click", function () { saveSvgAsPng(document.getElementById("chart"), "diagram.png") });

    //use pym to calculate chart dimensions
    if (pymChild) {
        pymChild.sendHeight();
    }

}  // ends draw graphic

function startOddsRatioChart() {
    //check whether browser can cope with svg
    if (Modernizr.svg) {
        //load config
        d3.json("config.json", function (error, config) {
            dvc = config;
            dvc.added = {};

            //load chart data
            d3.csv(dvc.essential.graphic_data_url, function (error, data) {
                data = data.filter(function (d) { return d.dataset === dvc.essential.dataset; });
                dvc.added.comparisonGroup = data.filter(function (d) { return d.chiffre === "NA"; })[0].date;
                graphic_data = data.filter(function (d) { return d.chiffre !== "NA"; });

                graphic_data.forEach(function (d) {
                    // d.date=d3.timeParse(dvc.essential.dateFormat)(d.date)
                    d.chiffre = +d.chiffre
                    d.lower = +d.lower
                    d.upper = +d.upper
                })
                //use pym to create iframed chart dependent on specified variables
                pymChild = new pym.Child({
                    renderCallback: function () { drawOddsRatioGraphic(dvc); }
                });
            });

        })

    } else {
        //use pym to create iframe containing fallback image (which is set as default)
        pymChild = new pym.Child();
        if (pymChild) {
            pymChild.sendHeight();
        }
    }
}

function startLineChart() {
    //check whether browser can cope with svg
    if (Modernizr.svg) {
        var dvc = lineChartConfig;
        var hash = window.location.hash.substr(1).split("-");
        windowLocationHash = hash;
        d3.csv(hash[0] || dvc.essential.graphic_data_url, function (error, data) {
            var category_column = data.columns[0];
            if (category_column === "imd_quintile" || category_column === "rural_urban" || category_column === "scgpuk11") {
                dvc.essential.directLabeling = false;
                dvc.optional.margin_md[1] = 35;
                dvc.optional.margin_lg[1] = 35;
                if (category_column === "imd_quintile") {
                    dvc.essential.colour_palette = ["#1c5276", "#3f72a0", "#5f93cc", "#6ba6de", "#83ccff"];
                    dvc.optional.stroke_width = 1.6;
                    data.forEach(function (d) {
                        if (d.imd_quintile === "C") return;
                        if (d.imd_quintile === "1") d.imd_quintile = "1 (most deprived)";
                        if (d.imd_quintile === "5") d.imd_quintile = "5 (least deprived)";
                        d.imd_quintile = "Quintile " + d.imd_quintile;
                    });
                }
            }
            data = data.filter(function (d) {
                return d[category_column] !== "C" &&
                    d[category_column] !== "X" &&
                    d[category_column] !== "6";
            });
            data.forEach(function (d) { d.date = d3.timeParse(dvc.essential.dateFormat)(d.Period); });

            var categories = [];
            data.forEach(function (d) {
                if (categories.indexOf(d[category_column]) < 0) {
                    categories.push(d[category_column]);
                }
            });
            var dataByCategory = {};
            categories.forEach(function (c) { dataByCategory[c] = []; });
            data.forEach(function (d) {
                var category = d[category_column];
                dataByCategory[category].push(d);
            });
            var groups = categories.map(function (c) {
                return { key: c, values: dataByCategory[c] };
            });

            flat_graphic_data = data;
            graphic_data_ = groups;
            pymChild = new pym.Child({ renderCallback: function () { drawLineGraphic(dvc); } });
        });

        //use pym to create iframe containing fallback image (which is set as default)
        pymChild = new pym.Child();
        if (pymChild) {
            pymChild.sendHeight();
        }
    }
}