Echarts 实现矩形比较可视化

286 阅读3分钟

想法

比较可视化有三种基本方法:并置、叠加、显式编码。常见的比较布局基本都是将这三种基本方法混合使用。下面是一些常见的比较布局的例子:

下面图片引用自论文 Comparative Layouts Revisited: Design Space, Guidelines, and Future Directions。感兴趣的可以去看看论文。

比较可视化.png

对于涉及到不同组的多个变量对进行一一比较时,常用的就是矩形形式的比较布局,如上图I-L。

那么使用Echarts,如何实现这种矩形形式的比较布局呢?

实现

观察可以发现,这种矩形形式的布局跟热力图很像,只是每个单元格内的图形样式不一样。因此可以在热力图的基础上进行设计,具体每个单元格显示什么图形,可自由发挥。

下面给出我设计实现的一种矩形形式的比较布局。

由于考虑到颜色编码不能够清晰比较两组的差距,因此我重新设计了一种类似的矩形比较布局。具体来说,使用矩形条来代替颜色进行比较,矩形条的高度编码变量对的值。颜色编码不同的组。

注意:不同场景下有不同的分析任务需求,本文只是给了一种最基本最简单的实现代码。如果有更复杂但与此相似的需求,只需要在下面代码的基础上修改对应的数据。下面就直接贴出ECharts的核心代码和效果图。如果大家有什么问题和想法,欢迎评论交流学习。

核心代码

var airPList = ['PM2.5', 'PM10', 'SO2', 'NO2', 'CO', 'O3'];
var data1 = [
    {
        "s": "NO2",
        "t": "CO",
        "p": "0.001"
    },
    {
        "s": "PM2.5",
        "t": "CO",
        "p": "0.0016"
    },
    {
        "s": "PM10",
        "t": "CO",
        "p": "0.008"
    },
    {
        "s": "SO2",
        "t": "CO",
        "p": "0.00177"
    },
    {
        "s": "CO",
        "t": "NO2",
        "p": "0.0001"
    },
    {
        "s": "SO2",
        "t": "NO2",
        "p": "0.0027"
    },
    {
        "s": "CO",
        "t": "O3",
        "p": "0.004"
    },
    {
        "s": "CO",
        "t": "PM2.5",
        "p": "0.0000"
    },
    {
        "s": "CO",
        "t": "PM10",
        "p": "0.003"
    },
    {
        "s": "SO2",
        "t": "PM10",
        "p": "0.0013"
    },
    {
        "s": "CO",
        "t": "SO2",
        "p": "0.0393"
    },
    {
        "s": "PM2.5",
        "t": "SO2",
        "p": "0.0127"
    },
];
var data2 = [
    {
        "s": "NO2",
        "t": "CO",
        "p": "0.00000"
    },
    {
        "s": "PM2.5",
        "t": "CO",
        "p": "0.006"
    },
    {
        "s": "CO",
        "t": "NO2",
        "p": "0.00000"
    },
    {
        "s": "SO2",
        "t": "NO2",
        "p": "0.002"
    },
    {
        "s": "CO",
        "t": "O3",
        "p": "0.02"
    },
    {
        "s": "CO",
        "t": "PM10",
        "p": "0.032"
    },
    {
        "s": "SO2",
        "t": "PM10",
        "p": "0.01322"
    },
    {
        "s": "CO",
        "t": "SO2",
        "p": "0.0047"
    },
    {
        "s": "PM2.5",
        "t": "SO2",
        "p": "0.02932"
    }
];

// 根据矩形内单元格的高度自定义修改
let [minH, maxH] = [0, 100];
let domain = [0, 1];  // p 值范围
let hScale = function(value) {
  return minH + (value - domain[0]) * (maxH / (domain[1] - domain[0]));
}
// 根据初始数据计算生成对应格式的数据
function calc(data) {
  let newData = [];
  for (let i = 0; i < data.length; i++) {
      let pValue = data[i]['p'];
      let curStrength = Number(((0.05 - pValue) / 0.05).toFixed(4));
      // 每条数据的 条形高度 和 偏移量Y
      let curBarH = Number(hScale(curStrength).toFixed(4));
      let symbolOffsetY = Number(((maxH - curBarH) / 2).toFixed(4));
      newData.push({
          value: [data[i]['t'], data[i]['s'], curStrength],
          symbolSize: [0, curBarH],
          symbolOffset: [0, symbolOffsetY],
      });
  }
  return newData;
}

let newData1 = calc(data1);
let newData2 = calc(data2);

// 随着单元的大小变化--自定义
let symbolSize = [40, 100];  // 矩形条的宽和高
let symbolOffsetX1 = '-60%';  // 偏移量X
let symbolOffsetX2 = '60%';
for (let i = 0; i < newData1.length; i++) {
  newData1[i].symbolSize[0] = symbolSize[0];
  newData1[i].symbolOffset[0] = symbolOffsetX1;
}
for (let i = 0; i < newData2.length; i++) {
  newData2[i].symbolSize[0] = symbolSize[0];
  newData2[i].symbolOffset[0] = symbolOffsetX2;
}

option = {
  tooltip: {
      formatter: function (params) {
          return '<div style="text-align: center;">'
              + params.seriesName + '</div>'
              + '<p>关系: ' + params.value[1] + ' → ' + params.value[0] + '</p>'
              + '<p>强度: ' + params.value[2] + '</p>';
      }
  },
  grid: {
      top: 20,
      left: 20,
      bottom: 5,
      right: 5,
      containLabel: true
  },
  xAxis: {
      show: true,
      position: 'top',
      type: 'category',
      data: airPList,
      boundaryGap: true,
      axisLine: {
          show: false
      },
      axisLabel: {
          color: '#000',
          rotate: 90,
          margin: 5, 
      },
      axisTick: {
          show: false,
          lineStyle: {
              color: '#FFFFFF'
          }
      },
      splitLine: {
          show: true,
          lineStyle: {
              color: '#000'
          }
      }
  },
  yAxis: {
      type: 'category',
      data: airPList,
      // boundaryGap: 0,
      inverse: true,
      axisLabel: {  // 坐标轴刻度标签的相关设置
          margin: 5,  // 刻度标签与轴线之间的距离
          // 刻度标签文字的颜色
          color: '#000',
          textStyle: {
              align: 'right',
          },
      },
      axisTick: {
          show: false,
      },
      axisLine: {
          show: false,
      },
      splitLine: {
          show: true,
          lineStyle: {
              color: '#000'
          }
      }
  },
  series: [
      {
          name: '1',
          type: 'scatter',
          data: newData1,
          symbol: "rect",  // 将散点设计成矩形形状
          // symbolSize: symbolSize,  // 统一设计,由于每个单元格不一样,所以应定制化设计
          // symbolOffset: ['-60%', 0],
          label: {
              show: false,
              color: '#000',
          },
          emphasis: {
              shadowBlur: 10,
              shadowColor: "rgba(255, 255, 255, 0.5)"
          }
      },
      {
          name: '2',
          type: 'scatter',
          data: newData2,
          symbol: "rect",  // 将散点设计成矩形形状
          // symbolSize: symbolSize,
          // symbolOffset: ['60%', 0],
          label: {
              show: false,
              color: '#000',
          },
          emphasis: {
              shadowBlur: 10,
              shadowColor: "rgba(255, 255, 255, 0.5)"
          }
      }
  ]
};

效果图

矩形比较可视化.png

如有问题,请指正我修改。欢迎评论交流!!!觉得不错请给个赞👍吧😁