# 序數比例尺
> [Wiki](Home) ? \[\[API--中文手冊\]\] ? \[\[比例尺\]\] ? **序數比例尺**
- - - - - -
- 本文檔是D3官方文檔中文翻譯,并保持與[最新版](https://github.com/mbostock/d3/wiki/API-Reference)同步。
- 如發現翻譯不當或有其他問題可以通過以下方式聯系譯者:
- 郵箱:zhang\_tianxu@sina.com
- QQ群:[D3數據可視化](http://jq.qq.com/?_wv=1027&k=ZGcqYF):205076374,[大數據可視化](http://jq.qq.com/?_wv=1027&k=S8wGMe):436442115
- Github小組:[VisualCrew](https://github.com/VisualCrew):<https://github.com/VisualCrew>
- 本頁譯文,我們作如下約定:
- **domain**:譯為 輸入域(或者定義域)
- **range**:譯為 輸出范圍(或值域)
- **band**:譯為 區間段(或頻段寬度),可以理解為線段
- **參數**:也就是 function 的參數,譯為 入參,比如:`function abc(x, y) {}`,函數 abc 的兩個參數 x 和 y,我們稱為:入參 x、入參 y
- - - - - -
**比例尺**是一系列函數,用來映射輸入域到輸出范圍。**序數比例尺**的輸入域是離散的,比如:一組名稱或類別。還有\[\[定量比例尺|數值比例尺\]\],其輸入域是連續的,比如:實數集、日期。比例尺在D3中是一個可選的功能,如果你喜歡自己處理數學的話大可不必使用它們。然而使用比例尺可以大大簡化映射數據到可視化編碼的必需代碼量。
一個比例尺對象,例如:[d3.scale.linear](%E6%95%B0%E5%80%BC%E6%AF%94%E4%BE%8B%E5%B0%BA#linear) 的返回值既是一個對象也是一個函數。因此,可以像函數一樣使用比例尺對象。并且比例尺有額外的函數可以改變它的行為。就像 D3 中的其他類,比例尺同樣支持鏈式語法 setter 方法直接返回比例尺對象,允許多個 setter 方法在一個簡潔的語句中調用。
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal) d3.scale.**ordinal**()
構造一個新的序數比例尺,使用空的輸入域和輸出范圍。如果序數比例尺沒有指定輸出范圍,取值時總會返回 undefined 。
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#_ordinal) **ordinal**(*x*)
傳入一個輸入域中的值 *x*,返回對應輸出范圍中的值。如果輸出范圍已指定(比如通過 [range](#ordinal_range)指定,但是不是通過 [rangeBands](#ordinal_rangeBands)、[rangeRoundBands](#ordinal_rangeRoundBands) 或 [rangePoints](#ordinal_rangePoints) 來指定的),并且入參 *x* 的值不在輸入域中,那么 *x* 就會被隱含地添加進到輸入域中;這之后,當使用相同的值 *x* 再次調用該函數時就會返回輸出范圍中相同的值 *y*。
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_domain) ordinal.**domain**(\[*values*\])
獲取或指定當前比例尺對象的輸入域。
如果指定了入參 *values* 的值,就會設置當前比例尺對象的輸入域為指定的 *values* 數組。*values* 數組中的第一個元素會被映射到輸出范圍中的第一個值、第二個元素會被映射到輸出范圍中的第二個值等等。輸入域 *values* 在內部會被存儲到一個關聯數組中作為從值到索引的映射,生成的索引會被用來從輸出范圍中取值,也就是取對應索引的值;這樣的話,序數比例尺的輸入域中的值就會被強制轉換為字符串,并且唯一地標識到輸出范圍中對應的值。
如果沒有指定 *values*,這個方法就會返回當前的域。
序數比例尺的輸入域是否指定是可選的,但是輸出范圍是必須明確地指定。因為,如 [ordianl(x)](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#_ordinal) 所述,如果 *x* 的值在輸入域中不存在,就會被隱式的新增到輸入域中;換句話說,輸入域是從使用情況中推斷而來的。雖然輸入域可能被隱式構造,最好還是顯式指定序數比例尺的域,以保證確定性的行為,而從使用情況來推斷輸入域是取決于順序。
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_range) ordinal.**range**(\[*values*\])
獲取或指定當前比例尺對象的輸出范圍。
如果指定了入參 *values* 的值,就會設置當前比例尺對象的輸出范圍為指定的 *values* 數組。 輸入域中的第一個元素會被映射到 *values* 的第一個值、輸入域中的第二個元素會被映射到 *values* 的第二個值等等。如果 *values* 中的值的個數少于輸入域中元素的個數,那么 *values* 中的值會被循環使用。
如果沒有指定 *values*,這個方法就會返回當前的域。
這個函數也可以被用來指定一組已經被明確計算好了的離散的輸出范圍,比如:一組類目型的顏色。其他一些情況,比如:序列散點圖、柱狀圖使用[rangePoints](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangePoints) 或 [rangeBands](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangeBands) 會更為方便,具體請先參考對應圖表的案例代碼。
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangePoints) ordinal.**rangePoints**(*interval*\[, *padding*\])
功能同[ordinal.range(\[values\])](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_range),只是適用范圍不同。
指定輸出范圍為一個連續的區間 *interval* ;*interval* 需要兩個數值元素,第一個表示區間的最小值、第二個表示區間的最大值。區間 *interval* 會被細分為 *n* 個等間隔的刻度“點”,*n* 的大小取決于輸入域數組的真實長度(也就是數組中每個元素的唯一性而確定的長度)。在這些被細分的刻度點中,第一個點的起始位置和最后一個點的結束位置會因為入參 *padding* 的值而做相應消減(見下圖),消減長度是:*padding* 個間隔長度的一半;默認情況下 *padding* 是 0 。*padding* 的值會當做間隔的倍數來使用。

```
var o = d3.scale.ordinal()
.domain([1, 2, 3, 4])
.rangePoints([0, 100]);
o.range(); // [0, 33.333333333333336, 66.66666666666667, 100]
o.rangePoints([0, 120], 1);
o.range() // [15, 45, 75, 105] 前面被空了 30*1/2=15 后面也被空了 15;其中 30 是間隔寬度
o.rangePoints([0, 120], 2);
o.range() // [24, 48, 72, 96] 前面被空了 24*2/2=24 后面也被空了 24;其中 24 是間隔寬度
o.rangePoints([0, 120], 3);
o.range() // [30, 50, 70, 90] 前面被空了 20*3/2=30 后面也被空了 30;其中 20 是間隔寬度
```
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangeRoundPoints) ordinal.**rangeRoundPoints**(*interval*\[, *padding*\])
功能同[ordinal.rangePoints(interval\[, padding\])](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangePoints),但是該函數可以美化輸出的刻度點,也就是保證整數。
```
var o = d3.scale.ordinal()
.domain([1, 2, 3, 4])
.rangeRoundPoints([0, 100]);
o.range(); // [1, 34, 67, 100]
```
需要提及的,湊整肯定會導致額外的 *padding* 被增減,通常是和輸入域的長度成一定比例;修改輸出范圍的區間長度,使其更緊湊便可以大大減少額外的 *padding* 被使用。
```
var o = d3.scale.ordinal()
.domain(d3.range(50))
.rangeRoundPoints([0, 95]);
o.range(); // [23, 24, 25, …, 70, 71, 72]
o.rangeRoundPoints([0, 100]);
o.range(); // [1, 3, 5, …, 95, 97, 98]
```
(或者,你也可以手動的處理,這真的有必要嗎???)
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangeBands) ordinal.**rangeBands**(*interval*\[, *padding*\[, *outerPadding*\]\])
功能同[ordinal.rangePoints(interval\[, padding\])](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangePoints),但是該函數是將區間切分成一個個小的區間段,而不是一個個刻度“點”。
指定輸出范圍為一個連續的區間 *interval* ;*interval* 需要兩個數值元素,第一個表示區間的最小值、第二個表示區間的最大值。區間 *interval* 會被切分為 *n* 個等間隔區間段,*n* 的大小取決于輸入域數組的真實長度(也就是數組中每個元素的唯一性而確定的長度)。每個區間段的寬度會因為打區間的首尾 *outerPadding* 值和每個區間段的 *padding* 值而有所消減,默認情況下 *padding* 是 0 。通常,*padding* 的取值范圍是 \[0, 1\],表示相鄰區間段間的間隔(或空白)占區間段的比例;比如: `padding=0.5` 表示區間段的實際寬度與相鄰區間段間的留白相等,參考下面圖片的說明。*outerPadding* 表示第一個區間的起始位置和最后一個區間的結束位置的留白,留白的長度與 *padding* 的使用方式類似,`outerPadding=0` 表示首尾頂著邊緣。

```
var o = d3.scale.ordinal()
.domain([1, 2, 3])
.rangeBands([0, 100]);
o.rangeBand(); // 33.333333333333336
o.range(); // [0, 33.333333333333336, 66.66666666666667]
o.rangeExtent(); // [0, 100]
```
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangeRoundBands) ordinal.**rangeRoundBands**(*interval*\[, *padding*\[, *outerPadding*\]\])
功能同[rangeBands](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangeBands),但是該函數可以美化輸出的區間段,也就是保證每個區間段的起點值都是整數。
```
var o = d3.scale.ordinal()
.domain([1, 2, 3])
.rangeRoundBands([0, 100]);
o.range(); // [1, 34, 67]
o.rangeBand(); // 33
o.rangeExtent(); // [0, 100]
```
需要提及的,湊整肯定會導致額外的 *padding* 被增減,通常是和輸入域的長度成一定比例;修改輸出范圍的區間長度,使其更緊湊便可以大大減少額外的 *padding* 被使用。
```
var o = d3.scale.ordinal()
.domain(d3.range(50))
.rangeRoundBands([0, 95]);
o.range(); // [23, 24, 25, …, 70, 71, 72]
o.rangeRoundBands([0, 100]);
o.range(); // [0, 2, 4, …, 94, 96, 98]
```
(或者,你也可以手動的處理,這真的有必要嗎???)
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangeBand) ordinal.**rangeBand**()
獲取區間段的寬度。只有當使用 [rangeBands](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangeBands) 或 [rangeBands](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangeRoundBands) 來指定輸出范圍時才有效,否則返回一律返回 0。
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_rangeExtent) ordinal.**rangeExtent**()
獲取當前比例尺對象的未被切分的輸出范圍:一個兩元素的數組,第一個元素表示最小值、第二個元素表示最大值。
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#ordinal_copy) ordinal.**copy**()
深度拷貝一個當前比例尺對象的副本,并返回,更改這個副本的屬性不會影響到原比例尺對象的屬性。
## Categorical Colors
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#category10) d3.scale.**category10**()
構造一個新的序數比例尺,使用以下10種類型的顏色:
 #1f77b4
 #ff7f0e
 #2ca02c
 #d62728
 #9467bd
 #8c564b
 #e377c2
 #7f7f7f
 #bcbd22
 #17becf
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#category20) d3.scale.**category20**()
構造一個新的序數比例尺,使用以下20種類型的顏色:
 #1f77b4
 #aec7e8
 #ff7f0e
 #ffbb78
 #2ca02c
 #98df8a
 #d62728
 #ff9896
 #9467bd
 #c5b0d5
 #8c564b
 #c49c94
 #e377c2
 #f7b6d2
 #7f7f7f
 #c7c7c7
 #bcbd22
 #dbdb8d
 #17becf
 #9edae5
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#category20b) d3.scale.**category20b**()
構造一個新的序數比例尺,使用以下20種類型的顏色:
 #393b79
 #5254a3
 #6b6ecf
 #9c9ede
 #637939
 #8ca252
 #b5cf6b
 #cedb9c
 #8c6d31
 #bd9e39
 #e7ba52
 #e7cb94
 #843c39
 #ad494a
 #d6616b
 #e7969c
 #7b4173
 #a55194
 #ce6dbd
 #de9ed6
[\#](%E5%BA%8F%E6%95%B0%E6%AF%94%E4%BE%8B%E5%B0%BA#category20c) d3.scale.**category20c**()
構造一個新的序數比例尺,使用以下20種類型的顏色:
 #3182bd
 #6baed6
 #9ecae1
 #c6dbef
 #e6550d
 #fd8d3c
 #fdae6b
 #fdd0a2
 #31a354
 #74c476
 #a1d99b
 #c7e9c0
 #756bb1
 #9e9ac8
 #bcbddc
 #dadaeb
 #636363
 #969696
 #bdbdbd
 #d9d9d9
## ColorBrewer
D3也通過 \[\[Cynthia Brewer|<http://colorbrewer2.org/>\]\] 綁定了一些奇妙的類目顏色比例尺。可以從 [lib/colorbrewer](mbostock/d3/tree/master/lib/colorbrewer) 找到這些顏色比例尺的 CSS 或 Javascript 實現。
對于 CSS,只要在需要著色的元素上指定 class 類如:像"q0-3"、"q1-3"或"q2-3",然后,在父元素(例如SVG元素)上設置需要的顏色比例尺的名稱到 class 類屬性如"RdBu"或"Blues"。具體參見: [calendar heatmap](http://mbostock.github.com/d3/talk/20111116/calendar.html)、[choropleth](http://mbostock.github.com/d3/talk/20111018/choropleth.html)
對于 JavaScript,可以使用 colorbrewer.RdBu\[9\] 或等同的方法作為 **d3.scale.ordinal** 的范圍如:
```
var o = d3.scale.ordinal()
.domain(["foo", "bar", "baz"])
.range(colorbrewer.RdBu[9]);
```
- - - - - -
[Gulu](https://github.com/tianxuzhang)[@VisualCrew小組](https://github.com/VisualCrew) 譯于 2014-11-24 23:21:05
[WeiFei365](https://github.com/WeiFei365)[@VisualCrew小組](https://github.com/VisualCrew) 校驗于 2015-12-01 22:32:09
- 目前,本頁結構完全和英文頁相同
- 已同步更新首頁的鏈接;
- 其他頁面的引用可以像英文文檔那樣直接引用;
- - - - - -