function dashunemployment(data, base = "dashunemployment") {
var graphic = d3.select('#' + base);
var keypoints = d3.select('#keypoints');
var thismeasure = "unemploymentrate";
var dvc, textdata, graphic_data, keys, annotations, lineNo, var_group, changeonQuarter, changeonPandemic;

function beforedrawgraphic(width) {
textdata = data.text.filter(function (d) { return d.measure == thismeasure });
drawGraphic(width, textdata);
d3.select("#" + base + "-wrapper .measureheading").text(textdata[0].heading)
d3.select("#" + base + "-wrapper .measuredefinition").text(textdata[0].definition)
d3.select("#" + base + "-wrapper .measurecommentary").html(textdata[0].commentary)
d3.select("#" + base + "-wrapper .measuresource").text(textdata[0].source)
}
function drawGraphic(width, textdata) {

//write the atomated up/down arrows
changeonQuarter = textdata[0]["quarterly change"];
d3.select("#" + base + "-wrapper .measureMonth")
.text(function (d) {
if (changeonQuarter == 0) { return "Quarterly change: ◀▶ 0.0pps" }
else if (changeonQuarter > 0) { return "Quarterly change: ▲" + changeonQuarter + "pps" }
else if (changeonQuarter < 0) { return "Quarterly change: ▼" + changeonQuarter + "pps" }
})

changeonPandemic = textdata[0]["change since DF20"];
d3.select("#" + base + "-wrapper .measurePandemic")
.text(function (d) {
if (changeonPandemic == 0) { return "Since Dec-Feb 2020: ◀▶ 0.0pps" }
else if (changeonPandemic > 0) { return "Since Dec-Feb 2020: ▲" + changeonPandemic + "pps" }
else if (changeonPandemic < 0) { return "Since Dec-Feb 2020: ▼" + changeonPandemic + "pps" }
})

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

//set variables for chart dimensions dependent on width of #graphic
var size, margin, chart_width, height;

if (parseInt(graphic.style("width")) < threshold_sm) {
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]
};
size = 0; // used for margin_centre and x_ticks
chart_width = parseInt(graphic.style("width")) - margin.left - margin.right;
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) {
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]
};
size = 1;
chart_width = parseInt(graphic.style("width")) - margin.left - margin.right;
height = Math.ceil((chart_width * dvc.optional.aspectRatio_md[1]) / dvc.optional.aspectRatio_md[0]) - margin.top - margin.bottom;
}

else {
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]
};
size = 2;
chart_width = parseInt(graphic.style("width")) - margin.left - margin.right;
height = Math.ceil((chart_width * dvc.optional.aspectRatio_lg[1]) / dvc.optional.aspectRatio_lg[0]) - margin.top - margin.bottom;
}

height = 80;
// 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(graphic_data, 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]);
//console.log("S "+fmt(d));
return fmt(d);
} else if (parseInt(graphic.style("width")) <= threshold_md) {
var fmt = d3.timeFormat(dvc.optional.xAxisTextFormat_sm_md_lg[1]);
//console.log("M "+fmt(d));
return fmt(d);
} else {
//console.log(dvc.optional.xAxisTextFormat_sm_md_lg[2] + ", " + d);
var fmt = d3.timeFormat(dvc.optional.xAxisTextFormat_sm_md_lg[2]);
//console.log("L "+fmt(d));
return fmt(d);
}
})
.tickPadding(5)

//specify number of ticks on x axis and whether 1st and last data point labels are included
if (parseInt(graphic.style("width")) < 1) {
xAxis.tickValues(x.ticks(graphic_data.length));
} else if (parseInt(graphic.style("width")) <= threshold_md) {
xAxis.tickValues(x.ticks(graphic_data.length))//.concat( x.domain());
} else {
xAxis.tickValues(x.ticks(graphic_data.length))//.concat( x.domain() );
}

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 !== ''; }) // nobody can tell me what this line actually does
.curve(d3.curveLinear)
.x(function (d) { return x(d.date); })
.y(function (d) { return y(d.amt); });

// parse data into columns
var lines = {};
for (var column in graphic_data[0]) {
if (column == 'date') continue;
lines[column] = graphic_data.map(function (d) {
return {
'date': d.date,
'amt': d[column]
};
});
}

// do some code to overwrite blanks with the last known point
keys = d3.keys(lines)
for (i = 0; i < keys.length; i++) {
// console.log(lines[keys[i]])
lines[keys[i]].forEach(function (d, j) {
if (d.amt != "null") {
counter = j;
} else {
d.date = lines[keys[i]][counter].date
d.amt = lines[keys[i]][counter].amt
}

})

}

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

y.domain(yDomain);

//console.log(chart_width +" , "+ height);
//console.log(chart_width + margin.left + margin.right +" , "+ (height + margin.top + margin.bottom));

//var svg = d3.select('#graphic').append('svg')
var svg = 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", "#666")
.text(function (d, i) { return dvc.essential.yAxisLabel });

svg.append("text")
.attr("x", x(graphic_data[graphic_data.length - 1].date) + 8)
.attr("y", y(graphic_data[graphic_data.length - 1][thismeasure]) + 3)
.attr("font-size", "14px")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.attr("fill", "#206095")
.text(d3.format(",.1f")(graphic_data[graphic_data.length - 1][thismeasure]));

