<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                >[info] 原文鏈接:https://bost.ocks.org/mike/bar/3/ 在前幾節我們制作了一個基本的條形圖,分別使用[HTML](https://bost.ocks.org/mike/bar/),然后改用了[SVG](https://bost.ocks.org/mike/bar/2/)實現;現在,我們將要提高顯示效果,將圖表旋轉為列式展覽,并且加上坐標軸。我們依然使用一個真實的數據集,這個數據集展示了在英語中26個字母的相對使用頻率。 ![](https://box.kancloud.cn/a8feb101ff629143c7e98dcda66469fa_932x490.png) #### **旋轉為列【Rotating into Columns】** 將一個條形圖旋轉為列大都涉及到將x和y進行交換。然而,一系列小的附帶變化也是需要的。這是直接操作SVG而不是使用一個高階可視化語法(比如[ggplot2](http://ggplot2.org/))的代價。另一方面,SVG提供了更好的可定制化;并且SVG是一個web標準,所以我們可以使用瀏覽器的開發者工具比如元素查看器,并且可以使用SVG做可視化之外的事情。 當將x比例尺改名為y比例尺時,range域(即值域)變為[height, 0]而不再是[0, width]。這是因為SVG的坐標系原點位于瀏覽器的左上角。我們想讓0值位于圖表的底部,而不是頂部。類似的,我們需要使用“`y`”和“`height`”屬性來定位條帶`rect`元素,然而之前我們僅需要設置“`width`”。(“`x`”屬性的默認值是0,之前的條帶都是左對齊) 我們之前將`barHeight`變量乘以每個數據點的索引來生成固定高度的條帶。這樣的結果是圖表的高度依賴于數據集的大小。但是這里我們需要相反的表現:圖表的寬度是固定的,而每個條帶的寬度可變。所以不再固定`barHeight`,而是通過可用的圖表寬度除以數據集大小【`data.length`】來計算`barWidth`。 最后,條帶標簽必須按列放置而不是按行,在列頂部下方居中。新的“`dy`”屬性值為“.75em”,將標簽錨定在文本的上限高度【[cap height](http://en.wikipedia.org/wiki/Cap_height)】左右,而不是在基線位置。 ~~~ <!DOCTYPE html> <meta charset="utf-8"> <style> .chart rect { fill: steelblue; } .chart text { fill: white; font: 10px sans-serif; text-anchor: middle; } </style> <svg class="chart"></svg> <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script> <script> var width = 960, height = 500; var y = d3.scale.linear() .range([height, 0]); var chart = d3.select(".chart") .attr("width", width) .attr("height", height); d3.tsv("data.tsv", type, function(error, data) { y.domain([0, d3.max(data, function(d) { return d.value; })]); var barWidth = width / data.length; var bar = chart.selectAll("g") .data(data) .enter().append("g") .attr("transform", function(d, i) { return "translate(" + i * barWidth + ",0)"; }); bar.append("rect") .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }) .attr("width", barWidth - 1); bar.append("text") .attr("x", barWidth / 2) .attr("y", function(d) { return y(d.value) + 3; }) .attr("dy", ".75em") .text(function(d) { return d.value; }); }); function type(d) { d.value = +d.value; // coerce to number return d; } </script> ~~~ #### **對序數編碼【Encoding Ordinal Data】** 不像數量型數據可以比較數值上的大小,做減法或除法,序數值通過等級進行比較。字母就是一種序數;在字母表中,A出現在B前面,B在C前面。D3的線性,冪,和對數比例尺用來編碼數量型數據,而[序數比例尺](https://github.com/mbostock/d3/wiki/Ordinal-Scales)則是用來編碼序數數據。因此我們可以使用一個序數比例尺,簡單的通過字母來定位條帶。 在其最明確的形式中,一個序數比例尺是從一個離散的數據集(比如名字)到一個對應的離散顯示集(比如像素位置)的映射。類似于數值型的比例尺,這2個集合也分別稱為定義域【domain】和值域【range】 ~~~ var x = d3.scale.ordinal() .domain(["A", "B", "C", "D", "E", "F"]) .range([0, 1, 2, 3, 4, 5]); ~~~ x("A")的結果就是0,x("B")的結果是1,等等。在指定定義域和值域時,最重要的就是值的順序:定義域中的i號元素,會映射到值域中的i號元素。 手動枚舉每個條帶的位置是十分枯燥的,所以替代的我們可以使用[rangeBands](https://github.com/mbostock/d3/wiki/Ordinal-Scales#wiki-ordinal_rangeBands)或者[rangePoints](https://github.com/mbostock/d3/wiki/Ordinal-Scales#wiki-ordinal_rangePoints)將一個連續范圍轉化為一組離散值。`rangeBands`方法計算范圍值,以便將圖表區域劃分為均勻間隔,均勻大小的區帶,就像條形圖那樣。類似的rangePoints方法計算均勻間隔的范圍值,比如散點圖。例如: ~~~ var x = d3.scale.ordinal() .domain(["A", "B", "C", "D", "E", "F"]) .rangeBands([0, width]); ~~~ 如果`width`是960,x("A")現在就是0,而x("B")則是160,等等。這些位置是每一個條帶的左邊界,而`x.rangeBand()`返回的是每個條帶的寬度。但是rangeBands也可以使用可選的第3個參數來為條帶之間添加補間【padding】,`rangeRoundBands`則是輸出的值會舍入為最接近的整數,整數值有助于將視覺元素與像素網格對其,保證圖形的邊緣清晰銳利。比較如下代碼: ~~~ var x = d3.scale.ordinal() .domain(["A", "B", "C", "D", "E", "F"]) .rangeRoundBands([0, width], .1); // .1為inner padding,即每檔寬度的10% ~~~ >[warning] 計算過程:960 / 6 = 160,每檔寬度為160,檔內間距為16,所以x("A")從第17個像素開始,即為17,除去7個間距,那么每個條帶的實際寬度為(960 - 7 \* 16) / 6 = 141 現在x("A")是17,每個條帶的寬度是141。并且,在我們的定義域中不需要硬編碼字母進去,我們可以從數據中使用[array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)和[array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)來計算它們。這些都放一起,就形成了如下代碼: ~~~ <!DOCTYPE html> <meta charset="utf-8"> <style> .chart rect { fill: steelblue; } .chart text { fill: white; font: 10px sans-serif; text-anchor: middle; } </style> <svg class="chart"></svg> <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script> <script> var width = 960, height = 500; var x = d3.scale.ordinal() .rangeRoundBands([0, width], .1); var y = d3.scale.linear() .range([height, 0]); var chart = d3.select(".chart") .attr("width", width) .attr("height", height); d3.tsv("data.tsv", type, function(error, data) { x.domain(data.map(function(d) { return d.name; })); y.domain([0, d3.max(data, function(d) { return d.value; })]); var bar = chart.selectAll("g") .data(data) .enter().append("g") .attr("transform", function(d) { return "translate(" + x(d.name) + ",0)"; }); bar.append("rect") .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }) .attr("width", x.rangeBand()); bar.append("text") .attr("x", x.rangeBand() / 2) .attr("y", function(d) { return y(d.value) + 3; }) .attr("dy", ".75em") .text(function(d) { return d.value; }); }); function type(d) { d.value = +d.value; // coerce to number return d; } </script> ~~~ #### **準備邊距【Preparing Margins】** 序數比例尺通常和D3的坐標軸組件一塊使用,用來快速顯示刻度標記,從而提高圖表的易讀性。但在添加坐標軸之前,我們需要清除邊距中的一些空間。 [按照慣例](https://bl.ocks.org/mbostock/3019563),D3中的邊距被指定為一個擁有頂部,右邊,底部,左邊屬性的對象。然后,圖表區域的整體尺寸,包括外邊距,通過減去外邊距來計算可用于圖形標記的內部尺寸。比如,對于一個960x500的圖表來說,合理值為: ~~~ var margin = {top: 20, right: 30, bottom: 30, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; ~~~ 因此,960和500分別就是整體寬度和高度,而計算出的內部`width`和`height`則分別為890和450。這些內部規格可以用來初始化比例尺的值域【ranges】。為了將外邊距應用到SVG容器中,我們對外設置了SVG元素的寬度和高度,然后添加一個`g`元素,使其偏移圖表原點一個左上角外補間的距離。 ~~~ var chart = d3.select(".chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); ~~~ 隨后添加到`chart`中的元素,都會繼承這個外邊距。 #### **添加坐標軸** 我們定義一個坐標軸,將其綁定到已經存在的x比例尺上,并聲明一個朝向。這樣我們的x坐標軸就會出現在條帶的底部,這里我們使用的是`"bottom"`朝向。 ~~~ var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); ~~~ 生成的`xAxis`對象可用來渲染多個坐標軸,只需要多次調用`selection.call`就行。可以想象它是一個橡皮圖章,可以在任何需要的地方打印出坐標軸。坐標軸元素相對于一個本地原點來定位,所以為了放在需要的位置,我們需要在包裹它的`g`元素上設置`"transform"`屬性: ~~~ chart.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); ~~~ 坐標軸容器還應該有個類名,方便我們應用樣式。這里的“axis”名字是隨便起的;你可以使用任何名字。復合類名,比如“x axis”,可用來依據維度來使用不同的坐標軸樣式,同時在所有維度上還可以保留一些共享的樣式。 坐標軸組件包含了一個`path`元素,用來展示定義域【domain】,還包含了多個類名為“.tick”的`g`元素,用來指示每個刻度標記。一個刻度依次包含了一個`text`標簽,和一個`line`標記。大多數的D3例子都使用了如下的極簡風格: ~~~ .axis text { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } ~~~ 這就創建了一個[R工程](http://www.r-project.org/)的懷舊坐標軸: ![](https://box.kancloud.cn/2dc15f21e97e0a27aeee1ff8d2e295e6_441x50.png) 但是,坐標軸是高度可定制的。下面這個更加精巧的坐標軸是仿[ggplot2](http://ggplot2.org/)的風格: ![](https://box.kancloud.cn/47adf92e90c201d0d916cc1ed7eb2949_442x76.png) 除了樣式之外,你還可以通過選擇其元素,并在坐標軸創建后修改它們,來進一步定制一個坐標軸的外觀;一個坐標軸的元素是它的公共API一部分。上面的[ggplot2風格的坐標軸](https://bl.ocks.org/mbostock/4349486)使用了2個平鋪的坐標來渲染,一個在圖表區域內部,而另一個在外面,位于底部外補間中。主刻度和副刻度使用了不同的樣式。 有了坐標軸,我們現在可以移除條帶中的標簽。完整代碼如下: ~~~ <!DOCTYPE html> <meta charset="utf-8"> <style> .bar { fill: steelblue; } .axis text { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .x.axis path { display: none; } </style> <svg class="chart"></svg> <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script> <script> var margin = {top: 20, right: 30, bottom: 30, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var x = d3.scale.ordinal() .rangeRoundBands([0, width], .1); var y = d3.scale.linear() .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left"); var chart = d3.select(".chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); d3.tsv("data.tsv", type, function(error, data) { x.domain(data.map(function(d) { return d.name; })); y.domain([0, d3.max(data, function(d) { return d.value; })]); chart.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); chart.append("g") .attr("class", "y axis") .call(yAxis); chart.selectAll(".bar") .data(data) .enter().append("rect") .attr("class", "bar") .attr("x", function(d) { return x(d.name); }) .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }) .attr("width", x.rangeBand()); }); function type(d) { d.value = +d.value; // coerce to number return d; } </script> ~~~ #### **傳詞達意【Communicating】** 在這點上,我恐怕要讓你失望了。 我努力解釋了圖表構造中的技術細節,但我卻掩蓋了有效可視化中的一個重要部分:有效的溝通。一個圖表再好看,如果它不能表達任何意思,那么就毫無用處!我們必須標記圖表,給讀者足夠的內容來理解它。 這個問題比你想象的更加普遍。當可視化數據時,很容易隱藏掉甚至忘掉你對數據集的額外理解以及初衷。你知道這是一個關于英語字母相對頻率的條形圖。但是除非你明確注明,你的讀者不一定能知曉這些。標簽,標題,圖例和其它說明要素對于理解是至關重要的。一個標題可以添加到Y軸上,通過添加一個text元素,并定位到需要的位置上。 ~~~ chart.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Frequency"); ~~~ 單位適當的數值格式,可以裁剪待顯示的數據,這同樣有助于提高圖表的易讀性。因為我們展示的是相對頻率,百分數就比默認的小數更適合一些。一個[格式化字符串](https://github.com/mbostock/d3/wiki/Formatting)作為[axis.ticks](https://github.com/mbostock/d3/wiki/SVG-Axes#wiki-ticks)的第2個參數將會定制刻度格式,并且比例尺將會針對刻度間隔自動選擇合適的精度。 ~~~ var yAxis = d3.svg.axis() .scale(y) .orient("left") .ticks(10, "%"); ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看