Skip to content

Instantly share code, notes, and snippets.

@russellsamora
Last active May 2, 2017 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save russellsamora/5dfe0e5ad8bff4556a2167d885a44ec7 to your computer and use it in GitHub Desktop.
Save russellsamora/5dfe0e5ad8bff4556a2167d885a44ec7 to your computer and use it in GitHub Desktop.
Weighted pivot scatter plot v2
license: mit
height: 500
border: no
*{box-sizing:border-box}body{color:#333;font-family:Helvetica,Arial,sans-serif}.graphic__hed{text-align:center;color:#333}.chart{max-width:40rem;margin:0 auto;text-align:center}.slider{max-width:20rem;margin:1rem auto;position:relative;padding-top:16.5px}.slider input{display:block;width:100%}.slider:before{content:'Quality';text-transform:uppercase;font-size:11px;letter-spacing:.05em;color:#888;display:inline-block;position:absolute;top:0;left:0}.slider:after{content:'Quantity';text-transform:uppercase;font-size:11px;letter-spacing:.05em;color:#888;display:inline-block;position:absolute;top:0;right:0}.g-axis line,.g-axis path{stroke:#ccc}.g-axis text{fill:#888}.g-axis .axis__label{text-transform:uppercase;font-size:11px;letter-spacing:.05em;fill:#888}.item{fill-opacity:.75}
"use strict";function weightData(t){var a=t.x,e=t.y;return dummyData.map(function(t){return _extends({},t,{score:t.x*a+t.y*e})}).sort(function(t,a){return d3.descending(t.score,a.score)}).map(function(t,a){return _extends({},t,{rank:a})}).reverse()}function resize(){var t=.8*Math.min(el.node().offsetWidth,window.innerHeight);chart.width(t).height(t),el.call(chart)}function scatterplot(){function t(t,a){return"translate("+t+", "+a+")"}function a(t){var a=t.container,e=t.data,n=a.selectAll("svg").data([e]),r=n.enter().append("svg"),i=r.append("g");i.append("g").attr("class","g-plot");var c=i.append("g").attr("class","g-axis"),s=c.append("g").attr("class","axis axis--x"),l=c.append("g").attr("class","axis axis--y");s.append("text").attr("class","axis__label").attr("text-anchor","start").text("Quantity"),l.append("text").attr("class","axis__label").attr("text-anchor","start").text("Quality")}function e(t){t.container,t.data}function n(t){var a=t.data,e=g*p/100,n=x*m/100,r=Math.floor(1.5*FONT_SIZE);l.domain([0,MAX_VAL]).range([0,e]),o.domain([0,MAX_VAL]).range([n,0]),d.domain([0,a.length]).range([r,2]),u.domain(a.map(function(t){return t.rank})).range(COLORS)}function r(a){var e=a.container,n=(a.data,e.select("svg"));n.attr("width",f).attr("height",h);var r=n.select("g"),i=x-x*m/100;r.attr("transform",t(1.5*s,s+i));var c=r.select(".g-plot"),g=c.selectAll(".item").data(function(t){return t},function(t){return t.index});g.enter().append("circle").attr("class","item").merge(g).attr("x",0).attr("y",0).attr("r",function(t){return d(t.rank)}).style("fill",function(t){return u(t.rank)}).style("stroke",function(t){return d3.color(u(t.rank)).darker(.7)}).attr("transform",function(a){return t(l(a.x),o(a.y))})}function i(a){var e=a.container,n=(a.data,e.select(".g-axis")),r=d3.axisLeft(o),i=d3.axisBottom(l);r.ticks(Math.max(0,Math.floor(m/10))),i.ticks(Math.max(0,Math.floor(p/10)));var c=n.select(".axis--x"),d=x*m/100,u=Math.ceil(s/2);c.attr("transform",t(0,u+d)).call(i);var f=n.select(".axis--y");f.attr("transform",t(-u,0)).call(r),c.select(".axis__label").attr("y",s-1),f.select(".axis__label").attr("x",-d).attr("y",-s+FONT_SIZE).attr("transform","rotate(-90)")}function c(t){var c=t.datum();a({container:t,data:c}),e({container:t,data:c}),n({container:t,data:c}),r({container:t,data:c}),i({container:t,data:c})}var s=3*FONT_SIZE,l=d3.scaleLinear(),o=d3.scaleLinear(),d=d3.scaleSqrt(),u=d3.scaleQuantile(),f=0,h=0,g=0,x=0,p=50,m=50;return c.width=function(){return arguments.length?(f=arguments.length<=0?void 0:arguments[0],g=f-2.5*s,c):f},c.height=function(){return arguments.length?(h=arguments.length<=0?void 0:arguments[0],x=h-2.5*s,c):h},c.weight=function(t){var a=t.x,e=t.y;return p=a,m=e,c},c}function handleInput(){var t=+this.value,a=t,e=100-t,n=weightData({x:a,y:e});chart.weight({x:a,y:e}),el.datum(n),el.call(chart)}function init(){el.datum(weightData({x:50,y:50})),el.call(chart),resize(),window.addEventListener("resize",resize),graphic.select(".slider input").on("input",handleInput)}var _extends=Object.assign||function(t){for(var a=1;a<arguments.length;a++){var e=arguments[a];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])}return t},graphic=d3.select(".graphic--2"),COLORS=["#ff3814","#fe5c34","#fc764f","#f88d69","#f2a385","#e8b8a0","#dbcdbd"],FONT_SIZE=11,MAX_VAL=10,dummyData=d3.range(0,50).map(function(t){return{index:t,x:.5+Math.random()*(MAX_VAL-1),y:.5+Math.random()*(MAX_VAL-1)}}),chart=scatterplot(),el=graphic.select(".chart");init();
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNjcmlwdC5qcyJdLCJuYW1lcyI6WyJ3ZWlnaHREYXRhIiwiX3JlZiIsIngiLCJ5IiwiZHVtbXlEYXRhIiwibWFwIiwiZCIsIl9leHRlbmRzIiwic2NvcmUiLCJjaGFydCIsInNjYXR0ZXJwbG90Iiwic29ydCIsImEiLCJiIiwiZDMiLCJkZXNjZW5kaW5nIiwicmFuayIsImkiLCJyZXZlcnNlIiwicmVzaXplIiwiTWF0aCIsIm1pbiIsImVsIiwibm9kZSIsIm9mZnNldFdpZHRoIiwid2luZG93IiwiaW5uZXJIZWlnaHQiLCJ3aWR0aCIsInNjYWxlUiIsInNjYWxlU3FydCIsInNjYWxlUXVhbnRpbGUiLCJoZWlnaHQiLCJfcmVmMiIsImNvbnRhaW5lciIsImRhdGEiLCJjaGFydFdpZHRoIiwic2VsZWN0QWxsIiwiY2hhcnRIZWlnaHQiLCJzdmciLCJlbnRlciIsImFwcGVuZCIsIndlaWdodFgiLCJzdmdFbnRlciIsImdFbnRlciIsImF0dHIiLCJheGlzIiwidGV4dCIsIl9yZWYzIiwidXBkYXRlU2NhbGVzIiwiX3JlZjQiLCJyYW5nZVkiLCJ3ZWlnaHRZIiwiRk9OVF9TSVpFIiwic2NhbGVYIiwiZG9tYWluIiwiTUFYX1ZBTCIsInJhbmdlIiwiZXhpdCIsInJhbmdlWCIsInNjYWxlWSIsImxlbmd0aCIsInNjYWxlQyIsIkNPTE9SUyIsIm1heFIiLCJzZWxlY3QiLCJnIiwidXBkYXRlRG9tIiwidHJhbnNsYXRlIiwibWFyZ2luIiwib2Zmc2V0IiwicGxvdCIsIml0ZW0iLCJpbmRleCIsInN0eWxlIiwiY29sb3IiLCJkYXJrZXIiLCJ1cGRhdGVBeGlzIiwiX3JlZjYiLCJheGlzTGVmdCIsImF4aXNCb3R0b20iLCJmbG9vciIsInRpY2tzIiwibWF4IiwiYnVmZmVyIiwiY2VpbCIsImNhbGwiLCJkYXR1bSIsInNjYWxlTGluZWFyIiwic3oiLCJhcmd1bWVudHMiLCJ3ZWlnaHQiLCJfcmVmNyIsImhhbmRsZUlucHV0IiwidmFsIiwidGhpcyIsInZhbHVlIiwid2Vp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RUFBQUEsSUFUbEJtQixHQUFBZ0UsTUFBTzdFLEdBQ1BhLEdBQUErRCxLQUFBNUUsT0FHQSxRQUFNb0YsUUFDTnZFLEdBQUFnRSxNQUFVTyxZQUFWM0YsRUFBQSxHQUFBQyxFQUFBLE1BQ0FtQixHQUFBK0QsS0FBVTVFLE9BQ1ZVLFNBV0FNLE9BQU93RSxpQkFBaUIsU0FBVTlFLFFBVGxDVixRQUFNaUYsT0FBU3hGLGlCQUFmZ0csR0FBQSxRQUFBTiw0TEFuTUtPLFFBQVVyRixHQUFHa0QsT0FBTyxlQUVwQkYsUUFBVSxVQUFXLFVBQVcsVUFBVyxVQUFXLFVBQVcsVUFBVyxXQUM1RVYsVUFBWSxHQUhaK0MsUUFBVXJGLEdBS1ZWLFVBQVlVLEdBQUcwQyxNQUFNLEVBQUcsSUFBSW5ELElBQUksU0FBQUMsR0FBQSxPQUh0Q2tFLE1BQU1WLEVBQ041RCxFQUFNa0QsR0FBQUEsS0FBQUEsVUFBTkcsUUFBQSxHQUNBcEQsRUFBTW9ELEdBQUFBLEtBQVU2QyxVQUFoQjdDLFFBQUEsTUFFQ2lCLE1BRDJDOUQsY0FFeENZLEdBQU1GLFFBQUtnRixPQUFMLFNBK0xUQyIsImZpbGUiOiJzY3JpcHQuanMiLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBncmFwaGljID0gZDMuc2VsZWN0KCcuZ3JhcGhpYy0tMicpXG5cbmNvbnN0IENPTE9SUyA9IFsnI2ZmMzgxNCcsICcjZmU1YzM0JywgJyNmYzc2NGYnLCAnI2Y4OGQ2OScsICcjZjJhMzg1JywgJyNlOGI4YTAnLCAnI2RiY2RiZCddXG5jb25zdCBGT05UX1NJWkUgPSAxMVxuY29uc3QgTUFYX1ZBTCA9IDEwXG5jb25zdCBkdW1teURhdGEgPSBkMy5yYW5nZSgwLCA1MCkubWFwKGQgPT4gKHtcblx0aW5kZXg6IGQsXG5cdHg6IDAuNSArIE1hdGgucmFuZG9tKCkgKiAoTUFYX1ZBTCAtIDEpLFxuXHR5OiAwLjUgKyBNYXRoLnJhbmRvbSgpICogKE1BWF9WQUwgLSAxKSxcbn0pKVxuXG5jb25zdCBjaGFydCA9IHNjYXR0ZXJwbG90KClcbmNvbnN0IGVsID0gZ3JhcGhpYy5zZWxlY3QoJy5jaGFydCcpXG5cbmZ1bmN0aW9uIHdlaWdodERhdGEoeyB4LCB5IH0pIHtcblx0cmV0dXJuIGR1bW15RGF0YS5tYXAoZCA9PiAoe1xuXHRcdC4uLmQsXG5cdFx0c2NvcmU6IGQueCAqIHggKyBkLnkgKiB5LFxuXHR9KSlcblx0LnNvcnQoKGEsIGIpID0+IGQzLmRlc2NlbmRpbmcoYS5zY29yZSwgYi5zY29yZSkpXG5cdC5tYXAoKGQsIGkpID0+ICh7XG5cdFx0Li4uZCxcblx0XHRyYW5rOiBpLFxuXHR9KSlcblx0LnJldmVyc2UoKVxufVxuXG5mdW5jdGlvbiByZXNpemUoKSB7XG5cdGNvbnN0IHN6ID0gTWF0aC5taW4oZWwubm9kZSgpLm9mZnNldFdpZHRoLCB3aW5kb3cuaW5uZXJIZWlnaHQpICogMC44XG5cdGNoYXJ0LndpZHRoKHN6KS5oZWlnaHQoc3opXG5cdGVsLmNhbGwoY2hhcnQpXG59XG5cbmZ1bmN0aW9uIHNjYXR0ZXJwbG90KCkge1xuXHRjb25zdCBtYXJnaW4gPSBGT05UX1NJWkUgKiAzXG5cdGNvbnN0IHNjYWxlWCA9IGQzLnNjYWxlTGluZWFyKClcblx0Y29uc3Qgc2NhbGVZID0gZDMuc2NhbGVMaW5lYXIoKVxuXHRjb25zdCBzY2FsZVIgPSBkMy5zY2FsZVNxcnQoKVxuXHRjb25zdCBzY2FsZUMgPSBkMy5zY2FsZVF1YW50aWxlKClcblxuXHRsZXQgd2lkdGggPSAwXG5cdGxldCBoZWlnaHQgPSAwXG5cdGxldCBjaGFydFdpZHRoID0gMFxuXHRsZXQgY2hhcnRIZWlnaHQgPSAwXG5cdGxldCB3ZWlnaHRYID0gNTBcblx0bGV0IHdlaWdodFkgPSA1MFxuXG5cdGZ1bmN0aW9uIHRyYW5zbGF0ZSh4LCB5KSB7XG5cdFx0cmV0dXJuIGB0cmFuc2xhdGUoJHt4fSwgJHt5fSlgXG5cdH1cblxuXHRmdW5jdGlvbiBlbnRlcih7IGNvbnRhaW5lciwgZGF0YSB9KSB7XG5cdFx0Y29uc3Qgc3ZnID0gY29udGFpbmVyLnNlbGVjdEFsbCgnc3ZnJykuZGF0YShbZGF0YV0pXG5cdFx0Y29uc3Qgc3ZnRW50ZXIgPSBzdmcuZW50ZXIoKS5hcHBlbmQoJ3N2ZycpXG4gICAgICBcdGNvbnN0IGdFbnRlciA9IHN2Z0VudGVyLmFwcGVuZCgnZycpXG5cdFx0XG5cdFx0Z0VudGVyLmFwcGVuZCgnZycpLmF0dHIoJ2NsYXNzJywgJ2ctcGxvdCcpXG5cblx0XHRjb25zdCBheGlzID0gZ0VudGVyLmFwcGVuZCgnZycpLmF0dHIoJ2NsYXNzJywgJ2ctYXhpcycpXG5cblx0XHRjb25zdCB4ID0gYXhpcy5hcHBlbmQoJ2cnKS5hdHRyKCdjbGFzcycsICdheGlzIGF4aXMtLXgnKVxuXG5cdFx0Y29uc3QgeSA9IGF4aXMuYXBwZW5kKCdnJykuYXR0cignY2xhc3MnLCAnYXhpcyBheGlzLS15JylcblxuXHRcdHguYXBwZW5kKCd0ZXh0JykuYXR0cignY2xhc3MnLCAnYXhpc19fbGFiZWwnKVxuXHRcdFx0LmF0dHIoJ3RleHQtYW5jaG9yJywgJ3N0YXJ0Jylcblx0XHRcdC50ZXh0KCdRdWFudGl0eScpXG5cblx0XHR5LmFwcGVuZCgndGV4dCcpLmF0dHIoJ2NsYXNzJywgJ2F4aXNfX2xhYmVsJylcblx0XHRcdC5hdHRyKCd0ZXh0LWFuY2hvcicsICdzdGFydCcpXG5cdFx0XHQudGV4dCgnUXVhbGl0eScpXHRcblx0fVxuXG5cdGZ1bmN0aW9uIGV4aXQoeyBjb250YWluZXIsIGRhdGEgfSkge1xuXHR9XG5cblx0ZnVuY3Rpb24gdXBkYXRlU2NhbGVzKHsgZGF0YSB9KSB7XG5cdFx0Y29uc3QgcmFuZ2VYID0gY2hhcnRXaWR0aCAqIHdlaWdodFggLyAxMDBcblx0XHRjb25zdCByYW5nZVkgPSBjaGFydEhlaWdodCAqIHdlaWdodFkgLyAxMDBcblx0XHRjb25zdCBtYXhSID0gTWF0aC5mbG9vcihGT05UX1NJWkUgKiAxLjUpXG5cdFx0c2NhbGVYXG5cdFx0XHQuZG9tYWluKFswLCBNQVhfVkFMXSlcblx0XHRcdC5yYW5nZShbMCwgcmFuZ2VYXSlcblxuXHRcdHNjYWxlWVxuXHRcdFx0LmRvbWFpbihbMCwgTUFYX1ZBTF0pXG5cdFx0XHQucmFuZ2UoW3JhbmdlWSwgMF0pXG5cblx0XHRzY2FsZVJcblx0XHRcdC5kb21haW4oWzAsIGRhdGEubGVuZ3RoXSlcblx0XHRcdC5yYW5nZShbbWF4UiwgMl0pXG5cblx0XHRzY2FsZUNcblx0XHRcdC5kb21haW4oZGF0YS5tYXAoZCA9PiBkLnJhbmspKVxuXHRcdFx0LnJhbmdlKENPTE9SUylcblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZURvbSh7IGNvbnRhaW5lciwgZGF0YSB9KSB7XG5cdFx0Y29uc3Qgc3ZnID0gY29udGFpbmVyLnNlbGVjdCgnc3ZnJylcblx0XHRcblx0XHRzdmdcblx0XHRcdC5hdHRyKCd3aWR0aCcsIHdpZHRoKVxuXHRcdFx0LmF0dHIoJ2hlaWdodCcsIGhlaWdodClcblxuXHRcdGNvbnN0IGcgPSBzdmcuc2VsZWN0KCdnJylcblx0XHRcblx0XHRjb25zdCBvZmZzZXQgPSBjaGFydEhlaWdodCAtIChjaGFydEhlaWdodCAqIHdlaWdodFkgLyAxMDApXG5cdFx0Zy5hdHRyKCd0cmFuc2Zvcm0nLCB0cmFuc2xhdGUobWFyZ2luICogMS41LCBtYXJnaW4gKyBvZmZzZXQpKVxuXG5cdFx0Y29uc3QgcGxvdCA9IGcuc2VsZWN0KCcuZy1wbG90JylcblxuXHRcdGNvbnN0IGl0ZW0gPSBwbG90LnNlbGVjdEFsbCgnLml0ZW0nKS5kYXRhKGQgPT4gZCwgZCA9PiBkLmluZGV4KVxuXHRcdFxuXHRcdGl0ZW0uZW50ZXIoKS5hcHBlbmQoJ2NpcmNsZScpXG5cdFx0XHQuYXR0cignY2xhc3MnLCAnaXRlbScpXG5cdFx0Lm1lcmdlKGl0ZW0pXG5cdFx0XHQuYXR0cigneCcsIDApXG5cdFx0XHQuYXR0cigneScsIDApXG5cdFx0XHQuYXR0cigncicsIGQgPT4gc2NhbGVSKGQucmFuaykpXG5cdFx0XHQuc3R5bGUoJ2ZpbGwnLCBkID0+IHNjYWxlQyhkLnJhbmspKVxuXHRcdFx0LnN0eWxlKCdzdHJva2UnLCBkID0+IGQzLmNvbG9yKHNjYWxlQyhkLnJhbmspKS5kYXJrZXIoMC43KSlcblx0XHRcdC5hdHRyKCd0cmFuc2Zvcm0nLCAgZCA9PiB0cmFuc2xhdGUoc2NhbGVYKGQueCksIHNjYWxlWShkLnkpKSlcblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZUF4aXMoeyBjb250YWluZXIsIGRhdGEgfSkge1xuXHRcdGNvbnN0IGF4aXMgPSBjb250YWluZXIuc2VsZWN0KCcuZy1heGlzJylcblxuXHRcdGNvbnN0IGF4aXNMZWZ0ID0gZDMuYXhpc0xlZnQoc2NhbGVZKVxuXHRcdGNvbnN0IGF4aXNCb3R0b20gPSBkMy5heGlzQm90dG9tKHNjYWxlWClcblxuXHRcdGF4aXNMZWZ0LnRpY2tzKE1hdGgubWF4KDAsIE1hdGguZmxvb3Iod2VpZ2h0WSAvIDEwKSkpXG5cdFx0YXhpc0JvdHRvbS50aWNrcyhNYXRoLm1heCgwLCBNYXRoLmZsb29yKHdlaWdodFggLyAxMCkpKVxuXHRcdGNvbnN0IHggPSBheGlzLnNlbGVjdCgnLmF4aXMtLXgnKVxuXHRcdFxuXHRcdGNvbnN0IG9mZnNldCA9IGNoYXJ0SGVpZ2h0ICogd2VpZ2h0WSAvIDEwMFxuXG5cdFx0Y29uc3QgYnVmZmVyID0gTWF0aC5jZWlsKG1hcmdpbiAvIDIpXG5cdFx0eC5hdHRyKCd0cmFuc2Zvcm0nLCB0cmFuc2xhdGUoMCwgYnVmZmVyICsgb2Zmc2V0KSlcblx0XHRcdC5jYWxsKGF4aXNCb3R0b20pXG5cblx0XHRjb25zdCB5ID0gYXhpcy5zZWxlY3QoJy5heGlzLS15JylcblxuXHRcdHkuYXR0cigndHJhbnNmb3JtJywgdHJhbnNsYXRlKC1idWZmZXIsIDApKVxuXHRcdFx0LmNhbGwoYXhpc0xlZnQpXG5cblx0XHR4LnNlbGVjdCgnLmF4aXNfX2xhYmVsJylcblx0XHRcdC5hdHRyKCd5JywgbWFyZ2luIC0gMSlcblxuXHRcdHkuc2VsZWN0KCcuYXhpc19fbGFiZWwnKVxuXHRcdFx0LmF0dHIoJ3gnLCAtb2Zmc2V0KVxuXHRcdFx0LmF0dHIoJ3knLCAtbWFyZ2luICsgRk9OVF9TSVpFKVxuXHRcdFx0LmF0dHIoJ3RyYW5zZm9ybScsIGByb3RhdGUoLTkwKWApXG5cdH1cblxuXHRmdW5jdGlvbiBjaGFydChjb250YWluZXIpIHtcblx0XHRjb25zdCBkYXRhID0gY29udGFpbmVyLmRhdHVtKClcblx0XHRcblx0XHRlbnRlcih7IGNvbnRhaW5lciwgZGF0YSB9KVxuXHRcdGV4aXQoeyBjb250YWluZXIsIGRhdGEgfSlcblx0XHR1cGRhdGVTY2FsZXMoeyBjb250YWluZXIsIGRhdGEgfSlcblx0XHR1cGRhdGVEb20oeyBjb250YWluZXIsIGRhdGEgfSlcblx0XHR1cGRhdGVBeGlzKHsgY29udGFpbmVyLCBkYXRhIH0pXG5cdH1cblxuXHRjaGFydC53aWR0aCA9IGZ1bmN0aW9uKC4uLmFyZ3MpIHtcblx0XHRpZiAoIWFyZ3MubGVuZ3RoKSByZXR1cm4gd2lkdGhcblx0XHR3aWR0aCA9IGFyZ3NbMF1cblx0XHRjaGFydFdpZHRoID0gd2lkdGggLSBtYXJnaW4gKiAyLjVcblx0XHRyZXR1cm4gY2hhcnRcblx0fVxuXG5cdGNoYXJ0LmhlaWdodCA9IGZ1bmN0aW9uKC4uLmFyZ3MpIHtcblx0XHRpZiAoIWFyZ3MubGVuZ3RoKSByZXR1cm4gaGVpZ2h0XG5cdFx0aGVpZ2h0ID0gYXJnc1swXVxuXHRcdGNoYXJ0SGVpZ2h0ID0gaGVpZ2h0IC0gbWFyZ2luICogMi41XG5cdFx0cmV0dXJuIGNoYXJ0XG5cdH1cblxuXHRjaGFydC53ZWlnaHQgPSBmdW5jdGlvbih7IHgsIHkgfSkge1xuXHRcdHdlaWdodFggPSB4XG5cdFx0d2VpZ2h0WSA9IHlcblx0XHRyZXR1cm4gY2hhcnRcblx0fVxuXG5cblxuXHRyZXR1cm4gY2hhcnRcbn1cblxuZnVuY3Rpb24gaGFuZGxlSW5wdXQoKSB7XG5cdGNvbnN0IHZhbCA9ICt0aGlzLnZhbHVlXG5cdGNvbnN0IHggPSB2YWxcblx0Y29uc3QgeSA9IDEwMCAtIHZhbFxuXHRjb25zdCB3ZWlnaHRlZCA9IHdlaWdodERhdGEoeyB4LCB5IH0pXG5cblx0Y2hhcnQud2VpZ2h0KHsgeCwgeSB9KVxuXHRlbC5kYXR1bSh3ZWlnaHRlZClcblx0ZWwuY2FsbChjaGFydClcbn1cblxuZnVuY3Rpb24gaW5pdCgpIHtcblx0ZWwuZGF0dW0od2VpZ2h0RGF0YSh7IHg6IDUwLCB5OiA1MCB9KSlcblx0ZWwuY2FsbChjaGFydClcblx0cmVzaXplKClcblx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHJlc2l6ZSlcblx0Z3JhcGhpYy5zZWxlY3QoJy5zbGlkZXIgaW5wdXQnKS5vbignaW5wdXQnLCBoYW5kbGVJbnB1dClcbn1cblxuaW5pdCgpXG5cbiJdfQ==
<!DOCTYPE html>
<title>weighted pivot scatter plot v2</title>
<link href='dist.css' rel='stylesheet' />
<body>
<div class='graphic graphic--2'>
<div class='chart'></div>
<div class='slider'><input type='range' min='0' max='100' value='50'></div>
</div>
<script src='https://d3js.org/d3.v4.min.js'></script>
<script src='dist.js'></script>
</body>
const graphic = d3.select('.graphic--2')
const COLORS = ['#ff3814', '#fe5c34', '#fc764f', '#f88d69', '#f2a385', '#e8b8a0', '#dbcdbd']
const FONT_SIZE = 11
const MAX_VAL = 10
const dummyData = d3.range(0, 50).map(d => ({
index: d,
x: 0.5 + Math.random() * (MAX_VAL - 1),
y: 0.5 + Math.random() * (MAX_VAL - 1),
}))
const chart = scatterplot()
const el = graphic.select('.chart')
function weightData({ x, y }) {
return dummyData.map(d => ({
...d,
score: d.x * x + d.y * y,
}))
.sort((a, b) => d3.descending(a.score, b.score))
.map((d, i) => ({
...d,
rank: i,
}))
.reverse()
}
function resize() {
const sz = Math.min(el.node().offsetWidth, window.innerHeight) * 0.8
chart.width(sz).height(sz)
el.call(chart)
}
function scatterplot() {
const margin = FONT_SIZE * 3
const scaleX = d3.scaleLinear()
const scaleY = d3.scaleLinear()
const scaleR = d3.scaleSqrt()
const scaleC = d3.scaleQuantile()
let width = 0
let height = 0
let chartWidth = 0
let chartHeight = 0
let weightX = 50
let weightY = 50
function translate(x, y) {
return `translate(${x}, ${y})`
}
function enter({ container, data }) {
const svg = container.selectAll('svg').data([data])
const svgEnter = svg.enter().append('svg')
const gEnter = svgEnter.append('g')
gEnter.append('g').attr('class', 'g-plot')
const axis = gEnter.append('g').attr('class', 'g-axis')
const x = axis.append('g').attr('class', 'axis axis--x')
const y = axis.append('g').attr('class', 'axis axis--y')
x.append('text').attr('class', 'axis__label')
.attr('text-anchor', 'start')
.text('Quantity')
y.append('text').attr('class', 'axis__label')
.attr('text-anchor', 'start')
.text('Quality')
}
function exit({ container, data }) {
}
function updateScales({ data }) {
const rangeX = chartWidth * weightX / 100
const rangeY = chartHeight * weightY / 100
const maxR = Math.floor(FONT_SIZE * 1.5)
scaleX
.domain([0, MAX_VAL])
.range([0, rangeX])
scaleY
.domain([0, MAX_VAL])
.range([rangeY, 0])
scaleR
.domain([0, data.length])
.range([maxR, 2])
scaleC
.domain(data.map(d => d.rank))
.range(COLORS)
}
function updateDom({ container, data }) {
const svg = container.select('svg')
svg
.attr('width', width)
.attr('height', height)
const g = svg.select('g')
const offset = chartHeight - (chartHeight * weightY / 100)
g.attr('transform', translate(margin * 1.5, margin + offset))
const plot = g.select('.g-plot')
const item = plot.selectAll('.item').data(d => d, d => d.index)
item.enter().append('circle')
.attr('class', 'item')
.merge(item)
.attr('x', 0)
.attr('y', 0)
.attr('r', d => scaleR(d.rank))
.style('fill', d => scaleC(d.rank))
.style('stroke', d => d3.color(scaleC(d.rank)).darker(0.7))
.attr('transform', d => translate(scaleX(d.x), scaleY(d.y)))
}
function updateAxis({ container, data }) {
const axis = container.select('.g-axis')
const axisLeft = d3.axisLeft(scaleY)
const axisBottom = d3.axisBottom(scaleX)
axisLeft.ticks(Math.max(0, Math.floor(weightY / 10)))
axisBottom.ticks(Math.max(0, Math.floor(weightX / 10)))
const x = axis.select('.axis--x')
const offset = chartHeight * weightY / 100
const buffer = Math.ceil(margin / 2)
x.attr('transform', translate(0, buffer + offset))
.call(axisBottom)
const y = axis.select('.axis--y')
y.attr('transform', translate(-buffer, 0))
.call(axisLeft)
x.select('.axis__label')
.attr('y', margin - 1)
y.select('.axis__label')
.attr('x', -offset)
.attr('y', -margin + FONT_SIZE)
.attr('transform', `rotate(-90)`)
}
function chart(container) {
const data = container.datum()
enter({ container, data })
exit({ container, data })
updateScales({ container, data })
updateDom({ container, data })
updateAxis({ container, data })
}
chart.width = function(...args) {
if (!args.length) return width
width = args[0]
chartWidth = width - margin * 2.5
return chart
}
chart.height = function(...args) {
if (!args.length) return height
height = args[0]
chartHeight = height - margin * 2.5
return chart
}
chart.weight = function({ x, y }) {
weightX = x
weightY = y
return chart
}
return chart
}
function handleInput() {
const val = +this.value
const x = val
const y = 100 - val
const weighted = weightData({ x, y })
chart.weight({ x, y })
el.datum(weighted)
el.call(chart)
}
function init() {
el.datum(weightData({ x: 50, y: 50 }))
el.call(chart)
resize()
window.addEventListener('resize', resize)
graphic.select('.slider input').on('input', handleInput)
}
init()
$gray = #888
$gray-light = #aaa
$gray-lighter = #ccc
$gray-dark = #333
$sans = Helvetica, Arial, sans-serif
$small-font = 11px
*
box-sizing border-box
body
color $gray-dark
font-family $sans
.graphic__hed
text-align center
color $gray-dark
.chart
max-width 40rem
margin 0 auto
text-align center
.slider
max-width 20rem
margin 1rem auto
position relative
padding-top $small-font * 1.5
input
display block
width 100%
&:before
content 'Quality'
text-transform uppercase
font-size $small-font
letter-spacing 0.05em
color $gray
display inline-block
position absolute
top 0
left 0
&:after
content 'Quantity'
text-transform uppercase
font-size $small-font
letter-spacing 0.05em
color $gray
display inline-block
position absolute
top 0
right 0
.g-axis
line, path
stroke $gray-lighter
text
fill $gray
.g-axis .axis__label
text-transform uppercase
font-size $small-font
letter-spacing 0.05em
fill $gray
.item
fill-opacity 0.75
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment