Skip to content

vi-enne/cambiSenato18

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 

Repository files navigation

<title>Cambi gruppo Senato XVIII</title> <style>

.node { stroke-width: 1.5px; }

</style> <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
Visualizzazione dei cambi di gruppo parlamentare al Senato durante la XVIII legislatura
2018-3-23
Lento
Medio
Veloce
Autore: V. Nicoletta - Dati: Openpolis (licenza CC-BY-NC-SA 4.0) - Cambi Camera dei Deputati clicca qui
Basato sulla visualizzazione A Day in the Life of Americans di Nathan Yau, e sul codice di Mohamed Khanafer (licenza MIT)
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> <script> var USER_SPEED = "slow";

var width = 900, height = 750, padding = 1, maxRadius = 3; // color = d3.scale.category10();

var sched_objs = [], curr_time = 0;

var act_codes = [ {"index": "9", "short": "Lega", "desc": "Lega"}, {"index": "0", "short": "Fratelli d'Italia", "desc": "FdI"}, {"index": "5", "short": "Autonomie", "desc": "Aut"}, {"index": "11", "short": "CAL-PC-Idv", "desc": "CAL-PC-Idv"}, {"index": "1", "short": "Misto", "desc": "Misto"}, {"index": "6", "short": "PD", "desc": "PD"}, {"index": "4", "short": "IPF-CD", "desc": "IpF"}, {"index": "3", "short": "M5S", "desc": "M5S"}, {"index": "2", "short": "Italia Viva-PSI", "desc": "IV"}, {"index": "7", "short": "Eu-MAIE-CD", "desc": "EU-MAIE-CD"}, {"index": "8", "short": "Forza Italia", "desc": "FI"}, {"index": "10", "short": "Fuori Parlamento", "desc": "Out"}, ];

var speeds = { "slow": 1000, "medium": 200, "fast": 20 };

var time_notes = [ { "start_time": 1, "stop_time": 60, "note": "Inizio XVIII legislatura della Repubblica Italiana" }, { "start_time": 540, "stop_time": 640, "note": "Nasce Italia Viva-PSI" }, { "start_time": 1040, "stop_time": 1060, "note": "Breve formazione del gruppo Eu-MAIE-CD" }, { "start_time": 1064, "stop_time": 1164, "note": "Espulsione senatori M5S che non hanno votato la fiducia al governo Draghi" }, { "start_time": 1406, "stop_time": 1466, "note": "Si forma per un giorno il gruppo CAL-Idv" }, { "start_time": 1496, "stop_time": 1540, "note": "Nasce CAL-PC-Idv" }, { "start_time": 1555, "stop_time": 1650, "note": "Nasce Insieme Per il Futuro-CD" }, { "start_time": 1665, "stop_time": 2029, "note": "Fine XVIII legislatura della Repubblica Italiana" }, ]; var notes_index = 0;

// Activity to put in center of circle arrangement var center_act = "Out", center_pt = { "x": 380, "y": 365 };

// Coordinates for activities var foci = {}; act_codes.forEach(function(code, i) { if (code.desc == center_act) { foci[code.index] = center_pt; } else { var theta = 2 * Math.PI / (act_codes.length-1); foci[code.index] = {x: 250 * Math.cos(i * theta)+380, y: 250 * Math.sin(i * theta)+365 }; } });

// Start the SVG var svg = d3.select("#chart").append("svg") .attr("width", width) .attr("height", height);

//Data loading
d3.csv('https://gist.githubusercontent.com/vi-enne/d2132a60b8580bf15dab94f787e48785/raw/8611bf63894051d60076199df61c90d1cd518524/senato18', function(data) { data.forEach(function(d) { var day_array = d.day.split(","); var activities = []; for (var i=0; i < day_array.length; i++) { // Duration if (i % 2 == 1) { activities.push({'act': day_array[i-1], 'duration': +day_array[i]}); } } sched_objs.push(activities); });

// Used for percentages by time
var act_counts = { "0": 0, "1": 0, "2": 0, "3": 0, "4": 0, "5": 0, "6": 0, "7": 0, "8": 0, "9": 0, "10": 0, "11": 0, "12": 0, "13": 0, "14": 0, "15": 0, "16": 0 };

// A node for each person's schedule
var nodes = sched_objs.map(function(o,i) {
	var act = o[0].act;
	act_counts[act] += 1;
	var init_x = foci[act].x + Math.random();
	var init_y = foci[act].y + Math.random();
	return {
		act: act,
		radius: 3,
		x: init_x,
		y: init_y,
		color: color(act),
		moves: 0,
		next_move_time: o[0].duration,
		sched: o,
	}
});

var force = d3.layout.force()
	.nodes(nodes)
	.size([width, height])
	// .links([])
	.gravity(0)
	.charge(0)
	.friction(.9)
	.on("tick", tick)
	.start();

var circle = svg.selectAll("circle")
	.data(nodes)
  .enter().append("circle")
	.attr("r", function(d) { return d.radius; })
	.style("fill", function(d) { return d.color; });
	// .call(force.drag);

// Activity labels
var label = svg.selectAll("text")
	.data(act_codes)
  .enter().append("text")
	.attr("class", "actlabel")
	.attr("x", function(d, i) {
		if (d.desc == center_act) {
			return center_pt.x;
		} else {
			var theta = 2 * Math.PI / (act_codes.length-1);
			return 340 * Math.cos(i * theta)+380;
		}
		
	})
	.attr("y", function(d, i) {
		if (d.desc == center_act) {
			return center_pt.y;
		} else {
			var theta = 2 * Math.PI / (act_codes.length-1);
			return 340 * Math.sin(i * theta)+365;
		}
		
	});

label.append("tspan")
	.attr("x", function() { return d3.select(this.parentNode).attr("x"); })
	// .attr("dy", "1.3em")
	.attr("text-anchor", "middle")
	.text(function(d) {
		return d.short;
	});
label.append("tspan")
	.attr("dy", "1.3em")
	.attr("x", function() { return d3.select(this.parentNode).attr("x"); })
	.attr("text-anchor", "middle")
	.attr("class", "actpct")
	.text(function(d) {
		return act_counts[d.index];
	});

// Update nodes based on activity and duration
function timer() {
	d3.range(nodes.length).map(function(i) {
		var curr_node = nodes[i],
			curr_moves = curr_node.moves; 

		// Time to go to next activity
		if (curr_node.next_move_time == curr_time) {
			if (curr_node.moves == curr_node.sched.length-1) {
				curr_moves = 0;
			} else {
				curr_moves += 1;
			}
		
			// Subtract from current activity count
			act_counts[curr_node.act] -= 1;
		
			// Move on to next activity
			curr_node.act = curr_node.sched[ curr_moves ].act;
		
			// Add to new activity count
			act_counts[curr_node.act] += 1;
		
			curr_node.moves = curr_moves;
			curr_node.cx = foci[curr_node.act].x;
			curr_node.cy = foci[curr_node.act].y;
		
			nodes[i].next_move_time += nodes[i].sched[ curr_node.moves ].duration;
		}
	});

	force.resume();
	curr_time += 1;

	// Update percentages
	label.selectAll("tspan.actpct")
		.text(function(d) {
			// return readablePercent(act_counts[d.index]);
			return act_counts[d.index];
		});

	// Update time
	var end_time = 2030
	var true_time = curr_time % end_time;
	d3.select("#current_time").text(daysToDate(true_time));
	
	// Update notes
	// var true_time = curr_time % 1440;
	if (true_time == time_notes[notes_index].start_time) {
		d3.select("#note")
			.style("top", "0px")
		  .transition()
			.duration(600)
			.style("top", "20px")
			.style("color", "#000000")
			.text(time_notes[notes_index].note);
	}

	// Make note disappear at the end.
	else if (true_time == time_notes[notes_index].stop_time) {
		
		d3.select("#note").transition()
			.duration(1000)
			.style("top", "300px")
			.style("color", "#ffffff");
			
		notes_index += 1;
		if (notes_index == time_notes.length) {
			notes_index = 0;
		}
	}

	setTimeout(timer, speeds[USER_SPEED]);
}
setTimeout(timer, speeds[USER_SPEED]);

function tick(e) {
  var k = 0.04 * e.alpha;

  // Push nodes toward their designated focus.
  nodes.forEach(function(o, i) {
	var curr_act = o.act;
	
	// Make sleep more sluggish moving.
	if (curr_act == "0") {
		var damper = 0.6;
	} else {
		var damper = 1;
	}
	o.color = color(curr_act);
    o.y += (foci[curr_act].y - o.y) * k * damper;
    o.x += (foci[curr_act].x - o.x) * k * damper;
  });

  circle
  	  .each(collide(.5))
  	  .style("fill", function(d) { return d.color; })
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });
}

// Resolve collisions between nodes.
function collide(alpha) {
  var quadtree = d3.geom.quadtree(nodes);
  return function(d) {
    var r = d.radius + maxRadius + padding,
        nx1 = d.x - r,
        nx2 = d.x + r,
        ny1 = d.y - r,
        ny2 = d.y + r;
    quadtree.visit(function(quad, x1, y1, x2, y2) {
      if (quad.point && (quad.point !== d)) {
        var x = d.x - quad.point.x,
            y = d.y - quad.point.y,
            l = Math.sqrt(x * x + y * y),
            r = d.radius + quad.point.radius + (d.act !== quad.point.act) * padding;
        if (l < r) {
          l = (l - r) / l * alpha;
          d.x -= x *= l;
          d.y -= y *= l;
          quad.point.x += x;
          quad.point.y += y;
        }
      }
      return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
    });
  };
}

// Speed toggle
d3.selectAll(".togglebutton")
  .on("click", function() {
    if (d3.select(this).attr("data-val") == "slow") {
        d3.select(".slow").classed("current", true);
		d3.select(".medium").classed("current", false);
        d3.select(".fast").classed("current", false);
    } else if (d3.select(this).attr("data-val") == "medium") {
        d3.select(".slow").classed("current", false);
		d3.select(".medium").classed("current", true);
        d3.select(".fast").classed("current", false);
    } 
	else {
        d3.select(".slow").classed("current", false);
		d3.select(".medium").classed("current", false);
		d3.select(".fast").classed("current", true);
    }
	
	USER_SPEED = d3.select(this).attr("data-val");
});

}); // @end d3.tsv

function color(activity) {

var colorByActivity = {
	"0": "#1a237e",
	"1": "#78909c",
	"2": "#ab47bc",
	"3": "#ffeb3b",
	"4": "#1b5e20",
	"5": "#bcaaa4",
	"6": "#f44336",
	"7": "#80deea",
	"8": "#0d47a1",
	"9": "#303f9f",
	"10": "#ffffff",
	"11": "#ff5722",
}

return colorByActivity[activity];

}

// Output readable percent based on count. function readablePercent(n) { var pct = 100 * n / 1000; if (pct < 1 && pct > 0) { pct = "<1%"; } else { pct = Math.round(pct) + "%"; }

return pct;

}

// Day. Data is days from 2018-03-23. function daysToDate(m) { m = Math.min(m,1665); var d = new Date("2018-03-23"); d.setDate(d.getDate()+m); var y = d.getFullYear(); var da = d.getDate(); var mo = d.getMonth() + 1; return (y+'-'+mo+'-'+da); }

</script>

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published