ایجاد نمودار treemap با استفاده از کتابخانه D3

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

 

کد:

 

var width = 800;
var height = 600;
 
var svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
 
var root = d3.hierarchy({values: iranPopulation}, d => d.values)
.sum(d => d.population)
.sort((a, b) => b.value - a.value);
 
d3.treemap()
.size([width, height])
.padding(2)
.round(true)
(root);
 
var nodes = svg.selectAll("g")
.data(root.leaves())
.enter()
.append("g")
.attr("transform", d => `translate(${d.x0},${d.y0})`);
 
nodes.append("rect")
.attr("width", d => d.x1 - d.x0)
.attr("height", d => d.y1 - d.y0)
.attr("fill", "steelblue");
 
nodes.append("text")
.attr("x", 5)
.attr("y", 16)
.attr("font-size", "10px")
.text(d => d.data.province)
.attr("fill", "white");
 
nodes.append("title")
.text(d => `${d.data.province}\nجمعیت: ${d.value}`);
 
svg.node()

 

خروجی:

 

 

تنظیمات اولیه SVG

 

ابتدا ابعاد SVG را تعیین کرده و عنصر SVG را ایجاد می‌کنیم. این عنصر بوم اصلی ما برای رسم نمودار خواهد بود.

 

var width = 800;
var height = 600;
 
var svg = d3.create("svg")
.attr("width", width)
.attr("height", height);

 

ساختار سلسله‌مراتبی داده‌ها

 

در این قسمت، داده‌های مربوط به جمعیت استان‌ها را به یک ساختار سلسله‌مراتبی تبدیل می‌کنیم. از متد sum برای محاسبه جمعیت هر استان و از متد sort برای مرتب‌سازی استفاده می‌کنیم تا بزرگ‌ترین مقدار در ابتدا قرار گیرد.

 

var root = d3.hierarchy({values: iranPopulation}, d => d.values)
.sum(d => d.population)
.sort((a, b) => b.value - a.value);

 

  • d3.hierarchy({values: iranPopulation}, d => d.values): این خط داده‌های ورودی را به یک ساختار سلسله‌مراتبی تبدیل می‌کند.
  • d3.hierarchy یک تابع از کتابخانه D3.js است که یک ساختار سلسله‌مراتبی از داده‌های مسطح ایجاد می‌کند.
  • {values: iranPopulation}: این بخش، داده‌های ورودی (جمعیت استان‌ها) را در یک شی قرار می‌دهد که دارای کلید values است. این کار به D3 کمک می‌کند تا داده‌ها را به‌صورت صحیح به‌عنوان یک سلسله‌مراتب پردازش کند.
  • d => d.values: این تابع به D3 می‌گوید که چگونه فرزندان هر گره را پیدا کند. در اینجا، d.values فرزندان گره جاری را برمی‌گرداند. این کار برای داده‌های ما که یک سطح دارند (استان‌ها) کافی است.
  • .sum(d => d.population): این خط جمعیت هر گره (استان) را محاسبه می‌کند.
  • sum یک متد از D3.js است که به هر گره سلسله‌مراتبی یک مقدار اختصاص می‌دهد. در اینجا، مقدار اختصاص داده شده همان جمعیت استان است.
  • d => d.population: این تابع به D3 می‌گوید که چگونه جمعیت هر استان را استخراج کند. برای هر گره، مقدار population را برمی‌گرداند.
  • .sort((a, b) => b.value - a.value): این خط گره‌های سلسله‌مراتبی را بر اساس مقدار (جمعیت) مرتب می‌کند.
  • sort یک متد از D3.js است که گره‌ها را بر اساس مقادیرشان مرتب می‌کند.
  • (a, b) => b.value - a.value: این تابع مرتب‌سازی، گره‌ها را به‌صورت نزولی (از بیشترین به کمترین مقدار) مرتب می‌کند. a.value و b.value مقادیر (جمعیت) گره‌های a و b هستند.

 

ایجاد Treemap Layout

 

با استفاده از d3.treemap، یک نقشه درختی ایجاد می‌کنیم. اندازه نقشه، فاصله بین مستطیل‌ها و گرد کردن گوشه‌های مستطیل‌ها را تنظیم می‌کنیم.

 

