d3.js条件词颜色填写wordcloud

时间:2017-04-11 21:11:37

标签: javascript csv d3.js scale

我创建了一个基于csv的d​​3.js文字云。

在csv中我有三列:

  • 字(字 - 唯一)
  • 计数(文字出现的次数)
  • 指数(这是计数高于平均值的数值与低于平均值的数量)

words.csv:

word    count   index
word1   457      239
word2   373      155
word3   76      -142
word4   345      127
word5   12      -206
word6   46      -172

我编写了以下代码(在youtube和jason davies的世界云包的帮助下),它可以创建单词云,但我不知道如何根据索引更改单词的颜色。

    <script>

    var width = 1500,
        height =400;

    var wordScale = d3.scale.linear().range([10,100]);

    var fill = d3.scale.category20c();
    d3.csv("words.csv", function(data) {  
        var subjects = data
            .map(function(d) {return {text: d.word, size: +d.count} })
            .sort(function(a,b) {return d3.descending (a.size, b.size); })
            .slice(0,100);

        wordScale.domain([
            d3.min(subjects, function(d) {return d.size; }),
            d3.max(subjects, function(d) {return d.size; }),
        ]);    

    // var layout = cloud()
        d3.layout.cloud().size([width, height])
        .words(subjects)
        .padding(1)
        .rotate(function() { return ~~(Math.random() * 2) * 0; })
        .font("Impact")
        .fontSize(function(d) { return wordScale(d.size); })
        .on("end", draw)
        .start();

    });

        function draw(words) {
          d3.select("#word-cloud").append("svg")
              .attr("width",width)
              .attr("height",height)
            .append("g")
              .attr("transform", "translate("+(width /2)+","+(height /2)+")")
              //where the center is
            .selectAll("text")
              .data(words)
            .enter().append("text")
              .style("font-size", function(d) { return d.size + "px"; })
              .style("font-family", "Impact")
              .style("fill", function(d, i) { return fill(i); })
              .attr("text-anchor", "middle")
              .attr("transform", function(d) {
                return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
              })
              .text(function(d) { return d.text; });
    }


        </script>


I need to change this line in the code `var fill = d3.scale.category20c();`

The goal would be that all words above the average (so positive index) are green and all words below the average (negative index) are grey. If  the transparency of the color/fill could be dependent on how much above or below the average the count is that would be amazing - but not necessary. 

    word    count   index   color
    word1   457      239    green
    word2   373      155    green
    word3   76      -142    grey
    word4   345      127    green
    word5   12      -206    grey
    word6   46      -172    grey

谢谢!

更新:

根据Dan的回答尝试以下内容,但索引:

    mycolor = d3.rgb("#00cc66");

var width = 1500,
    height =400;

var wordScale = d3.scale.linear().range([10,90]);
var colorScale = d3.scale.linear().range([10,90]);

// var fill = d3.scale.category20c();
d3.csv("words.csv", function(data) {  
    var subjects = data
        .map(function(d) {return {text: d.word, size: +d.count, clr: d.index } })
        .sort(function(a,b) {return d3.descending (a.size, b.size); })
        .slice(0,100);

    wordScale.domain([
        d3.min(subjects, function(d) {return d.size; }),
        d3.max(subjects, function(d) {return d.size; }),
    ]);   

    colorScale.domain([
        d3.min(subjects, function(d) {return d.clr; }),
        d3.max(subjects, function(d) {return d.clr; }),
    ]);  

// var layout = cloud()
    d3.layout.cloud().size([width, height])
    .words(subjects)
    .padding(1)
    .rotate(function() { return ~~(Math.random() * 2) * 0; })
    .font("Impact")
    .fontSize(function(d) { return wordScale(d.size); })
    .on("end", draw)
    .start();

});

    function draw(words) {
      d3.select("#word-cloud").append("svg")
          .attr("width",width)
          .attr("height",height)
        .append("g")
          .attr("transform", "translate("+(width /2)+","+(height /2)+")")
          //where the center is
        .selectAll("text")
          .data(words)
        .enter().append("text")
          .style("fill", function(d) { return d.clr >= 50 ? mycolor : "grey";})
          .style("opacity", function(d) { return d.clr / 100 })
          .style("font-size", function(d) { return d.size + "px"; })
          .style("font-family", "Impact")
          // .style("fill", function(d, i) { return fill(i); })
          .attr("text-anchor", "middle")
          .attr("transform", function(d) {
            return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
          })
          .text(function(d) { return d.text; });
}

不幸的是,我运行时没有显示任何内容(也没有错误信息)。

1 个答案:

答案 0 :(得分:2)

