鸡尾酒配方数据可视化

时间:2016-04-03 12:48:14

标签: javascript d3.js visualization data-visualization

一般对数据可视化感兴趣并且越来越熟悉Javascripts D3库,我发现了不同鸡尾酒配方的可视化:Information is beautiful - Cocktails

我想知道这是怎么做到的?有没有机会用D3js完成这项工作,或者像这样基本上是一个高度手动的任务?

为了可视化鸡尾酒中成分的相对数量,可以使用堆叠布局。然而,我不知道如何处理不同形状的鸡尾酒杯。

2 个答案:

答案 0 :(得分:4)

那么,让我们在d3(这里有有趣的)中讨论是否这是一个好主意的对话,并谈谈如何我们可以在d3中执行此操作。下面的代码借用了这个SVG image,然后应用渐变填充来显示鸡尾酒的各个部分。最后,你用一些标签把它包起来......

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
  <style>
    svg{
      font: 12px sans-serif;
    }
  </style>
</head>

<body>
  <script>
  
    // our cocktail glass
    var glassPath = "m 60,350 c -4.74218,-0.7989 -7.33654,-2.5714 -7.33654,-5.0124 0,-2.4848 2.03654,-4.0776 5.21357,-4.0776 1.54746,0 3.59496,-0.4138 4.55,-0.9197 1.97894,-1.0481 9.10335,-3.4326 24.23643,-8.1118 5.775,-1.7856 11.4,-3.6018 12.5,-4.0358 1.1,-0.434 4.3253,-1.3074 7.16733,-1.9408 5.71266,-1.2732 7.4813,-2.8015 9.21631,-7.9635 0.64176,-1.9094 2.38458,-4.7427 3.87294,-6.2962 l 2.70609,-2.8245 -0.2841,-27.7039 c -0.15625,-15.2371 -0.68535,-33.7788 -1.17577,-41.2038 -0.49042,-7.425 -1.20657,-21.825 -1.59145,-32 -0.94914,-25.0923 -1.70127,-27.1843 -15.45994,-43 -3.11003,-3.575 -7.5473,-9.326 -9.8606,-12.7799 -4.25363,-6.3511 -14.06748,-25.7631 -14.0826,-27.8558 -0.005,-0.6246 -0.68044,-2.4246 -1.50205,-4 -0.82161,-1.57534 -1.49661,-3.90636 -1.5,-5.18002 -0.003,-1.27366 -0.46743,-3.17763 -1.0312,-4.23105 -0.56377,-1.05341 -1.45572,-4.96133 -1.98212,-8.68426 -0.88933,-6.28986 -2.39223,-14.81377 -3.51606,-19.94188 -0.65359,-2.98237 -5.07693,-8.04956 -9.42012,-10.7913 -3.31741,-2.09419 -6.56863,-3.11638 -17.55666,-5.51985 -13.14833,-2.87601 -26.01544,-13.25971 -31.54627,-25.45769 -3.44329,-7.59403 -6.63083,-22.12177 -6.86935,-31.30823 l -0.0844,-3.25 131,0 131,0 -0.0844,3.25 c -0.23852,9.18646 -3.42606,23.7142 -6.86935,31.30823 -5.53083,12.19798 -18.39794,22.58168 -31.54627,25.45769 -10.98803,2.40347 -14.23925,3.42566 -17.55666,5.51985 -4.34319,2.74174 -8.76653,7.80893 -9.42012,10.7913 -1.12383,5.12811 -2.62673,13.65202 -3.51606,19.94188 -0.5264,3.72293 -1.41835,7.63085 -1.98212,8.68426 -0.56377,1.05342 -1.02781,2.95739 -1.0312,4.23105 -0.003,1.27366 -0.67839,3.60468 -1.5,5.18002 -0.82161,1.5754 -1.49753,3.3754 -1.50205,4 -0.0151,2.0927 -9.82897,21.5047 -14.0826,27.8558 -2.3133,3.4539 -6.75057,9.2049 -9.8606,12.7799 -13.75867,15.8157 -14.5108,17.9077 -15.45994,43 -0.38488,10.175 -1.10103,24.575 -1.59145,32 -0.49042,7.425 -1.01952,25.9667 -1.17577,41.2038 l -0.2841,27.7039 2.70609,2.8245 c 1.48836,1.5535 3.23118,4.3868 3.87294,6.2962 1.73501,5.162 3.50365,6.6903 9.21631,7.9635 2.84203,0.6334 6.06733,1.5068 7.16733,1.9408 1.1,0.434 6.725,2.2502 12.5,4.0358 15.13308,4.6792 22.25749,7.0637 24.23643,8.1118 0.95504,0.5059 3.00254,0.9197 4.55,0.9197 5.51258,0 7.05386,4.7477 2.50848,7.727 -2.52335,1.6539 -7.71319,1.7828 -77.25,1.9187 -40.9997,0.08 -76.41846,-0.17 -78.70837,-0.5557 z"
    
    // some drinks to show
    var data = [
      {
        drink: "Angel Face",
        parts: [
          { 
            unit: 3,
            name: "Calvados"
          },{ 
            unit: 3,
            name: "Apricot Brandy"
          },{ 
            unit: 3,
            name: "Gin"
          }
        ]
      }, {
        drink: "Aviation",
        parts: [
          { 
            unit: 1.5,
            name: "Maraschino"
          },{ 
            unit: 1.5,
            name: "Lemon Juice"
          },{ 
            unit: 4.5,
            name: "Gin"
          }
        ]
      }
    ];
    
    // 47 percent of our glass is where the liquid is
    var colorPercent = 47,
      // 3 percent is the empty spot on top
      // 50 percent is the stem
      startPercent = 50 - colorPercent,
      // width and height of the glass
      drinkWidth = 265,
      drinkHeight = 350,
      colors = d3.scale.category10();

    // calculate percentages...
    data.forEach(function(d0){
      var totPercent = startPercent,
          total = d3.sum(d0.parts, function(d1){ return d1.unit; });
      d0.gradient = [];
      d0.parts.forEach(function(d1){
        d1.startPercent = totPercent;
        d0.gradient.push({
          percent: totPercent,
          color: colors(d1.name)
        });
        totPercent += ((d1.unit / total) * colorPercent);
        d1.endPercent = totPercent;
        d0.gradient.push({
          percent: totPercent,
          color: colors(d1.name)
        });
      });
    });
    
    var svg = d3.select('body')
      .append('svg')
      .attr('width', (drinkWidth * data.length) + 5)
      .attr('height', drinkHeight + 20);
      

    // a g for each glass;
    var glass = svg.selectAll('.drink')
      .data(data)
      .enter()
      .append('g')
      .attr('class', 'drink')
      .attr('transform', function(d,i){
        return 'translate(' + (drinkWidth * i) + ',0)';
      })
    
    // the glass
    glass
      .append('path')
      .attr('d', glassPath)
      .style('stroke', 'black')
      .style('fill', function(d,i){
        return 'url(#grad' + i + ')';
      });
      
    // text labels of drink
    glass
      .append("text")
      .attr("x", drinkWidth / 2)
      .attr("y", drinkHeight)
      .text(function(d){
        return d.drink;
      })
      .attr("dy", "1em")
      .style("text-anchor", "middle")
      .style("font-size", "16");
      
    // text labels of drink parts
    glass.selectAll('.label')
      .data(function(d){
        return d.parts;
      })
      .enter()
      .append('text')
      .attr('class', 'label')
      .text(function(d){
        return d.unit + " " + d.name;
      })
      .style("fill", "black")
      .attr("x", drinkWidth / 2)
      .attr("y", function(d){
        return (((d.startPercent + d.endPercent) / 2) / 100) * drinkHeight;
      })
      .attr("dy", "1em")
      .style("text-anchor", "middle");
      
    // our gradients
    var grad = svg.append('defs')
      .selectAll('linearGradient')
      .data(data)
      .enter()
      .append('linearGradient')
      .attr('id', function(d,i){
        return "grad" + i;
      })
      .attr('x1', '0%')
      .attr('x2', '0%')
      .attr('y1', '0%')
      .attr('y2', '100%');
      
    // no liquid top of glass
    grad.append("stop")
      .attr("offset", "0%")
      .style("stop-color", "white");
      
    grad.append("stop")
      .attr("offset", startPercent + "%")
      .style("stop-color", "white");
    
    var e = grad.selectAll('.color')
      .data(function(d){
        return d.gradient
      })
      .enter();

    e.append("stop")
      .attr('id', function(d,i){
        return 'stop' + 1;
      })
      .attr("offset", function(d){
        return d.percent + '%';
      })
      .style("stop-color", function(d){
        return d.color;
      });

    // stem of glass
    grad.append("stop")
      .attr("offset", "50%")
      .style("stop-color", "black");
    
    grad.append("stop")
      .attr("offset", "100%")
      .style("stop-color", "black");
    
  </script>
