2012-08-31 21 views
9

Tôi đang triển khai bản đồ nhiệt có màu nền của ô được xác định bằng thang màu d3. Một số giá trị là phân loại; giá trị của chúng có thể thuộc N loại chuỗi tùy ý khác nhau như ["6TH", "7TH", "5TH", "4TH"].Quy mô màu liên tục từ miền riêng biệt của chuỗi?

Cho màu bắt đầu d3.rgb ("xanh") và màu cuối d3.rgb ("đỏ"), làm cách nào tôi có thể tạo thang màu ánh xạ một miền riêng biệt của chuỗi thành một dải màu liên tục?

tôi đã cố gắng

var scale = d3.scale.ordinal() 
    .domain(["6TH", "7TH", "5TH", "4TH"]) 
    .rangeBands([ d3.rgb("blue"), d3.rgb("red") ]); 

mà rõ ràng không hoạt động.

Trả lời

29

Trước tiên, tôi sẽ xem xét sử dụng một trong các cân có sẵn Colorbrewer; xem colorbrewer2.org. Các tệp này cũng có sẵn dưới dạng tệp JavaScript và CSS trong kho lưu trữ git của D3; xem lib/colorbrewer. Ví dụ, nếu bạn có bốn giá trị rời rạc trong miền của bạn, và bạn muốn có một quy mô phân kỳ màu đỏ-xanh, bạn có thể nói:

var color = d3.scale.ordinal() 
    .domain(["6TH", "7TH", "5TH", "4TH"]) 
    .range(colorbrewer.RdBu[4]); 

(Bạn sẽ cần một <script src="colorbrewer.js"></script> ở đâu đó trước đây, quá.) ColorBrewer có một loạt các quy mô màu sắc phân cấp, phân kỳ và phân loại được thiết kế tốt.

Nếu bạn nhấn mạnh vào việc cuộn thang màu của riêng mình, tôi khuyên bạn nên nội suy theo số L*a*b* or HCL color space để có nhận thức chính xác. Bạn có thể thực hiện việc này bằng cách sử dụng d3.interpolateLab hoặc d3.interpolateHcl. Ví dụ: d3.interpolateLab("red", "blue")(.5) trả về một màu giữa màu đỏ và xanh lam.

Để tính toán màu cho dải phạm vi thứ tự của bạn, bạn có thể sử dụng bộ nội suy hoặc bạn có thể tìm thấy thang đo tuyến tính tạm thời thuận tiện hơn.Ví dụ:

var categories = ["6TH", "7TH", "5TH", "4TH"]; 

var color = d3.scale.ordinal() 
    .domain(categories) 
    .range(d3.range(categories.length).map(d3.scale.linear() 
     .domain([0, categories.length - 1]) 
     .range(["red", "blue"]) 
     .interpolate(d3.interpolateLab))); 
+1

Cập nhật: D3's Colorbrewer lib đã chuyển sang kho lưu trữ [d3-scale-chromatic] (https://github.com/d3/d3-scale-chromatic). – danasilver

3

Bạn có ý tưởng đúng, bạn chỉ cần xử lý từng kênh màu R/G/B. Ví dụ, trong vanilla JavaScript bạn có thể làm như sau:

var a = [255, 0, 0], // First color 
    b = [0, 0, 255], // Other color 
    bands = 5,  // Bands is the length of your domain 
    i, 
    delta = [];  // Difference between color in each channel 

// Compute difference between each color 
for (i = 0; i < 4; i++){ 
    delta[i] = (a[i] - b[i])/(bands + 1); 
} 

// Use that difference to create your bands 
for (i = 0; i <= bands + 1; i++){ 
    var r = Math.round(a[0] - delta[0] * i); 
    var g = Math.round(a[1] - delta[1] * i); 
    var b = Math.round(a[2] - delta[2] * i); 
    console.log("<div style='background-color: #" + dec2hex(r) + dec2hex(g) + dec2hex(b) + "'>Band " + i + "</div>"); 
} 

// A helper function for formatting 
function dec2hex(i) { 
    return (i+0x100).toString(16).substr(-2).toUpperCase(); 
} 

Theo d3 documentation, bạn có thể trích xuất mỗi kênh màu bằng cách sử dụng r, gb thuộc tính của một đối tượng màu:

# d3.rgb(color)

Tạo màu RGB mới bằng cách phân tích chuỗi màu được chỉ định. Nếu màu không phải là một chuỗi, nó bị ép buộc thành một chuỗi; do đó, hàm tạo này cũng có thể được sử dụng để tạo một bản sao của một màu hiện có, hoặc buộc chuyển đổi màu d3.hsl thành RGB.

...

Màu kết quả được lưu trữ dưới dạng giá trị kênh nguyên màu đỏ, xanh lá cây và xanh lam trong phạm vi [0,255]. Các kênh có sẵn dưới dạng các thuộc tính r, g và b của đối tượng được trả về.

Vì vậy, ở phía trên cùng của ví dụ trên, bạn có thể nói:

var myColor = d3.rgb("blue"), 
    a = [myColor.r, myColor.g, myColor.b], 
... 

Điều đó giúp đỡ?

+0

Vâng, nó chắc chắn đã giúp! Cảm ơn, làm việc hoàn hảo. – ekerner

0

Bạn luôn có thể chuỗi một thang đo thứ tự và tỷ lệ tuyến tính.

Quy mô đầu tiên sẽ tạo ra các giá trị có thể định lượng từ các giá trị rời rạc của bạn và thang thứ hai sẽ nội suy các giá trị này trên thang màu.

Something như thế này:

// Your categories 
 
var data = ["6TH", "7TH", "5TH", "4TH"], 
 

 
    // Define ordinal to linear scale... 
 
    ordinal = d3.scale.ordinal().domain(data).rangePoints([0, 1]), 
 

 
    // ...and linear to color scale 
 
    linear = d3.scale.linear().domain([0, 1]).range([d3.rgb("blue"), d3.rgb("red")]); 
 

 
// Now define your artificial 'compound' scale 
 
function scale(d) { 
 
    return linear(ordinal(d)); 
 
} 
 

 
// And then use it on your D3 code 
 
d3.selectAll('div') 
 
    .data(data) 
 
    .enter() 
 
    .append('div') 
 
    .style('background', scale) // <- et voilà ;) 
 
    .text(function(d) { 
 
    return d; 
 
    });
div { 
 
    color: white; 
 
    width: 3em; 
 
    padding: 1em; 
 
    margin: .2em 
 
    text-align: center; 
 
    font-family: Arial, Helvetica, sans-serif; 
 
    font-weight: bold 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Các vấn đề liên quan