Skip to content

Instantly share code, notes, and snippets.

@ABSegler
Forked from mbostock/.block
Last active September 14, 2018 21:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save ABSegler/9791707 to your computer and use it in GitHub Desktop.
Save ABSegler/9791707 to your computer and use it in GitHub Desktop.
Piers Parallel Coordinates MS Visualization

This parallel coordinates visualization of Piers Plowman Manuscripts traces several features of the manuscript corpus in a succession of sliders that can be activated by clicking on an axis and dragging the mouse to highlight a section of the axis. The selection can be refined by clicking and dragging the top or bottom, and the whole selection can be slid up and down the axis to highlight various manuscript trajectories. You may activate sliders on as many axes as you choose, and you can reset a single slider by reducing its selection to zero or erase them all by reloading the page.

A single line traces a single manuscript's stats across each of the axes.

The first two axes trace the earliest and latest possible dates for a MS's production according to A.V.C. Schmidt's dating in his parallel text edition. Some liberties have been taken to make the relative dating periods numerical, thus "early fifteenth century" is expressed as 1400-1415, while "mid fifteenth century" is expressed as 1440-1460.

The second two axes chart the position of Piers in the MS relative to all the works contained in it. The number for "position" indicates in which spot Piers is placed, thus "2" means Piers is second out of however many works in the MS. The top end represents the Vernon MS, but could not be represented numerically without the scale making the majority of data illegible. Thus, while the Vernon has over 370 works, and Piers comes near the end of them, this has been reduced to 30 out of 40 simply to mark the Vernon as the high end without completely obscuring the information for all the other MSS.

The next two sliders represent two numbers that are of particular importance to me. They trace the number of lines of Piers poetry (usually ranging from 2500 to 7000) and relate that directly to how much of the manuscript Piers happens to occupy. As I show elsewhere in my research, there is a strong correlation between longer forms of the poem taking up more of the manuscripts, and not necessarily because they would be inconvenient to compile (as at least four of them appear in compilations).

The second axis from the right (or 7th in order) is an unusual axis that attempts to turn geospatial information into a numerical scale. I have used arbitrary data points inside each of the regions from which MSS show signs of origination to "represent" the whole region. I have also chosen Malvern itself as the point of origin from which to measure distance because of both the strong clustering of the corpus in the Southwest Midlands (and specifically in Southwest Worcestershire), and Malvern Hills' being the location of Will's own origin. Some MSS cannot be located anywhere in particular, so I have arbitrarily chosen to place them at 70 miles from origin, 70 representing half the distance between Malvern and London. It is a generous radius with a high probability of containing most of the manuscripts in question.

The final axis is a number scale that assigns a number to each of the different textual varieties according to this rubric:

1- A-text
2- AB hybrid
3- B-text
4- BC hybrid (which usually includes a few lines of A, being the BmBoCot family)
5- C-text
6- AC hybrid
7- the BC Conflated text of Hm114
8- Z-text

The code below has been modified from that of Mike Bostock's Parallel Coordinates Block (http://bl.ocks.org/mbostock/7586334).