对于上面的代码,即;假设wordScale介于10和100之间:

在绘图功能中,在代码的.append("text")部分,

按如下方式编辑填充功能。根据大小高于/低于中点(55),这将变为绿色/灰色。随意使用比下面硬编码更好的颜色值:

.style("fill", function(d) { return d.size >= 55 ? "green" : "grey";})

要完成您的其他请求,请在fill下方添加以下样式。这将设置相对于大小的不透明度(介于0.1和1之间)。同样,您可以根据需要调整这些值。

.style("opacity", function(d) { return d.size / 100 })

如果您进行了这些修改,也可以将var fill放在代码顶部。

更新的答案:

注意,我无法得到Jason Davies&#39;远程加载没有脚本错误,但没有时间进行调试。在他的脚本之后向下滚动以获得实际答案。我还没有添加任何旋转元素。

&#13;
&#13;
!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b=b.d3||(b.d3={}),b=b.layout||(b.layout={}),b.cloud=a()}}(function(){var a;return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c||a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){function h(a){return a.text}function i(){return"serif"}function j(){return"normal"}function k(a){return Math.sqrt(a.value)}function l(){return 30*(~~(6*Math.random())-3)}function m(){return 1}function n(a,b,c,d){if(!b.sprite){var h=a.context,i=a.ratio;h.clearRect(0,0,(f<<5)/i,g/i);var j=0,k=0,l=0,m=c.length;for(--d;++d<m;){b=c[d],h.save(),h.font=b.style+" "+b.weight+" "+~~((b.size+1)/i)+"px "+b.font;var n=h.measureText(b.text+"m").width*i,o=b.size<<1;if(b.rotate){var p=Math.sin(b.rotate*e),q=Math.cos(b.rotate*e),r=n*q,s=n*p,t=o*q,u=o*p;n=Math.max(Math.abs(r+u),Math.abs(r-u))+31>>5<<5,o=~~Math.max(Math.abs(s+t),Math.abs(s-t))}else n=n+31>>5<<5;if(o>l&&(l=o),j+n>=f<<5&&(j=0,k+=l,l=0),k+o>=g)break;h.translate((j+(n>>1))/i,(k+(o>>1))/i),b.rotate&&h.rotate(b.rotate*e),h.fillText(b.text,0,0),b.padding&&(h.lineWidth=2*b.padding,h.strokeText(b.text,0,0)),h.restore(),b.width=n,b.height=o,b.xoff=j,b.yoff=k,b.x1=n>>1,b.y1=o>>1,b.x0=-b.x1,b.y0=-b.y1,b.hasText=!0,j+=n}for(var v=h.getImageData(0,0,(f<<5)/i,g/i).data,w=[];--d>=0;)if(b=c[d],b.hasText){for(var n=b.width,x=n>>5,o=b.y1-b.y0,y=0;y<o*x;y++)w[y]=0;if(null==(j=b.xoff))return;k=b.yoff;for(var z=0,A=-1,B=0;B<o;B++){for(var y=0;y<n;y++){var C=x*B+(y>>5),D=v[(k+B)*(f<<5)+(j+y)<<2]?1<<31-y%32:0;w[C]|=D,z|=D}z?A=B:(b.y0++,o--,B--,k++)}b.y1=b.y0+A,b.sprite=w.slice(0,(b.y1-b.y0)*x)}}}function o(a,b,c){c>>=5;for(var k,d=a.sprite,e=a.width>>5,f=a.x-(e<<4),g=127&f,h=32-g,i=a.y1-a.y0,j=(a.y+a.y0)*c+(f>>5),l=0;l<i;l++){k=0;for(var m=0;m<=e;m++)if((k<<h|(m<e?(k=d[l*e+m])>>>g:0))&b[j+m])return!0;j+=c}return!1}function p(a,b){var c=a[0],d=a[1];b.x+b.x0<c.x&&(c.x=b.x+b.x0),b.y+b.y0<c.y&&(c.y=b.y+b.y0),b.x+b.x1>d.x&&(d.x=b.x+b.x1),b.y+b.y1>d.y&&(d.y=b.y+b.y1)}function q(a,b){return a.x+a.x1>b[0].x&&a.x+a.x0<b[1].x&&a.y+a.y1>b[0].y&&a.y+a.y0<b[1].y}function r(a){var b=a[0]/a[1];return function(a){return[b*(a*=.1)*Math.cos(a),a*Math.sin(a)]}}function s(a){var b=4,c=b*a[0]/a[1],d=0,e=0;return function(a){var f=a<0?-1:1;switch(Math.sqrt(1+4*f*a)-f&3){case 0:d+=c;break;case 1:e+=b;break;case 2:d-=c;break;default:e-=b}return[d,e]}}function t(a){for(var b=[],c=-1;++c<a;)b[c]=0;return b}function u(){return document.createElement("canvas")}function v(a){return"function"==typeof a?a:function(){return a}}var d=a("d3-dispatch").dispatch,e=Math.PI/180,f=64,g=2048;b.exports=function(){function I(a){a.width=a.height=1;var b=Math.sqrt(a.getContext("2d").getImageData(0,0,1,1).data.length>>2);a.width=(f<<5)/b,a.height=g/b;var c=a.getContext("2d");return c.fillStyle=c.strokeStyle="red",c.textAlign="center",{context:c,ratio:b}}function J(b,c,d){for(var l,m,n,f=(a[0],a[1],c.x),g=c.y,h=Math.sqrt(a[0]*a[0]+a[1]*a[1]),i=A(a),j=F()<.5?1:-1,k=-j;(l=i(k+=j))&&(m=~~l[0],n=~~l[1],!(Math.min(Math.abs(m),Math.abs(n))>=h));)if(c.x=f+m,c.y=g+n,!(c.x+c.x0<0||c.y+c.y0<0||c.x+c.x1>a[0]||c.y+c.y1>a[1])&&(!d||!o(c,b,a[0]))&&(!d||q(c,d))){for(var y,p=c.sprite,r=c.width>>5,s=a[0]>>5,t=c.x-(r<<4),u=127&t,v=32-u,w=c.y1-c.y0,x=(c.y+c.y0)*s+(t>>5),z=0;z<w;z++){y=0;for(var B=0;B<=r;B++)b[x+B]|=y<<v|(B<r?(y=p[z*r+B])>>>u:0);x+=s}return delete c.sprite,!0}return!1}var a=[256,256],b=h,c=i,e=k,s=j,x=j,y=l,z=m,A=r,B=[],C=1/0,D=d("word","end"),E=null,F=Math.random,G={},H=u;return G.canvas=function(a){return arguments.length?(H=v(a),G):H},G.start=function(){function l(){for(var b=Date.now();Date.now()-b<C&&++i<h&&E;){var c=k[i];c.x=a[0]*(F()+.5)>>1,c.y=a[1]*(F()+.5)>>1,n(d,c,k,i),c.hasText&&J(f,c,g)&&(j.push(c),D.call("word",G,c),g?p(g,c):g=[{x:c.x+c.x0,y:c.y+c.y0},{x:c.x+c.x1,y:c.y+c.y1}],c.x-=a[0]>>1,c.y-=a[1]>>1)}i>=h&&(G.stop(),D.call("end",G,j,g))}var d=I(H()),f=t((a[0]>>5)*a[1]),g=null,h=B.length,i=-1,j=[],k=B.map(function(a,d){return a.text=b.call(this,a,d),a.font=c.call(this,a,d),a.style=s.call(this,a,d),a.weight=x.call(this,a,d),a.rotate=y.call(this,a,d),a.size=~~e.call(this,a,d),a.padding=z.call(this,a,d),a}).sort(function(a,b){return b.size-a.size});return E&&clearInterval(E),E=setInterval(l,0),l(),G},G.stop=function(){return E&&(clearInterval(E),E=null),G},G.timeInterval=function(a){return arguments.length?(C=null==a?1/0:a,G):C},G.words=function(a){return arguments.length?(B=a,G):B},G.size=function(b){return arguments.length?(a=[+b[0],+b[1]],G):a},G.font=function(a){return arguments.length?(c=v(a),G):c},G.fontStyle=function(a){return arguments.length?(s=v(a),G):s},G.fontWeight=function(a){return arguments.length?(x=v(a),G):x},G.rotate=function(a){return arguments.length?(y=v(a),G):y},G.text=function(a){return arguments.length?(b=v(a),G):b},G.spiral=function(a){return arguments.length?(A=w[a]||a,G):A},G.fontSize=function(a){return arguments.length?(e=v(a),G):e},G.padding=function(a){return arguments.length?(z=v(a),G):z},G.random=function(a){return arguments.length?(F=a,G):F},G.on=function(){var a=D.on.apply(D,arguments);return a===D?G:a},G};var w={archimedean:r,rectangular:s}},{"d3-dispatch":2}],2:[function(b,c,d){!function(b,e){"object"==typeof d&&void 0!==c?e(d):"function"==typeof a&&a.amd?a(["exports"],e):e(b.d3=b.d3||{})}(this,function(a){"use strict";function c(){for(var e,a=0,b=arguments.length,c={};a<b;++a){if(!(e=arguments[a]+"")||e in c)throw new Error("illegal type: "+e);c[e]=[]}return new d(c)}function d(a){this._=a}function e(a,b){return a.trim().split(/^|\s+/).map(function(a){var c="",d=a.indexOf(".");if(d>=0&&(c=a.slice(d+1),a=a.slice(0,d)),a&&!b.hasOwnProperty(a))throw new Error("unknown type: "+a);return{type:a,name:c}})}function f(a,b){for(var e,c=0,d=a.length;c<d;++c)if((e=a[c]).name===b)return e.value}function g(a,c,d){for(var e=0,f=a.length;e<f;++e)if(a[e].name===c){a[e]=b,a=a.slice(0,e).concat(a.slice(e+1));break}return null!=d&&a.push({name:c,value:d}),a}var b={value:function(){}};d.prototype=c.prototype={constructor:d,on:function(a,b){var h,c=this._,d=e(a+"",c),i=-1,j=d.length;{if(!(arguments.length<2)){if(null!=b&&"function"!=typeof b)throw new Error("invalid callback: "+b);for(;++i<j;)if(h=(a=d[i]).type)c[h]=g(c[h],a.name,b);else if(null==b)for(h in c)c[h]=g(c[h],a.name,null);return this}for(;++i<j;)if((h=(a=d[i]).type)&&(h=f(c[h],a.name)))return h}},copy:function(){var a={},b=this._;for(var c in b)a[c]=b[c].slice();return new d(a)},call:function(a,b){if((e=arguments.length-2)>0)for(var e,f,c=new Array(e),d=0;d<e;++d)c[d]=arguments[d+2];if(!this._.hasOwnProperty(a))throw new Error("unknown type: "+a);for(f=this._[a],d=0,e=f.length;d<e;++d)f[d].value.apply(b,c)},apply:function(a,b,c){if(!this._.hasOwnProperty(a))throw new Error("unknown type: "+a);for(var d=this._[a],e=0,f=d.length;e<f;++e)d[e].value.apply(b,c)}},a.dispatch=c,Object.defineProperty(a,"__esModule",{value:!0})})},{}]},{},[1])(1)});

