D3で折れ線グラフを作成します。js v.5

私たちのゲームをステップアップし、ゼロから折れ線グラフを作成する時が来ました。 折れ線グラフだけでなく、任意の数の線を収容できるマルチシリーズグラフです。 複数の行を処理することに加えて、時間と線形スケール、軸、およびラベルを使用します–またはむしろ、それらを私たちのために動作させます。 やるべきことがたくさんあるので、私はあなたのD3サーバーを解雇し、亀裂を取得してみましょうお勧めします。

私たちはこの美しさを創造します! 楽しい!

ドキュメントの準備

最初のステップとして、視覚化のためのデータとファイル構造を準備する必要があります。 Line_chartを作成します。html、スタイル。css、およびデータ。あなたのプロジェクトフォルダ内のcsvとそれに続くスニペットでそれらを移入します。 これは私たちを始めるでしょう。

これをline_chartに貼り付けます。htmlファイル。 このコードはsvg要素を定義しているので、すぐに描画を開始できます。 私はまた、基本的な構造を事前に作成したので、特定のセクションで作業するときに文書をナビゲートする方が簡単です。

スタイルを残します。css文書は今のところ空です。 次の行をデータに貼り付けます。——- 折れ線グラフには、列A、B、およびCに対応する複数の系列が表示されます。

date,A,B,C20-Jul-2019,10,20,1621-Jul-2019,11,22,1822-Jul-2019,13,19,2123-Jul-2019,11,17,2224-Jul-2019,15,16,2025-Jul-2019,16,19,1826-Jul-2019,19,21,1827-Jul-2019,22,25,1528-Jul-2019,18,24,1229-Jul-2019,14,20,1630-Jul-2019,14,18,1831-Jul-2019,16,18,2101-Aug-2019,15,20,2202-Aug-2019,14,21,19

データ準備

最初のステップ、そして全体の視覚化のための重要なステップは、データを正しく読み取ることです。 私は理由のために複数のシリーズの例を使用しました:単一のパスをプロットするのは非常に簡単ですが、複数の行(特に未定義の数)を処理するには、 データセクションに以下を貼り付け、htmlドキュメントをリロードし、ブラウザでコンソールログを確認します:

