Coder Social home page Coder Social logo

shibing624 / similarity Goto Github PK

View Code? Open in Web Editor NEW
1.4K 40.0 324.0 77.96 MB

similarity: Text similarity calculation Toolkit for Java. 文本相似度计算工具包,java编写,可用于文本相似度计算、情感分析等任务,开箱即用。

Home Page: https://shibing624.github.io/similarity/

License: Apache License 2.0

Java 100.00%
nlp similarity sentiment semantic java sim-scores

similarity's Introduction

jitpack Stars License Apache 2.0 GitHub issues Wechat Group

Similarity

similarity, compute similarity score between text strings, Java written.

similarity,相似度计算工具包,可用于文本相似度计算、情感倾向分析等,Java编写。

similarity是由一系列算法组成的Java版相似度计算工具包,目标是传播自然语言处理中相似度计算方法。similarity具备工具实用、性能高效、架构清晰、语料时新、可自定义的特点。

Feature

similarity提供下列功能:

  • 词语相似度计算

    • 词林编码法相似度[推荐]
    • 汉语语义法相似度
    • 知网词语相似度
    • 字面编辑距离法
  • 短语相似度计算

    • 简单短语相似度[推荐]
  • 句子相似度计算

    • 词性和词序结合法[推荐]
    • 编辑距离算法
    • Gregor编辑距离法
    • 优化编辑距离法
  • 段落相似度计算

    • 余弦相似度[推荐]
    • 编辑距离
    • 欧几里得距离
    • Jaccard相似性系数
    • Jaro距离
    • Jaro–Winkler距离
    • 曼哈顿距离
    • SimHash + 汉明距离
    • Sørensen–Dice系数
  • 知网义原

    • 词语义原树
  • 情感分析

    • 正面倾向程度
    • 负面倾向程度
    • 情感倾向性
  • 近似词

    • word2vec

在提供丰富功能的同时,similarity内部模块坚持低耦合、模型坚持惰性加载、词典坚持明文发布,使用方便,帮助用户训练自己的语料。

Usage

引入Jar包

Maven

<repositories>
  <repository>
    <id>jitpack.io</id>
    <url>https://jitpack.io</url>
  </repository>
</repositories>
<dependency>
  <groupId>com.github.shibing624</groupId>
  <artifactId>similarity</artifactId>
  <version>1.1.6</version>
</dependency>

Gradle

gradle的引入:jitpack

使用示例

import org.xm.Similarity;
import org.xm.tendency.word.HownetWordTendency;

public class demo {
    public static void main(String[] args) {
        double result = Similarity.cilinSimilarity("电动车", "自行车");
        System.out.println(result);

        String word = "混蛋";
        HownetWordTendency hownetWordTendency = new HownetWordTendency();
        result = hownetWordTendency.getTendency(word);
        System.out.println(word + "  词语情感趋势值:" + result);
    }
}

功能演示

1. 词语相似度计算

文本长度:词语粒度

推荐使用词林相似度:org.xm.Similarity.cilinSimilarity,是基于同义词词林的相似度计算方法

example: src/test/java/org.xm/WordSimilarityDemo.java

package org.xm;

public class WordSimilarityDemo {

    public static void main(String[] args) {
        String word1 = "教师";
        String word2 = "教授";
        double cilinSimilarityResult = Similarity.cilinSimilarity(word1, word2);
        double pinyinSimilarityResult = Similarity.pinyinSimilarity(word1, word2);
        double conceptSimilarityResult = Similarity.conceptSimilarity(word1, word2);
        double charBasedSimilarityResult = Similarity.charBasedSimilarity(word1, word2);

        System.out.println(word1 + " vs " + word2 + " 词林相似度值:" + cilinSimilarityResult);
        System.out.println(word1 + " vs " + word2 + " 拼音相似度值:" + pinyinSimilarityResult);
        System.out.println(word1 + " vs " + word2 + " 概念相似度值:" + conceptSimilarityResult);
        System.out.println(word1 + " vs " + word2 + " 字面相似度值:" + charBasedSimilarityResult);
    }
}
  • result:

word_sim result

2. 短语相似度计算

文本长度:短语粒度

推荐使用短语相似度:org.xm.Similarity.phraseSimilarity,本质是通过两个短语具有的相同字符,和相同字符的位置计算其相似度的方法

