d3.js v5 实现类汉诺塔结构的数据可视化

本文介绍了一种基于汉诺塔结构的可视化设计方案,用于对比两个实体的50个属性值,包括定性和定量属性,通过颜色和条形图的长度进行映射。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

需求要实现一个类似于汉诺塔的结构,但是还有一点不一样,每一层的大小是打乱的,不是按照顺序排列的,塔的两侧是两个同类别但是不同值的属性值,这个图的作用主要用来对比两个“实体”的所有属性的值。 汉诺塔

设计

在实际设计的时候,发现每个“实体”50个属性值,其中属性值可以分为两类:

  1. 定性类:比如派系,类别等属性,这一类属性统称为定性类,一般在可视化设计的时候,用颜色映射。
  2. 定量类:比如流量,大小,方向等数值类的属性统称为定量类,一般在可视化设计的时候,用长短,或者大小来映射。

有了这些设计,那么方案也就出来了,就是设计一个汉诺塔结构的坐标轴,一直竖直方向,一个横向等坐标轴,竖直方向的轴放在中间,如下图所示。然后就是两侧采用不用方向的横向条形图来可视化,数值类属性的条形图全部采用刚蓝色显示,将具体的数值使用颜色来映射。定性类属性采用颜色映射,所以条形图在表示定性类属性的时候,长度全部是最大值。

坐标轴设计图片

核心代码

1. 绘制坐标轴

添加svg

let self = this;
      self.infoSvg = d3
        .select("#attr-compare-div")
        .append("svg")
        .attr("class", "infosvg")
        .attr("width", "400px")
        .attr("height", "790px");

设置x轴缩放,绘制x轴

let xScale = d3
        .scaleBand()
        .domain(["当前节点", "对比节点"])
        .range([20, self.InfoSvgWidth]);
      let xAxis = self.infoSvg
        .append("g")
        .attr("class", "xAixs")
        .attr("transform", "translate(0, " + self.InfoSvgHeight + ")")
        .call(d3.axisBottom(xScale));

设置y轴缩放,绘制y轴

let yNumNameList = [];
      for (let index = 1; index <= 30; index++) {
        yNumNameList.push("num" + index);
      }
      for (let index = 1; index <= 20; index++) {
        yNumNameList.push("culster" + index);
      }
      console.log(yNumNameList);
      self.yAxisScale = d3
        .scaleBand()
        .domain(yNumNameList)
        .range([0, self.InfoSvgHeight]);
      let yAxis = self.infoSvg
        .append("g")
        .attr("class", "yAixs")
        .attr("transform", "translate(" + self.InfoSvgWidth * 0.5 + ",0)")
        .call(d3.axisLeft(self.yAxisScale));
2. 绘制横向条形图

首先添加svg

let barChartSvgLeft = d3
        .select(".infosvg")
        .append("g")
        .attr("class", "barChartSvgLeft");

处理数据,将50个属性放在list中

let currAllData = [];
      currAllData.push(...node.attr_num_list);
      currAllData.push(...node.attr_culster_list);

绘制横向条形图

      let bar = barChartSvgLeft
        .selectAll(".bar_left")
        .data(currAllData)
        .enter()
        .append("rect");
      bar
        .attr("x", function(d, i) {
          if (i <= 29) {
            return 0.5 * self.InfoSvgWidth - self.infoSvgXScaleList[i](d.value);
          } else {
            return 0;
          }
        })
        .attr("y", function(d, i) {
          return i * self.yScaleBandWidth;
        })
        .attr("width", function(d, i) {
          if (i <= 29) return self.infoSvgXScaleList[i](d.value);
          else return self.InfoSvgWidth / 2;
        })
        .attr("height", function(d, i) {
          return self.yScaleBandWidth - 2;
        })
        .attr("fill", function(d, i) {
          if (i <= 29) return "steelblue";
          else {
            // console.log(self.colorScale(d.value));
            return self.colorScale(d.value);
          }
        });

需要重新绘制Y轴,这样就不会被条形图遮挡

if (!d3.selectAll(".yAixs").empty()) {
        d3.selectAll(".yAixs").remove();
      }
      //需要重新绘制Y轴,这样就不会被条形图遮挡
      let yAxis = self.infoSvg
        .append("g")
        .attr("class", "yAixs")
        .attr("transform", "translate(" + self.InfoSvgWidth * 0.5 + ",0)")
        .call(d3.axisLeft(self.yAxisScale));

设置条形图文字

barChartSvgLeft
        .selectAll(".bar-text")
        .data(currAllData)
        .enter()
        .append("text")
        .text(function(d) {
          return d.value;
        })
        .attr("x", function(d, i) {
          // console.log("x is "+0.5*self.InfoSvgWidth-self.infoSvgXScaleList[i](d.value));
          if (i <= 29)
            return 0.5 * self.InfoSvgWidth - self.infoSvgXScaleList[i](d.value);
          else return 0;
        })
        .attr("y", function(d, i) {
          // console.log("y is "+(i*self.yScaleBandWidth-self.yScaleBandWidth/2));
          return i * self.yScaleBandWidth + self.yScaleBandWidth / 2 + 4;
        })
        .attr("fill", "white");

最终效果图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值