d3.treemap()
.size([width, height])
.padding(2)
.round(true)
(root);

 

  • d3.treemap(): این تابع از کتابخانه D3.js برای ایجاد یک نمودار Treemap استفاده می‌شود.
  • treemap یک layout (چیدمان) در D3.js است که داده‌های سلسله‌مراتبی را به یک سری مستطیل‌ها نگاشت می‌کند. این مستطیل‌ها نمایانگر گره‌های سلسله‌مراتبی هستند و اندازه هر مستطیل متناسب با مقدار گره (در اینجا جمعیت استان‌ها) است.
  • .size([width, height]): این خط اندازه نمودار Treemap را تنظیم می‌کند.
  • size یک متد از D3.js است که ابعاد (عرض و ارتفاع) نمودار را تعیین می‌کند.
  • [width, height]: این آرایه شامل دو مقدار width و height است که به ترتیب عرض و ارتفاع نمودار Treemap را مشخص می‌کنند. این مقادیر قبلاً در کد به عنوان 800 و 600 تعریف شده‌اند.
  • .padding(2): این خط فاصله (padding) بین مستطیل‌ها را تنظیم می‌کند.
  • padding یک متد از D3.js است که فاصله بین مستطیل‌های نمودار Treemap را مشخص می‌کند.
  • 2: این مقدار به معنی 2 پیکسل فاصله بین مستطیل‌ها است. این فاصله باعث می‌شود مستطیل‌ها از هم جدا شوند و نمایش بهتری داشته باشند.
  • .round(true): این خط ابعاد مستطیل‌ها را گرد (rounded) می‌کند.
  • round یک متد از D3.js است که تعیین می‌کند آیا ابعاد مستطیل‌ها باید گرد شوند یا نه.
  • true: این مقدار به معنی فعال کردن گرد کردن ابعاد مستطیل‌ها است. این کار باعث می‌شود مختصات مستطیل‌ها به اعداد صحیح گرد شوند که ممکن است در برخی موارد نمایش بهتری داشته باشد.
  • (root): این خط تنظیمات فوق را به داده‌های سلسله‌مراتبی اعمال می‌کند.
  • root: این متغیر نمایانگر ساختار سلسله‌مراتبی داده‌های جمعیت استان‌های ایران است که قبلاً تعریف شده است.

 

رسم مستطیل‌ها و برچسب‌ها

 

برای هر برگ درخت (استان)، یک گروه g ایجاد کرده و مستطیل مربوط به آن را رسم می‌کنیم. رنگ مستطیل‌ها را steelblue تنظیم می‌کنیم.

 

var nodes = svg.selectAll("g")
.data(root.leaves())
.enter()
.append("g")
.attr("transform", d => `translate(${d.x0},${d.y0})`);
 
nodes.append("rect")
.attr("width", d => d.x1 - d.x0)
.attr("height", d => d.y1 - d.y0)
.attr("fill", "steelblue");

 

  • svg.selectAll("g"): این خط همه عناصر گروه <g> در SVG را انتخاب می‌کند.
  • selectAll: این متد در D3.js برای انتخاب همه عناصر مشخص شده در داخل یک عنصر پدر (در اینجا svg) استفاده می‌شود.
  • "g": این آرگومان مشخص می‌کند که همه عناصر گروه <g> انتخاب شوند.
  • .data(root.leaves()): این خط داده‌های برگ (leaves) را به انتخاب گروه‌ها پیوند می‌دهد.
  • root.leaves(): این متد برگ‌های سلسله‌مراتبی (leaf nodes) را که همان استان‌ها هستند، بازمی‌گرداند.
  • data: این متد داده‌ها را به انتخاب عناصر پیوند می‌دهد.
  • .enter(): این متد عناصر جدید را برای داده‌های وارد شده (داده‌هایی که عنصر متناظر خود را ندارند) ایجاد می‌کند.
  • enter: این مرحله در D3.js مسئول ایجاد عناصر DOM جدید برای داده‌های ورودی است.
  • .append("g"): این متد یک عنصر گروه <g> جدید برای هر داده وارد شده ایجاد می‌کند و آن را به SVG اضافه می‌کند.
  • append: این متد یک عنصر جدید به عنصر پدر موجود (در اینجا svg) اضافه می‌کند.
  • .attr("transform", d => translate(${d.x0},${d.y0})): این خط موقعیت هر گروه <g> را براساس مختصات x0 و y0 تنظیم می‌کند.
  • attr: این متد یک صفت (attribute) به عنصر اضافه می‌کند.
  • transform: این صفت مشخص می‌کند که عنصر باید به چه مختصاتی منتقل شود.
  • d => translate(${d.x0},${d.y0})``: این تابع برای هر داده (d) یک ترجمه (translation) ایجاد می‌کند که گروه <g> را به مختصات x0 و y0 منتقل می‌کند.
  • nodes.append("rect"): این متد یک عنصر مستطیل <rect> به هر گروه <g> اضافه می‌کند.
  • append: این متد یک عنصر جدید به عنصر پدر موجود (در اینجا nodes که همان گروه‌های <g> هستند) اضافه می‌کند.
  • .attr("width", d => d.x1 - d.x0): این خط عرض هر مستطیل را براساس مختصات x1 و x0 تنظیم می‌کند.
  • attr: این متد یک صفت (attribute) به عنصر اضافه می‌کند.
  • width: این صفت عرض مستطیل را مشخص می‌کند.
  • d => d.x1 - d.x0: این تابع عرض مستطیل را به‌صورت تفاوت بین مختصات x1 و x0 محاسبه می‌کند.
  • .attr("height", d => d.y1 - d.y0): این خط ارتفاع هر مستطیل را براساس مختصات y1 و y0 تنظیم می‌کند.
  • attr: این متد یک صفت (attribute) به عنصر اضافه می‌کند.
  • height: این صفت ارتفاع مستطیل را مشخص می‌کند.
  • d => d.y1 - d.y0: این تابع ارتفاع مستطیل را به‌صورت تفاوت بین مختصات y1 و y0 محاسبه می‌کند.
  • .attr("fill", "steelblue"): این خط رنگ پرشدگی (fill) هر مستطیل را تنظیم می‌کند.
  • attr: این متد یک صفت (attribute) به عنصر اضافه می‌کند.
  • fill: این صفت رنگ پرشدگی مستطیل را مشخص می‌کند.
  • "steelblue": این مقدار رنگ پرشدگی مستطیل‌ها را به رنگ آبی فولادی تنظیم می‌کند.

 