</body>

</html>

答案 1 :(得分:2)

在D3中做这样的事情就像用你的智能手机敲打一块钉子一样 - 最终你会完成工作,但是你选择了错误的工具来做到这一点。

像智能手机一样,D3有很多可能性,但是这项任务需要大量的视觉细节,D3没有完成调整。

你看,图形编辑器工具有一个原因 - 它们可以让你创建具有出色字体,颜色,图层等的合成图像。鸡尾酒信息图非常适合这样的任务 - 您可以轻松地在画布上轻松添加小薄荷叶,桃子苦味和黑莓。

另一方面,在图形编辑器中进行简单的条形图。我已经这样做了(不要问我为什么)而且我必须做一些数学计算才能画出正确比例的酒吧。

您需要完成每种类型工作的工具。重要的是要知道如何选择合适的。 D3代表数据驱动文档 - 这就说明了一切。每当有DATA时,选择D3。

你可以说鸡尾酒信息图中有数据。确实。但我想告诉你一个简单而又非常重要的数据可视化概念:信噪比(检查this文章解释了这个概念),这在某种程度上就像是一个多少的质量指标噪音存在于您的数据中(不要将设计与噪音混淆)。在回答这个问题时,我提出了信号与设计比率©。 (我没有任何研究支持这个,所以请耐心等待),它告诉你需要多少设计除了数据。在鸡尾酒信息图中,你有比设计更多的设计 - 因此D3不适合这项任务。

作为结论:每项任务最适合用于完成它的特定工具。学会为您的任务选择合适的工具 - 这将至少为您节省时间。