Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
jheer committed Dec 21, 2011
0 parents commit 6cabd78
Show file tree
Hide file tree
Showing 84 changed files with 13,691 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
_site
node_modules
.DS_Store
3 changes: 3 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
examples/
lib/
.DS_Store
26 changes: 26 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Copyright (c) 2011, Stanford University
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* The name Stanford University may not be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 changes: 39 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# See the README for installation instructions.

NODE_PATH ?= ./node_modules
JS_COMPILER = $(NODE_PATH)/uglify-js/bin/uglifyjs

JS_FILES = \
c3.js

all: \
$(JS_FILES) \
$(JS_FILES:.js=.min.js) \
package.json

c3.js: \
src/start.js \
src/c3/def.js \
src/c3/load.js \
src/c3/init.js \
src/c3/api.js \
src/end.js

%.min.js: %.js Makefile
@rm -f $@
$(JS_COMPILER) < $< > $@

c3.%: Makefile
@rm -f $@
cat $(filter %.js,$^) > $@
@chmod a-w $@

install:
mkdir -p node_modules
npm install

package.json: c3.js src/package.js
node src/package.js > $@

clean:
rm -f c3*.js
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# C3

**C3** (Categorical Color Components) is a JavaScript library for
modeling color naming data. It can be used to create a variety of
applications, including improved color selection, image editing,
or palette analysis tools.

C3 also includes backend components (written in Java) for processing
raw color naming data and producing a compact model of color naming.
The resulting JSON model file is loaded by the client C3 library.

### Browser Support