افزودن برچسب‌ها و tooltip

 

برای نمایش نام هر استان درون مستطیل، از عنصر text استفاده می‌کنیم و موقعیت آن را تنظیم می‌کنیم تا داخل مستطیل قرار گیرد. همچنین، با استفاده از عنصر title، tooltipی حاوی نام استان و جمعیت آن اضافه می‌کنیم که با قرار گرفتن ماوس روی مستطیل نمایش داده می‌شود.

 

nodes.append("text")
.attr("x", 5)
.attr("y", 16)
.attr("font-size", "10px")
.text(d => d.data.province)
.attr("fill", "white");
 
nodes.append("title")
.text(d => `${d.data.province}\nجمعیت: ${d.value}`);

 

  • nodes.append("text"): این خط یک عنصر متنی <text> به هر گروه <g> اضافه می‌کند.
  • .attr("x", 5): این خط موقعیت افقی (محور x) متن را نسبت به گروه <g> تنظیم می‌کند.
  • .attr("y", 16): این خط موقعیت عمودی (محور y) متن را نسبت به گروه <g> تنظیم می‌کند.
  • .attr("font-size", "10px"): این خط اندازه فونت متن را تنظیم می‌کند.
  • .text(d => d.data.province): این خط محتوای متنی را تنظیم می‌کند.
  • d => d.data.province: این تابع برای هر داده (d) مقدار province را از داده‌های استان بازمی‌گرداند و به عنوان محتوای متنی تنظیم می‌کند.
  • .attr("fill", "white"): این خط رنگ متن را تنظیم می‌کند.
  • nodes.append("title"): این خط یک عنصر عنوان <title> به هر گروه <g> اضافه می‌کند.
  • .text(d => ${d.data.province}\nجمعیت: ${d.value}): این خط محتوای عنوان را تنظیم می‌کند.
  • d => ${d.data.province}\nجمعیت: ${d.value}``: این تابع برای هر داده (d) نام استان و جمعیت آن را در قالب یک رشته بازمی‌گرداند و به عنوان محتوای عنوان تنظیم می‌کند.

 

با اجرای این کد، یک نمودار Treemap خواهید داشت که به‌صورت بصری و کارآمد، جمعیت استان‌های ایران را نمایش می‌دهد. این نمودار به شما کمک می‌کند تا مقایسه‌ای سریع و آسان بین جمعیت استان‌های مختلف داشته باشید. این روش یکی از بهترین راه‌ها برای نمایش داده‌های سلسله‌مراتبی به‌صورت بصری است و به‌خوبی می‌تواند اطلاعات پیچیده را به‌صورت ساده و قابل‌فهم ارائه دهد.