用ElasticSearch和Protovis实现数据可视化

搜索引擎最重要的目的,嗯,不出意料就是搜索。你传给它一个请求,然后它依照相关性返回你一串匹配的结果。我们可以根据自己的内容创造各种请求结构,试验各种不同的分析器,搜索引擎都会努力尝试提供最好的结果。

不过,一个现代的全文搜索引擎可以做的比这个更多。因为它的核心是基于一个为了高效查询匹配文档而高度优化过的数据结构——倒排索引。它也可以为我们的数据完成复杂的聚合运算,在这里我们叫它facets。(不好翻译,后文对这个单词都保留英文)

facets通常的目的是提供给用户某个方面的导航或者搜索。 当你在网上商店搜索“相机”,你可以选择不同的制造商,价格范围或者特定功能来定制条件,这应该就是点一下链接的事情,而不是通过修改一长串查询语法。
Facet搜索为数不多的几个可以把强大的请求能力开放给最终用户的办法之一,详见Moritz Stefaner的试验“Elastic Lists”,或许你会有更多灵感。

但是,除了链接和复选框,其实我们还能做的更多。比如利用这些数据画图,而这就是我们在这篇文章中要讲的。

实时仪表板
在几乎所有的分析、监控和数据挖掘服务中,或早或晚的你都会碰到这样的需求:“我们要一个仪表板!”。因为大家都爱仪表板,可能因为真的有用,可能单纯因为它漂亮~这时候,我们不用写任何OLAP实现,用facets就可以完成一个很漂亮很给力的分析引擎。

下面的截图就是从一个社交媒体监控应用上获取的。这个应用不单用ES来搜索和挖掘数据,还通过交互式仪表板提供数据聚合功能。
当用户深入数据,添加一个关键字,使用一个自定义查询,所有的图都会实时更新,这就是facet聚合的工作方式。仪表板上不是数据定期计算好的的静态快照,而是一个用于数据探索的真正的交互式工具。

在本文中,我们将会学习到怎样从ES中获取数据,然后怎么创建这些图表。

关系聚合(terms facet)的饼图
第一个图,我们用ES中比较简单的termsfacet来做。这个facet会返回一个字段中最常见的词汇和它的计数值。

首先我们先插入一些数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
curl -X DELETE "http://localhost:9200/dashboard"
curl -X POST "http://localhost:9200/dashboard/article" -d ‘
             { "title" : "One",
               "tags"  : ["ruby", "java", "search"]}
‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘
             { "title" : "Two",
               "tags"  : ["java", "search"] }
‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘
             { "title" : "Three",
               "tags"  : ["erlang", "search"] }
‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘
             { "title" : "Four",
               "tags"  : ["search"] }
‘
curl -X POST "http://localhost:9200/dashboard/_refresh"

你们都看到了,我们存储了一些文章的标签,每个文章可以多个标签,数据以JSON格式发送,这也是ES的文档格式。

现在,要知道文档的十大标签,我们只需要简单的请求:

1
2
3
4
5
6
7
8
curl -X POST "http://localhost:9200/dashboard/_search?pretty=true" -d ‘
{
    "query" : { "match_all" : {} },
    "facets" : {
        "tags" : { "terms" : {"field" : "tags", "size" : 10} }
    }
}
‘

你看到了,我接受所有文档,然后定义一个terms facet叫做“tags”。这个请求会返回如下样子的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
    "took" : 2,
    // ... snip ...
    "hits" : {
        "total" : 4,
        // ... snip ...
    },
    "facets" : {
        "tags" : {
            "_type" : "terms",
            "missing" : 1,
            "terms" : [
                { "term" : "search", "count" : 4 },
                { "term" : "java",   "count" : 2 },
                { "term" : "ruby",   "count" : 1 },
                { "term" : "erlang", "count" : 1 }
            ]
        }
    }
}

JSON中facets部分是我们关心的,特别是facets.tags.terms数组。它告诉我们有四篇文章打了search标签,两篇java标签,等等…….(当然,我们或许应该给请求添加一个size参数跳过前面的结果)