example: src/test/java/org.xm/PhraseSimilarityDemo.java

public static void main(String[] args) {
    String phrase1 = "继续努力";
    String phrase2 = "持续发展";
    double result = Similarity.phraseSimilarity(phrase1, phrase2);

    System.out.println(phrase1 + " vs " + phrase2 + " 短语相似度值:" + result);
}
  • result:

phrase sim result

3. 句子相似度计算

文本长度:句子粒度

推荐使用词形词序句子相似度:org.xm.similarity.morphoSimilarity,一种既考虑两个句子相同文本字面,也考虑相同文本出现的前后顺序的相似度方法

example: src/test/java/org.xm/SentenceSimilarityDemo.java

public static void main(String[] args) {
    String sentence1 = "**人爱吃鱼";
    String sentence2 = "湖北佬最喜吃鱼";

    double morphoSimilarityResult = Similarity.morphoSimilarity(sentence1, sentence2);
    double editDistanceResult = Similarity.editDistanceSimilarity(sentence1, sentence2);
    double standEditDistanceResult = Similarity.standardEditDistanceSimilarity(sentence1,sentence2);
    double gregeorEditDistanceResult = Similarity.gregorEditDistanceSimilarity(sentence1,sentence2);

    System.out.println(sentence1 + " vs " + sentence2 + " 词形词序句子相似度值:" + morphoSimilarityResult);
    System.out.println(sentence1 + " vs " + sentence2 + " 优化的编辑距离句子相似度值:" + editDistanceResult);
    System.out.println(sentence1 + " vs " + sentence2 + " 标准编辑距离句子相似度值:" + standEditDistanceResult);
    System.out.println(sentence1 + " vs " + sentence2 + " gregeor编辑距离句子相似度值:" + gregeorEditDistanceResult);
}
  • result:

sentence sim result

4. 段落文本相似度计算

文本长度:段落粒度(一段话,25字符 < length(text) < 500字符)

推荐使用词形词序句子相似度:org.xm.similarity.text.CosineSimilarity,一种考虑两个段落中相同的文本,经过切词,词频和词性权重加权,并用余弦计算相似度的方法

example: src/test/java/org.xm/similarity/text/CosineSimilarityTest.java

@Test
public void getSimilarityScore() throws Exception {
        String text1 = "对于俄罗斯来说,最大的战果莫过于夺取乌克兰首都基辅,也就是现任总统泽连斯基和他政府的所在地。目前夺取基辅的战斗已经打响。";
        String text2 = "迄今为止,俄罗斯的入侵似乎没有完全按计划成功执行——英国国防部情报部门表示,在乌克兰军队激烈抵抗下,俄罗斯军队已经损失数以百计的士兵。尽管如此,俄军在继续推进。";
        TextSimilarity cosSimilarity = new CosineSimilarity();
        double score1 = cosSimilarity.getSimilarity(text1, text2);
        System.out.println("cos相似度分值:" + score1);

        TextSimilarity editSimilarity = new EditDistanceSimilarity();
        double score2 = editSimilarity.getSimilarity(text1, text2);
        System.out.println("edit相似度分值:" + score2);
        }
  • result:
cos相似度分值:0.399143
edit相似度分值:0.0875

5. 基于义原树的情感分析

example: src/test/java/org/xm/tendency/word/HownetWordTendencyTest.java

@Test
public void getTendency() throws Exception {
    HownetWordTendency hownet = new HownetWordTendency();
    String word = "美好";
    double sim = hownet.getTendency(word);
    System.out.println(word + ":" + sim);
    System.out.println("混蛋:" + hownet.getTendency("混蛋"));
}
  • result:

tendency result

本例是基于义原树的词语粒度情感极性分析,关于文本情感分析有pytextclassifier,利用深度神经网络模型、SVM分类算法实现的效果更好。

6. 近义词推荐

example: src/test/java/org/xm/word2vec/Word2vecTest.java

@Test
public void testHomoionym() throws Exception {
    List<String> result = Word2vec.getHomoionym(RAW_CORPUS_SPLIT_MODEL, "武功", 10);
    System.out.println("武功 近似词:" + result);
}

