grid = (data, scale=5, options=({vectext: true})) => {
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("max-width", "100%")
.attr("height", "auto")
.attr("height", "intrinsic");
var xRange = margin.left + (height - margin.bottom)/2;
var yRange = margin.top + (height - margin.bottom - margin.top)/2;
var yOffset = `translate(${xRange}, 0)`;
var xOffset = `translate(0, ${yRange})`;
var xyOffset = `translate(${xRange},${yRange})`;
var yAxis = svg.append("g").attr("transform", yOffset)
.call(d3.axisLeft(y).tickValues([]).tickSizeOuter(0));
var xAxis = svg.append("g").attr("transform", xOffset)
.call(d3.axisBottom(x).tickValues([]).tickSizeOuter(0));
svg.append("svg:defs").append("svg:marker")
.attr("id", "triangle")
.attr("refX", 10)
.attr("refY", 4)
.attr("markerWidth", 10)
.attr("markerHeight", 10)
.attr("markerUnits","userSpaceOnUse")
.attr("orient", "auto")
.append("path")
.attr("d", "M 0 0 L 0 8 L 10 4 L 0 0")
.style("fill", "black");
var vec = svg.append("g").attr("transform", xyOffset)
.selectAll("path").data(data).enter().append("path")
.attr("id", function(d, i) { return "r" + i; })
.attr("fill", "black")
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("d", function(d) { return pathString(0, 0, d.x*scale, d.y*scale) })
.attr("marker-end", "url(#triangle)");
if(options.vectext == true) {
var vecText = svg.append("g").attr("transform", xyOffset)
.selectAll("text").data(data).enter().append("text")
.attr("text-anchor", "middle")
.attr("dy", "1em")
.attr("font-size", "10")
.append("textPath")
.attr("xlink:href", function(d, i) { return "#r" + i; })
.attr("startOffset", "45%")
.text(function(d, i) { return "r" + i; });
}
return svg.node();
}