Experimental attemp at positioning a collection of a term variations through time. In this case, a set of transcription from the inscription 'pnn'. Size is based on counting occurrences for each transcription.
Layout uses the d3.forceChart() plugin, using square as the default shape. Need to tweak the settings and the plugin as well in order to achieve a better placement considering rectangular shapes.
Data is a sample from a database for amphorae and epigraphy, by CEIPAC.
Viz to be part of a data-driven exploratory interface in the context of the EPNet Project, an ERC Advanced Grant project intending to set up an innovative framework to investigate the political and economical mechanisms that characterised the dynamics of the commercial trade system during the Roman Empire.
xxxxxxxxxx
<html>
<head>
<style>
body {
font: 14px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: black;
}
.axis path { stroke: none; }
text {
font-size: 10px;
}
rect {
fill: tomato;
opacity: .5;
stroke: white;
}
</style>
</head>
<body>
<script src="lodash.min.js"></script>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src='datalib.min.js'></script>
<script src="force-chart.js"></script>
<script>
var margin = { top: 10, left: 100, bottom: 30, right: 50 },
width = 960 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var x = function(d) { return d.xpos; };
var xScale = d3.scale.linear()
.domain([-10, 30])
.range([0, width]);
areaScale = d3.scale.linear().range([.5, 2]);
var xValue = function(d) {
return xScale(x(d));
};
var xAxis = d3.svg.axis().scale(xScale).orient("bottom");
var inscriptionChart = d3.forceChart()
.size([width, height])
.shape('square')
.draggable(true)
.x(xValue)
.y(height/2)
.rStart(5)
.r(10)
.xGravity(15) // make the x-position more accurate
.yGravity(1/50); // ...and the y-position more flexible
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json("data.json", function(error, data) {
if (error) throw error;
// count occurrences by inscription variation
var countByKey = _(
dl.groupby('FullTranscription')
.count()
.execute(data)
)
.mapKeys(function(o) { return o.FullTranscription; })
.mapValues(function(value, key) { return value.count; })
.value();
// add counting on each instance of the
// inscription variations and assign a random
// value for x-positioning
data.forEach(function(d) {
d.count = countByKey[d.FullTranscription];
d.xpos = _.random(-5, 25);
})
areaScale.domain([0, d3.max(data, function(d) { return d.count; } )] );
// Draw axes
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis)
.append("text")
.attr("dx", width)
.attr("dy", -6)
.style("text-anchor", "end")
.text("Transcription Production Date");
// layout inscriptions
var chart = svg.append("g").call(inscriptionChart, data)
.attr("class", "inscriptions");
var nodes = chart.selectAll(".node").append("g");
nodes.append('text')
.attr("text-anchor", "middle")
.attr('alignment-baseline', "middle")
.attr("fill", 'black')
.attr("color", "black")
.attr('transform', function(d) {
console.log(d.count, areaScale(d.count))
return 'scale(' + areaScale(d.count) + ')'
})
.text(function(d) { return d.FullTranscription; });
nodes.append('rect').each(function(rect) {
var textElem = d3.select(this.parentElement).select('text');
var textBBox = textElem.node().getBBox();
//the BBOX does not take into account the scale transform
var scale = d3.transform(textElem.attr("transform")).scale[0];
d3.select(this)
.attr('x' , scale * (-textBBox.width/2))
.attr('y' , scale * (-textBBox.height/2))
.attr('width', scale * textBBox.width)
.attr('height', scale * textBBox.height)
});
});
</script>
</body>
</html>
https://d3js.org/d3.v3.min.js