Skip to content

Instantly share code, notes, and snippets.

@johnpoole
Forked from puzzler10/README.md
Last active February 16, 2021 21:50
Show Gist options
  • Save johnpoole/0d677c77ca797f1947143c1378223197 to your computer and use it in GitHub Desktop.
Save johnpoole/0d677c77ca797f1947143c1378223197 to your computer and use it in GitHub Desktop.
Pipeline GUI

Viz of pipeline batches

id start_time product_type_id nomination_id
1 2021-02-08 07:00:00 1 1
2 2021-02-08 08:06:48 6 6
3 2021-02-08 15:48:20 5 5
4 2021-02-09 06:54:00 3 3
5 2021-02-09 11:00:47 5 5
6 2021-02-10 02:06:27 4 4
7 2021-02-10 06:49:28 3 3
8 2021-02-10 10:56:16 5 5
9 2021-02-11 02:01:55 1 1
10 2021-02-11 06:44:56 5 5
11 2021-02-11 21:50:36 3 3
12 2021-02-12 01:57:24 4 4
13 2021-02-12 06:40:25 6 6
14 2021-02-12 14:13:15 5 5
15 2021-02-13 05:18:54 3 3
16 2021-02-13 10:58:32 5 5
17 2021-02-14 02:04:11 3 3
18 2021-02-14 07:43:49 4 4
19 2021-02-14 12:26:50 5 5
20 2021-02-15 03:32:29 1 1
21 2021-02-15 08:15:30 5 5
22 2021-02-15 15:48:20 3 3
23 2021-02-15 23:21:10 5 5
24 2021-02-16 06:54:00 4 4
25 2021-02-16 10:40:25 3 3
26 2021-02-16 16:20:02 5 5
27 2021-02-17 04:35:53 2 2
28 2021-02-17 10:15:30 5 5
29 2021-02-18 01:21:10 1 1
30 2021-02-18 06:04:11 4 4
31 2021-02-18 09:50:36 3 3
32 2021-02-18 14:33:37 5 5
33 2021-02-19 04:20:02 3 3
34 2021-02-19 09:03:03 4 4
35 2021-02-19 12:49:28 6 6
36 2021-02-19 20:22:18 1 1
37 2021-02-20 01:16:38 5 5
38 2021-02-20 16:22:18 3 3
39 2021-02-20 21:05:19 5 5
40 2021-02-21 12:10:59 4 4
41 2021-02-21 15:57:24 3 3
42 2021-02-21 22:33:37 5 5
43 2021-02-22 13:39:17 3 3
44 2021-02-22 19:18:54 1 1
45 2021-02-22 23:50:36 5 5
46 2021-02-23 14:56:16 3 3
47 2021-02-23 20:35:53 4 4
48 2021-02-24 00:22:18 5 5
49 2021-02-24 15:27:58 3 3
50 2021-02-24 21:07:35 5 5
51 2021-02-25 12:13:15 4 4
52 2021-02-25 15:59:40 3 3
53 2021-02-25 21:39:17 5 5
54 2021-02-26 12:44:56 1 1
55 2021-02-26 17:39:17 5 5
56 2021-02-27 08:44:56 3 3
57 2021-02-27 16:17:46 4 4
58 2021-02-27 20:04:11 5 5
59 2021-02-28 11:09:51 3 3
60 2021-02-28 16:49:28 5 5
61 2021-03-01 07:55:08 6 6
62 2021-03-01 15:27:58 1 1
63 2021-03-01 20:10:59 3 3
64 2021-03-02 00:20:02 4 4
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
.axis { font: 14px sans-serif; }
div.tooltip {
position: absolute;
text-align: center;
width: 200px;
height: 58px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<body>
<!-- load the d3.js library -->
<svg width="2000" height="350"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/queue.v1.min.js"></script>
<script>
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 50, left: 50},
width = 1960 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var batches;
// parse the date / time
var parseTime = d3.timeParse("%Y-%m-%d %H:%M:%S");
var formatTime = d3.timeFormat("%e %B %H:%M");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
let drag = d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended);
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
var svg = d3.select("svg")
svg.append('rect')
.attr('class', 'zoom')
.attr('cursor', 'move')
.attr('fill', 'none')
.attr('pointer-events', 'all')
.attr('width', width)
.attr('height', height)
svg.append("g")
.attr("class", "legendOrdinal")
.attr("transform", "translate(20,20)");
var focus = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Get the data
queue()
.defer(d3.csv, 'batches.csv')
.defer(d3.csv, 'productType.csv')
.await(process);
function process(error, data, ptypes) {
var categories = [];
var categoryObj = {};
ptypes.forEach( p => {
if( !categoryObj[p.name])
categoryObj[p.name] = {};
});
categories = Object.keys(categoryObj)
/* var ordinal = d3.scaleOrdinal()
.domain(categories)
.range(categories.map((val, i) =>
d3.interpolateYlGnBu(i / (categories.length - 1))
));
*/
var ordinal = d3.scaleOrdinal(d3.schemePastel1).domain(categories);
var legendOrdinal = d3.legendColor()
.scale(ordinal);
svg.select(".legendOrdinal")
.call(legendOrdinal);
//d3.csv("data.csv", function(error, data) {
if (error) throw error;
data.forEach( function(d) {
d.date = parseTime(d.start_time);
})
data.forEach( function(d){
ptypes.forEach( function(p){
if( d.product_type_id === p.id)
d.product = p.name
})
})
batches = setEndDates( data );
// Scale the range of the data
x.domain(d3.extent(batches, function(d) { return d.date; }));
y.domain([0, d3.max(batches, function(d) { return 500; })]);
focus.selectAll('rect')
.data(batches)
.enter()
.append('rect')
.attr('r', 10.0)
.attr("rx", 6)
.attr("ry", 6)
.attr('x', function(d) { return x(d.date); })
.attr('y', function(d) { return y(height*3/4); })
.attr('height',20)
.attr('width', function(d) {
return x(d.enddate) - x(d.date);
})
.style("stroke-width", 1) // set the stroke width
.style("stroke", "black")
.style('cursor', 'pointer')
.style('fill', function(d){ return ordinal(d.product);})
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(formatTime(d.date) + "<br/>" + d.product + "<br/>" + Math.round( 88.3*diff_minutes(d.date, d.enddate))+" bbl")
.style("left", (d3.event.pageX-100) + "px")
.style("top", (d3.event.pageY - 88) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});;
focus.selectAll('rect')
.call(drag);
// Add the X Axis
focus.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m-%d")))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
// Add the Y Axis
// focus.append("g")
// .attr("class", "axis")
// .call(d3.axisLeft(y));
}
function dragstarted(d) {
d3.select(this).raise().classed('active', true);
}
function dragged(d) {
d.date = x.invert(d3.event.x);
d.close = y.invert(d3.event.y);
d3.select(this)
.attr('x', x(d.date))
.attr('y', y(height*3/4))
}
function dragended(d) {
d3.select(this).classed('active', false);
batches = setEndDates( batches );
var list = focus.selectAll('rect').sort( function(a, b){
return a.date - b.date;
});
list.attr('x', function(d) {
return x(d.date);
}).attr('width', function(d) {
return x(d.enddate) - x(d.date)
})
}
function setEndDates(data){
var previous =null;
var batches = data.sort( function(a, b){
return a.date - b.date;
});
batches.forEach(function(d, i) {
if( previous )
previous.enddate = d.date;
previous = d;
if( i === batches.length-1)
d.enddate = d.date;
});
return batches;
}
function diff_minutes(dt2, dt1)
{
var diff =(dt2.getTime() - dt1.getTime()) / 1000;
diff /= 60;
return Math.abs(Math.round(diff));
}
</script>
</body>
id name
1 Bow River
2 North Texas and Oklahoma Sweet
3 Oklahoma Common Sweet
4 West Texas & New Mexico Sour
5 West Texas Domestic Sweet
6 West Texas Intermediate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment