scatterplot.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. Shiny.addCustomMessageHandler("scatterplot_values", function(message) {
  2. var dataset = message[0];
  3. var info = message[1];
  4. // for dropdown
  5. var filters = ["regiao", "uf", "mesorregiao", "microrregiao",
  6. "ds_grupo_agcausadores", "cnae_secao", "ds_natureza_lesao",
  7. "cbo_grande_grupo", "agrupamento_parte_do_corpo",
  8. "ds_tipo_acidente", "ds_tipo_local_acidente", "turno"];
  9. var current_grouping = "regiao";
  10. var margin = {top: 20, right: 50, bottom: 20, left: 50},
  11. width = (window.innerWidth * 0.8) - margin.right - margin.left,
  12. height = (window.innerHeight * 0.95) - margin.top - margin.bottom;
  13. // Create the scatterplot canvas
  14. var scatterplot = d3.select("#scatterplot_area")
  15. .append("svg")
  16. .attr("width", width + margin.left + margin.right)
  17. .attr("height", height + margin.top + margin.bottom)
  18. .append("g")
  19. .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  20. var xScale = d3.scaleLinear()
  21. .domain(d3.extent(dataset, function(d) { return d[0]; }))
  22. .range([0, width]);
  23. var yScale = d3.scaleLinear()
  24. .domain(d3.extent(dataset, function(d) { return d[1]; }))
  25. .range([height, 0]);
  26. /*var colorScale = d3.scaleSequential()
  27. .domain(info[current_grouping].filter(onlyUnique))
  28. .interpolator(d3.interpolateRainbow);*/
  29. var colorScale = d3.scaleOrdinal()
  30. .domain(info[current_grouping].filter(onlyUnique))
  31. .range(d3.range(info[current_grouping].filter(onlyUnique).length)
  32. .map(d3.scaleSequential()
  33. .domain([0, info[current_grouping].filter(onlyUnique).length])
  34. .interpolator(d3.interpolateRainbow)));
  35. var saved_selections = [];
  36. var brush = d3.polybrush()
  37. //Polybrush goes against convention and ignores the previous translation?
  38. .x(d3.scaleLinear().range([-margin.left, width]))
  39. .y(d3.scaleLinear().range([height, -margin.top]))
  40. .on("start", function() {
  41. scatterplot.selectAll(".selected").classed("selected", false);
  42. tooltip.style("visibility", "hidden");
  43. })
  44. .on("brush", highlightBrushedPoints)
  45. .on("end", displayTable);
  46. scatterplot.append("g")
  47. .attr("class", "brush")
  48. .call(brush);
  49. // functions
  50. function clearTableRows() {
  51. hideTableColNames();
  52. d3.selectAll(".row_data").remove();
  53. }
  54. function hideTableColNames() {
  55. d3.select("table").style("visibility", "hidden");
  56. }
  57. function showTableColNames() {
  58. d3.select("table").style("visibility", "visible");
  59. }
  60. function highlightBrushedPoints() {
  61. scatterplot.selectAll(".point").classed("selected", function(d) {
  62. if (brush.isWithinExtent(xScale(d[0]), yScale(d[1]))) {
  63. return true;
  64. } else {
  65. return false;
  66. }
  67. });
  68. }
  69. function displayTable() {
  70. // Save and unsave selections
  71. // Still don get why this only works with body
  72. d3.select("body").on("keydown", function() {
  73. var key = d3.event.key;
  74. switch(key) {
  75. case "s":
  76. save_selection();
  77. break;
  78. case "c":
  79. unsave_selection();
  80. break;
  81. default:
  82. break;
  83. }
  84. });
  85. }
  86. var points = scatterplot.append("g").attr("id", "points");
  87. // Criar círculos
  88. points.selectAll("circle")
  89. .data(dataset)
  90. .enter()
  91. .append("circle")
  92. .attr("class", "point")
  93. .attr("id", function(d, i) {
  94. return i;
  95. })
  96. .attr("r", 3)
  97. .attr("cx", function(d) {
  98. return xScale(d[0]);
  99. })
  100. .attr("cy", function(d) {
  101. return yScale(d[1]);
  102. })
  103. .style("fill", function(d, i) {
  104. return colorScale(info[current_grouping][i]);
  105. })
  106. .on("mouseover", function(d) {
  107. var id = d3.select(this).attr('id');
  108. if(d3.select(this).attr('class') == "point saved") {
  109. t_text = "";
  110. d3.selectAll(".saved").each(function() {
  111. id = d3.select(this).attr('id');
  112. t_text += info.municipio[id] + ", " + info.uf[id] + "<br/>";
  113. });
  114. } else {
  115. t_text = info.municipio[id] + ", " + info.uf[id];
  116. }
  117. tooltip.html(t_text);
  118. return tooltip.style("visibility", "visible");
  119. })
  120. .on("mouseout", function(d) {
  121. return tooltip.style("visibility", "hidden");
  122. })
  123. .on("mousemove", function() {
  124. return tooltip.style("top", (d3.event.pageY-10) + "px").style("left", (d3.event.pageX+10) + "px");
  125. });
  126. // Save a selection
  127. function save_selection() {
  128. s = d3.selectAll(".point.selected");
  129. s.classed("saved", true);
  130. saved_selections.push(s);
  131. // highlight on map
  132. s.each(function() {
  133. id = d3.select(this).attr('id');
  134. var town = info.municipio[id].replace(/[\s']/g,'');
  135. var state = info.uf[id].replace(/\s/g,'');
  136. d3.select("."+town+"."+state)
  137. .style("stroke", "red")
  138. .style("stroke-width", 3);
  139. });
  140. }
  141. // this might be used in the future
  142. /*function unsave_selection(i) {
  143. s = saved_selections.splice(i, 1);
  144. s.classed("saved", false);
  145. }*/
  146. // temporary
  147. function unsave_selection() {
  148. saved_selections = [];
  149. var s = d3.selectAll(".point.saved")
  150. .classed("saved", false);
  151. // Remove highligh on map
  152. s.each(function() {
  153. id = d3.select(this).attr('id');
  154. var town = info.municipio[id].replace(/[\s']/g,'');
  155. var state = info.uf[id].replace(/\s/g,'');
  156. d3.select("."+town+"."+state).style("stroke", "black")
  157. .style("stroke-width", 0.5);
  158. });
  159. }
  160. // Update circle colors based on grouping
  161. function updateColors() {
  162. points.selectAll("circle")
  163. .style("fill", function(d,i) {
  164. return colorScale(info[current_grouping][i]);
  165. });
  166. }
  167. // Select or deselect a group colouring
  168. function toggleGroupColor() {
  169. var selectValue = d3.select('select').property('value');
  170. points.selectAll("circle")
  171. .filter(function(d, i) {
  172. return info[current_grouping][i] == selectValue;
  173. })
  174. .style("fill", function(d, i) {
  175. if(d3.select(this).style('fill') == "black") {
  176. return colorScale(selectValue);
  177. } else {
  178. return "black";
  179. }
  180. });
  181. }
  182. function toggleAllColors() {
  183. cb = d3.select(this);
  184. if(cb.property("checked")) {
  185. d3.selectAll('.checkbox').property('checked', true);
  186. points.selectAll("circle")
  187. .style("fill", function(d, i) {
  188. return colorScale(info[current_grouping][i]);
  189. });
  190. } else {
  191. d3.selectAll('.checkbox').property('checked', false);
  192. points.selectAll("circle")
  193. .style("fill", "black");
  194. }
  195. }
  196. // Create a dropdown menu
  197. var select = d3.select("#sct_dropdown_area")
  198. .append('select')
  199. .attr('class', 'filters_select')
  200. .on('change', onchange);
  201. var options = select
  202. .selectAll('option')
  203. .data(filters)
  204. .enter()
  205. .append('option')
  206. .text(function (d) { return d; });
  207. function onchange() {
  208. var selectValue = d3.select('.filters_select')
  209. .property('value');
  210. for(var i = 0; i < filters.length; i++) {
  211. if(selectValue == filters[i]) {
  212. current_grouping = selectValue;
  213. colorScale.domain(info[current_grouping].filter(onlyUnique))
  214. .range(d3.range(info[current_grouping].filter(onlyUnique).length)
  215. .map(d3.scaleSequential()
  216. .domain([0, info[current_grouping].filter(onlyUnique).length])
  217. .interpolator(d3.interpolateRainbow)));
  218. }
  219. }
  220. updateColors();
  221. create_categories_menu();
  222. };
  223. // Create a menu to select grouping categories
  224. function create_categories_menu() {
  225. var categories = info[current_grouping].filter(onlyUnique);
  226. categories.sort();
  227. d3.select('.categories_select').remove();
  228. var select = d3.select("#sct_checkbox_area")
  229. .append('div')
  230. .attr('class', 'categories_select')
  231. .append('select')
  232. .on('change', 0);//on change does nothing, except enable to click on options
  233. var options = select
  234. .selectAll('option')
  235. .data(categories)
  236. .enter()
  237. .append('option').attr("class", "non-picked")
  238. .text(function (d) { return d; })
  239. .on("click", function(d){
  240. if(d3.select(this).attr("class") == "picked") {
  241. d3.select(this).attr("class", "non-picked");
  242. toggleGroupColor();// Allows recolouring the points without selection of other categorie.
  243. } else {
  244. d3.select(this).attr("class", "picked");
  245. toggleGroupColor();
  246. }
  247. });
  248. }
  249. // Create a toggle all checkbox
  250. var all_box = d3.select("#sct_checkboxall_area")
  251. .append("div")
  252. .attr("class", "checkbox");
  253. all_box.append("input")
  254. .attr("type", "checkbox")
  255. .attr("checked", "true")
  256. .attr("id", "cb_all")
  257. .on("change", toggleAllColors);
  258. all_box.append("label")
  259. .attr("for", "cb_all")
  260. .text("tudo");
  261. create_categories_menu();
  262. // filter function to get only unique values in array
  263. function onlyUnique(value, index, self) {
  264. return self.indexOf(value) === index;
  265. }
  266. // tooltip code
  267. var tooltip = d3.select("body")
  268. .append("div")
  269. .style("position", "absolute")
  270. .style("z-index", "10")
  271. .style("visibility", "hidden")
  272. .style("opacity", 1)
  273. .style("color", "white")
  274. .style("padding", "8px")
  275. .style("background-color", "rgba(0, 0, 0, 0.75)")
  276. .style("border-radius", "6px")
  277. .style("font", "12px sans-serif")
  278. .text("tooltip");
  279. var t_text = "";
  280. // MAP code
  281. var projection = d3.geoEquirectangular();
  282. //.translate([width, height/3])
  283. //.scale(1000);
  284. var path = d3.geoPath()
  285. .projection(projection);
  286. var static_map = d3.select("#map_area")
  287. .append("svg")
  288. .attr("width", width)
  289. .attr("height", height);
  290. var zooming = function(o) {
  291. var offset = [d3.event.transform.x, d3.event.transform.y];
  292. var newScale = d3.event.transform.k * 2000;
  293. projection.translate(offset)
  294. .scale(newScale);
  295. static_map.selectAll("path")
  296. .style("stroke", "black")
  297. .style("stroke-width", 0.5)
  298. .attr("d", path);
  299. // highlight again after zoom
  300. var s = d3.selectAll(".point.saved");
  301. s.each(function() {
  302. id = d3.select(this).attr('id');
  303. var town = info.municipio[id].replace(/[\s']/g,'');
  304. var state = info.uf[id].replace(/\s/g,'');
  305. d3.select("."+town+"."+state)
  306. .style("stroke", "red")
  307. .style("stroke-width", 3);
  308. });
  309. };
  310. var zoom = d3.zoom()
  311. .on("zoom", zooming);
  312. map = static_map.append("g")
  313. .attr("id", "towns")
  314. .call(zoom)
  315. .call(zoom.transform, d3.zoomIdentity
  316. .translate(width, height/3)
  317. .scale(0.25));
  318. d3.json("municipio.json").then(function(json) {
  319. map.selectAll("path")
  320. .data(json.features)
  321. .enter()
  322. .append("path")
  323. .attr("d", path)
  324. .attr("class", function(d) {
  325. return d.properties.UF.replace(/\s/g,'') + " " + d.properties.NOME.replace(/[\s']/g,'');
  326. })
  327. .style("stroke", "black")
  328. .style("stroke-width", 0.5)
  329. .style("fill", function(d) {
  330. switch(d.properties.REGIAO) {
  331. case "Centro-Oeste":
  332. return "#6e40aa";
  333. case "Nordeste":
  334. return "#fe4b83";
  335. case "Norte":
  336. return "#e2b72f";
  337. case "Sudeste":
  338. return "#52f667";
  339. case "Sul":
  340. return "#23abd8";
  341. default:
  342. return "#ccc";
  343. }
  344. })
  345. .on("mouseover", function(d) {
  346. tooltip.html(d.properties.NOME + " - " + d.properties.UF);
  347. return tooltip.style("visibility", "visible").style("opacity", 1);
  348. })
  349. .on("mouseout", function(d){
  350. return tooltip.style("visibility", "hidden").style("opacity", 1);
  351. }).on("mousemove", function() {
  352. return tooltip.style("top",(d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");
  353. });
  354. });
  355. });