/// ACTUAL START OF ANSWER ///

// fake JSON data in place of CSV file.

data = [{
    word: "word1",
    count: 457,
    index: 239
  },
  {
    word: "word2",
    count: 373,
    index: 155
  },
  {
    word: "word3",
    count: 76,
    index: -142
  },
  {
    word: "word4",
    count: 345,
    index: 127
  },
  {
    word: "word5",
    count: 12,
    index: -206
  },
  {
    word: "word6",
    count: 46,
    index: -172
  }
]

//  the script


    var width = 700, // amended to make result easier to see
        height =400;

    var wordScale = d3.scale.linear().range([10,100]);

//    d3.csv("words.csv", function(data) {  // uncomment when using CSV
        var subjects = data
            .map(function(d) {return {text: d.word, size: +d.count, in: +d.index} }) // note use of +d.index, to ensure it's held as a number when read from csv, same as +d.count
            .sort(function(a,b) {return d3.descending (a.size, b.size); })
            .slice(0,100);

        wordScale.domain([
            d3.min(subjects, function(d) {return d.size; }),
            d3.max(subjects, function(d) {return d.size; }),
        ]);    

    // var layout = cloud()
        d3.layout.cloud().size([width, height])
        .words(subjects)
        .padding(1)
        .rotate(function() { return ~~(Math.random() * 2) * 0; })
        .font("Impact")
        .fontSize(function(d) { return wordScale(d.size); })
        .on("end", draw)
        .start();

 //   }); uncomment when using csv

        function draw(words) {
          d3.select("#word-cloud").append("svg")
              .attr("width",width)
              .attr("height",height)
            .append("g")
              .attr("transform", "translate("+(width /2)+","+(height /2)+")")
              //where the center is
            .selectAll("text")
              .data(words)
            .enter().append("text")
              .style("font-size", function(d) { return d.size + "px"; })
              .style("font-family", "Impact")
              .style("fill", function(d, i) { return d.in > 0 ? "#00cc66" : "grey" })
              .style("opacity", function(d) { return d.in > 0 ? d.size/100 : (50 - d.size) / 100 } ) // bit of a hack to get furthest from index to become darker
              .attr("text-anchor", "middle")
              .attr("transform", function(d) {
                return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
              })
              .text(function(d) { return d.text; });
    }
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!--
word    count   index
word1   457      239
word2   373      155
word3   76      -142
word4   345      127
word5   12      -206
word6   46      -172
-->
<div id="word-cloud"></div>
&#13;
&#13;
&#13;

相关问题