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

در این مقاله به شما نشان خواهیم داد که چگونه با استفاده از کتابخانه D3.js یک نمودار scatter plot ایجاد کنید. نمودارهای پراکندگی (scatter plot) ابزاری قدرتمند برای نمایش رابطه بین دو متغیر هستند. با استفاده از D3.js، می‌توان به سادگی داده‌ها را به عناصر گرافیکی متصل کرد و آن‌ها را به صورت پویا و تعاملی نمایش داد.

 

کد کامل نمودار:

 

var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = 500 - margin.left - margin.right,
height = 400 - 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 x = d3.scaleBand()
.domain(education.map(d => d.age))
.range([0, width])
.padding(0.1);
g.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x));
 
var y = d3.scaleLinear()
.domain([0, 4])
.range([height, 0]);
g.append("g")
.call(d3.axisLeft(y));
 
var color = d3.scaleOrdinal()
.domain(["men", "women"])
.range([ "#440154ff", "#21908dff"]);
 
g.selectAll("circle")
.data(education)
.join("circle")
.attr("cx", d => x(d.age) + x.bandwidth() / 2)
.attr("cy", d => y(d.men))
.attr("r", 5)
.style("fill", color("men"))
.select(function(d) {
return g.append("circle")
.attr("cx", x(d.age) + x.bandwidth() / 2)
.attr("cy", y(d.women))
.attr("r", 5)
.style("fill", color("women"));
});
 
svg.node();

 

خروجی کد:

 

 

 تنظیمات اولیه و ساخت بوم SVG

 

ابتدا باید بوم اصلی (SVG) و حاشیه‌های اطراف آن را تعریف کنیم. این مرحله به ما کمک می‌کند تا بتوانیم عناصر نمودار را به‌صورت دقیق در مکان مناسب قرار دهیم:

 

 

var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = 500 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
 
var svg = d3.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

 

  • var margin = {top: 10, right: 30, bottom: 30, left: 60};     این خط یک شیء JavaScript به نام margin تعریف می‌کند که حاشیه‌های اطراف نمودار را تعیین می‌کند. این حاشیه‌ها شامل فاصله از بالا (top)، راست (right)، پایین (bottom) و چپ (left) است. این فضاها به ما اجازه می‌دهند تا نمودار را در مرکز بوم SVG قرار دهیم و از هر طرف فضای خالی داشته باشیم (مثلاً برای محورها و برچسب‌ها).
  • width = 500 - margin.left - margin.right;     در اینجا متغیر width تعیین می‌شود که عرض فضای قابل استفاده برای نمودار را محاسبه می‌کند. 500 عرض کل SVG است و با کم کردن مقادیر margin.left و margin.right، عرض نهایی فضای داخلی نمودار محاسبه می‌شود.
  • height = 400 - margin.top - margin.bottom; به همین صورت، متغیر height محاسبه می‌شود که نشان‌دهنده ارتفاع فضای داخلی نمودار است. ارتفاع کل 400 پیکسل در نظر گرفته شده و با کم کردن حاشیه‌های بالا و پایین (top و bottom) ارتفاع نهایی بدست می‌آید.
  • var svg = d3.create("svg") این خط یک عنصر SVG جدید با استفاده از D3.js ایجاد می‌کند.
  • .attr("width", width + margin.left + margin.right) عرض کل SVG برابر است با عرض فضای داخلی نمودار (width) به علاوه‌ی حاشیه‌های چپ و راست.
  • .attr("height", height + margin.top + margin.bottom); مشابه با عرض، ارتفاع SVG نیز شامل ارتفاع فضای داخلی نمودار به همراه حاشیه‌های بالا و پایین است.

 

ساخت گروه اصلی برای نمودار

 

با استفاده از `g`، یک گروه ایجاد می‌کنیم تا تمام عناصر نمودار را در داخل آن قرار دهیم و بتوانیم آن را به مکان دلخواه در بوم منتقل کنیم:

 

var g = svg.append("g")
.attr("transform",`translate(${margin.left}, ${margin.top})`);

 

  • var g = svg.append("g") در اینجا یک عنصر گروهی یا g به عنصر svg اضافه می‌شود. تمام عناصر نمودار (مثل محورها، نقاط داده و خطوط) درون این گروه قرار می‌گیرند تا بتوانیم به راحتی موقعیت و سایر ویژگی‌های آن‌ها را به‌طور گروهی مدیریت کنیم.

  • .attr("transform",`translate(${margin.left}, ${margin.top})`); این خط ویژگی transform عنصر گروهی g را تنظیم می‌کند. ویژگی transform به شما اجازه می‌دهد که یک عنصر SVG را جابجا، چرخانده یا مقیاس‌بندی کنید.

  • در اینجا از تابع translate() استفاده می‌شود تا موقعیت گروه به‌اندازه‌ی حاشیه‌های چپ و بالا جابجا شود.

  • translate(${margin.left}, ${margin.top}) به این معنی است که گروه به‌اندازه‌ی margin.left از سمت چپ و margin.top از بالا حرکت می‌کند.

 

تعریف مقیاس‌ها و محورها

 

در این مرحله از دو مقیاس برای محورهای X و Y استفاده می‌کنیم. محور X مقیاس دسته‌ای (band scale) است که با استفاده از `age` داده‌ها تنظیم می‌شود و محور Y مقیاس خطی (linear scale) است که بین مقادیر صفر تا چهار متغیر است:

 

 

var x = d3.scaleBand()
.domain(education.map(d => d.age))
.range([0, width])
.padding(0.1);
g.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x));
 
var y = d3.scaleLinear()
.domain([0, 4])
.range([height, 0]);
g.append("g")
.call(d3.axisLeft(y));

 

  • var x = d3.scaleBand() این خط مقیاس دسته‌ای (scaleBand) را برای محور X تعریف می‌کند. از این نوع مقیاس برای داده‌های دسته‌ای (مانند گروه‌های سنی) استفاده می‌شود.

  • .domain(education.map(d => d.age)) این خط دامنه‌ی مقیاس را مشخص می‌کند که شامل تمام مقادیر دسته‌ای age از داده‌های education است. این دامنه تعیین می‌کند که هر دسته چقدر فضا بگیرد.

  • .range([0, width]) این خط تعیین می‌کند که مقادیر محور X از ۰ تا مقدار عرض (width) مقیاس‌بندی شوند، یعنی نمودار به طور کامل در عرض بوم SVG کشیده شود.

  • .padding(0.1); این خط فاصله‌ی بین دسته‌های داده در محور X را مشخص می‌کند. این فاصله باعث می‌شود که بین ستون‌های داده فاصله‌ای کوچک وجود داشته باشد.

  • g.append("g") .attr("transform", `translate(0, ${height})`) .call(d3.axisBottom(x)); این خط یک گروه (g) برای محور X به گروه اصلی نمودار اضافه می‌کند و محور را در پایین نمودار (با استفاده از translate) رسم می‌کند. d3.axisBottom(x) محور X را بر اساس مقیاس x ایجاد می‌کند.

  • var y = d3.scaleLinear() این خط یک مقیاس خطی برای محور Y تعریف می‌کند که برای داده‌های پیوسته (مانند مقادیر عددی) استفاده می‌شود.

  • .domain([0, 4]) دامنه‌ی مقیاس Y بین ۰ تا ۴ تنظیم شده است، که نشان‌دهنده محدوده‌ی مقادیر داده‌ها در محور Y است.

  • .range([height, 0]); مقیاس Y از پایین (height) به بالا (0) تنظیم شده است، که معکوس است تا مقادیر بالاتر در بالای نمودار نمایش داده شوند.

  • g.append("g") .call(d3.axisLeft(y)); این خط محور Y را به گروه g اضافه می‌کند و از تابع d3.axisLeft(y) برای رسم محور Y در سمت چپ نمودار استفاده می‌شود.

 

اضافه کردن داده‌ها به نمودار

 

در نهایت، از عناصر دایره‌ای (`circle`) برای نمایش داده‌ها استفاده می‌کنیم. برای هر رکورد در داده‌ها، دو دایره رسم می‌شود که یکی برای مردان و دیگری برای زنان است:

 

var color = d3.scaleOrdinal()
.domain(["men", "women"])
.range([ "#440154ff", "#21908dff"]);
 
