JavaScript 图表入门指南(四)
十、jqPlot 条形图
Abstract
在这一章中,你将处理另一大类图表:条形图。在前一章中,您已经了解了 jqPlot 中默认图表类型——折线图的特征。现在,使用 BarRenderer 插件,您将发现主 jqPlot 对象的结构是如何随着新的属性和对象而逐渐丰富的。通过实际例子,你会看到如何用rendererOptions改变属性和对象属性的值。
在这一章中,你将处理另一大类图表:条形图。在前一章中,您已经了解了 jqPlot 中默认图表类型——折线图的特征。现在,使用 BarRenderer 插件,您将发现主 jqPlot 对象的结构是如何随着新的属性和对象而逐渐丰富的。通过实际例子,你会看到如何用rendererOptions改变属性和对象属性的值。
有时,使用同一组数据可以获得不同的表示。学习如何选择最适合你需求的表现形式是本书的基本目标之一。为此,使用一组数据,您将看到如何从分组条形图切换到堆叠条形图,在这两种情况下都可以在垂直和水平表示之间进行选择。
此外,您将了解如何使用 jqPlot 库来表示组合图表,例如,如何同时表示折线图和条形图,以及如何通过降低绘图速度来获得简单但引人注目的动画。,您还将熟悉一种特殊类型的条形图,Marimekko 图,它是由 jqPlot 库以非常令人满意的方式实现的。
在本章的最后一部分,我将介绍 jqPlot 中事件的使用。这是一个复杂的主题,但是由于特殊的 jQuery 函数,您只需几行代码就可以实现显著的交互效果。本章最后给出了这方面的一个典型例子:如何定制工具提示。
使用 BarRenderer 插件创建条形图
当您有一组分为不同类别的数据,并且需要将这些类别相互比较时,条形图可能是最适合您需求的表示形式。您已经看到,在不包含任何插件的情况下,默认情况下传入的数据被解释为连接起来形成一条线的点。为了告诉 jqPlot 输入的数据必须用于绘制条形图,您必须在 HTML 页面的<head>部分放置一组插件:
<script type="text/javascript" src="../src/plugins/jqplot.dateAxisRenderer.min.js"></script>
<script type="text/javascript"
src="../src/plugins/jqplot.canvasAxisTickRenderer.min.js"></script>
<script type="text/javascript" src="../src/plugins/jqplot.categoryAxisRenderer.min.js"></script>
<script type="text/javascript" src="../src/plugins/jqplot.barRenderer.min.js"></script>
或者,如果您更喜欢使用内容交付网络(CDN)服务,您可以按照以下方式进行:
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.dateAxisRenderer.min.js
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasAxisTickRenderer.min.js
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.categoryAxisRenderer.min.js
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.barRenderer.min.js
要设置输入数据以便在条形图中使用,您必须插入一个格式为[label,y]的数组,其中 x 不再出现,但一个指示性标签取而代之。这个标签通常是一个字符串值。事实上,当我们谈论条形图时,我们不再对跟踪一个变量(y 值)相对于另一个变量(x 值)的趋势感兴趣,而是对比较数据(标签)的类别或组感兴趣。对于此示例,您将使用五个组,每个组代表一个州,作为标签报告:
var data = [['Germany', 12], ['Italy', 8], ['Spain', 6], ['France', 10], ['UK', 7]];
一旦包含了 BarRenderer 插件,就必须激活它,将它的引用分配给series对象中的renderer属性(参见清单 10-1)。您将对第二个插件 CategoryAxisRenderer 做同样的事情,只为xaxis对象指定它。
清单 10-1。ch10_01a.html
var options = {
title: 'Foreign Customers',
series:[{renderer:$.jqplot.BarRenderer}],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer
}
}
};
$.jqplot ('myChart', [data], options);
接下来,在 HTML 页面的<body>部分,添加以下行:
<div id="myChart" style="height:300px; width:500px;"></div>
这样,你就得到一个简单的条形图,如图 10-1 所示。数据数组中包含的每个状态都由一个蓝色条表示,其高度对应于 y 值。
图 10-1。
A simple bar chart
旋转轴刻度标签
通常,可能需要或希望旋转 x 轴上报告的刻度标签。例如,文本可能太长而无法报告,为了保持标签的可读性,您需要将它们写成以一定角度倾斜。这种旋转是通过包含 CanvasTextRenderer 插件实现的:
<script type="text/javascript" src="../src/plugins/jqplot.canvasTextRenderer.min.js"></script>
或者,如果您更喜欢使用 CDN 服务,您可以按如下方式操作:
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasTextRenderer.min.js></剧本>
这里,简单地包含插件是不够的;您还必须通过将它的引用传递给tickRenderer属性来激活它,如清单 10-2 所示。然后,您需要在tickOptions中指定某些属性:您将angle属性设置为–30 度。使用此值,您可以指示文本相对于 x 轴的倾斜度。如果该值为正值,文本将顺时针方向旋转;如果为负(如清单 10-2 所示),则逆时针旋转。
清单 10-2。ch10_01b.html
var options = {
title: 'Foreign customers',
series:[{ renderer: $.jqplot.BarRenderer }],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
tickOptions: {
angle: -30,
fontSize: '10pt'
}
}
}
};
$.jqplot ('myChart', [data], options);
如果您现在在浏览器中加载网页,在图表的底部,您会看到所有标签都相对于 x 轴逆时针旋转(见图 10-2 )。
图 10-2。
A bar chart with rotated labels on the x axis
修改条形之间的间距
使用条形图时,最常见的需求可能是改变条形之间的间距。这个间距可以通过设置不同值的barMargin属性来直接调整。因为这个属性不属于jqplot对象,而是特定于 BarRenderer 插件,所以您必须在rendererOptions中指定它。每当您包含一个渲染器插件时,您也包含了一组不属于原始jqplot对象的全新属性。所以,如果你想要一个不同于这些属性的默认值,你需要在rendererOptions中写这个属性,设置新的值。例如,让我们在条形之间应用一个 30 像素的空间,如清单 10-3 所示。
清单 10-3。ch10_02.html
var options = {
title: 'Foreign Customers',
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
rendererOptions: {
barMargin: 30
},
},
axes: {
因为图表的宽度保持不变,作为将barMargin属性增加到 30 的结果,所有的条形都比以前窄了(见图 10-3 )。
图 10-3。
The space between bars is adjustable with a new property introduced by the plug-in
在条形顶部添加值
jqPlot 库允许您处理偶数点标签。虽然您也可以在折线图中使用它们,但是点标签是条形图的重要组成部分。如果激活点标签,将在条形上方明确显示 y 值,从而增强值的可读性,尤其是对于堆积条形图。要激活此功能,您需要包括另一个插件:
<script type="text/javascript" src="../src/plugins/jqplot.pointLabels.min.js"></script>
或者,如果您更喜欢使用 CDN 服务,您可以按如下方式操作:
<script type="text/javascript"
src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.pointLabels.min.js
您可能已经注意到 PointLabels 不是渲染器插件,因此它已经处于活动状态。这一次,不需要在renderer属性中传递引用。这个过程非常简单快捷:在options中,你将pointLabels对象的show属性设置为'true'(见清单 10-4)。
清单 10-4。ch10_03.html
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
pointLabels: { show: true }
},
如图 10-4 所示,激活点标签后,y 值将出现在每个条的上方。
图 10-4。
A bar chart reporting the y value above each bar
具有负值的条形
一般来说,我们习惯于看到所有 y 值都为正的条形图,但情况并非总是如此。但是,如果您想在条形图上表示负值,就必须小心。如果您尝试使用包含负值的输入数据数组,如下例所示
var data = [['Germany', -12], ['Italy', -8], ['Spain', -6], ['France', -10], ['UK', -7]];
你得到了图 10-5 中的条形图。
图 10-5。
This bar chart has interpreted the negative values badly
这不是你真正想要的。这些条被画出来,好像它们仍然是正的。只有点标签正确显示 y 值。此外,y 轴上报告的值与条形的表示不相关,条形应该从顶部开始,向下到 y 轴上相应的负值。为了克服所有这些问题,您需要将fillToZero属性设置为'true',这是一个属于 BarRenderer 插件的属性;因此,你必须在rendererOptions中指定这一点(见清单 10-5)。
清单 10-5。ch10_04a.html
var options = {
title: 'Foreign Customers',
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
rendererOptions: { fillToZero: true },
pointLabels: { show: true }
},
...
现在,jqPlot 可以正确地表示负棒线(见图 10-6 )。
图 10-6。
A simple bar chart with negative values
当正值和负值都出现在同一个条形图中时,此功能更容易理解:
var data = [['Germany', -12], ['Italy', 8], ['Spain', -6], ['France', 10], ['UK', -7]];
正如你在图 10-7 中所看到的,稍微深一点的颜色区分了具有负值的条形。
图 10-7。
A simple bar chart with positive and negative values
包含多组数据的条形图
你已经看到了折线图是如何管理多个序列的,所以你可能认为条形图也有同样的可能性。在从单系列到多系列的转换中,您需要对输入数据的组织方式进行一些更改。因此,您从单个序列的输入数据数组的格式开始:
var data = [['Germany', 12], ['Italy', 8], ['Spain', 6], ['France', 10], ['UK', 7]];
首先,您必须指定一个定制的ticks数组,它必须包含数据的组或类别的名称(您想要在 x 轴上报告的值)。刻度数应该与每个系列中 y 值的数量相匹配。
var ticks = ['Germany', 'Italy', 'Spain', 'France', 'UK'];
因为您正在处理多个系列,所以您可以指定至少三个数据系列。每个系列代表数据的进一步分类,因此您可以通过报告数据所属组的标签来区分它们。现在,你只需要为每个序列插入 y 值(来自ticks数组),如清单 10-6 所示,假设每个序列的 x 值是相同的。
清单 10-6。ch10_05.html
var data = [12, 8, 6, 10, 7]; // Electronics customers
var data2 = [14, 12, 4, 14, 11]; // Software customers
var data3 = [18, 10, 5, 9, 9]; // Mechanics customers
关于表示系列的名称,你必须在series对象中指定它们(见清单 10-7),将它们逐个分配给每个系列的label属性。
清单 10-7。ch10_05.html
var options = {
title: 'Foreign Customers',
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
},
series:[
{label: 'Electronics'},
{label: 'Software'},
{label: 'Mechanics'}
],
axes: {
...
现在,和往常一样,在options中,你将ticks数组赋给xaxis对象的ticks属性(见清单 10-8)。这样,您已经将 x 轴上生成的每个记号分配给数组中包含的一个字符串。
清单 10-8。ch10_05.html
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
}
},
您已经看到,处理多个系列只是增加了数据的进一步分类。除了划分到 x 轴上表示的类别之外,数据还划分到多个系列中,每个系列表示一个不同的组。为了区分一个系列和另一个系列,需要用不同的颜色绘制相应的线条。但是,如果您就此打住,观察此图表的用户将不会获得任何关于哪个组由哪种颜色表示的信息。因此需要引入一个图例(见清单 10-9)。
清单 10-9。ch10_05.html
var options = {
title: 'Foreign Customers',
seriesDefaults: {
renderer: $.jqplot.BarRenderer,
},
series:[
{label: 'Electronics'},
{label: 'Software'},
{label: 'Mechanics'}
],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
}
},
legend: {
show: true,
placement: 'outsideGrid',
location: 'e'
}
};
$.jqplot ('myChart', [data, data2, data3], options);
这样你就得到一个多系列条形图,如图 10-8 所示。正如您所看到的,当您使用多个系列时,您必须使用不同的颜色来区分它们。
图 10-8。
A multiseries bar chart containing a legend
垂直和水平条形图
查看图 10-8 中的图表,您会注意到每组都用一种颜色表示。默认情况下,分配的颜色遵循 jqPlot 内部指定的顺序,该顺序反映在折线图中。每个国家在 x 轴上的区段中有三列,每个区段由网格线界定。
这种条形图一般定义为垂直条形图。没有什么可以阻止我们用水平方向的条来表示相同的输入数据,但是这里也需要对输入数据数组的格式进行修改。在这种情况下,有必要使用[y,n]对,其中n是分配给一个字符串的整数值(见清单 10-10)。字符串是包含在ticks数组中的标签描述,n是它的索引。
清单 10-10。ch10_06.html
var data = [[12, 1], [8, 2], [6, 3], [10, 4], [7, 5]];
var data2 = [[14, 1], [12, 2], [4, 3], [14, 4], [11, 5]];
var data3 = [[18, 1], [10, 2], [5, 3], [9, 4], [9, 5]];
var ticks = ['Germany', 'Italy', 'Spain', 'France', 'UK'];
更改输入数据数组的格式后,必须将barDirection属性设置为'horizontal' ( 'vertical'是默认值)。如清单 10-11 所示,您必须在seriesDefaults中这样做,以便将水平方向应用于所有系列。这一次,需要将ticks数组赋给yaxis对象中的ticks属性,而不是像以前一样赋给xaxis对象。
清单 10-11。ch10_06.html
var options = {
title: 'Foreign Customers',
seriesDefaults:{
renderer: $.jqplot.BarRenderer,
rendererOptions: {
barDirection: 'horizontal'
}
},
series:[
{label: 'Electronics'},
{label: 'Software'},
{label: 'Mechanics'}
],
axes: {
yaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
}
},
legend: {
show: true,
placement: 'outsideGrid',
location: 'e'
}
};
$.jqplot ('myChart', [data, data2, data3], options);
现在,你得到了如图 10-9 所示的水平多系列条形图。
图 10-9。
A horizontal multiseries bar chart
垂直堆积条形图
当您需要将数据系列分解成其组成部分,同时保留将这些数据系列作为一个整体进行比较的能力时,您必须使用堆积图。jqPlot 库支持这样的图表。对于堆积条形图,添加点标签尤其合适,这样可以使图表更具可读性。报告的值是累积的,也就是堆栈中底层条形的总和,如清单 10-12 所示。
清单 10-12。ch10_07.html
var data = [12, 8, 6, 10, 7];
var data2 = [14, 12, 4, 14, 11];
var data3 = [18, 10, 5, 9, 9];
var ticks = ['Germany', 'Italy', 'Spain', 'France', 'UK'];
var options = {
title: 'Foreign Customers',
stackSeries: true,
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
pointLabels: { show: true,location: 's' }
},
series:[
{label: 'Electronics'},
{label: 'Software'},
{label: 'Mechanics'}
],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
}
},
legend: {
show: true,
placement: 'outsideGrid',
location: 'e'
}
};
$.jqplot ('myChart', [data, data2, data3], options);
通过设置pointLabels属性的值,可以指定显示点标签的位置:'n'、's'、' e'、'w'、'ne'、'nw'、'se'或'sw'。这些值应该被解释为指示绘制点标签的方向的基本点,相对于条形的顶部。在本例中,您选择's' (south)在条形顶部下方的彩色区域显示数值,如图 10-10 所示。
图 10-10。
A vertical multiseries stacked bar chart
水平堆叠条形图
同样,您可以创建水平堆积条形图。在这种情况下,为了表示线段内的点标签,你需要将它们设置为'w' (west)(见清单 10-13)。
清单 10-13。ch10_08.html
var data = [[12, 1], [8, 2], [6, 3], [10, 4], [7, 5]];
var data2 = [[14, 1], [12, 2], [4, 3], [14, 4], [11, 5]];
var data3 = [[18, 1], [10, 2], [5, 3], [9, 4], [9, 5]];
var ticks = ['Germany', 'Italy', 'Spain', 'France', 'UK'];
var options = {
title: 'Foreign Customers',
stackSeries: true,
seriesDefaults:{
renderer: $.jqplot.BarRenderer,
rendererOptions: {
barDirection: 'horizontal'
},
pointLabels: { show: true, location: 'w' }
},
series:[
{label: 'Electronics'},
{label: 'Software'},
{label: 'Mechanics'}
],
axes: {
yaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
}
},
legend: {
show: true,
placement: 'outsideGrid',
location: 'e'
}
};
$.jqplot ('myChart', [data, data2, data3], options);
在图 10-11 中,您可以看到数值是如何显示在靠近条形末端(西部)的彩色区域。
图 10-11。
A horizontal multiseries stacked bar chart
组合图表:条形图中的线条
组合图表是在单个图表中组合两种或多种图表类型的图表。在下面的示例中,您将考虑在一个图表中同时显示条形图系列和折线图系列。对于这种表示,您需要使用一个双 y 轴。每个系列都有自己的单位和大小,因此必须符合这些轴之一。因此,你必须使用主轴和副轴。您还必须激活自动缩放功能,以便强制 y 轴对齐刻度线,从而获得一致的网格线。
因此,让我们定义两个输入序列(见清单 10-14)。数组data包含要显示为条形图的[label1,y1]对数值。数组line包含要显示为折线图的[label2,y2]对数值。
清单 10-14。ch10_09.html
var data = [['Germany', 12], ['Italy', 8], ['Spain' ,6], ['France', 10], ['UK', 7]];
var line = [['BMW', 45], ['AlfaRomeo', 30], ['Seat', 24],['Renault', 36], ['Mini', 30]];
这个案例有助于理解使用多个 y 轴的效用(jqPlot 最多支持九个 y 轴和两个 x 轴)。这里,您有两个序列,它们的顺序由您在函数$.jqplot()中作为第二个参数传递它们的顺序来定义:
$.jqplot ('myChart', [data, line], options);
数组data(用于条形图的系列)排在第一位,数组line(用于折线图)排在第二位。这一点非常重要。建立了这个顺序后,在options中,您需要在series对象中指定两个元素,如清单 10-15 所示。仅在第一个元素中,您激活了 BarRenderer 插件,而在第二个元素中,您定义了两个辅助轴:x2axis和y2axis。现在,您有四个轴可以使用,因此,您必须在axes对象中指定它们。在yaxis和y2axis上,您必须激活自动缩放。
清单 10-15。ch10_09.html
var options = {
title: 'Foreign customers',
series:[{renderer: $.jqplot.BarRenderer},
{
xaxis: 'x2axis',
yaxis: 'y2axis'
}],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer
},
x2axis: {
renderer: $.jqplot.CategoryAxisRenderer
},
yaxis: {
autoscale: true
},
y2axis: {
autoscale: true,
renderOptions: {
alignTicks: true
}
}
}
};
其结果是图 10-12 中的图表,同时包含条和线。
图 10-12。
A line chart combined with a bar chart
动画情节
jqPlot 库还为您提供了动画图表的能力。为此,您不需要任何额外的插件。从前面的例子开始,组合图(见清单 10-15),你可以为每个系列分配不同的速度。在定义绘图速度时,就好像您正在减慢浏览器创建图表元素的速度。这会在绘制过程中产生动态效果,从而创建动画。此外,通过分配不同的速度给不同的部分,你可以获得非常好的效果。
正如我们在清单 10-16 中看到的,在options中,您必须通过将animate和animateReplot属性设置为'true'来激活动画功能。然后,使用数值(毫秒数)为每个系列定义不同的速度。
清单 10-16。ch10_10.html
var options = {
animate: true,
animateReplot: true,
title: 'Foreign Customers',
series:[{
renderer: $.jqplot.BarRenderer,
rendererOptions: {
animation: {
speed: 2500
},
}
},{
xaxis: 'x2axis',
yaxis: 'y2axis',
rendererOptions: {
animation: {
speed: 2500
},
}
}],
axes: {
xaxis: { renderer: $.jqplot.CategoryAxisRenderer },
x2axis: {renderer: $.jqplot.CategoryAxisRenderer },
yaxis: { autoscale:true, numberTicks: 6 },
y2axis: { autoscale:true, numberTicks: 6 }
}
};
当您在浏览器中加载此图表时,您会获得一个动画,其中缓慢而平滑地绘制了一个折线图和一个条形图。图 10-13 显示了动画如何在连续的阶段中发展。折线图是按照数据点的顺序从左到右绘制的,同时,条形会增长到各自的 y 值。
图 10-13。
An animated combined line–bar chart
马里梅科海图
一种可以从条形图派生出来的图表是所谓的 Marimekko 图表(也称为 mekko 图表),因其与 Marimekko 印刷品相似而得名。这种图表已经被商业界所采用。Marimekko 图表本质上是堆叠柱形图。然而,这里所有的栅栏都是一样高的。此外,条形之间没有空间,条形被分成几段,其高度与百分比相关(见图 10-14 )。
Marimekko 图表旨在报告两个轴上的百分比值:x 轴上每个条形所在位置的每个类别所占的百分比,以及 y 轴上每个类别所占的百分比,由每个条形所划分的段表示。
图 10-14。
A Marimekko pattern
jqPlot 允许您使用两个特定的插件来开发这种图表:MekkoRenderer 和 MekkoAxisRenderer:
<script class="include" type="text/javascript"
src="../src/plugins/jqplot.mekkoRenderer.min.js"></script>
<script class="include" type="text/javascript"
src="../src/plugins/jqplot.mekkoAxisRenderer.min.js"></script>
<script class="include" type="text/javascript"
src="../src/plugins/jqplot.canvasTextRenderer.min.js"></script>
<script class="include" type="text/javascript"
src="../src/plugins/jqplot.canvasAxisLabelRenderer.min.js"></script>
或者,如果您更喜欢使用 CDN 服务,您可以按如下方式操作:
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.mekkoRenderer.min.js></剧本>
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.mekkoAxisRenderer.min.js></剧本>
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasTextRenderer.min.js></剧本>
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.canvasAxisLabelRenderer.min.js></剧本>
除了这两个插件,您还需要包括 CanvasTextRenderer 和 CanvasAxisLabelRenderer。为图表中的每个条形指定数据。您可以将数据指定为 y 值数组或[标签,值]对数组。在清单 10-17 中,注意标签只用于第一个系列;后续系列的标签将被忽略。
清单 10-17。ch10_11.html
var bar1 = [['bananas', 10],['apples', 7],['pears', 4],
['peaches', 8],['lemons', 7],['oranges',5]];
var bar2 = [9, 5, 8, 11, 9, 4];
var bar3 = [11, 4, 7, 3, 8, 7];
var bar4 = [5, 8, 11, 4, 12, 3];
var barLabels = ['Italy', 'Spain', 'France', 'Greece'];
在options中,您激活 MekkoRenderer 插件,将其分配给seriesDefaults对象。通过将legend对象的show属性设置为'true',可以在图表的右侧添加一个图例。如果您想在 x 轴下方放置每个条形的标签,您必须将barLabels数组分配给 x 轴上的barLabels属性。
清单 10-18。ch10 _ 11 . html[无标注]
var options = {
title: 'Fruit Consumption in 2012',
seriesDefaults:{renderer: $.jqplot.MekkoRenderer},
legend:{show: true},
axesDefaults:{
renderer: $.jqplot.MekkoAxisRenderer
},
axes:{
xaxis:{
barLabels: barLabels,
tickOptions:{formatString: '%d'}
}
}
};
$.jqplot('myChart', [bar1, bar2, bar3, bar4], options);
现在,你得到了如图 10-15 所示的 Mekko 图。
图 10-15。
A Mekko chart
条形图事件
在条形图中,如果您将光标移动到一个条上,默认情况下它会高亮显示。当鼠标悬停在某个条上时,以及当您单击某个条时,都会触发事件。捕捉和管理这些事件的能力非常重要,jqPlot 库允许您这样做。您可以为不同类型的事件实现特定的响应操作,从而使您的图表更具交互性。您获得的响应可能取决于您找到鼠标指针的位置或您单击的目标。
表 10-1 报告的事件,由于其丰富的元素,适合在条形图中应用。让我们一个一个地看看这些事件。
表 10-1。
Handling Events with the jqPlot Library
| 事件 | 被触发时 | | --- | --- | | `jqplotDataClick` | 在数据点上单击鼠标左键。 | | `jqplotRightClick` | 用鼠标右键单击数据点。 | | `jqplotDataMouseOver` | 你把鼠标放在数据点上。 | | `jqplotDataHighlight` | 数据点被突出显示。 | | `jqplotDataUnhighlight` | 数据点未突出显示。 |jqplotDataClick 事件
本示例显示了jqplotDataClick事件——被点击的序列索引、点及其数据值。
让我们从第一个例子开始,简单的条形图(见清单 10-19)。
清单 10-19。ch10_12.html
var data = [['Germany', 12], ['Italy', 8], ['Spain', 6],
['France', 10], ['UK', 7]];
var options = {
title: 'Foreign Customers',
series:[{renderer: $.jqplot.BarRenderer}],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer
}
}
};
$.jqplot ('myChart', [data], options);
在 jQuery ready()函数中,添加清单 10-20 中的函数。这是一个 jQuery 函数,其中将jqplotDataClick事件与函数的执行绑定在一起。作为参数,该事件接受 jqPlot 对象的一些属性值,如seriesIndex、pointIndex和data。这些值将被转换成一个字符串,并用 jQuery html()函数连接起来。这个 HTML 文本将被发送到网页中的info1元素。
清单 10-20。ch10_12.html
$('#myChart').bind('jqplotDataClick',
function (ev, seriesIndex, pointIndex, data) {
$('#info1').html('series: ' + seriesIndex +
', point: '+pointIndex+', data: '+data);
}
);
现在,您在想要显示带有值的文本的地方添加一个<span>元素。这个元素将显示一个“还没有”的消息,直到你点击一个酒吧。然后,根据所点击的点,新文本将用值替换消息:
<div><span>You clicked: </span><span id="info1">Nothing yet</span></div>
图 10-16 显示了当用户点击“France”栏时触发的事件对应的消息。
图 10-16。
By clicking a bar, you can obtain its values
jqplotRightClick 事件
这个例子涵盖了 jqPlot 提供的另一个事件:jqplotRightClick。这个事件需要在options中显式激活(见清单 10-21)。这导致 jqPlot 在用户右键单击一个栏时触发一个jqplotRightClick事件。
清单 10-21。ch10_13.html
var options = {
title: 'Foreign Customers',
captureRightClick: true,
series:[{renderer: $.jqplot.BarRenderer}],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer
}
}
};
接下来,您需要用清单 10-22 中的函数替换前面的 jqPlot 函数。
清单 10-22。ch10_13.html
$('#myChart').bind('jqplotDataRightClick',
function (ev, seriesIndex, pointIndex, data) {
$('#info1').html('series: ' + seriesIndex +
', point: '+pointIndex+', data: '+data);
}
);
一般效果是一样的,只是这次你要右击而不是左键。右键单击“西班牙”栏会得到图 10-17 中的结果。
图 10-17。
By right-clicking a bar, you obtain its values
其他条形图事件
通常,您可能想要捕获另一个事件:当鼠标停留在一个条上时,jqPlot 触发一个jqplotDataMouseOver事件。当您显式禁用突出显示时,也会生成此事件。当用户将鼠标放在栏上时,该事件将持续触发。相比之下,另一个事件jqplotDataHighlight只触发一次,即当用户第一次将鼠标放在工具栏上时。当用户离开酒吧时,jqPlot 触发第三个事件:jqplotDataUnhighlight。只有启用突出显示时,才会生成后两个事件。
继续上一个例子(见清单 10-22),你用另外两个函数替换捕获jqplotDataClick事件的 jQuery 函数(见清单 10-23)。第一个函数会在您将鼠标放在一个栏上时,立即向info1元素发送一个具有相同值的 HTML 文本。第二个将在您离开工具栏时用'Nothing'替换info1元素中的前一个字符串。
清单 10-23。ch10_14a.html
$('#myChart').bind('jqplotDataHighlight',
function (ev, seriesIndex, pointIndex, data) {
$('#info1').html('series: ' + seriesIndex +
', point: '+pointIndex+', data: '+data);
}
);
$('#myChart').bind('jqplotDataUnhighlight',
function (ev) {
$('#info1').html('Nothing');
}
);
现在,您希望看到jqplotDataMouseOver事件和jqPlotDataHighlight事件之间的行为差异。要理解这种差异,最好的方法就是用一个例子来比较它们。这一次,您将计算当鼠标悬停在一个条上时触发的事件数。为此,定义一个计数器nEvents,将其初始化为 0。正如预期的那样,使用jqPlotDataHighlight事件,每当您将鼠标放在一个条上时,计数器被设置为 1,当您移出该条时,计数器的值为 0。对于jqplotDataMouseOver事件,行为非常不同:计数器持续增加,将光标保持在同一个条上。在这两种情况下,您都使用jqplotDataUnhighlight事件在每次离开酒吧时重置计数器。
首先,您需要更改info1 HTML 元素:
<div><span>Events: </span><span id="info1">Nothing yet</span></div>
然后,为了研究jqplotDataHighlight事件的行为,用清单 10-24 中的两个函数替换这两个 jQuery 函数。
清单 10-24。ch10_14b.html
nEvents = 0;
$('#myChart').bind('jqplotDataHighlight',
function (ev, seriesIndex, pointIndex, data) {
nEvents = nEvents + 1;
$('#info1').html(nEvents);
}
);
$('#myChart').bind('jqplotDataUnhighlight',
function (ev) {
$('#info1').html('Nothing');
nEvents = 0;
}
);
如图 10-18 所示,当鼠标停留在“西班牙”栏上时,计数器给出稳定的 1。
图 10-18。
Counting how many jqPlotDataHighlight events occur
为了研究jqplotDataMouseOver事件的行为,您可以用清单 10-25 中的两个函数替换这两个 jQuery 函数。
清单 10-25。ch10_14c.html
nEvents = 0;
$('#myChart').bind('jqplotDataMouseOver',
function (ev, seriesIndex, pointIndex, data) {
nEvents = nEvents + 1;
$('#info1').html(nEvents);
}
);
$('#myChart').bind('jqplotDataUnhighlight',
function (ev) {
$('#info1').html('Nothing');
nEvents = 0;
}
);
如图 10-19 所示,当鼠标停留在“西班牙”栏上时,计数器不断增加数值。
图 10-19。
Counting how many jqplotDataMouseOver events occur
点按栏以文本形式显示信息
由于 jqPlot 在管理事件方面的潜力,让我们借此机会看一个常见的案例。通过单击一个条形,您可以获得有关该条形的信息,并将其显示在 HTML 页面上的文本框中。这是通过将侦听器绑定到jqlotDataClick事件来实现的。
在这个例子中,我们从生成水平堆积条形图的代码开始(见清单 10-26)。
清单 10-26。ch10_15.html
var data = [12, 8, 6, 10, 7];
var data2 = [14, 12, 4, 14, 11];
var data3 = [18, 10, 5, 9, 9];
var ticks = ['Germany', 'Italy', 'Spain', 'France', 'UK'];
var options = {
title: 'Foreign Customers',
stackSeries: true,
seriesDefaults:{
renderer: $.jqplot.BarRenderer,
pointLabels: { show: true, location: 's' }
},
series:[
{label: 'Electronics'},
{label: 'Software'},
{label: 'Mechanics'}
],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
}
},
legend: {
show: true,
placement: 'outsideGrid',
location: 'e'
}
};
$.jqplot ('myChart', [data, data2, data3], options);
和前面的事件示例一样,最后您添加一个 jQuery 函数来捕获jqplotDataClick事件,并向info1元素发送一组信息(参见清单 10-27)。
清单 10-27。ch10_15.html
$('#myChart').bind('jqplotDataClick',
function (ev, seriesIndex, pointIndex, data) {
$('#info1').html('series: ' + seriesIndex +
', point: '+pointIndex+', data: '+data);
}
);
每当您点击一个条时,该功能将刷新您放置了<span>元素的地方显示的信息,其中'info1'为id。在这里,您将<span>元素添加到 HTML 页面:
<span id="info1">Information will be provided here </span>
现在,通过单击一个条形的突出显示区域,您可以在文本框中获得与该条形相关的所有数据,如图 10-20 所示。
图 10-20。
By clicking a stacked bar, you obtain its values
处理图例
使用条形图时,您利用了图例,这是大多数图表的关键组成部分。图例是 jqPlot 中定义的元素。通常,您只需要调用options中的legend对象,就可以在图表旁边弹出图例。在这里,您将更详细地分析这个有用的元素。
什么时候有必要使用图例?当您处理多序列数据时,也就是说,当您有一组数据时,通常用不同的颜色来区分。图例除了在一个小空间中报告每种颜色和一个区分该组元素的标签之间存在的关系之外,什么也不做。
添加图例
前面的例子(见图 10-20 )非常适合研究传说。通过观察堆积图,您可以很容易地看到每个国家的条形图由三部分组成,这三部分用不同的颜色表示。因此,您知道图表中显示了三个系列。此外,您还知道每个系列占总价值的比例,但是仍然缺少关键信息:哪些类别由哪些颜色表示。通过添加图例,您将阐明三种颜色与这些类别之间的关联:“机械”、“软件”和“电子”
因此,继续使用前一个例子中的代码(参见清单 10-26 和 10-27),让我们将legend定义添加到options对象中,如清单 10-28 所示。为此,您不必包含任何插件;你只需要将show属性设置为'true'。
清单 10-28。ch10_15.html
var options = {
...
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
}
},
legend: {
show: true,
placement: 'outsideGrid',
location: 'e'
}
};
$.jqplot ('myChart', [data,data2,data3],options);
图 10-21 显示了带有图例的图表。
图 10-21。
A stacked bar chart with a legend
placement属性指定您想要图例的位置;省略它,您将获得默认行为:图例绘制在图表内部。为了避免覆盖条形,您可以通过设置location属性来改变图例的位置,如清单 10-29 所示。
清单 10-29。ch10_16a.html
legend: {
show: true,
}
这样,如图 10-22 所示,图表被改变,图例被画在里面(默认),在右上角('ne'【东北】)。
图 10-22。
The default legend position is inside the chart, in the top-right corner
对于更彻底的方法,最好使用级联样式表(CSS)定制。您将为图例使用一些 CSS 类来修改默认属性——主要是 CSS 类table.jqplot-table-legend。
例如,您可以将规范添加到清单 10-30 提供的 CSS 类中。
清单 10-30。ch10_16b.html
<style>
table.jqplot-table-legend {
background-color: rgba(175, 175, 175, 1);
font: "Arial Narrow";
font-style: italic;
font-size: 13pt;
color: white;
}
</style>
并且,图例将会改变,如图 10-23 所示。
图 10-23。
The modified legend, using CSS styles
增强的图例
如果查看 jqPlot 发行版中的几个插件,会发现一个与 legends 相关的插件:EnhancedLegendRenderer。这个插件扩展了图例的功能:单击图例项,可以显示或隐藏相应的序列。用一个具体的例子就可以看出这一点。首先,将插件包含在您的 web 页面中:
<script type="text/javascript"
src="../src/plugins/jqplot.enhancedLegendRenderer.min.js"></script>
或者,如果您更喜欢使用 CDN 服务,您可以按如下方式操作:
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins/jqplot.enhancedLegendRenderer.min.js></剧本>
然后,你必须激活options中的插件,就像你激活其他插件一样,如清单 10-31 所示。
清单 10-31。ch10_16c.html
legend: {
renderer: $.jqplot.EnhancedLegendRenderer,
show: true,
placement: 'outsideGrid',
location: 'ne'
}
在浏览器中加载页面后,您会得到图 10-24 中的图表。如果单击图例中的某个项目,相应的系列将从图表中消失,留下一个空白。如果您只想分析系列的子集,而忽略其他部分,这将非常有用。因此,让我们单击图例中的“软件”,看看会发生什么。
图 10-24。
You can hide a series by selecting an item in the legend
在图 10-24 的图例中,属于软件系列的橙色部分已经消失,项目“软件”被划掉。
这种效果是累积的,你可以一个接一个地隐藏所有的系列。如果您再次单击删除线项目,相应的系列将再次出现在图表中。
自定义图例突出显示
您已经看到了如何使用 jqPlot 默认提供的图例。但是,您可以通过在 HTML 中实现一个简单的表来创建自定义图例,然后动态填充它,用您的系列的标签填充它。因为您必须从头开始创建自己的图例,所以首先需要选择一种样式。你可以通过使用一个外部 CSS 文件或者直接在网页中编写样式来定义 CSS 样式,如清单 10-32 所示。
清单 10-32。ch10_17.html
<style type="text/css">
table.sample {
border-width: thin;
border-spacing: 0px;
border-style: outset;
border-color: rgb(221, 221, 221);
border-collapse: collapse;
}
table.sample th {
border-width: 1px;
padding: 1px;
border-style: inset;
border-color: gray;
}
table.sample td {
border-width: 1px;
padding: 1px;
border-style: inset;
border-color: gray;
}
</style>
您已经使用了三个不同的 CSS 类。第一个指定整个表格的样式。另外两个被定义为分别为标题和单元格指定特定的样式。
在定义了样式之后,为了我们的目的,你可以使用一个简单的条形图的代码(见清单 10-33)。
清单 10-33。ch10_17.html
var data = [['Germany', 12], ['Italy', 8], ['Spain', 6], ['France', 10], ['UK', 7]];
var options = {
title: 'Foreign Customers',
series:[{renderer:$.jqplot.BarRenderer}],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer
}
}
};
$.jqplot ('myChart', [data], options);
下一步是将自定义图例绑定到jqplotDataHighlight和jqplotDataUnhighlight事件(见清单 10-34)。您已经看到了这些,以及如何使用 jQuery 方法将对象绑定到它们。在这种情况下,你会做得更多;您将确保整个定制图例是仅用几行 jQuery 动态创建的。这些将包括数据数组。与 jqPlot 提供的默认图例相比,在这里您可以获得比表示组系列成员的标签更多的内容。还可以添加汇总值(使用 JavaScript 函数)或简单的 y 值。
清单 10-34。ch10_17.html
$(document).ready(function(){
var data = ...
var options = ...
$.jqplot ('myChart', [data], options);
$.each(data, function(index, val) {
$('#legend1').append('<tr><td>'+val[0]+'</td><td>'+val[1]+'</td></tr>');
});
$('#myChart').bind('jqplotDataHighlight',
function (ev, seriesIndex, pointIndex, data) {
var color = 'rgb(100%, 90%, 50%)';
$('#legend1 tr').css('background-color', '#ffffff');
$('#legend1 tr').eq(pointIndex+1).css('background-color', color);
});
$('#myChart').bind('jqplotDataUnhighlight',
function (ev, seriesIndex, pointIndex, data) {
$('#legend1 tr').css('background-color', '#ffffff');
});
});
第一个 jQuery 函数处理数据数组的值。另外两个在鼠标经过图例项时将图例绑定到突出显示事件。此外,这些函数还将样式属性的变化绑定到这些事件,在本例中是项目的背景颜色。
现在,您需要定义两个不同的区域来插入图表和图例。您可以使用 HTML 表格来实现这一点。因此,你将清单 10-35 中的代码添加到 HTML 页面的<body>部分。
清单 10-35。ch10_17.html
<table style="margin-left:auto; margin-right:auto;">
<tr>
<td><div id="myChart" style="width:460px; height:340px;"></div></td>
<td><div style="height:340px;">
<table id="legend1" class="sample" >
<tr><th>Nation</th><th>Customers</th></tr>
</table>
</div>
</td>
</tr>
</table>
最后,您可以加载带有新自定义图例的新页面(参见图 10-25 )。
图 10-25。
A custom HTML legend
自定义工具提示
除了图例,条形图中另一个非常常用的项目是工具提示。正如有可能使用代码创建自定义图例一样,也有可能自定义工具提示,创建非常新颖的效果。当你将鼠标放在一个条上并高亮显示它时,会显示一个工具提示,但是,与默认的 jqPlot 工具提示不同,它完全是以 HTML 格式构建的。这极大地拓展了你艺术表达的可能性,给你的星盘增添了一丝个性(使用 jqPlot,一切都有过于“标准 jqPlot”的风险)。在这个例子中,你想要展示一个小图标图像如何给一个条形图一个非常好的效果。
在开始编写代码之前,让我们创建一个目录,并将其命名为flags(您可以随意命名)。在这个目录中,您将存储所有要使用的可移植网络图形(PNG)图像文件。这些图标是各国的国旗,您将在条形图的 x 轴上报告。从互联网上很容易找到并下载这些 PNG 文件。
Note
在工具提示中显示标志所需的 PNG 文件包含在本书随附的源代码中,您可以在本书的 press 产品页面( www.apress.com/9781430262893 )的“源代码/下载”选项卡中找到。
完成标志图像后,第一步是创建自定义工具提示。您需要将工具提示绑定到jqplotDataHighlight和jqplotDataUnhighlight事件。您可以用几行 jQuery 动态创建定制的工具提示。
这里,你从你已经使用过的条形图开始(见清单 10-36),因为它代表了一个简单的例子来理解开发这种定制工具提示的方法。
清单 10-36。ch10_18.html
var data = [['Germany', 12], ['Italy', 8], ['Spain', 6], ['France', 10], ['UK', 7]];
var options = {
title: 'Foreign Customers',
series:[{renderer:$.jqplot.BarRenderer}],
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer
}
}
};
$.jqplot ('myChart', [data], options);
你必须添加另外两个数据数组,包含一些字符串(见清单 10-37)。您将在动态生成的工具提示中使用这些。
清单 10-37。ch10_18.html
var tick = ['Germany', 'Italy', 'Spain', 'France', 'UK'];
var icon = ['germany.png', 'italy.png', 'spain.png', 'france.png', 'uk.png'];
您将jqplot()函数的返回值赋给一个变量,因为您稍后将需要使用它。
var myPlot = $.jqplot ('myChart', [data], options);
清单 10-38 给出了将事件绑定到自定义工具提示的 jQuery 代码。
清单 10-38。ch10_18.html
$('#myChart').bind('jqplotDataHighlight',
function (ev, seriesIndex, pointIndex, data) {
var chart_left = $('#myChart').offset().left;
var chart_top = $('#myChart').offset().top;
var x = data[0]*95+20;
var y = myPlot.axes.yaxis.u2p(data[1]);
var color = 'rgb(30%,50%,60%)';
$('#tooltip1').css({left:chart_left+x, top:chart_top+y});
$('#tooltip1').html('<span style="font-size:16px; font-weight:bold; color:' +
color + ';">' + tick[data[0] - 1] +
'</span><br/><img src="flags/'+ icon[data[0] - 1]+
'" width="30" height="20"><br/> n:' + data[1]);
$('#tooltip1').show();
}
);
$('#myChart').bind('jqplotDataUnhighlight',
function (ev, seriesIndex, pointIndex, data) {
$('#tooltip1').empty();
$('#tooltip1').hide();
}
);
最后,你必须在网页的<body>部分创建两个<div>元素,如清单 10-39 所示。在第一个元素中,jqPlot 将在画布上生成您的自定义工具提示;在第二个例子中,jqPlot 将创建绘制条形图的画布。
清单 10-39。ch10_18.html
<div id="myChart" style="height:300px; width:500px;"></div>
<div id="tooltip1" style="position:absolute; height:0px; width:0px;"></div>
图 10-26 显示了高亮显示的“德国”栏,旁边有定制的工具提示。这种情况会发生在条形图中的所有条形上,每次用户将鼠标悬停在条形上突出显示它们时,每个条形都会在工具提示中显示相应的标志。
图 10-26。
A bar chart with custom tool tips
摘要
在本章中,您已经看到了如何使用 BarRenderer 插件在条形图中表示您的数据。您开始看到,随着这个渲染器插件的引入,jqPlot 主对象的结构逐渐被新的属性和对象所丰富。通过实际的例子,您学习了如何用rendererOptions改变属性和对象属性的值。
您还了解了使用同一组数据有时可能会获得不同的表示。知道如何选择哪种表示更适合你的需求是本书的基本目标之一。为此,您在分组条形图和堆积条形图中使用了相同的数据集。在这两种情况下,您都用垂直和水平条实现了数据表示。
在本章的后面,你看了一些例子,展示了 jqPlot 如何允许你使用特殊函数来处理事件。此外,您还进一步研究了图例组件以及使用 HTML 代码定制图例的可能性。然后,您将相同的方法应用于工具提示。
通常,需要条形图表示的数据类型也可以通过另一种类型的图表来很好地表示:饼图。在下一章中,您将发现 jqPlot 库如何处理这种类型的图表。
十一、jqPlot 饼图和圆环图
Abstract
饼图和圆环图是将数据分解成各个组成部分的绝佳方式。饼图是一个圆形的图表,分为扇形或“切片”,其主要目的是说明它们的相对比例:每个切片的弧长与它所代表的数量成比例。圆环图与饼图非常相似,但中间有一个洞,并支持多个系列的比较。在这一章中,你将会看到这两种图表。本章最后讨论了多维饼图。
饼图和圆环图是将数据分解成各个组成部分的绝佳方式。饼图是一个圆形的图表,分为扇形或“切片”,其主要目的是说明它们的相对比例:每个切片的弧长与它所代表的数量成比例。圆环图与饼图非常相似,但中间有一个洞,并支持多个系列的比较。在这一章中,你将会看到这两种图表。本章最后讨论了多维饼图。
饼图
在 jqPlot 中,默认情况下,数据被解释为折线图。如果您想在饼图中显示您的数据,您需要包括 PieRenderer 插件:
<script type="text/javascript" src="../src/plugins/jqplot.pieRenderer.min.js">
</script>
或者,如果您更喜欢使用内容交付网络(CDN)服务,您可以按如下方式操作:
<script type="text/javascript" src="http://cdn.jsdelivr.net/jqplot/1.0.8/plugins
为了更好地理解这个插件的用法,让我们以一个人在给定时间内消耗的食物量为例。在这种情况下,饼图被证明是数据表示的最佳选择。所有吃的食物组成了整个群体,各种类型的食物就是你要比较的成分。每一种食物都将由一片用不同颜色标识的薄片来代表。每一片的大小将给出一个食物种类在一个人饮食中所占比例的精确概念。你可以从[label,amount]对值的数据数组开始,如清单 11-1 所示。
清单 11-1。ch11_01a.html
var data = [ ['Dairy', 212],['Meat', 140], ['Grains', 276],
['Fish', 131],['Vegetables', 510], ['Fruit', 325] ];
现在,您可以定义选项。正如您在清单 11-2 中看到的,您需要激活插件并将其应用于defaultSeries对象。
清单 11-2。ch11_01a.html
var options = {
seriesDefaults: {
renderer: jQuery.jqplot.PieRenderer,
rendererOptions: {
showDataLabels: true
}
}
};
$.jqplot ('myChart', [data], options);
图 11-1 显示了一个简单的饼图,没有附加属性的说明。
图 11-1。
A simple pie chart
如图 11-1 所示,在其扇区内,饼图默认报告百分比。相反,如果您想要显示该值,如图 11-2 的右上角所示,您需要在renderOptions中的dataLabels属性上设置'value',如清单 11-3 所示。
清单 11-3。ch11_01b.html
rendererOptions: {
showDataLabels: true,
dataLabels: 'value'
}
如果你想添加一个边距来分隔饼图的各个部分,如图 11-2 的左下方所示,我们需要将sliceMargin属性设置为 6(参见清单 11-4)。
清单 11-4。ch11_01c.html
rendererOptions: {
showDataLabels: true,
dataLabels: 'value',
sliceMargin: 6
}
此外,如果你想显示带有空切片的饼状图,如图 11-2 的右下方所示,你可以将fill属性设置为'false'并将lineWidth属性设置为 5,以便用稍微粗一点的线条来给切片加阴影(见清单 11-5)。
清单 11-5。ch11_01d.html
rendererOptions: {
showDataLabels: true,
dataLabels: 'value',
sliceMargin: 6,
fill: false,
// stroke the slices with a little thicker line.
lineWidth: 5
}
图 11-2。
Different ways to set a pie chart
圆环图
饼图的一个主要问题是它们不能同时显示多个系列。因此,您必须决定是否用饼图单独表示每个系列,或者最好使用圆环图(也拼写为“甜甜圈”)。这种图表需要并使用与饼图相同的选项;因此,从饼图到圆环图的转换是即时的。您将通过一个简单的例子来了解这种转换的简单性。
首先,与饼图一样,您需要包含一个特定的插件来获得一个圆环图:
<script type="text/javascript" src="../src/plugins/jqplot.donutRenderer.min.js"> </script>
你必须在options对象中做的唯一改变是在渲染器调用中用DonutRenderer替换pieRenderer对象,然后修改rendererOptions object中第一个扇区的起始角度。默认情况下,图表从圆圈的左侧开始,但通常必须从顶部开始。因此,有必要将startAngle属性设置为–90 度(见清单 11-6)。
清单 11-6。ch11_02.html
var options = {
seriesDefaults: {
// Make this a pie chart.
renderer:$.jqplot.DonutRenderer,
rendererOptions: {
showDataLabels: true,
dataLabels: 'value',
sliceMargin: 3,
startAngle: -90
}
}
};
jQuery.jqplot ('myChart', [data], options);
这样你就得到了一个甜甜圈图(见图 11-3 ,与图 11-2 右下方的饼状图非常相似。
图 11-3。
A simple donut chart
但是,我们选择使用圆环图而不是饼图,因为它允许我们同时表示多个系列,从而比较其组成部分的比例。因此,继续这个例子,你可以比较两个不同群体的人所吃的食物。清单 11-7 说明了如何添加另一个数据数组。
清单 11-7。ch11_02.html
var data2 = [
['Dairy', 185],['Meat', 166], ['Grains', 243],
['Fish', 166],['Vegetables', 499], ['Fruit', 370]
];
将第二个数组添加到data,修改清单:
$.jqplot ('myChart', data,``data2
图 [11-4 展示了报告两个数值系列的圆环图。
图 11-4。
A multiseries donut chart
看着图 11-4 ,你可以立刻看到一些基本的东西不见了:一个图例。图例是必需的,因为插件会自动为每个扇区分配一种颜色,因此没有颜色参考,很难理解图表。因此,在您将图例的show属性设置为'true'之后,您可以选择图例的位置。为了确定在哪个位置放置图例,jqPlot 使用 location 属性,将与基本方向对应的值分配给该属性:'n'(北)、's'(南)、'e'(东)和'w'(西)。但是,也可以使用组合,例如'ne',来指示东北方向的位置。
假设您决定将图例定位在图表的右侧,那么您将'e'分配给location属性(参见清单 11-8)。
清单 11-8。ch11_02.html
legend: {
show:true,
location: 'e'
}
图例自动报告数据数组中包含的标签,如图 11-5 所示。
图 11-5。
A multiseries donut chart with a legend
多级饼图
多级饼图是一种现代格式,非常适合可视化用于显示层次关系的数据。这种图表提供了一个层次结构,从圆圈中心的根节点开始,您可以跟踪成员资格,因为它们逐渐移动到外部圆圈。为了更好地理解这种图表,让我们以一系列动物为例,逐步确定它们的等级群体。
作为输入数据数组,你想插入三个数组(见清单 11-9)。这将产生三个层次。在第一个数组中,插入最后一级,直到第三个数组,它代表根。
清单 11-9。ch11_03.html
var data = [ ['Cat', 1],['Dog', 1], ['Mouse', 1],['Snake', 1],
['Turtle', 1], ['Jellyfish', 1], ['Cuttlefish', 1] ];
var data2 = [ ['Mammals', 3],['Reptiles', 2], ['Mollusks', 2] ];
var data3 = [ ['Vertebrates', 5],['Invertebrates', 2] ];
要生成多级饼图,实际上需要修改一个圆环图,将内孔的直径设置为零。在这种情况下,您需要显示标签所代表的动物或动物群的名称,而不是显示数值;您必须将dataLabels属性设置为'label'。最后要修改的是颜色的设置。jqPlot 提供的默认颜色是不够的,有必要为层次结构的每个级别定义一组颜色。优选地,将相似的颜色分配给属于同一组的动物,并且对于层级的连续级别也是如此。在清单 11-10 中,特别注意了分配给每个系列的颜色序列(层次级别)。
清单 11-10。ch11_03.html
var options = {
seriesDefaults: {
renderer:$.jqplot.DonutRenderer,
rendererOptions: {
showDataLabels: true,
dataLabels: 'label',
startAngle: -90,
innerDiameter: 0,
ringMargin: 2,
shadow: false
}
},
series: [
{
seriesColors: ['#4bb2c5', '#4baacc', '#4b88aa', '#bbb2c5',
'#bbaa99', '#c5dd99', '#dddd77']
},
{
seriesColors: ['#4bbbbb', '#ccb2c5', '#c5ff99']
},
{
seriesColors: ['#aa5555', '#a3ffaa']
}]
};
$.jqplot ('myChart', [data, data2, data3], options);
最终,你的努力会得到图 11-6 中的多级饼图的回报。
图 11-6。
A multilevel pie chart
摘要
在本章中,您已经了解了 jqPlot 库如何允许您通过饼图(具有单个数据系列)或圆环图(具有多个数据系列)来表示数据,同时还可以快速了解一些主要属性以及如何在选项中设置它们。在本章的最后一部分,您创建了一个多级饼图:这是一个经典的例子,说明了如何通过适当地修改某些属性来生成一种不属于库所建议的标准图表的图表类型。
在下一章中,您将看到 jqPlot 库如何让您实现蜡烛图,以及如何处理特定的数据格式开盘-盘高-盘低-收盘(OHLC),这是这种图表的基础。
十二、jqPlot 蜡烛图
Abstract
蜡烛图广泛用于分析一段时间内的货币或价格变动。该图表由一系列竖线组成,称为烛台。它们显示了给定时间内的开盘价、收盘价、最低价和最高价(见图 12-1)。因此,这种图表通常被称为 OHLC 图表(当它报告开盘-盘高-盘低-收盘值时)或 HLC 图表(当它只报告盘高-盘低-收盘值时)。
蜡烛图广泛用于分析一段时间内的货币或价格变动。该图表由一系列竖线组成,称为烛台。它们显示给定时间段内的开盘价、收盘价、最低价和最高价(见图 12-1 )。因此,这种图表通常被称为 OHLC 图表(当它报告开盘-盘高-盘低-收盘值时)或 HLC 图表(当它只报告盘高-盘低-收盘值时)。
图 12-1。
Different ways to represent OHLC data: (a) line, (b) real body
烛台可能被描绘成简单的线条或末端有线条(称为灯芯或阴影)的盒子(称为实体)。每个烛台的高度表明了一个特定时期的价格范围。在箱形表示中,真实的主体是开盘价和收盘价之间的区域。但是,如果烛台用简单的垂直线表示,两个小的水平刻度表示开盘价(向左刻度)和收盘价(向右刻度)。此外,在蜡烛图中,根据价格是上涨还是下跌,数据图的颜色也不同。
在本章中,您将看到如何表示特定的OHLC数据。你还将学习如何用线条或实体来格式化这样的图表。不过,首先,您需要包含 OHLCRenderer 插件。
OHLC 图表
要使 jqPlot 能够绘制蜡烛图,您必须在 web 页面中包含一个特定的插件:OHLCRenderer。
您还需要包括 DateAxisRenderer 插件,因为在蜡烛图中,您通常将日期值放在 x 轴上:
<script type="text/javascript" src="../src/plugins/jqplot.dateAxisRenderer.min.js">
</script>
<script type="text/javascript" src="../src/plugins/jqplot.ohlcRenderer.min.js">
</script>
关于输入数据数组,您必须遵守特定的顺序:
['timestamp', open, max, min, close]
对于这个例子,您使用的是一组在线可用的真实数据。这些数据取自一个由免费工具 Dukascopy 生成的逗号分隔值(CSV)文件,这个工具也可以在网上获得( www.dukascopy.com )。您选择 2012 年大约一个月的欧元兑美元汇率值。让我们将所有这些值赋给一个变量,如清单 12-1 所示。
清单 12-1。ch12_01a.html
var ohlc = [
['8/08/2012 0:00:01', 1.238485, 1.2327, 1.240245, 1.23721],
['8/09/2012 0:00:01', 1.23721, 1.22671, 1.23873, 1.229295],
['8/10/2012 0:00:01', 1.2293, 1.22417, 1.23168, 1.228975],
['8/12/2012 0:00:01', 1.229075, 1.22747, 1.22921, 1.22747],
['8/13/2012 0:00:01', 1.227505, 1.22608, 1.23737, 1.23262],
['8/14/2012 0:00:01', 1.23262, 1.23167, 1.238555, 1.232385],
['8/15/2012 0:00:01', 1.232385, 1.22641, 1.234355, 1.228865],
['8/16/2012 0:00:01', 1.22887, 1.225625, 1.237305, 1.23573],
['8/17/2012 0:00:01', 1.23574, 1.22891, 1.23824, 1.2333],
['8/19/2012 0:00:01', 1.23522, 1.23291, 1.235275, 1.23323],
['8/20/2012 0:00:01', 1.233215, 1.22954, 1.236885, 1.2351],
['8/21/2012 0:00:01', 1.23513, 1.23465, 1.248785, 1.247655],
['8/22/2012 0:00:01', 1.247655, 1.24315, 1.254415, 1.25338],
['8/23/2012 0:00:01', 1.25339, 1.252465, 1.258965, 1.255995],
['8/24/2012 0:00:01', 1.255995, 1.248175, 1.256665, 1.2512],
['8/26/2012 0:00:01', 1.25133, 1.25042, 1.252415, 1.25054],
['8/27/2012 0:00:01', 1.25058, 1.249025, 1.25356, 1.25012],
['8/28/2012 0:00:01', 1.250115, 1.24656, 1.257695, 1.2571],
['8/29/2012 0:00:01', 1.25709, 1.251895, 1.25736, 1.253065],
['8/30/2012 0:00:01', 1.253075, 1.248785, 1.25639, 1.25097],
['8/31/2012 0:00:01', 1.25096, 1.249375, 1.263785, 1.25795],
['9/02/2012 0:00:01', 1.257195, 1.256845, 1.258705, 1.257355],
['9/03/2012 0:00:01', 1.25734, 1.25604, 1.261095, 1.258635],
['9/04/2012 0:00:01', 1.25865, 1.25264, 1.262795, 1.25339],
['9/05/2012 0:00:01', 1.2534, 1.250195, 1.26245, 1.26005],
['9/06/2012 0:00:01', 1.26006, 1.256165, 1.26513, 1.26309],
['9/07/2012 0:00:01', 1.26309, 1.262655, 1.281765, 1.281625],
['9/09/2012 0:00:01', 1.28096, 1.27915, 1.281295, 1.279565],
['9/10/2012 0:00:01', 1.27957, 1.27552, 1.28036, 1.27617],
['9/11/2012 0:00:01', 1.27617, 1.2759, 1.28712, 1.28515],
['9/12/2012 0:00:01', 1.28516, 1.281625, 1.29368, 1.290235] ];
在options中,通过调用series对象来激活 OHLCRenderer 插件。因为需要处理 x 轴上的日期值,所以必须激活xaxis对象中的dateAxisRenderer对象。使用这种类型的图表,最好定义您想要表示的时间段,而不考虑输入数据,以便更精确地控制显示的内容。为此,在xaxis对象中指定min和max属性。您还可以看到,使用dateAxisRenderer,您可以选择节拍间隔,使用文字表达式('1 day'、'n days'、'1 week'、'n weeks'、'1 month'、'n months',其中n是大于 1 的任何整数)。此外,请注意yaxis尚未定义,或者说 y 值已归属于y2axis。这样做是为了让 y 轴位于图表的右边,而不是默认的左边(见清单 12-2)。
清单 12-2。ch12_01a.html
var options = {
title: 'EUR-USD Exchange',
seriesDefaults:{ yaxis: 'y2axis'},
axes: {
xaxis: {
renderer: $.jqplot.DateAxisRenderer,
tickOptions: {formatString: '%b %e'},
min: "08-07-2012 16:00",
max: "09-12-2012 16:00",
tickInterval: "1 weeks"
},
y2axis: {
tickOptions:{ formatString: '$%.2f'}
}
},
series: [{ renderer: $.jqplot.OHLCRenderer}]
};
$.jqplot('myChart', [ohlc], options);
你现在有了如图 12-2 所示的 OHLC 圆图。
图 12-2。
An OHLC chart with lines
只要有整数,就像在输入数据数组中输入一样表示它们。但是,这并不总是可能的。通常,您必须处理小数点后有许多位数并且长度不同的数字。因此,有必要将这些数字标准化,只报告有效数字。您可以通过设置formatString属性来实现这一点。这个特例需要一个带两个小数点的浮点值:'%.2f'。
使用真实的身体和阴影
您刚刚看到的烛台图表是用棒线格式化的。如果你想要一个有真实物体和阴影的盒子,你需要设置一个额外的属性:candlestick(见清单 12-3)。
清单 12-3。ch12_01b.html
series: [{
renderer: $.jqplot.OHLCRenderer,
rendererOptions:{ candleStick: true }
}]
现在,让我们看看代替小节线上水平刻度的真实物体。在图 12-3 中,白色方框表示价格上涨时(开盘价低于收盘价),黑色方框表示价格下跌时(收盘价低于开盘价)。
图 12-3。
An OHLC chart with boxes
对比烛台
偶尔,你需要在特定时间比较代表不同类别的烛台。在这种情况下,x 轴上没有日期,而是主题本身的名称。输入数据数组将是不同的;您必须使用 OHLC 数据所属类别的标签来分隔这些数据。对于每个实体,插入一个包含五个值的数组:
[n, open, max, min, close]
这里,n不是时间戳,而是对应于刻度数组的索引的整数。因此,您在data1数组中定义这些 OHLC 值,如清单 12-4 所示。在ticks数组中,使用四个不同的标签来表示四个 OHLC 值中的每一个。
清单 12-4。ch12_02.html
var data1 = [[1, 75, 80, 40, 55], [2, 30, 60, 15, 50],
[3, 64, 75, 48, 50], [4, 67, 78, 20, 36]];
var ticks = ['Apple', 'Ubuntu', 'Microsoft', 'Android'];
将对 DateAxisRenderer 插件的调用替换为对 CategoryAxisRenderer 插件的调用:
<script type="text/javascript" src="../src/plugins/jqplot.categoryAxisRenderer.min.js">
</script>
<script type="text/javascript" src="../src/plugins/jqplot.ohlcRenderer.min.js">
</script>
如清单 12-5 所示,options中的设置非常简单。首先,您必须用renderer属性中的$.jqplot.CategoryAxisRenderer替换$.jqplot.DateAxisRenderer。此外,将ticks数组分配给xaxis中的ticks对象。
清单 12-5。ch12_02.html
var options = {
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
},
},
series: [{
renderer: $.jqplot.OHLCRenderer,
rendererOptions:{ candleStick: true}
}]
};
$.jqplot ('myChart', [data1], options);
这张图表完美地描绘了一个真实身体的盒子;价格下跌时该框被填充,价格上涨时该框被清空(见图 12-4 )。
图 12-4。
A comparative candlestick chart
摘要
在本章中,您已经看到了如何通过蜡烛图来表示特定的 OHLC 数据。您还学习了如何用线条或实体来格式化此类图表。
在下一章,我将讨论一整类图表,它们有一个共同的特点:它们的目的是表示数据的分布。通过这次探索,您将发现如何用 jqPlot 库实现散点图、气泡图和块图。