我创建了一个基于csv的d3.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; });
}
不幸的是,我运行时没有显示任何内容(也没有错误信息)。
答案 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;远程加载没有脚本错误,但没有时间进行调试。在他的脚本之后向下滚动以获得实际答案。我还没有添加任何旋转元素。
!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;