g.selectAll("circle")
.data(education)
.join("circle")
.attr("cx", d => x(d.age) + x.bandwidth() / 2)
.attr("cy", d => y(d.men))
.attr("r", 5)
.style("fill", color("men"))
.select(function(d) {
return g.append("circle")
.attr("cx", x(d.age) + x.bandwidth() / 2)
.attr("cy", y(d.women))
.attr("r", 5)
.style("fill", color("women"));
});

 

  • var color = d3.scaleOrdinal() این خط یک مقیاس ترتیبی (Ordinal Scale) در D3.js تعریف می‌کند که برای نگاشت مقادیر دسته‌ای به رنگ‌های خاص استفاده می‌شود. به عبارتی دیگر، به هر دسته یک رنگ خاص اختصاص داده می‌شود.
  • .domain(["men", "women"]) این خط دامنه‌ی مقیاس رنگی را تعیین می‌کند که شامل دو دسته‌ی "men" (مردان) و "women" (زنان) است. این مقیاس، داده‌های مربوط به این دو دسته را به رنگ‌های مختلف متصل می‌کند.
  • .range([ "#440154ff", "#21908dff"]); این خط دو رنگ را به عنوان خروجی مقیاس رنگی تنظیم می‌کند. رنگ #440154ff برای مردان و رنگ #21908dff برای زنان استفاده خواهد شد.
  • g.selectAll("circle") .data(education) این خط، تمام عناصر circle موجود در گروه g را انتخاب می‌کند و داده‌های education را به آن‌ها متصل می‌کند. اگر دایره‌ای وجود نداشته باشد، این مرحله برای اضافه کردن آن‌هاست.
  • .join("circle") این خط برای اتصال داده‌های جدید به دایره‌ها استفاده می‌شود و اگر دایره‌ای موجود نباشد، آن را ایجاد می‌کند. این فرآیند به روزرسانی و یا ایجاد دایره‌های جدید را انجام می‌دهد.
  • .attr("cx", d => x(d.age) + x.bandwidth() / 2) این خط مقدار cx (موقعیت افقی دایره‌ها) را بر اساس مقادیر age در داده‌ها تنظیم می‌کند. موقعیت دایره‌ها وسط هر دسته در محور X است.
  • .attr("cy", d => y(d.men)) این خط مقدار cy (موقعیت عمودی دایره‌ها) را برای داده‌های مربوط به مردان تنظیم می‌کند. این مقادیر بر اساس محور Y محاسبه می‌شوند.
  • .attr("r", 5) شعاع دایره‌ها برای نمایش داده‌ها به مقدار ۵ تنظیم می‌شود. این مقدار نشان‌دهنده اندازه هر نقطه در نمودار است.
  • .style("fill", color("men")) این خط رنگ دایره‌ها را بر اساس مقیاس رنگی و برای داده‌های مربوط به مردان تنظیم می‌کند.
  • .select(function(d) {return g.append("circle") این قسمت از کد، برای هر داده‌ی موجود یک دایره‌ی اضافی در گروه g ایجاد می‌کند که به داده‌های زنان اختصاص دارد.
  • .attr("cx", x(d.age) + x.bandwidth() / 2) این خط نیز دایره‌های مربوط به زنان را دقیقاً در همان موقعیت افقی دایره‌های مردان قرار می‌دهد.
  • .attr("cy", y(d.women)) این خط مقدار cy (موقعیت عمودی دایره‌ها) را برای داده‌های زنان تنظیم می‌کند. این مقادیر بر اساس محور Y محاسبه می‌شوند.
  • .style("fill", color("women")); این خط رنگ دایره‌های مربوط به داده‌های زنان را بر اساس مقیاس رنگی تنظیم می‌کند.

 

در این مقاله، یک نمودار پراکندگی ساده با استفاده از D3.js ایجاد کردیم. این نمودار به شما کمک می‌کند تا روابط میان دو متغیر را به صورت گرافیکی بررسی کنید و به صورت پویا و تعاملی داده‌ها را نمایش دهید. D3.js به شما اجازه می‌دهد تا نمودارهای پیچیده و سفارشی‌سازی شده‌ای ایجاد کنید و داده‌های خود را به شکل‌های مختلفی تجزیه و تحلیل کنید.

برای اطلاعات بیشتر و کدهای کامل، می‌توانید از مستندات D3.js استفاده کنید.