@Test
public void testHomoionymName() throws Exception {
    String model = RAW_CORPUS_SPLIT_MODEL;
    List<String> result = Word2vec.getHomoionym(model, "乔帮主", 10);
    System.out.println("乔帮主 近似词:" + result);

    List<String> result2 = Word2vec.getHomoionym(model, "阿朱", 10);
    System.out.println("阿朱 近似词:" + result2);

    List<String> result3 = Word2vec.getHomoionym(model, "少林寺", 10);
    System.out.println("少林寺 近似词:" + result3);
}
  • 训练过程:

word2vec train

  • result:

word2vec result

Word2vec词向量训练用的java版word2vec训练工具Word2VEC_java,训练语料是小说天龙八部,通过词向量实现得到近义词。 用户可以训练自定义语料,也可以用中文维基百科训练通用词向量。

Todo

文本相似性度量

  • 关键词匹配(TF-IDF、BM25)
  • 浅层语义匹配(WordEmbed隐语义模型,用word2vec或glove词向量直接累加构造的句向量)
  • 深度语义匹配模型(DSSM、CLSM、DeepMatch、MatchingFeatures、ARC-II、DeepMind见MatchZoo),BERT类语义匹配模型SentenceBERT、CoSENT见text2vec

Contact

  • Issue(建议):GitHub issues
  • 邮件我:xuming: [email protected]
  • 微信我: 加我微信号:xuming624, 备注:姓名-公司-NLP 进NLP交流群。

License

授权协议为 The Apache License 2.0,可免费用做商业用途。请在产品说明中附加similarity的链接和授权协议。

Contribute

项目代码还很粗糙,如果大家对代码有所改进,欢迎提交回本项目,在提交之前,注意以下两点:

  • test添加相应的单元测试
  • 运行所有单元测试,确保所有单测都是通过的

之后即可提交PR。

Reference

  • [DSSM] Po-Sen Huang, et al., 2013, Learning Deep Structured Semantic Models for Web Search using Clickthrough Data
  • [CLSM] Yelong Shen, et al, 2014, A Latent Semantic Model with Convolutional-Pooling Structure for Information Retrieval
  • [DeepMatch] Zhengdong Lu & Hang Li, 2013, A Deep Architecture for Matching Short Texts
  • [MatchingFeatures] Zongcheng Ji, et al., 2014, An Information Retrieval Approach to Short Text Conversation
  • [ARC-II] Baotian Hu, et al., 2015, Convolutional Neural Network Architectures for Matching Natural Language Sentences
  • [DeepMind] Aliaksei Severyn, et al., 2015, Learning to Rank Short Text Pairs with Convolutional Deep Neural Networks

similarity's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

similarity's Issues

关于词典的问题

最近我在学习如何对一个句子做情感分析,看了您的项目。有一些问题想请教一下。

  1. resources目录下面的sememe.xmlconcept.xml这些语料是什么语料?
  2. HownetWordTendency.java文件中的POSITIVE_SEMEMESNEGATIVE_SEMEMES您是如何挑选的?
  3. 这个词的negative值是1,这个应该是有点问题。

还有一个bug:如果只分析一个单词并且该单词没有在义原中会有java.lang.StackOverflowError。经过调试发现问题在ConceptSimilarity.java文件中getConceptsautoCombineConcepts循环调用导致:

    public Collection<Concept> getConcepts(String key) {
        Collection<Concept> concepts = super.getConcepts(key);
        if (StringUtil.isBlank(concepts)) {
            concepts = autoCombineConcepts(key, null);
        }
        return concepts;
    }
    public Collection<Concept> autoCombineConcepts(String newWord, Collection<Concept> refConcepts) {
        ...
        Collection<Concept> concepts = getConcepts(conceptWord);
        ...
    }

词库扩展咨询

你好啊,github上搜到你的项目,相识度匹配等使用工具,正好项目中需要研究。不过需要请教下,我如何扩充 词库呢?
1.词林词库,目前是按照一个的格式存储在xml的,如何扩展?
2.同义词词库,一样的如何扩展?
3.义原词库,如何扩展?
望能指点下。

morphoSimilarity(String sentence1, String sentence2)方法抛出exception

java.lang.NoSuchMethodError: com.hankcs.hanlp.corpus.tag.Nature.name()Ljava/lang/String;