const timeConv = d3.timeParse("%d-%b-%Y");const dataset = d3.csv("data.csv");dataset.then(function(data) { const slices = data.columns.slice(1).map(function(id) { return { id: id, values: data.map(function(d){ return { date: timeConv(d.date), measurement: +d }; }) }; });console.log("Column headers", data.columns);console.log("Column headers without date", data.columns.slice(1));// returns the sliced datasetconsole.log("Slices",slices); // returns the first sliceconsole.log("First slice",slices);// returns the array in the first sliceconsole.log("A array",slices.values); // returns the date of the first row in the first sliceconsole.log("Date element",slices.values.date); // returns the array's lengthconsole.log("Array length",(slices.values).length);

データセットで呼び出される変換を1つずつ確認してみましょう:–data。columnsはcsvヘッダー–データを返します。列。slice(1)は日付列なしでcsvヘッダーを返します(スライスは1でインデックス付けされた列から始まります)–map()は配列のすべての要素で関数を呼び出します(A,B,Cで構成されます)–それらの各要素を’slice’と呼びましょう–map()は列名を各スライスにid要素として割り当てます–その後、各スライスにvalues配列を割り当てます–values要素がどのように関数を呼び起こすかに注意してください。 ここでは、元のデータセットからの情報をマップします:配列は2つの列、日付と測定で構成されます。 日付は最初の列から導出され(日付形式に変換されます)、測定値はスライスの列に対応する列から取得されますid.At これらの変換の終わりには、a、B、およびCの3つの配列が得られ、それぞれ2つの列があります:dateとmeasurement。 これは、データセットをスライスするための驚くほど柔軟な方法です:それが持っている列の数に関係なく! それはすべてこれらのいくつかの行で行われます。 私はあなたがスニペットを確認するのに役立ついくつかの情報をコンソールに印刷しました。

コンソールログ

詳細については、コンソールログを確認してください

スケールの準備

データが読み込まれた後、スケールメカニズムを設定する必要 これは、svgの不動産に応じてチャートを印刷するために行われます。 スケールは、データ入力(日付と値)をsvg平面上の座標に変換します。 スケールセクションに次の行を貼り付けます。

const xScale = d3.scaleTime().range();const yScale = d3.scaleLinear().rangeRound();xScale.domain(d3.extent(data, function(d){ return timeConv(d.date)}));yScale.domain();

日付をx軸に、値をy軸にプロットします。 D3には、日付をスケーリングするためのscaleTime()メソッドと、連続値のためのscaleLinear()メソッドが用意されています。 最初にスケールの範囲を決定します:入力値を変換する必要があります。 この場合、データ値を0からsvgの幅に、数値をsvgの高さから0に伸ばします。 第二のステップとして、我々は、入力データドメインを指定します。 ドメインは、データセットが取ることができる指定された最小値と最大値の間のすべての値で構成されます。 これらの値を手動で検索する代わりに、組み込みのD3関数–d3を渡します。extent()は配列の最小値と最大値を(自然な順序で)返します–これは日付セット–d3で完全に機能します。max()は、配列の最大値を返します。 この例では、最初に各配列から最大値を抽出してから、3つすべての最大値を選択する方法に注意してください。 私はまた、純粋に主観的な審美的な理由のために最大値に4を追加しました:私はグラフの上にいくつかのスペースを持ちたいと思っていました。

スケールが設定されました。 あなたはスケールの十分を持っていないと、より多くの例を見たい場合は、私の前のチュートリアルを見てみましょう。

よく構成されたスケールは、svg上の値のプロットを開始することができます。 データセットを呼び起こすたびに、適切なスケールを呼び出すだけです。

もう何か描こう! 正しくプロットされていれば、データが期待どおりに読み取られ、想像したとおりに適切にスケーリングされていることが保証されます。

これを準備セクションの下の軸に貼り付けます:

const yaxis = d3.axisLeft().scale(yScale); const xaxis = d3.axisBottom().scale(xScale);

そして、これは描画セクションの下の軸に:

svg.append("g") .attr("class", "axis") .attr("transform", "translate(0," + height + ")") .call(xaxis);svg.append("g") .attr("class", "axis") .call(yaxis);

そして、我々はx軸とy軸をプロットしていることと同じくらい簡単!

軸はこちら!

確かに、軸は世界で最もエレガントではありません(そこにはいくつかのきれいな軸があります)が、彼らはここにあります! 私たちは読者のためにそれらをより友好的にするために適用することができますいくつかの追加の微調整があります。

最初にx軸を見てみましょう:日付には面白いことがあります。 左から読むと、「Sat20」、「Jul21」、「Mon22」が得られ、ある時点で「August」に到達します。 月と日は、バリエーションの不服従のミックスに来ているように思えます。 私たちは、このフリースタイルに入れて終了する必要があり、これによって私たちは、画面に印刷したいのですが、どのような日付形式を決定する必要が D3.axis()メソッドを使用すると、目盛りの数、ポイント間の間隔、表示形式など、あらゆる種類のものを調整できます。 のは、両方の軸のためにそれらのいくつかを設定してみましょう。

準備セクションの座標軸の定義を次のスニペットに置き換え、視覚化を更新します:

const yaxis = d3.axisLeft() .ticks((slices.values).length) .scale(yScale);const xaxis = d3.axisBottom() .ticks(d3.timeDay.every(1)) .tickFormat(d3.timeFormat('%b %d')) .scale(xScale);

上記のコードは、y軸の設定されたティック数(14個、または配列要素/csv行がある数)を指定します。 X軸の場合、目盛りは毎日1日の粒度で表示されます。 これは、tickプロパティをd3に設定することによって達成されました。タイムデイすべて(1) 表示される日付の形式には、各ティックの日と省略された月が表示されます。 これらの変更の後、私たちはやや改善された軸で終わります:

オルドヌング、ついに

不従順な日付はもはや問題ではない!

それをさらに良くするために(それは可能ですか!!!)y軸にラベルを追加して、値が何を表しているかを示すことができます。 日付は自明ですが、数字自体には情報がありません。 Y軸の描画に以下を追加して、ラベルを追加します(好きなように呼び出します–私は周波数を使用しました)。:

//this you hadsvg.append("g") .attr("class", "axis") .call(yaxis)//this you append .append("text") .attr("transform", "rotate(-90)") .attr("dy", ".75em") .attr("y", 6) .style("text-anchor", "end") .text("Frequency");

(ラベルにはスタイルが設定されていないため、グラフには表示されませんが、私とGoogle Chrome developer toolsを信じて、そこにあります)

ラベル

y軸ラベルが見えない

最後に、軸の外観を改善しましょう。 改善することによって、私は意味します:すべての単一要素の色、幅、およびレンダリングを設定し、使用するフォントを決定します。 以下をcssファイルに貼り付け、自由に独自のスタイルを決定してください:

/* AXES *//* ticks */.axis line{stroke: #706f6f;stroke-width: 0.5;shape-rendering: crispEdges;}/* axis contour */.axis path {stroke: #706f6f;stroke-width: 0.7;shape-rendering: crispEdges;}/* axis text */.axis text {fill: #2b2929;font-family: Georgia;font-size: 120%;}

ティックはによって制御されます。軸のライン要素は、実際の軸がで設定されている間。パス要素。 軸はシャープに見え(著者の謙虚な意見)、いくつかのデータを歓迎する準備ができています:

それ以上の騒ぎをせずに、チャートをプロットしてみましょう!

折れ線グラフ

線は基本的にd3です。2D平面上の(x、y)座標の束を接続するpaths()。 行を作成するには、x座標とy座標をどこに見つけるかを指示し、それをsvgに追加する必要があります。 以前に作成したプレースホルダに次のスニペットを貼り付けて、コードを一緒に確認しましょう。

これは準備セクションの下の行ビットになっているはずです:

const line = d3.line() .x(function(d) { return xScale(d.date); }) .y(function(d) { return yScale(d.measurement); });

このスニペットでは、ラインコンストラクタd3と呼びました。2つのアクセサを使用するline():水平面上の値のためのx、および垂直軸のためのy。 ここでは、配列、日付、測定値の最も細かい値を指すだけです(これはネストされたcsv構造について心配する時間ではありません)。 それが完了したら、描画セクションの下の線に次のものを貼り付けます:

const lines = svg.selectAll("lines") .data(slices) .enter() .append("g"); lines.append("path") .attr("d", function(d) { return line(d.values); });

これにはいくつかの説明が必要です。 変数linesは、svgから未確認の数の行を選択し、スライスセット(行A、b、およびC)を指すことによって、D3に3行があることをすぐに伝えます。 次に、それぞれにg要素を追加します:グループ化要素は、当然のことながら私たちの生活を楽にします。 G要素は、特定のグラフ系列(配列内のスライスとも呼ばれます)に関係するすべてのものを収集します:線(上でパスとして表されます)、そのデータポイント

最初に行に追加するのは、グラフの行そのものです(実際には3つの空のgコンテナです)。 私たちはd3と呼んでいます。パスを描画するためのデータ上のline()コンストラクタ。 最初に各スライスの下の値にアクセスする必要がある方法を参照してください。 これは、必要に応じて日付と測定値を取得するコンストラクターに渡されます。

変更が保存された後、視覚化は次のように更新されます:

折れ線グラフの代わりに、山グラフ

さて、これは完璧ではありませんが、私を信じて、私たちはそこに着いています! チャートにいくつかの審美的な修正を適用し、それがどのように整形するかを観察してみましょう。 スタイルに以下を追加します。css:

/* LINE CHART */path {fill: none;stroke: #ed3700;}

図形を線として再表示するには、fillをnoneに設定する必要があります。 グラフを更新する:

線が現れました

折れ線グラフとグラフ上に一緒に立ち往生している線の束を分けるのは何ですか? シリーズを区別する能力。 現時点では前者しかありません。

まず、コード内の行を区別する必要があります。 それぞれの行クラスにidを追加しましょう–準備パーツの行セクションに次のものを追加します:

let id = 0;const ids = function () { return "line-"+id++;}

この小さなコードは、追加されたすべての行に行idを自動的に割り当てるために利用できるカウンタを作成します。 パスのclassプロパティでカウンタを参照してみましょう。 LINESセクションのコードを調整して、classプロパティを追加します:

const lines = svg.selectAll("lines") .data(slices) .enter() .append("g"); lines.append("path") .attr("class", ids) .attr("d", function(d) { return line(d.values); });

そして魔法のように、各パスは独自のクラスを取得します!

パスクラス

行には独自のidが与えられます

cssでこれらのクラスを参照し、各行に独自の一意の文字を与えることが残っています。 Cssの折れ線グラフセクションを次のように変更します:

/* LINE CHART */path.line-0 {fill: none;stroke: #ed3700;}path.line-1 {fill: none;stroke: #2b2929;stroke-dasharray: 2;}path.line-2 {fill: none;stroke: #9c9c9c;stroke-dasharray: 6;}

私は色を修正するだけでなく、各行のストロークを変更する方法に注意してください。 すべての人々の約10%がある程度の色盲を持っており、公平に色を区別することは私たちの誰にとっても難しいことがあります。 あまりにも多くのデータ系列があり、その色相がすべてのモニターで異なって表示される場合、色は一緒に混ざります。

変更が適用された後、以下に示すように、グラフ上で線が明確に分離されます:

線は互いに視覚的に異なっています

今、シリーズは区別されていますが、基礎となるデータを記憶し、かなり病気の視覚的想像力を持っていない限り、ど シリーズの認識で私たちの大部分を支援するために、私はグラフの右側にシリーズ名を追加することを提案します。 線の描画セクションに以下を追加します:

lines.append("text") .attr("class","serie_label") .datum(function(d) { return { id: d.id, value: d.values}; }) .attr("transform", function(d) { return "translate(" + (xScale(d.value.date) + 10) + "," + (yScale(d.value.measurement) + 5 ) + ")";}) .attr("x", 5) .text(function(d) { return ("Serie ") + d.id; });

スニペットは各行の末尾をローカライズし、テキスト要素を追加します。 テキストは、行に応じてSerie A、Serie B、またはSerie Cとして印刷されます。 シリーズラベルを調整するには、cssドキュメントに次のものを追加します:

.serie_label {fill: #2b2929;font-family: Georgia;font-size: 80%;}

ラベルが追加されます! いい時代だ

各シリーズは、独自のラベルを持って

我々はすべてこれが一つのハンサムな折れ線グラフであることに同意することができます! 私は以下の完全なコードを貼り付けました。 チャートに対話性を追加する2つのシナリオを示すチュートリアルの2番目の部分を確認してください。

より多くのデータsciency/データ視覚化プロジェクトのためのTwitterで私に従ってください!

コードサンプル

line_chart。

css:

/* AXES *//* ticks */.axis line{stroke: #706f6f;stroke-width: 0.5;shape-rendering: crispEdges;}/* axis contour */.axis path {stroke: #706f6f;stroke-width: 0.7;shape-rendering: crispEdges;}/* axis text */.axis text {fill: #2b2929;font-family: Georgia;font-size: 120%;}/* LINE CHART */path.line-0 { fill: none; stroke: #ed3700;}path.line-1 { fill: none; stroke: #2b2929; stroke-dasharray: 2;}path.line-2 { fill: none; stroke: #9c9c9c; stroke-dasharray: 6;}.serie_label { fill: #2b2929; font-family: Georgia; font-size: 80%;}

データ。