C3 should work on any browser. However, the included example applications
require a modern browser that supports [SVG](http://www.w3.org/TR/SVG/)
and the Canvas tag. The examples should work on Firefox, Chrome (Chromium),
Safari (WebKit), Opera and IE9.

Note: Chrome has strict permissions for reading files out of the local file
system. Some examples use AJAX which works differently via HTTP instead of local
files. For the best experience, load the C3 examples from your own machine via
HTTP. Any static file web server will work; for example you can run Python's
built-in server:

python -m SimpleHTTPServer 8888

Once this is running, go to: <http://localhost:8888/examples/>

### Development Setup

This repository should work out of the box if you just want to create
applications using C3. On the other hand, if you want to extend C3 with new
features, fix bugs, or run tests, you'll need to install a few more things.

C3 uses UglifyJS to minimize the resulting JS file. UglifyJS depends on
[Node.js](http://nodejs.org/) and [NPM](http://npmjs.org/). If you are
developing on Mac OS X, an easy way to install Node and NPM is using
[Homebrew](http://mxcl.github.com/homebrew/):

brew install node
brew install npm

Next, from the root directory of this repository, install C3's dependencies:

make install

You can see the list of dependencies in package.json. NPM will install the
packages in the node_modules directory.
205 changes: 205 additions & 0 deletions c3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
(function(){c3 = {version: "1.0.0"}; // semver

c3.load = function(uri, async) {
async = async || false;
var req = new XMLHttpRequest();
var onload = function() {
if (!async || req.readyState == 4) {
if (req.status == 200 || req.status == 0) {
c3_init(JSON.parse(req.responseText));
c3_api();
} else {
alert("Error Loading C3 Data");
}
}
};
req.open('GET', uri, false);
if (async) req.onreadystatechange = onload;
req.send(null);
if (!async) onload();
}

function c3_init(json) {
var i, C, W, T, A, ccount, tcount;

// parse colors
c3.color = [];
for (i=0; i<json.color.length; i+=3) {
c3.color[i/3] = d3.lab(json.color[i], json.color[i+1], json.color[i+2]);
}
C = c3.color.length;

// parse terms
c3.terms = json.terms;
W = c3.terms.length;

// parse count table
c3.T = T = [];
for (var i=0; i<json.T.length; i+=2) {
T[json.T[i]] = json.T[i+1];
}

// construct counts
c3.color.count = ccount = []; for (i=0; i<C; ++i) ccount[i] = 0;
c3.terms.count = tcount = []; for (i=0; i<W; ++i) tcount[i] = 0;
d3.keys(T).forEach(function(idx) {
var c = Math.floor(idx / W),
w = Math.floor(idx % W),
v = T[idx] || 0;
ccount[c] += v;
tcount[w] += v;
});

// parse word association matrix
c3.A = A = json.A;
}

function c3_api() {
var C = c3.color.length,
W = c3.terms.length,
T = c3.T,
A = c3.A,
ccount = c3.color.count,
tcount = c3.terms.count;

c3.count = function(c, w) {
return T[c*W+w] || 0;
}

c3.terms.prob = function(w, c) {
return (T[c*W+w]||0) / tcount[w];
}

c3.terms.entropy = function(w) {
var H = 0, p;
for (var c=0; c<C; ++c) {
p = (T[c*W+w]||0) / tcount[w];
if (p > 0) H += p * Math.log(p) / Math.LN2;
}
return H;
}

c3.terms.perplexity = function(w) {
var H = c3.terms.entropy(w);
return Math.pow(2, -H);
}

c3.terms.cosine = function(a, b) {
var sa=0, sb=0, sc=0, ta, tb;
for (var c=0; c<C; ++c) {
ta = (T[c*W+a]||0);
tb = (T[c*W+b]||0);
sa += ta*ta;
sb += tb*tb;
sc += ta*tb;
}
return sc / (Math.sqrt(sa*sb));
}

c3.color.prob = function(c, w) {
return (T[c*W+w]||0) / ccount[c];
}

c3.color.entropy = function(c) {
var H = 0, p;
for (var w=0; w<W; ++w) {
p = (T[c*W+w]||0) / ccount[c];
if (p > 0) H += p * Math.log(p) / Math.LN2;
}
return H;
}

c3.terms.hellinger = function(a, b) {
var bc=0, pa, pb, z = Math.sqrt(tcount[a]*tcount[b]);
for (var c=0; c<C; ++c) {
pa = (T[c*W+a]||0);
pb = (T[c*W+b]||0);
bc += Math.sqrt(pa*pb);
}
return Math.sqrt(1 - bc / z);
}

c3.color.perplexity = function(c) {
var H = c3.color.entropy(c);
return Math.pow(2, -H);
}

c3.color.cosine = function(a, b) {
var sa=0, sb=0, sc=0, ta, tb;
for (var w=0; w<W; ++w) {
ta = (T[a*W+w]||0);
tb = (T[b*W+w]||0);
sa += ta*ta;
sb += tb*tb;
sc += ta*tb;
}
return sc / (Math.sqrt(sa*sb));
}

c3.color.hellinger = function(a, b) {
var bc=0, pa, pb, z = Math.sqrt(ccount[a]*ccount[b]);
for (var w=0; w<W; ++w) {
pa = (T[a*W+w]||0);
pb = (T[b*W+w]||0);
bc += Math.sqrt(pa*pb);
}
return Math.sqrt(1 - bc / z);
}

c3.terms.relatedTerms = function(w, limit) {
var sum = 0, c = c3.terms.center[w], list = [];
for (var i=0; i<W; ++i) {
if (i != w) list.push({index: i, score: A[i*W+w]});
}
list.sort(function(a, b) {
var ca, cb, dL1, dL2, da1, da2, db1, db2,
cmp = b.score - a.score;
if (Math.abs(cmp) < 0.00005) {
// break near ties by distance between centers
ca = c3.terms.center[a.index];
cb = c3.terms.center[b.index];
cmp = ca.de00(c) - cb.de00(c);
}
return cmp;
});
list.unshift({index: w, score: A[w*W+w]});
return limit ? list.slice(0,limit) : list;
}

c3.terms.relatedColors = function(w, limit) {
var list = [];
for (var c=0; c<C; ++c) {
var s = (T[c*W+w] || 0) / ccount[c];
if (s > 0) list.push({index: c, score: s});
}
list.sort(function(a,b) { return b.score - a.score; });
return limit ? list.slice(0,limit) : list;
}

c3.color.relatedTerms = function(c, limit, minCount) {
var cc = c*W, list = [], sum = 0, s, cnt = c3.terms.count;
for (var w=0; w<W; ++w) {
if ((s = T[cc+w]) !== undefined) {
list.push({index: w, score: s});
sum += s;
}
}
if (minCount) {
list = list.filter(function(d) { return cnt[d.index] > minCount; });
}
list.sort(function(a,b) { return b.score - a.score; });
list.forEach(function(d) { d.score /= sum; });
return limit ? list.slice(0, limit) : list;
}

// compute representative colors
c3.terms.center = d3.range(W).map(function(w) {
var list = c3.terms.relatedColors(w, 5)
.map(function(d) { return c3.color[d.index]; });
var L = 0, a = 0, b = 0, N = list.length;
list.forEach(function(c) { L += c.L; a += c.a; b += c.b; });
return d3.lab(Math.round(L/N), Math.round(a/N), Math.round(b/N));
});
}

})();
1 change: 1 addition & 0 deletions c3.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions data/xkcd/c3_data.json

Large diffs are not rendered by default.

Binary file added data/xkcd/xkcd.csv.gz
Binary file not shown.
Loading

0 comments on commit 6cabd78

Please sign in to comment.