这种比例类型的数据最合适的可视化方案就是饼图,或者它的变体:油炸圈饼图。
我们将使用Protovis一个JavaScript的数据可视化工具集。Protovis是100%开源的,你可以想象它是数据可视化方面的RoR。和其他类似工具形成鲜明对比的是,它没有附带一组图标类型来供你“选择”。而是定义了一组原语和一个灵活的DSL,这样你可以非常简单的创建自定义的可视化。创建饼图就非常简单。

因为ES返回的是JSON数据,我们可以通过Ajax调用加载它。不要忘记你可以clone或者下载实例的全部源代码。

首先需要一个HTML文件来容纳图标然后从ES里加载数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!DOCTYPE html>
<html>
<head>
    <title>ElasticSearch Terms Facet Donut Chart</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <!-- Load JS libraries -->
    <script src="jquery-1.5.1.min.js"></script>
    <script src="protovis-r3.2.js"></script>
    <script src="donut.js"></script>
    <script>
        $( function() { load_data(); });
        var load_data = function() {
            $.ajax({   url: ‘http://localhost:9200/dashboard/article/_search?pretty=true‘
                     , type: ‘POST‘
                     , data : JSON.stringify({
                           "query" : { "match_all" : {} },
                           "facets" : {
                               "tags" : {
                                   "terms" : {
                                       "field" : "tags",
                                       "size"  : "10"
                                   }
                               }
                           }
                       })
                     , dataType : ‘json‘
                     , processData: false
                     , success: function(json, statusText, xhr) {
                           return display_chart(json);
                       }
                     , error: function(xhr, message, error) {
                           console.error("Error while loading data from ElasticSearch", message);
                           throw(error);
                       }
            });
            var display_chart = function(json) {
                Donut().data(json.facets.tags.terms).draw();
            };
        };
    </script>
</head>
<body>
  <!-- Placeholder for the chart -->
  <div id="chart"></div>
</body>
</html>

文档加载后,我们通过Ajax收到和之前curl测试中一样的facet。在jQuery的Ajaxcallback里我们通过封装的display_chart()把返回的JSON传给Donut()函数.

Donut()函数及注释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
var Donut = function(dom_id) {
    if (‘undefined‘ == typeof dom_id)  {                // Set the default DOM element ID to bind
        dom_id = ‘chart‘;
    }
    var data = function(json) {                         // Set the data for the chart
        this.data = json;
        return this;
    };
    var draw = function() {
        var entries = this.data.sort( function(a, b) {  // Sort the data by term names, so the
            return a.term < b.term ? -1 : 1;            // color scheme for wedges is preserved
        }),                                             // with any order
        values  = pv.map(entries, function(e) {         // Create an array holding just the counts
            return e.count;
        });
        // console.log(‘Drawing‘, entries, values);
        var w = 200,                                    // Dimensions and color scheme for the chart
            h = 200,
            colors = pv.Colors.category10().range();
        var vis = new pv.Panel()                        // Create the basis panel
            .width(w)
            .height(h)
            .margin(0, 0, 0, 0);
        vis.add(pv.Wedge)                               // Create the "wedges" of the chart
            .def("active", -1)                          // Auxiliary variable to hold mouse over state
            .data( pv.normalize(values) )               // Pass the normalized data to Protovis
            .left(w/3)                                  // Set-up chart position and dimension
            .top(w/3)
            .outerRadius(w/3)
            .innerRadius(15)                            // Create a "donut hole" in the center
            .angle( function(d) {                       // Compute the "width" of the wedge
                return d * 2 * Math.PI;
             })
            .strokeStyle("#fff")                        // Add white stroke
            .event("mouseover", function() {            // On "mouse over", set the "wedge" as active
                this.active(this.index);
                this.cursor(‘pointer‘);
                return this.root.render();
             })
            .event("mouseout",  function() {            // On "mouse out", clear the active state
                this.active(-1);
                return this.root.render();
            })
            .event("mousedown", function(d) {           // On "mouse down", perform action,
                var term = entries[this.index].term;    // such as filtering the results...
                return (alert("Filter the results by ‘"+term+"‘"));
            })
            .anchor("right").add(pv.Dot)                // Add the left part of he "inline" label,
                                                        // displayed inside the donut "hole"
            .visible( function() {                      // The label is visible when its wedge is active
                return this.parent.children[0]
                       .active() == this.index;
            })
            .fillStyle("#222")
            .lineWidth(0)
            .radius(14)
            .anchor("center").add(pv.Bar)               // Add the middle part of the label
            .fillStyle("#222")
            .width(function(d) {                        // Compute width:
                return (d*100).toFixed(1)               // add pixels for percents
                              .toString().length*4 +
                       10 +                             // add pixels for glyphs (%, etc)
                       entries[this.index]              // add pixels for letters (very rough)
                           .term.length*9;
            })
            .height(28)
            .top((w/3)-14)
            .anchor("right").add(pv.Dot)                // Add the right part of the label
            .fillStyle("#222")
            .lineWidth(0)
            .radius(14)
            .parent.children[2].anchor("left")          // Add the text to label
                   .add(pv.Label)
            .left((w/3)-7)
            .text(function(d) {                         // Combine the text for label
                return (d*100).toFixed(1) + "%" +
                       ‘ ‘ + entries[this.index].term +
                       ‘ (‘ + values[this.index] + ‘)‘;
            })
            .textStyle("#fff")
            .root.canvas(dom_id)                        // Bind the chart to DOM element
            .render();                                  // And render it.
    };
    return {                                            // Create the public API
        data   : data,
        draw   : draw
    };
};

现在你们看到了,一个简单的JSON数据转换,我们就可以创建出丰富的有吸引力的关于我们文章标签分布的可视化图标。完整的例子在这里。

当你使用完全不同的请求,比如显示某个特定作者的文章,或者特定日期内发表的文章,整个可视化都照样正常工作,代码是可以重用的。

日期直方图(date histogram facets)时间线
Protovis让创建另一种常见的可视化类型也非常容易:时间线。任何类型的数据,只要和特定日期相关的,比如文章发表,事件发生,目标达成,都可以被可视化成时间线。
好了,让我们往索引里存一些带有发表日期的文章吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
curl -X DELETE "http://localhost:9200/dashboard"
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "1",  "published" : "2011-01-01" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "2",  "published" : "2011-01-02" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "3",  "published" : "2011-01-02" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "4",  "published" : "2011-01-03" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "5",  "published" : "2011-01-04" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "6",  "published" : "2011-01-04" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "7",  "published" : "2011-01-04" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "8",  "published" : "2011-01-04" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "9",  "published" : "2011-01-10" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "10", "published" : "2011-01-12" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "11", "published" : "2011-01-13" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "12", "published" : "2011-01-14" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "13", "published" : "2011-01-14" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "14", "published" : "2011-01-15" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "15", "published" : "2011-01-20" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "16", "published" : "2011-01-20" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "17", "published" : "2011-01-21" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "18", "published" : "2011-01-22" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "19", "published" : "2011-01-23" }‘
curl -X POST "http://localhost:9200/dashboard/article" -d ‘{ "t" : "20", "published" : "2011-01-24" }‘
curl -X POST "http://localhost:9200/dashboard/_refresh"

我们用ES的date histogram facet来获取文章发表的频率。

1
2
3
4
5
6
7
8
9
10
11
12
13
curl -X POST "http://localhost:9200/dashboard/_search?pretty=true" -d ‘
{
    "query" : { "match_all" : {} },
    "facets" : {
        "published_on" : {
            "date_histogram" : {
                "field"    : "published",
                "interval" : "day"
            }
        }
    }
}
‘

注意我们是怎么设置间隔为天的。这个很容易就可以替换成周,月 ,或者年。