at org.xm.tokenizer.Tokenizer.lambda$segment$0(Tokenizer.java:50)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at org.xm.tokenizer.Tokenizer.segment(Tokenizer.java:51)
at org.xm.similarity.sentence.morphology.MorphoSimilarity.segment(MorphoSimilarity.java:131)
at org.xm.similarity.sentence.morphology.MorphoSimilarity.getSimilarity(MorphoSimilarity.java:55)
at org.xm.Similarity.morphoSimilarity(Similarity.java:125)

word2vec训练问题

Word2vec.trainModel可以训练多个小文件嘛
可以把多个模型合成一个大模型嘛

引用后项目日志输出全变成了debug

jar中logback.xml的配置导致引用它得spring boot项目所有输出变成debug。

	<root level="DEBUGE">
		<appender-ref ref="FILE" />
		<appender-ref ref="STDOUT" />
	</root>

人名识别有问题啊

Exception in thread "main" java.lang.StackOverflowError
at java.util.LinkedList.node(LinkedList.java:569)
at java.util.LinkedList$ListItr.(LinkedList.java:879)
at java.util.LinkedList.listIterator(LinkedList.java:868)
at java.util.AbstractList.listIterator(AbstractList.java:299)
at java.util.AbstractSequentialList.iterator(AbstractSequentialList.java:239)
at org.xm.similarity.word.hownet.concept.ConceptSimilarity.autoCombineConcepts(ConceptSimilarity.java:131)
at org.xm.similarity.word.hownet.concept.ConceptSimilarity.getConcepts(ConceptSimilarity.java:103)
at org.xm.similarity.word.hownet.concept.ConceptSimilarity.autoCombineConcepts(ConceptSimilarity.java:132)
at org.xm.similarity.word.hownet.concept.ConceptSimilarity.getConcepts(ConceptSimilarity.java:103)
at org.xm.similarity.word.hownet.concept.ConceptSimilarity.autoCombineConcepts(ConceptSimilarity.java:132)

加依赖报错

Could not find artifact com.github.shibing624:similarity:pom:1.1.6 in aliyun

JaroWinklerDistanceTextSimilarity无限递归?

调用JaroWinklerDistanceTextSimilarity的相似度方法时发现,org.xm.similarity.text.JaroWinklerDistanceTextSimilarity#getSimilarityImpl中会调用super.getSimilarity导致无限递归且没有递归出口
Exception in thread "main" java.lang.StackOverflowError at java.base/java.text.SimpleDateFormat.zeroPaddingNumber(SimpleDateFormat.java:1405) at java.base/java.text.SimpleDateFormat.subFormat(SimpleDateFormat.java:1180) at java.base/java.text.SimpleDateFormat.format(SimpleDateFormat.java:997) at java.base/java.text.SimpleDateFormat.format(SimpleDateFormat.java:967) at java.base/java.text.DateFormat.format(DateFormat.java:374) at ch.qos.logback.core.util.CachingDateFormatter.format(CachingDateFormatter.java:49) at ch.qos.logback.classic.pattern.DateConverter.convert(DateConverter.java:63) at ch.qos.logback.classic.pattern.DateConverter.convert(DateConverter.java:23) at ch.qos.logback.core.pattern.FormattingConverter.write(FormattingConverter.java:37) at ch.qos.logback.core.pattern.PatternLayoutBase.writeLoopOnConverters(PatternLayoutBase.java:119) at ch.qos.logback.classic.PatternLayout.doLayout(PatternLayout.java:149) at ch.qos.logback.classic.PatternLayout.doLayout(PatternLayout.java:39) at ch.qos.logback.core.encoder.LayoutWrappingEncoder.doEncode(LayoutWrappingEncoder.java:134) at ch.qos.logback.core.OutputStreamAppender.writeOut(OutputStreamAppender.java:194) at ch.qos.logback.core.OutputStreamAppender.subAppend(OutputStreamAppender.java:219) at ch.qos.logback.core.OutputStreamAppender.append(OutputStreamAppender.java:103) at ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(UnsynchronizedAppenderBase.java:88) at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:48) at ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:273) at ch.qos.logback.classic.Logger.callAppenders(Logger.java:260) at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:442) at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:396) at ch.qos.logback.classic.Logger.debug(Logger.java:503) at org.xm.similarity.text.TextSimilarity.getSimilarity(TextSimilarity.java:53) at org.xm.similarity.text.JaroWinklerDistanceTextSimilarity.getSimilarityImpl(JaroWinklerDistanceTextSimilarity.java:64) at org.xm.similarity.text.TextSimilarity.getSimilarity(TextSimilarity.java:59) at org.xm.similarity.text.JaroWinklerDistanceTextSimilarity.getSimilarityImpl(JaroWinklerDistanceTextSimilarity.java:64) at org.xm.similarity.text.TextSimilarity.getSimilarity(TextSimilarity.java:59) at org.xm.similarity.text.JaroWinklerDistanceTextSimilarity.getSimilarityImpl(JaroWinklerDistanceTextSimilarity.java:64) at org.xm.similarity.text.TextSimilarity.getSimilarity(TextSimilarity.java:59) at org.xm.similarity.text.JaroWinklerDistanceTextSimilarity.getSimilarityImpl(JaroWinklerDistanceTextSimilarity.java:64) at org.xm.similarity.text.TextSimilarity.getSimilarity(TextSimilarity.java:59) at org.xm.similarity.text.JaroWinklerDistanceTextSimilarity.getSimilarityImpl(JaroWinklerDistanceTextSimilarity.java:64) at org.xm.similarity.text.TextSimilarity.getSimilarity(TextSimilarity.java:59) at org.xm.similarity.text.JaroWinklerDistanceTextSimilarity.getSimilarityImpl(JaroWinklerDistanceTextSimilarity.java:64) at org.xm.similarity.text.TextSimilarity.getSimilarity(TextSimilarity.java:59) at org.xm.similarity.text.JaroWinklerDistanceTextSimilarity.getSimilarityImpl(JaroWinklerDistanceTextSimilarity.java:64) at org.xm.similarity.text.TextSimilarity.getSimilarity(TextSimilarity.java:59) ...

bug

文本比较:ccc 和 cccccccc竟然返回 0.0

句子相似度

以“**人不爱吃鱼”和“**人喜爱吃鱼”为测试样例,词形词序句子相似度值为0.73,优化的编辑距离句子相似度值、标准编辑距离句子相似度值和 gregeor 编辑距离句子相似度值均 0.5,对于这种相似度计算无法令人满意的情况是否有更好的解决办法

发布到了jitpack

离线jar包版本的没注释太难受了

	<repositories>
		<repository>
		    <id>jitpack.io</id>
		    <url>https://jitpack.io</url>
		</repository>
	</repositories>
<dependency>
	    <groupId>com.github.shibing624</groupId>
	    <artifactId>similarity</artifactId>
	    <version>-SNAPSHOT</version>
	</dependency>

jenkins发布失败

[ERROR] Failed to execute goal on project : Could not resolve dependencies for project com.singhand:yaoguang-event:jar:0.0.1-SNAPSHOT: Failed to collect dependencies at com.github.shibing624:similarity:jar:1.1.6: Failed to read artifact descriptor for com.github.shibing624:similarity:jar:1.1.6: Could not transfer artifact com.github.shibing624:similarity:pom:1.1.6 from/to jitpack.io (https://jitpack.io/): sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.

这个依赖太坑了吧

依赖里面引用了guava 13.1,和我项目中的guava 30.1 冲突了, 但是排除之后还是会时不时报Preconditions里面的checkState方法参数不对,结果发现还有一个google-collections包,Preconditions类是google-collections里面加载的

如果要用新版的guava或者引用的依赖里面有新版的guava,一定要排除google-collections

关于运行SentenceSimilarityDemo提示找不到CoreNatureDictionary.txt.bin文件的问题

刚重置了一下本地环境,没有复现问题。
1.你下载完Similarity项目后,如果是IDEA环境,请reimport一下maven;如果是eclipse环境,请先clean-package一下,然后再试一下demo。
2.若你按以上处理没有解决问题,请下载data数据,https://pan.baidu.com/s/1jIydVsq 下载完后直接把data放在主目录下就好。该文件是我中文分词(https://github.com/shibing624/xmnlp)的数据包。

如果希望将句子和词语之间做匹配应该如何操作合适呢?

我希望将一个句子直接进行分类,但是我手上没有一个标注好的分类数据集,所以只能求助于开放的模型,通过暴力匹配计算相似度来实现句子分类。那么如果直接将句子和词语编码后计算相似度,是否会有相似性的性能体现出来呢?

如何加入自己的数据

作者的使用的词语都比较通用,请问如何加入自己特定领域的术语用于语句相似度分析呢?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.