Day28-D3 进阶图表:气泡图

本篇大纲:绘制气泡图的关键、资料下载、范例图表的画面与互动效果、绘制图表

今天的一天一图表,我们要来画气泡图
https://ithelp.ithome.com.tw/upload/images/20211010/20134930tM8oZ3u9I9.jpg

绘制气泡图的关键

气泡图其实是散点图的延伸,差别在於 气泡图多了一道步骤要设定气泡的大小,因此我们要特别设定圆点大小要看哪项资料去设定,并 多建立一个比例尺 去设定这项资料的范围。

资料下载

我们这次要使用的资料是这一份,这份资料比较了不同国家的平均寿命、人口数量与GDP,并且也把不同国家分别隶属五大洲的哪一洲分别归类,资料结构长这样
https://ithelp.ithome.com.tw/upload/images/20211010/20134930DdQjReAODo.jpg

范例图表的画面与互动效果

秉持我们一贯的作风,图表当然不只有画面啦!这次我们简单加上一个tooltip,滑鼠滑过气泡时会显示该气泡代表哪一国,具体画面如下:
https://i.imgur.com/VzTGa71.gif

绘制气泡图

现在我们赶快开始吧~首先,一样先取资料并建立svg

// css
.bubbleChart{
	margin: auto;
	width: 80%;
	min-width: 300px;
	position: relative;
}
// html
<h4 class="text-center mt-4">比较不同国家的平均寿命、人口数量与GDP</h4>
<div class="bubbleChart""></div>
// js
// 先取资料
let data = []
async function getData(){
  let dataGet;

  const url = 'https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/4_ThreeNum.csv'

  dataGet = await d3.csv(`${url}`);
  data = dataGet
  bubbleChart()
}
getData()

// 建立气泡图
function bubbleChart(){
  // RWD 清除原本的图型
  d3.select(".bubbleChart").select('svg').remove()

  // 设定svg与边界
  const margin = {top: 10, right: 20, bottom: 30, left: 50},
      svgWidth = parseInt(d3.select('.bubbleChart').style('width')),
      svgHeight = svgWidth*0.8
      width = svgWidth - margin.left - margin.right,
      height = svgHeight - margin.top - margin.bottom;

  // 建立svg
  const svg = d3.select(".bubbleChart")
      .append("svg")
      .attr("width", svgWidth)
      .attr("height", svgHeight)
      .append("g")
      .attr("transform", `translate(${margin.left},${margin.top})`);

// 接下来的程序码放这边...
// 接下来的程序码放这边...
// 接下来的程序码放这边...

}

// RWD
d3.select(window).on("resize", bubbleChart);

接下来,我们把XY轴需要的资料整理出来,并建立XY轴跟比例尺

// 整理XY轴资料
const xData = data.map((i) => parseInt(i.gdpPercap))
const yData = data.map((i) => i.lifeExp)

// 建立X比例尺与轴线
const x = d3.scaleLinear()
  .domain([0, d3.max(xData)])
  .range([ 0, width ])
  .nice()

const xAxis = d3.axisBottom(x)
                .tickFormat(d=> '$'+ d)

svg.append("g")
  .attr("transform", `translate(0, ${height})`)
  .call(xAxis);

// 建立Y比例尺与轴线
const y = d3.scaleLinear()
  .domain(d3.extent(yData))
  .range([height, 0])
  .nice()

const yAxis = d3.axisLeft(y)
                .tickFormat(d => d+'岁')

svg.append("g")
  .call(yAxis);

下一步是关键,我们要把用来设定气泡大小的资料整理出来,并建立它的比例尺

// 整理人口数量资料,用来设定气泡大小
const zData = data.map((i) => i.pop)

// 按照人口去设定气泡大小的比例尺
const z = d3.scaleLinear()
  .domain([d3.min(zData), 1310000000])
  .range([4, 40]);

接着设定气泡的颜色,我们这边用不同州来设定气泡颜色~

// 设定气泡颜色,根据不同洲来设定
const myColor = d3.scaleOrdinal()
    .domain(["Asia", "Europe", "Americas", "Africa", "Oceania"])
    .range(d3.schemeSet2);

这样就可以来绑定点点啦

// 绑定气泡
const bubble = svg.append('g')
  .selectAll("dot")
  .data(data)
  .join("circle")
    .attr("class", "bubbles")
    .attr("cx", d => x(d.gdpPercap))
    .attr("cy", d => y(d.lifeExp))
    .attr("r", d => z(d.pop))
    .style("fill", d => myColor(d.continent))

当当当~基本的气泡图完成啦!
https://ithelp.ithome.com.tw/upload/images/20211010/20134930w7sZt8EQnq.jpg

接下来简单绑上 tooltips 并设定mouse event

// 建立标签tooltips
const tooltip = d3.select(".bubbleChart")
  .append("div")
    .style("opacity", 0)
    .attr("class", "tooltip")
    .style("background-color", "black")
    .style("border-radius", "5px")
    .style("padding", "10px")
    .style("color", "white")

// 设定显示、移动、隐藏tooltips的滑鼠事件方法
const showTooltip = function(event, d) {
  console.log(event)
  // 渐渐出现
  tooltip
    .transition()
    .duration(200)
  
  // 设定样式与呈现文字
  tooltip
    .style("opacity", 1)
    .html("Country: " + d.country)
    .style("left", (event.x)/2 + "px")
    .style("top", (event.y)/2+30 + "px")
}
const moveTooltip = function(event, d) {
  tooltip
    .style("opacity", 1)
    .style("left", (event.x)/2 + "px")
    .style("top", (event.y)/2+30 + "px")
}
const hideTooltip = function(event, d) {
  tooltip
    .transition()
    .duration(200)
    .style("opacity", 0)
}

// 绑定滑鼠事件
bubble.on("mouseover", showTooltip )
      .on("mousemove", moveTooltip )
      .on("mouseleave", hideTooltip )

完成!
https://i.imgur.com/VzTGa71.gif


Github Page 图表与 Github 程序码

最後附上本章的程序码:想看完整程序码的请上 Github,想直接操作图表的则去 Github Page 吧!请自行取用~


<<:  Day 25 Figma 设计档的多啦时光机 - 档案历史纪录与版本控制

>>:  【程序】基础沟通问题 转生成恶役菜鸟工程师避免 Bad End 的 30 件事 - 27

国外便宜独服收集

此文仅收集便宜的独立服务器,排名不分先后,不定期更新,有不对的或想投稿的请在在评论区评论 Onepr...

DAY 27 Django 简易入门教学(四)-建立 Django 视图

Django 视图(View) 今天让我们来新增自己的第一个视图(View)吧! 前往 myapp/...

Day12 [实作] 使用浏览器来拍照并加上滤镜

上一篇尝试了 WebRTC 的切换设备并显示自己的影像,今天我们将通过上一次的程序码来做拍照的功能并...

DAY8:验证码辨识(一)

今天要来跟大家分享验证码辨识,因为公司也有用到,我就搭配一个网站,让大家来尝试看看,这个网站是"身分...

DAY15 服务室--JSON Server自己开

前言 我们现在有了 Nuxt.js 建立的环境、有了 Vuex 来做资料的处理,现在就差资料要从哪里...