请求会返回像下面这样的JSON:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
    "took" : 2,
    // ... snip ...
    "hits" : {
        "total" : 4,
        // ... snip ...
    },
    "facets" : {
        "published" : {
            "_type" : "histogram",
            "entries" : [
                { "time" : 1293840000000, "count" : 1 },
                { "time" : 1293926400000, "count" : 2 }
                // ... snip ...
            ]
        }
    }
}

我们要注意的是facets.published.entries数组,和上面的例子一样。同样需要一个HTML页来容纳图标和加载数据。机制既然一样,代码就直接看这里吧。

既然已经有了JSON数据,用protovis创建时间线就很简单了,用一个自定义的area chart即可。

完整带注释的Timeline()函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
var Timeline = function(dom_id) {
    if (‘undefined‘ == typeof dom_id) {                 // Set the default DOM element ID to bind
        dom_id = ‘chart‘;
    }
    var data = function(json) {                         // Set the data for the chart
        this.data = json;
        return this;
    };
    var draw = function() {
        var entries = this.data;                        // Set-up the data
            entries.push({                              // Add the last "blank" entry for proper
              count : entries[entries.length-1].count   // timeline ending
            });
        // console.log(‘Drawing, ‘, entries);
        var w = 600,                                    // Set-up dimensions and scales for the chart
            h = 100,
            max = pv.max(entries, function(d) {return d.count;}),
            x = pv.Scale.linear(0, entries.length-1).range(0, w),
            y = pv.Scale.linear(0, max).range(0, h);
        var vis = new pv.Panel()                        // Create the basis panel
            .width(w)
            .height(h)
            .bottom(20)
            .left(20)
            .right(40)
            .top(40);
         vis.add(pv.Label)                              // Add the chart legend at top left
            .top(-20)
            .text(function() {
                 var first = new Date(entries[0].time);
                 var last  = new Date(entries[entries.length-2].time);
                 return "Articles published between " +
                     [ first.getDate(),
                       first.getMonth() + 1,
                       first.getFullYear()
                     ].join("/") +
                     " and " +
                     [ last.getDate(),
                       last.getMonth() + 1,
                       last.getFullYear()
                     ].join("/");
             })
            .textStyle("#B1B1B1")
         vis.add(pv.Rule)                               // Add the X-ticks
            .data(entries)
            .visible(function(d) {return d.time;})
            .left(function() { return x(this.index); })
            .bottom(-15)
            .height(15)
            .strokeStyle("#33A3E1")
            .anchor("right").add(pv.Label)              // Add the tick label (DD/MM)
            .text(function(d) {
                 var date = new Date(d.time);
                 return [
                     date.getDate(),
                     date.getMonth() + 1
                 ].join(‘/‘);
             })
            .textStyle("#2C90C8")
            .textMargin("5")
         vis.add(pv.Rule)                               // Add the Y-ticks
            .data(y.ticks(max))                         // Compute tick levels based on the "max" value
            .bottom(y)
            .strokeStyle("#eee")
            .anchor("left").add(pv.Label)
                .text(y.tickFormat)
                .textStyle("#c0c0c0")
        vis.add(pv.Panel)                               // Add container panel for the chart
           .add(pv.Area)                                // Add the area segments for each entry
           .def("active", -1)                           // Auxiliary variable to hold mouse state
           .data(entries)                               // Pass the data to Protovis
           .bottom(0)
           .left(function(d) {return x(this.index);})   // Compute x-axis based on scale
           .height(function(d) {return y(d.count);})    // Compute y-axis based on scale
           .interpolate(‘cardinal‘)                     // Make the chart curve smooth
           .segmented(true)                             // Divide into "segments" (for interactivity)
           .fillStyle("#79D0F3")
           .event("mouseover", function() {             // On "mouse over", set segment as active
               this.active(this.index);
               return this.root.render();
           })
           .event("mouseout",  function() {             // On "mouse out", clear the active state
               this.active(-1);
               return this.root.render();
           })
           .event("mousedown", function(d) {            // On "mouse down", perform action,
               var time = entries[this.index].time;     // eg filtering the results...
               return (alert("Timestamp: ‘"+time+"‘"));
           })
           .anchor("top").add(pv.Line)                  // Add thick stroke to the chart
           .lineWidth(3)
           .strokeStyle(‘#33A3E1‘)
           .anchor("top").add(pv.Dot)                   // Add the circle "label" displaying
                                                        // the count for this day
           .visible( function() {                       // The label is only visible when
               return this.parent.children[0]           // its segment is active
                          .active() == this.index;
            })
           .left(function(d) { return x(this.index); })
           .bottom(function(d) { return y(d.count); })
           .fillStyle("#33A3E1")
           .lineWidth(0)
           .radius(14)
           .anchor("center").add(pv.Label)             // Add text to the label
           .text(function(d) {return d.count;})
           .textStyle("#E7EFF4")
           .root.canvas(dom_id)                        // Bind the chart to DOM element
           .render();                                  // And render it.
    };
    return {                                            // Create the public API
        data   : data,
        draw   : draw
    };
};

完整示例代码在这里。不过先去下载protovis提供的关于area的原始文档,然后观察当你修改interpolate(‘cardinal’)成interpolate(‘step-after’)后发生了什么。对于多个facet,画叠加的区域图,添加交互性,然后完全定制可视化应该都不是什么问题了。

重要的是注意,这个图表完全是根据你传递给ES的请求做出的响应,使得你有可能做到简单立刻的完成某项指标的可视化需求。比如“显示这个作者在这个主题上最近三个月的出版频率”。只需要提交这样的请求就够了:

1
author:John AND topic:Search AND published:[2011-03-01 TO 2011-05-31]

总结
当你需要为复杂的自定义查询做一个丰富的交互式的数据可视化时,使用ES的facets应该是最容易的办法之一,你只需要传递ES的JSON响应给Protovis这样的工具就好了。

通过模仿本文中的方法和代码,你可以在几小时内给你的数据跑通一个示例。

REFERENECE : http://www.chepoo.com/elasticsearch-protovis.html | IT技术精华网

时间: 2024-12-20 12:19:26

用ElasticSearch和Protovis实现数据可视化的相关文章

55种开源数据可视化工具简介

55种开源数据可视化工具简介 雪姬 2015-04-21 11:47:56 数据可视化 评论(2)   数据时代数据可视化成为理解和表达数据的有效甚至是唯一的手段. 一共56个,盘点最实用的大数据可视化分析工具 工欲善其事必先利其器,本文对55个流行的数据可视化工具开源协议,主页,文档,案例等资源的进行简单介绍,其中包括著名的D3.js,R,Gephi,Raphaël,Processing.js,Tableau Public,Google Chart Tools,Arbor.js等,资料来源ht

55个最实用大数据可视化分析工具

该文转自[IT168 技术] 近年来,随着云和大数据时代的来临,数据可视化产品已经不再满足于使用传统的数据可视化工具来对数据仓库中的数据抽取.归纳并简单的展现.传统的数据可视化工具仅仅将数据加以组合,通过不同的展现方式提供给用户,用于发现数据之间的关联信息.新型的数据可视化产品必须满足互联网爆发的大数据需求,必须快速的收集.筛选.分析.归纳.展现决策者所需要的信息,并根据新增的数据进行实时更新.因此,在大数据时代,数据可视化工具必须具有以下特性: (1)实时性:数据可视化工具必须适应大数据时代数

55个最实用的大数据可视化分析工具

俗话说的好:工欲善其事,必先利其器!一款好的工具可以让你事半功倍,尤其是在大数据时代,更需要强有力的工具通过使数据有意义的方式实现数据可视化,还有数据的可交互性:我们还需要跨学科的团队,而不是单个数据科学家.设计师或数据分析员:我们更需要重新思考我们所知道的数据可视化,图表和图形还只能在一个或两个维度上传递信息, 那么他们怎样才能与其他维度融合到一起深入挖掘大数据呢?此时就需要倚仗大数据可视化(BDV)工具,因此,笔者收集了适合各个平台各种行业的多个图表和报表工具,这些工具中不乏有适用于NET.

针对Elasticsearch的开源分析及可视化平台——Kibana

Kibana是一个针对Elasticsearch的开源分析及可视化平台,用来搜索.查看交互存储在Elasticsearch索引中的数据.使用Kibana,可以通过各种图表进行高级数据分析及展示. Kibana让海量数据更容易理解.它操作简单,基于浏览器的用户界面可以快速创建仪表板(dashboard)实时显示Elasticsearch查询动态. 在云市不需要复杂部署安装,一键使用Kibana.设置Kibana也非常简单,无需编码或者额外的基础架构,一分钟只能就能启动Elasticsearch索引

前端数据可视化

原文 在大数据时代,很多时候我们需要在网页中显示数据统计报表,从而能很直观地了解数据的走向,开发人员很多时候需要使用图表来表现一些数据.随着Web技术的发展,从传统只能依靠于flash.IE的vml,各个浏览器尚不统一的svg,到如今规范统一的canvas.svg为代表的html5技术,表现点.线.面要素的技术已经越来越规范成熟.我把前端数据可视化分为了五种:1.图表2.图谱3.地图4.关系图5.立体图我将按照顺序介绍62款前端可视化插件,下面就分享下34款图表插件:1.amchartsurl:

最实用的大数据可视化分析工具汇总(3/4)

一款好的工具可以让你事半功倍,尤其是在大数据时代,更需要强有力的工具通过使数据有意义的方式实现数据可视化.这些工具中不乏有适用于.NET.Java.Flash.HTML5.Flex等平台的,也不乏有适用于常规图表报表.甘特图.流程图.金融图表.工控图表.数据透视表.OLAP多维分析等图表报表开发的,下面就来看看全球备受欢迎的的可视化工具都有哪些吧! 二十九.Gantti Gantti是一个开源的PHP类,帮助用户即时生成Gantti图表.使用Gantti创建图表无需使用JavaScript,纯H

前端数据可视化插件(一)图表

摘要: 在大数据时代,很多时候我们需要在网页中显示数据统计报表,从而能很直观地了解数据的走向,开发人员很多时候需要使用图表来表现一些数据.随着Web技术的发展,从传统只能依靠于flash.IE的vml,各个浏览器尚不统一的svg,到如今规范统一的canvas.svg为代表的html5技术,表现点.线.面要素的技术已经越来越规范成熟.我把前端数据可视化分为了五种: 图表 图谱 地图 关系图 立体图 我将按照顺序介绍64款前端可视化插件,下面就分享下34款图表插件 amchartsurl: http

大数据可视化分析工具推荐

各个互联网公司通过大量的用户数据.信息进行统计分析,而这些大量繁杂的数据在经过可视化工具处理后,就能以图形化的形式展现在用户面前,清晰直观.随着各种数据的增加,这种可视化工具越来越得到开发者们的欢迎. 下面推荐25款可视化工具供大家选择和使用. 1.Modest Maps Modest Maps是一个轻量级.可扩展的.可定制的和免费的地图显示类库,这个类库能帮助开发人员在他们自己的项目里能够与地图进行交互.ModestMaps提供一个核心健壮的带有很多hooks与附加functionality函

ROCKET 数据可视化可以如此简单

Rocket(http://www.zhoushankj.com) 致力于使数据友好并且充满活力. 简单!简单!简单!重要的事情说三遍.图形化操作,布局灵活,所见即所得.通过拖.拉.拽就可以灵活布局. 所有的属性配置均是所见即所得,不用操作完了还要刷新还要等待.图表丰富 涵盖各行业图表,满足各种需求. 柱图.折线图.饼图.散点图.地图.雷达图.仪表盘.漏斗图.水球图.表格.列表.富文本.标题... 还有各种常用形式的快捷操作噢,看下面而且Rocket是支持定制图表的噢!!! 多数据源 支持关系型