ایجاد نمودار چند خطی در کتابخانه D3

در این مقاله قصد داریم نحوه ایجاد نمودار چند خطی را در کتابخانه D3 آموزش دهیم، پس با ما همراه باشید.

ما برای رسم نمودار چند خطی در این مقاله از فایلی شاملی آرایه‌ای از objectها که حاوی مقادیر month, year و count است استفاده کرده‌ایم.

 

کد ایجاد نمودار چند خطی در کتابخانه D3:

 

var margin = {top: 10, right: 30, bottom: 30, left: 60};
var width = 700 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
 
var svg = d3.create('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
 
var g = svg.append('g')
.attr('transform', `translate(${margin.left}.${margin.top})`);
 
var correctData = d3.group(requestsMonthly, d => d.year);
 
var x = d3.scaleLinear()
.domain([1, d3.max(requestsMonthly, d => d.month)])
.range([20, width - 50]);
g.append('g')
.attr('transform', `translate(0, ${height})`)
.call(d3.axisBottom(x))
 
var y = d3.scaleLinear()
.domain([0, d3.max(requestsMonthly, d => d.count)])
.range([height, 30]);
g.append('g')
.attr('transform', `translate(20, 0)`)
.call(d3.axisLeft(y));
 
var color = d3.scaleOrdinal()
.range(['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#000000'])
 
g.selectAll('.line')
.data(correctData)
.join('path')
.attr('fill', 'none')
.attr('stroke', function(d) {return color(d[0])})
.attr('stroke-width', 1.5)
.attr('d', function(d){
return d3.line()
.x(function(d) { return x(d.month) })
.y(function(d) { return y(d.count) })
(d[1]);
})
 
g.selectAll('.dot-group')
.data(correctData)
.join('g')
.attr('class', 'dot-group')
.selectAll('circle')
.data(function(d) { return d[1]; })
.join('circle')
.attr('cx', function(d) { return x(d.month); })
.attr('cy', function(d) { return y(d.count); })
.attr('r', 3)
.style('fill', function(d) { return color(d.year); })
.append("title")
.text(d => d3.format(',')(d.count));
 
var legend = g.append('g')
.attr('class', 'legend')
.attr('transform', `translate(${width - 30}, 20)`);
 
legend.selectAll('rect')
.data(correctData)
.join('rect')
.attr('x', 0)
.attr('y', (d, i) => i * 20)
.attr('width', 10)
.attr('height', 10)
.style('fill', d => color(d[0]));
 
legend.selectAll('text')
.data(correctData)
.join('text')
.attr('x', 15)
.attr('y', (d, i) => i * 20 + 9)
.style('font-size', '12px')
.text(d => d[0]);
 
g.append('text')
.attr('x', width / 2)
.attr('y', height + margin.top + 20)
.attr('text-anchor', 'middle')
.style('font-size', '14px')
.text('ماه');
 
g.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', 0 - height / 2)
.attr('y', -45)
.attr('text-anchor', 'middle')
.style('font-size', '14px')
.text('تعداد');
 
svg.node()

 

خروجی کد:

 

 

تنظیمات اولیه برای رسم نمودار در کتابخانه D3

 

در ابتدا ابعاد SVG و یک گروه داخلی (g) برای اضافه کردن محتوا به SVG تعریف می‌شود. این تنظیمات شامل همچنین مرزها و فضای پرشده توسط SVG است.

 

var margin = {top: 10, right: 30, bottom: 30, left: 60};
var width = 700 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
 
var svg = d3.create('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
 
var g = svg.append('g')
.attr('transform', `translate(${margin.left}.${margin.top})`);

 

  • var margin = {top: 10, right: 30, bottom: 30, left: 60}; -> مشخص کردن فاصله از حاشیه‌ها
  • var width = 700 - margin.left - margin.right; -> مشخص کردن عرض SVG
  • var height = 500 - margin.top - margin.bottom; -> مشخص کردن ارتفاع SVG
  • var svg = d3.create('svg') -> ایجاد تگ SVG
  • attr('width', width + margin.left + margin.right) -> مقداردهی به عرض SVG
  • attr('height', height + margin.top + margin.bottom) -> مقداردهی به ارتفاع SVG
  • var g = svg.append('g') -> ایجاد تگ g برای گروه‌بندی عناصری که به SVG اضافه خواهند شد
  • attr('transform', `translate(${margin.left}.${margin.top})`) -> جابجا کردن تگ g

 

تبدیل داده‌ها در کتابخانه D3

 

پس از آن، با استفاده از تابع group داده‌ها را بر اساس سال‌ها گروه‌بندی می‌کنیم تا برای هر سال، داده‌های مربوط به آن را در یک زیرمجموعه داشته باشیم.

 

var correctData = d3.group(requestsMonthly, d => d.year);

 

  • var correctData = d3.group(requestsMonthly, d => d.year)

 

مقیاس‌بندی محورها در کتابخانه D3

 

در مرحله بعد، مقیاس‌بندی برای محورهای x و y انجام می‌دهیم. این مقیاس‌ها به ترتیب برای تاریخ (ماه) و تعداد استفاده می‌شوند.

 

var x = d3.scaleLinear()
.domain([1, d3.max(requestsMonthly, d => d.month)])
.range([20, width - 50]);
 
var y = d3.scaleLinear()
.domain([0, d3.max(requestsMonthly, d => d.count)])
.range([height, 30]);

 

  • var x = d3.scaleLinear() -> مشخص کردن محدوده مقیاس محور افقی با استفاده از تابع scaleLinear
  • domain([1, d3.max(requestsMonthly, d => d.month)]) -> مشخص کردن دامنه مقیاس محور افقی با استفاده از شروع و پایان داده‌ها
  • range([20, width - 50]) -> محدوده‌ای که در svg اشغال می‌کند.
  • var y = d3.scaleLinear() -> مشخص کردن مقیاس محور عمودی با استفاده از تابع scaleLinear
  • domain([0, d3.max(requestsMonthly, d => d.count)]) ->  مشخص کردن دامنه مقیاس محور عمودی با استفاده از شروع و پایان داده‌ها
  • range([height, 30]) -> محدوده‌ای که در svg اشغال می‌کند

 

ایجاد محورها در کتابخانه D3

 

پس از مقیاس‌بندی، محورهای x و y را با استفاده از توابع d3.axisBottom() و d3.axisLeft() ایجاد می‌کنیم و به مختصات SVG اضافه می‌کنیم.

 

g.append('g')
.attr('transform', `translate(0, ${height})`)
.call(d3.axisBottom(x))
 
g.append('g')
.attr('transform', `translate(20, 0)`)
.call(d3.axisLeft(y));

 

  • g.append('g') -> افزودن گروه g برای رسم محور افقی در svg
  • attr('transform', `translate(0, ${height})`) -> جابجایی گروه g
  • call(d3.axisBottom(x)) -> استفاده از axisBottom برای ایجاد محور افقی
  • g.append('g') -> افزودن گروه g برای رسم محور عمودی در svg
  • attr('transform', `translate(20, 0)`) -> جابجایی گروه g
  • call(d3.axisLeft(y)); -> استفاده از axisLeft برای ایجاد محور عمودی و مقداردهی با آن با استفاده از مقیاس‌هایی که قبلا تعریف کرده‌ایم

 

مقیاس‌بندی رنگ‌ها در کتابخانه D3


با استفاده از scaleOrdinal مقیاس رنگ را برای تمایز داده‌های مختلف انجام می‌دهیم.

 

var color = d3.scaleOrdinal()
.range(['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#000000'])


var color = d3.scaleOrdinal().range(['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#000000'])

 

رسم خطوط در کتابخانه D3

 

در این بخش خطوط را برای هر دسته از داده‌ها ایجاد می‌کنیم.

 

g.selectAll('.line')
.data(correctData)
.join('path')
.attr('fill', 'none')
.attr('stroke', function(d) {return color(d[0])})
.attr('stroke-width', 1.5)
.attr('d', function(d){
return d3.line()
.x(function(d) { return x(d.month) })
.y(function(d) { return y(d.count) })
(d[1]);
})

 

  • g.selectAll('.line') -> انتخاب تمام المان‌های با کلاس "line" که در داخل المان g قرار دارند
  • data(correctData) -> متصل کردن داده‌ها به المان‌های انتخاب شده، با استفاده از داده‌هایی که در متغیر correctData ذخیره شده‌اند
  • join('path') -> ایجاد مسیر (path) برای هر داده
  • attr('fill', 'none') -> مشخص کردن ویژگی fill به none برای جلوگیری از پر کردن داخل مسیر
  • attr('stroke', function(d) {return color(d[0])}) -> مشخص کردن ویژگی stroke برای تغییر رنگ خط، با استفاده از مقداری که از آرایه correctData گرفته شده و به مقیاس رنگ متصل می‌شود
  • attr('stroke-width', 1.5) -> مشخص کردن ضخامت خط
  • attr('d', function(d){ -> مشخص کردن مسیر دقیق خط با استفاده از تابع d3.line() برای ایجاد خطوط به ازای هر دسته داده
  • return d3.line() -> یجاد یک تابع خطی جدید با استفاده از d3.line()
  • x(function(d) { return x(d.month) }) -> مشخص کردن مختصات x برای هر نقطه بر اساس ماه مربوطه از داده
  • y(function(d) { return y(d.count) }) -> مشخص کردن مختصات y برای هر نقطه بر اساس تعداد مربوطه از داده
  • d[1]);}) -> انتخاب داده‌های مورد نیاز برای رسم خطوط، که در آرایه دوم از داده‌های correctData ذخیره شده است

 

نمایش نقاط داده در کتابخانه D3


در این بخش نقاط داده‌ها در هر دسته را ایجاد می‌کنیم.

 

g.selectAll('.dot-group')
.data(correctData)
.join('g')
.attr('class', 'dot-group')
.selectAll('circle')
.data(function(d) { return d[1]; })
.join('circle')
.attr('cx', function(d) { return x(d.month); })
.attr('cy', function(d) { return y(d.count); })
.attr('r', 3)
.style('fill', function(d) { return color(d.year); })

 

  • g.selectAll('.dot-group') -> انتخاب تمام المان‌های با کلاس "dot-group" که در داخل المان g قرار دارند
  • data(correctData) -> متصل کردن داده‌ها به المان‌های انتخاب شده، با استفاده از داده‌هایی که در متغیر correctData ذخیره شده‌اند
  • join('g') -> ایجاد گروه (g) برای هر داده
  • attr('class', 'dot-group') ->  مشخص کردن ویژگی class به "dot-group" برای هر گروه جدید ایجاد شده
  • selectAll('circle') -> انتخاب تمام المان‌های دایره در داخل هر گروه
  • data(function(d) { return d[1]; }) -> متصل کردن داده‌ها به المان‌های دایره‌ای انتخاب شده، با استفاده از داده‌هایی که در زیرداده‌های correctData ذخیره شده‌اند
  • join('circle') -> ایجاد یک عضو وصل‌شونده جدید از نوع دایره (circle) برای هر داده
  • attr('cx', function(d) { return x(d.month); }) -> مشخص کردن مختصات مرکزی x برای هر دایره بر اساس ماه مربوطه از داده
  • attr('cy', function(d) { return y(d.count); }) -> مشخص کردن مختصات مرکزی y برای هر دایره بر اساس تعداد مربوطه از داده
  • attr('r', 2.5) -> مشخص کردن شعاع دایره
  • style('fill', function(d) { return color(d.year); }); -> مشخص کردن رنگ پر دایره بر اساس سال مربوطه از داده، با استفاده از مقیاس رنگ تعریف شده در متغیر color

 

ایجاد راهنمای نمودار در کتابخانه D3

 

در این بخش راهنمای نمودار را اضافه می‌کنیم.

 

var legend = g.append('g')
.attr('class', 'legend')
.attr('transform', `translate(${width - 30}, 20)`);
 
legend.selectAll('rect')
.data(correctData)
.join('rect')
.attr('x', 0)
.attr('y', (d, i) => i * 20)
.attr('width', 10)
.attr('height', 10)
.style('fill', d => color(d[0]));
 
legend.selectAll('text')
.data(correctData)
.join('text')
.attr('x', 15)
.attr('y', (d, i) => i * 20 + 9)
.style('font-size', '12px')
.text(d => d[0]);

 

  • legend.selectAll('rect') -> انتخاب تمام المان‌های مستطیلی در داخل المان legend
  • data(correctData) -> متصل کردن داده‌ها به المان‌های انتخاب شده، با استفاده از داده‌هایی که در متغیر correctData ذخیره شده‌اند
  • join('rect') ->  ایجاد نوع مستطیل (rect) برای هر داده
  • attr('x', 0) -> مشخص کردن مختصات x برای مستطیل
  • attr('y', (d, i) => i * 20) -> مشخص کردن مختصات y برای مستطیل‌ها بر اساس اندیس آن‌ها، به طوری که هر مستطیل در یک خط مجاور قرار گیرد
  • attr('width', 10) -> مشخص کردن عرض مستطیل
  • attr('height', 10) -> مشخص کردن ارتفاع مستطیل
  • style('fill', d => color(d[0])); -> مشخص کردن رنگ پر مستطیل بر اساس داده‌های سال مربوطه، با استفاده از مقیاس رنگ تعریف شده در متغیر color
  • legend.selectAll('text') -> انتخاب تمام المان‌های متنی در داخل المان legend
  • data(correctData) -> متصل کردن داده‌ها به المان‌های انتخاب شده، با استفاده از داده‌هایی که در متغیر correctData ذخیره شده‌اند
  • join('text') -> ایجاد یک عضو وصل‌شونده جدید از نوع متن (text) برای هر داده
  • attr('x', 15) -> مشخص کردن مختصات x برای متن
  • attr('y', (d, i) => i * 20 + 9) -> مشخص کردن مختصات y برای متن‌ها بر اساس اندیس آن‌ها، به طوری که هر متن در وسط مستطیل متناظر قرار گیرد
  • style('font-size', '12px') -> مشخص کردن اندازه قلم متن
  • text(d => d[0]); -> مشخص کردن متن برابر با داده‌های سال مربوطه

 

ایجاد برچسب‌های محور افقی و عمودی در کتابخانه D3

 

و در انتها برچسب محورهای عمودی و افقی را اضافه می‌کنیم.

 

g.append('text')
.attr('x', width / 2)
.attr('y', height + margin.top + 20)
.attr('text-anchor', 'middle')
.style('font-size', '14px')
.text('ماه');
 
g.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', 0 - height / 2)
.attr('y', -45)
.attr('text-anchor', 'middle')
.style('font-size', '14px')
.text('تعداد');

 

  • g.append('text') -> ایجاد متن در تگ g برای محور افقی
  • attr('x', width / 2) -> شروع متن در محور افقی
  • attr('y', height + margin.top + 20) -> شروع متن در محور عمودی
  • attr('text-anchor', 'middle') -> مشخص کردن نقطه مرجع قرار گیری متن
  • style('font-size', '14px') -> اندازه فونت
  • text('ماه'); -> مشخص کردن مقدار متن
  • g.append('text') -> ایجاد متن در تگ g برای محور عمودی
  • attr('transform', 'rotate(-90)') -> چرخش متن
  • attr('x', 0 - height / 2)-> شروع متن در محور عمودی
  • attr('y', -45) -> شروع متن در محور عمودی
  • attr('text-anchor', 'middle') -> مشخص کردن نقطه مرجع قرار گیری متن
  • style('font-size', '14px') -> اندازه فونت
  • text('تعداد'); -> مشخص کردن مقدار متن