svg.append('circle')
.attr('cx', x(graphic_data[graphic_data.length - 1].date))
.attr("cy", y(graphic_data[graphic_data.length - 1][thismeasure]))
.attr('r', 4)
.attr("fill", "#206095");

//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 + 20) + ')'
} else {
return 'translate(0,' + height + ')'
}
})
.call(xAxis);

graphic.select(".x").select("path").style("stroke", "#666")

//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])
}
});
}

//just first and last points
graphic.select("g.x.axis").selectAll(".tick").attr("class", function (d, i) {
return "ticky ticky" + i;
})
graphic.selectAll(".ticky").style("display", "none");
graphic.select(".ticky0").style("display", "block").selectAll("text").text(textdata[0].startdate).attr("text-anchor", "start")
graphic.select(".ticky" + (graphic_data.length - 1)).style("display", "block").selectAll("text").text(textdata[0].enddate).attr("text-anchor", "end")

graphic.select("g.y.grid").style("display", "none");

//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 lines
svg.append('g').selectAll('path')
.data(d3.entries(lines).filter(line.defined()))
.enter()
.append('path')
//.attr('class', 'line')
.style("stroke", "#206095")
.style("fill", 'none')
.style("stroke-width", 3)
.style("stroke-linecap", 'round')
.attr("class", function (d) { return "alllines line" + d.key })
.style("stroke-linejoin", 'round')
.attr('d', function (d) {
return line(d.value);
});

graphic.selectAll(".alllines").style("display", "none");
graphic.selectAll(".line" + thismeasure).style("display", "block");

// graphic_data.forEach(function(d,i){
// svg.append('circle')
// .attr('cx',x(graphic_data[i].date))
// .attr('cy',y(graphic_data[i].payrolledemployees))
// .attr('r', 4)
// .attr("fill",function(){
// if(graphic_data[i].payrolledemployees == 0) {return "none"}
// else{return '#003C57'}
// });
// })

// add markers
if (parseInt(graphic.style("width")) > threshold_sm && dvc.optional.lineMarkers == true) {
for (var column in graphic_data[0]) {
if (column == 'date') continue;
svg.append("g")
.selectAll("circles")
.data(lines[column]) // raw data
.enter()
.append('circle')
.style('fill', '#fff')
.style('stroke', function (d) { return dvc.essential.colour_palette[column]; })
.style('stroke-width', 2)
.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();

//d3.select("g.y.grid").style("display","none")

function writeAnnotation() {

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

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

graphic.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");

graphic.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)');

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

swoopySel.selectAll('text')
.attr("font-size", "13px")
.attr("font-weight", "bold")
.attr("fill", "#27A0CC")
.attr("class", function (d, i) { return "annotexty" + i })
.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() {

var prevX = 0;
var prevY = 0;
lineNo = 0;
var lineNoOld = 0;

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

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

var_group.append("rect")
.attr("class", "rect" + i)
.attr("fill", dvc.essential.colour_palette[d])
.attr("x", 0)
.attr("y", 0)
.attr("width", function (d) {
if (dvc.essential.legendStyle == "rect") {
return 15;
} else {
return 20;
}
})
.attr("height", function (d) {
if (dvc.essential.legendStyle == "rect") {
return 15;
} else {
return 3;
}
})

var_group.append("text")
.text(dvc.essential.legendLabels[i])
.attr("class", "legend" + i)
.attr("text-anchor", "start")
.style("font-size", "14px")
.style("fill", "#666")
.attr('y', 15)
.attr('x', 0);

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

function calcPosition() {

var BBox = this.getBBox()

//prevY =BBox.width
graphic.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 * 20) + 20);
})
.attr("x", function (d) { return prevX + 25; })

graphic.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 * 20) + 12);

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

prevX = prevX + BBox.width + 50

}; // end function calcPosition()
}); // end foreach
}// end function createLegend()

function createLineLabels() {

for (var column in graphic_data[0]) {
if (column == 'date') continue;

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(graphic_data[graphic_data.length - 1]["date"]) + dvc.essential.directLabelingAdjust[column]['x']
var ycoord = y(graphic_data[graphic_data.length - 1][column]) + dvc.essential.directLabelingAdjust[column]['y'];
return "translate(" + xcoord + "," + ycoord + ")";
})
.attr("x", 10)
.attr("dy", ".35em")
.attr("class", "label")
.style("fill", dvc.essential.colour_palette[column])
.text(column)
.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 = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y") + 5,
dy = 0,
tspan = text.text(null).append("tspan").attr("x", 5).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 5).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}

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

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

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

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

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

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

} // ends draw graphic

d3.json("../" + base + "/config.json", function (error, config) {
dvc = config

//load chart data
graphic_data = data.charts.filter(function (d) { return d[thismeasure] !== "" });

graphic_data.forEach(function (d) {
if (typeof d.date === "string") d.date = d3.timeParse(dvc.essential.dateFormat)(d.date);
});
beforedrawgraphic();
});
}