<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.background path {
fill: none;
stroke: #ccc;
stroke-opacity: .4;
shape-rendering: crispEdges;
}
.foreground path {
fill: none;
stroke: steelblue;
stroke-opacity: .7;
}
.brush .extent {
fill-opacity: .3;
stroke: #fff;
shape-rendering: crispEdges;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text {
text-shadow: 0 1px 0 #fff;
cursor: move;
}
.tooltip {
background-color: rgba(220,220,220,0.5);
color: #333;
margin: 10px;
height: 25px;
padding-right: 10px;
padding-left: 10px;
padding-top: 10px;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip")
.attr("class","tooltip");
var m = [30, 10, 10, 10],
w = 960 - m[1] - m[3],
h = 500 - m[0] - m[2];
var x = d3.scale.ordinal().rangePoints([0, w], 1),
y = {},
dragging = {};
var line = d3.svg.line(),
axis = d3.svg.axis().orient("left"),
background,
foreground;
var svg = d3.select("body").append("svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
d3.csv("PiersParallelCoordinates.csv", function(error, piers) {
// Extract the list of dimensions and create a scale for each.
x.domain(dimensions = d3.keys(piers[0]).filter(function(d) {
return d != "name" && (y[d] = d3.scale.linear()
.domain(d3.extent(piers, function(p) { return +p[d]; }))
.range([h, 0]));
}));
// Add grey background lines for context.
background = svg.append("g")
.attr("class", "background")
.selectAll("path")
.data(piers)
.enter().append("path")
.attr("d", path);
// Add blue foreground lines for focus.
foreground = svg.append("g")
.attr("class", "foreground")
.selectAll("path")
.data(piers)
.enter().append("path")
.attr("d", path)
.on("mouseover", function(n){
d3.select(this).transition().duration(100)
.style({'stroke' : '#F00'});
tooltip.text(n.name);
return tooltip.style("visibility", "visible");
})
.on("mousemove", function(){return tooltip.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px");})
.on("mouseout", function(d){
d3.select(this).transition().duration(100)
.style({'stroke': 'steelblue' })
.style({'stroke-width' : '2'});
return tooltip.style("visibility", "hidden");
});
// Add a group element for each dimension.
var g = svg.selectAll(".dimension")
.data(dimensions)
.enter().append("g")
.attr("class", "dimension")
.attr("transform", function(d) { return "translate(" + x(d) + ")"; })
.call(d3.behavior.drag()
.on("dragstart", function(d) {
dragging[d] = this.__origin__ = x(d);
background.attr("visibility", "hidden");
})
.on("drag", function(d) {
dragging[d] = Math.min(w, Math.max(0, this.__origin__ += d3.event.dx));
foreground.attr("d", path);
dimensions.sort(function(a, b) { return position(a) - position(b); });
x.domain(dimensions);
g.attr("transform", function(d) { return "translate(" + position(d) + ")"; })
})
.on("dragend", function(d) {
delete this.__origin__;
delete dragging[d];
transition(d3.select(this)).attr("transform", "translate(" + x(d) + ")");
transition(foreground)
.attr("d", path);
background
.attr("d", path)
.transition()
.delay(500)
.duration(0)
.attr("visibility", null);
}));
// Add an axis and title.
g.append("g")
.attr("class", "axis")
.each(function(d) { d3.select(this).call(axis.scale(y[d])); })
.append("text")
.attr("text-anchor", "middle")
.attr("y", -9)
.text(String);
// Add and store a brush for each axis.
g.append("g")
.attr("class", "brush")
.each(function(d) { d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brushstart", brushstart).on("brush", brush)); })
.selectAll("rect")
.attr("x", -8)
.attr("width", 16);
});
function position(d) {
var v = dragging[d];
return v == null ? x(d) : v;
}
function transition(g) {
return g.transition().duration(500);
}
// Returns the path for a given data point.
function path(d) {
return line(dimensions.map(function(p) { return [position(p), y[p](d[p])]; }));
}
// When brushing, don’t trigger axis dragging.
function brushstart() {
d3.event.sourceEvent.stopPropagation();
}
// Handles a brush event, toggling the display of foreground lines.
function brush() {
var actives = dimensions.filter(function(p) { return !y[p].brush.empty(); }),
extents = actives.map(function(p) { return y[p].brush.extent(); });
foreground.style("display", function(d) {
return actives.every(function(p, i) {
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
}) ? null : "none";
});
}
</script>
name Terminus post quem Terminus ante quem No. of Works in MS Position of Piers Lines of Piers Percent MS Piers Occupies Dist from Malvern Textual Variety
Trinity College Dublin 212 D.4.1 1390 1400 1 1 7345 96.7 30 5
Cambridge University Library Dd.3.13 1390 1400 1 1 7347 100 30 5
Bodley MS 851 1390 1400 6 6 1300 11.5 10 8
Bodley MS Poet.a.1 1398 1403 40 30 2429 4.5 60 1
Cambridge University Library Dd.1.17 1398 1403 23 18 7311 7.3 30 3
Corpus Christi College Oxford 201 1398 1403 1 1 7364 95.6 180 3
Bodley MS Laud 581 1398 1403 1 1 7302 97.8 10 3
Bodley MS Rawlinson Poet. 38 1398 1403 1 1 7312 95.3 20 3
Bodley MS Laud 656 1398 1403 5 2 7347 76 60 5
Bodley MS Digby 171 1398 1403 1 1 7345 100 10 5
BL Additional 35157 1398 1403 2 1 7346 95.4 20 5
BL Cotton Vespasian B.16 1398 1403 7 7 7358 93.4 30 5
Huntington Library Hm 143 (X) 1398 1403 2 2 7345 95.5 10 5
Huntington Library Hm137 1398 1403 1 1 7346 100 40 5
Trinity College Cambridge B.15.17 1398 1403 3 1 6255 88.4 120 3
Trinity College Cambridge R.3.14 1398 1403 1 1 7303 98.6 140 6
Bodley MS 814 1400 1410 1 1 7345 100 30 3
University of London S.L.V.17 1400 1410 2 1 7345 85.3 10 5
Cambridge University Library Additional 4325 1400 1410 1 1 7355 95.4 20 5
University of London S.L.V.88 1400 1410 1 1 7447 98 20 5
BL Additional 34779 1400 1410 1 1 7367 97.9 50 5
BL Additional MS 10574 1400 1410 1 1 7273 100 30 4
Huntington Library MS 128 1400 1415 6 4 7304 43 40 3
Lincoln's Inn no. 150 1400 1425 5 5 1897 13.5 70 1
University College, Oxford MS 45 1400 1425 11 1 2511 40 130 1
BL Harley MS 3954 1400 1425 7 7 2744 25.4 180 2
BL Additional MS 35287 1400 1425 1 1 7302 100 140 3
Oriel College Oxford MS 79 1400 1425 1 1 7316 80.3 130 3
Bodley MS Digby 102 1400 1425 4 1 7346 67.4 70 5
BL Harley 2376 1400 1425 1 1 7345 100 40 5
National Library of Wales no. 733B 1400 1425 1 1 5530 100 70 6
Duke of Westminster's MS 1400 1425 1 1 6250 97.3 70 6
BL Cotton Caligula A.XI 1400 1425 4 3 7308 40.6 30 4
University of Liverpool F.4.8 1420 1420 1 1 6554 95.1 110 6
Society of Antiquaries no. 687 1423 1427 10 8 2567 14.2 180 1
BL Harley 6041 1423 1427 2 1 5948 94 150 6
Yates Thompson MS 1423 1427 2 1 7312 95 140 3
Bodley MS Douce 104 1427 1427 1 1 7345 100 70 5
Cambridge University Library Ff.5.35 1400 1450 2 2 7353 80.5 60 5
Bodley MS 851* 1439 1450 6 7 5708 40.4 10 8
Cambridge University Library Ll.4.14 1425 1450 9 1 7316 66.5 140 3
Huntington Library Hm 114 1425 1450 6 1 7800 40 190 7
Ingilby; Pierpont Morgan MS 818 1440 1460 3 3 2561 72.3 170 1
Bodley MS Rawlinson 137 1440 1460 2 1 2678 91.4 160 1
BL Harley 875 1425 1475 1 1 1952 100 50 1
Corpus Christi College Cambridge 293 1450 1475 1 1 7352 100 50 5
Trinity College Dublin 213 (D.4.12) 1450 1500 6 2 1616 36.1 260 1
Bodley MS Ashmole 1468 1475 1500 1 1 2565 19 160 1
Bodley MS Douce 323 1475 1500 2 2 2558 23 70 1
Cambridge University Library Gg.iv.31 1500 1525 1 1 7306 95.3 70 3
BL Royal 18.B.xvii 1500 1525 2 2 7355 88.6 70 5
Bodley MS Digby 145 1531 1531 3 1 6259 72.8 130 6
Tokyo, Toshiyuki Takamiya ms 23 1540 1560 1 1 7306 100 70 3
Crowley's Prints 1550 1550 1 1 7306 100 140 3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment