在这里插入图片描述

目录

  1. 概述
  2. 工具功能
  3. 核心实现
  4. Kotlin 源代码
  5. JavaScript 编译代码
  6. ArkTS 调用代码
  7. 实战案例
  8. 最佳实践

概述

本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个完整的数据可视化颜色映射工具,特别是渐变色生成工具。数据可视化中的颜色映射是将数值数据转换为视觉颜色的关键技术,帮助用户快速理解数据的分布和趋势。这个案例展示了如何使用 Kotlin 的色彩科学来创建一个功能丰富的渐变色生成工具。

渐变色生成工具能够根据用户指定的数据范围,自动生成多种颜色映射方案,包括蓝-红渐变、热力图映射和灰度映射等。这些映射方案基于感知均匀的色彩空间原理,确保颜色变化与数据变化相匹配。通过 KMP,这个工具可以无缝编译到 JavaScript,在 OpenHarmony 应用中运行,为数据分析师和可视化设计师提供专业的颜色映射服务。

工具的特点

  • 多种映射方案:支持蓝-红渐变、热力图映射、灰度映射等多种方案
  • 感知均匀色彩空间:采用 HSL 色彩空间确保颜色变化均匀
  • 灵活的数据范围:支持任意的最小值和最大值
  • 丰富的应用场景:适用于地图、财务、科学、性能监控等领域
  • 色盲友好:提供多种映射方案满足不同用户需求
  • 跨端兼容:一份 Kotlin 代码可同时服务多个平台

工具功能

1. 数据范围输入

工具支持灵活的数据范围输入:

  • 最小值:数据范围的下界
  • 最大值:数据范围的上界
  • 范围验证:确保最小值小于最大值
  • 动态映射:根据数据范围动态生成颜色映射

2. 蓝-红渐变映射

蓝-红渐变是最常见的数据可视化颜色映射方案:

  • 原理:从蓝色(240°)渐变到红色(0°)
  • 特点:直观易懂,冷暖对比明显
  • 应用:温度数据、性能指标、浓度分布等
  • 步数:10 个颜色步骤,覆盖整个数据范围

3. 热力图映射

热力图映射使用多个颜色阶段表示数据强度:

  • 颜色阶段:蓝色 → 青色 → 黄色 → 红色
  • 特点:5 个关键颜色点,视觉冲击力强
  • 应用:地图热力图、人口密度、污染指数等
  • 感知:颜色变化与数据强度相对应

4. 灰度映射

灰度映射使用从黑到白的灰度表示数据:

  • 原理:从黑色(0%)到白色(100%)
  • 特点:简洁清晰,适合打印和复印
  • 应用:黑白打印、医学影像、科学数据等
  • 优势:色盲友好,对比度高

5. 应用场景支持

工具支持多种应用场景:

  • 地图热力图:温度、人口密度、污染指数
  • 财务数据:收益、损失、增长率
  • 科学数据:浓度、强度、频率
  • 性能监控:CPU、内存、网络使用率
  • 医学影像:CT、MRI、X光强度

6. 最佳实践指导

工具提供数据可视化的最佳实践:

  • 感知均匀色彩空间:使用 LAB 或 Viridis
  • 避免彩虹色:容易误导用户
  • 色盲考虑:提供多种映射方案
  • 清晰图例:提供颜色与数据的对应关系
  • 设备测试:在不同显示设备上测试

核心实现

算法原理

数据可视化颜色映射工具的核心算法包括:

  1. 数据归一化:将数据范围映射到 0-1
  2. 色调计算:根据归一化值计算色调
  3. HSL 转换:在 HSL 色彩空间中生成颜色
  4. RGB 转换:将 HSL 转换为 RGB
  5. HEX 转换:将 RGB 转换为 HEX 格式

蓝-红渐变映射

蓝-红渐变映射使用线性插值在色调空间中:

ratio = (value - min) / (max - min)
hue = 240 * (1 - ratio)  // 从 240°(蓝色)到 0°(红色)

热力图映射

热力图映射使用分段的色调映射:

if ratio < 0.25:
    hue = 240  // 蓝色
else if ratio < 0.5:
    hue = 180  // 青色
else if ratio < 0.75:
    hue = 60   // 黄色
else:
    hue = 0    // 红色

灰度映射

灰度映射使用亮度变化表示数据:

ratio = (value - min) / (max - min)
lightness = ratio * 100
gray = lightness * 255 / 100

Kotlin 源代码

// 案例 39: 数据可视化中的颜色映射 - 渐变色生成工具
@OptIn(ExperimentalJsExport::class)
@JsExport
fun dataVisualizationColorMapper(inputData: String = "0 100"): String {
    if (inputData.isEmpty()) {
        return "❌ 错误: 输入不能为空\n请输入: 最小值 最大值\n示例: 0 100"
    }
    
    val parts = inputData.trim().split(" ")
    if (parts.size != 2) {
        return "❌ 错误: 输入格式不正确\n请输入: 最小值 最大值"
    }
    
    val minValue = parts[0].toDoubleOrNull()
    val maxValue = parts[1].toDoubleOrNull()
    
    if (minValue == null || maxValue == null) {
        return "❌ 错误: 数值输入无效"
    }
    
    if (minValue >= maxValue) {
        return "❌ 错误: 最小值必须小于最大值"
    }
    
    // 1. 生成渐变色映射(从蓝色到红色)
    val colorSteps = 10
    val colorMappings = mutableListOf<String>()
    
    for (i in 0 until colorSteps) {
        val ratio = i.toDouble() / (colorSteps - 1)
        val value = minValue + (maxValue - minValue) * ratio
        
        // HSL色彩空间:蓝色(240°) -> 红色(0°)
        val hue = 240 * (1 - ratio)
        val saturation = 100.0
        val lightness = 50.0
        
        val rgb = hslToRgb(hue, saturation / 100.0, lightness / 100.0)
        val hex = rgbToHex(rgb.first, rgb.second, rgb.third)
        
        colorMappings.add("${(value * 100).toInt() / 100.0} -> #$hex")
    }
    
    // 2. 生成热力图颜色映射
    val heatmapColors = mutableListOf<String>()
    for (i in 0 until 5) {
        val ratio = i.toDouble() / 4
        val value = minValue + (maxValue - minValue) * ratio
        
        val hue = when {
            ratio < 0.25 -> 240.0 // 蓝色
            ratio < 0.5 -> 180.0 // 青色
            ratio < 0.75 -> 60.0 // 黄色
            else -> 0.0 // 红色
        }
        
        val rgb = hslToRgb(hue, 1.0, 0.5)
        val hex = rgbToHex(rgb.first, rgb.second, rgb.third)
        
        heatmapColors.add("${(value * 100).toInt() / 100.0} -> #$hex")
    }
    
    // 3. 生成灰度映射
    val grayscaleColors = mutableListOf<String>()
    for (i in 0 until 5) {
        val ratio = i.toDouble() / 4
        val value = minValue + (maxValue - minValue) * ratio
        
        val lightness = (ratio * 100).toInt()
        val gray = (lightness * 255 / 100)
        val hex = rgbToHex(gray, gray, gray)
        
        grayscaleColors.add("${(value * 100).toInt() / 100.0} -> #$hex")
    }
    
    // 4. 获取应用场景
    val applicationScenes = mutableListOf<String>()
    applicationScenes.add("• 地图热力图: 温度、人口密度、污染指数")
    applicationScenes.add("• 财务数据: 收益、损失、增长率")
    applicationScenes.add("• 科学数据: 浓度、强度、频率")
    applicationScenes.add("• 性能监控: CPU、内存、网络使用率")
    applicationScenes.add("• 医学影像: CT、MRI、X光强度")
    
    // 5. 获取最佳实践
    val bestPractices = mutableListOf<String>()
    bestPractices.add("• 使用感知均匀的色彩空间 (如 LAB)")
    bestPractices.add("• 避免使用彩虹色 (容易误导)")
    bestPractices.add("• 考虑色盲用户的需求")
    bestPractices.add("• 提供清晰的图例说明")
    bestPractices.add("• 测试在不同显示设备上的效果")
    
    return "📊 数据可视化颜色映射工具\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "📈 数据范围\n" +
           "最小值: $minValue\n" +
           "最大值: $maxValue\n" +
           "范围: ${(maxValue - minValue * 100).toInt() / 100.0}\n\n" +
           "🌈 蓝-红渐变映射\n" +
           colorMappings.joinToString("\n") + "\n\n" +
           "🔥 热力图映射\n" +
           heatmapColors.joinToString("\n") + "\n\n" +
           "⚫ 灰度映射\n" +
           grayscaleColors.joinToString("\n") + "\n\n" +
           "🎯 应用场景\n" +
           applicationScenes.joinToString("\n") + "\n\n" +
           "✅ 最佳实践\n" +
           bestPractices.joinToString("\n") + "\n\n" +
           "💡 色彩空间说明\n" +
           "• RGB: 计算机显示,不感知均匀\n" +
           "• HSL: 直观,但不感知均匀\n" +
           "• LAB: 感知均匀,推荐用于数据可视化\n" +
           "• Viridis: 专为数据可视化设计\n\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "✅ 颜色映射生成完成!"
}

// 辅助函数: HSL转RGB
fun hslToRgb(h: Double, s: Double, l: Double): Triple<Int, Int, Int> {
    val c = (1 - kotlin.math.abs(2 * l - 1)) * s
    val hPrime = h / 60.0
    val x = c * (1 - kotlin.math.abs(hPrime % 2 - 1))
    
    val (r1, g1, b1) = when {
        hPrime < 1 -> Triple(c, x, 0.0)
        hPrime < 2 -> Triple(x, c, 0.0)
        hPrime < 3 -> Triple(0.0, c, x)
        hPrime < 4 -> Triple(0.0, x, c)
        hPrime < 5 -> Triple(x, 0.0, c)
        else -> Triple(c, 0.0, x)
    }
    
    val m = l - c / 2
    val r = ((r1 + m) * 255).toInt()
    val g = ((g1 + m) * 255).toInt()
    val b = ((b1 + m) * 255).toInt()
    
    return Triple(r, g, b)
}

// 辅助函数: RGB转HEX
fun rgbToHex(r: Int, g: Int, b: Int): String {
    val rHex = r.toString(16).padStart(2, '0').uppercase()
    val gHex = g.toString(16).padStart(2, '0').uppercase()
    val bHex = b.toString(16).padStart(2, '0').uppercase()
    return rHex + gHex + bHex
}

Kotlin 代码详解

这个 Kotlin 函数实现了一个完整的数据可视化颜色映射工具。函数接收一个字符串参数,包含数据范围的最小值和最大值。

首先,函数进行输入验证,确保最小值小于最大值。

接下来,函数生成三种不同的颜色映射方案:

  1. 蓝-红渐变映射:使用 10 个颜色步骤,从蓝色渐变到红色
  2. 热力图映射:使用 5 个关键颜色点(蓝 → 青 → 黄 → 红)
  3. 灰度映射:使用 5 个灰度级别

对于每个颜色映射,函数计算对应的数据值,然后将其转换为 HEX 颜色代码。

最后,函数返回一个格式化的结果字符串,包含所有三种映射方案、应用场景和最佳实践。


JavaScript 编译代码

// 编译后的 JavaScript 代码(部分示例)
function dataVisualizationColorMapper(inputData) {
    if (inputData === undefined) {
        inputData = "0 100";
    }
    
    if (inputData.length === 0) {
        return "❌ 错误: 输入不能为空\n请输入: 最小值 最大值\n示例: 0 100";
    }
    
    var parts = inputData.trim().split(" ");
    if (parts.length !== 2) {
        return "❌ 错误: 输入格式不正确\n请输入: 最小值 最大值";
    }
    
    var minValue = parseFloat(parts[0]);
    var maxValue = parseFloat(parts[1]);
    
    if (isNaN(minValue) || isNaN(maxValue)) {
        return "❌ 错误: 数值输入无效";
    }
    
    if (minValue >= maxValue) {
        return "❌ 错误: 最小值必须小于最大值";
    }
    
    // 生成蓝-红渐变映射
    var colorSteps = 10;
    var colorMappings = [];
    
    for (var i = 0; i < colorSteps; i++) {
        var ratio = i / (colorSteps - 1);
        var value = minValue + (maxValue - minValue) * ratio;
        
        var hue = 240 * (1 - ratio);
        var saturation = 100.0;
        var lightness = 50.0;
        
        var rgb = hslToRgb(hue, saturation / 100.0, lightness / 100.0);
        var hex = rgbToHex(rgb[0], rgb[1], rgb[2]);
        
        colorMappings.push((Math.floor(value * 100) / 100) + " -> #" + hex);
    }
    
    // 生成热力图颜色映射
    var heatmapColors = [];
    for (var i = 0; i < 5; i++) {
        var ratio = i / 4;
        var value = minValue + (maxValue - minValue) * ratio;
        
        var hue;
        if (ratio < 0.25) {
            hue = 240.0;
        } else if (ratio < 0.5) {
            hue = 180.0;
        } else if (ratio < 0.75) {
            hue = 60.0;
        } else {
            hue = 0.0;
        }
        
        var rgb = hslToRgb(hue, 1.0, 0.5);
        var hex = rgbToHex(rgb[0], rgb[1], rgb[2]);
        
        heatmapColors.push((Math.floor(value * 100) / 100) + " -> #" + hex);
    }
    
    // 生成灰度映射
    var grayscaleColors = [];
    for (var i = 0; i < 5; i++) {
        var ratio = i / 4;
        var value = minValue + (maxValue - minValue) * ratio;
        
        var lightness = Math.floor(ratio * 100);
        var gray = Math.floor(lightness * 255 / 100);
        var hex = rgbToHex(gray, gray, gray);
        
        grayscaleColors.push((Math.floor(value * 100) / 100) + " -> #" + hex);
    }
    
    var applicationScenes = [
        "• 地图热力图: 温度、人口密度、污染指数",
        "• 财务数据: 收益、损失、增长率",
        "• 科学数据: 浓度、强度、频率",
        "• 性能监控: CPU、内存、网络使用率",
        "• 医学影像: CT、MRI、X光强度"
    ];
    
    var bestPractices = [
        "• 使用感知均匀的色彩空间 (如 LAB)",
        "• 避免使用彩虹色 (容易误导)",
        "• 考虑色盲用户的需求",
        "• 提供清晰的图例说明",
        "• 测试在不同显示设备上的效果"
    ];
    
    return "📊 数据可视化颜色映射工具\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "📈 数据范围\n" +
           "最小值: " + minValue + "\n" +
           "最大值: " + maxValue + "\n" +
           "范围: " + (Math.floor((maxValue - minValue) * 100) / 100) + "\n\n" +
           "🌈 蓝-红渐变映射\n" +
           colorMappings.join("\n") + "\n\n" +
           "🔥 热力图映射\n" +
           heatmapColors.join("\n") + "\n\n" +
           "⚫ 灰度映射\n" +
           grayscaleColors.join("\n") + "\n\n" +
           "🎯 应用场景\n" +
           applicationScenes.join("\n") + "\n\n" +
           "✅ 最佳实践\n" +
           bestPractices.join("\n") + "\n\n" +
           "💡 色彩空间说明\n" +
           "• RGB: 计算机显示,不感知均匀\n" +
           "• HSL: 直观,但不感知均匀\n" +
           "• LAB: 感知均匀,推荐用于数据可视化\n" +
           "• Viridis: 专为数据可视化设计\n\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "✅ 颜色映射生成完成!";
}

function hslToRgb(h, s, l) {
    var c = (1 - Math.abs(2 * l - 1)) * s;
    var hPrime = h / 60.0;
    var x = c * (1 - Math.abs(hPrime % 2 - 1));
    
    var r1, g1, b1;
    if (hPrime < 1) {
        r1 = c; g1 = x; b1 = 0;
    } else if (hPrime < 2) {
        r1 = x; g1 = c; b1 = 0;
    } else if (hPrime < 3) {
        r1 = 0; g1 = c; b1 = x;
    } else if (hPrime < 4) {
        r1 = 0; g1 = x; b1 = c;
    } else if (hPrime < 5) {
        r1 = x; g1 = 0; b1 = c;
    } else {
        r1 = c; g1 = 0; b1 = x;
    }
    
    var m = l - c / 2;
    var r = Math.floor((r1 + m) * 255);
    var g = Math.floor((g1 + m) * 255);
    var b = Math.floor((b1 + m) * 255);
    
    return [r, g, b];
}

function rgbToHex(r, g, b) {
    var rHex = r.toString(16).padStart(2, '0').toUpperCase();
    var gHex = g.toString(16).padStart(2, '0').toUpperCase();
    var bHex = b.toString(16).padStart(2, '0').toUpperCase();
    return rHex + gHex + bHex;
}

JavaScript 代码详解

Kotlin 代码编译到 JavaScript 后,保留了原有的逻辑结构,但使用 JavaScript 的语法和 API。主要的转换包括:

  1. 循环:Kotlin 的 for 循环转换为 JavaScript 的 for 循环
  2. 条件语句:Kotlin 的 when 表达式转换为 JavaScript 的 if-else
  3. 数组操作:Kotlin 的 mutableListOf() 转换为 JavaScript 的数组
  4. 数学函数:保持相同的数学计算逻辑

ArkTS 调用代码

import { dataVisualizationColorMapper } from './hellokjs';

@Entry
@Component
struct Index {
  @State message: string = '准备就绪';
  @State minValue: string = '0';
  @State maxValue: string = '100';
  @State resultText: string = '';
  @State isLoading: boolean = false;

  aboutToAppear(): void {
    this.generateNewCase();
  }

  generateNewCase(): void {
    this.resultText = '';
    this.message = '准备就绪';
    
    const samples = [
      { min: '0', max: '100' },
      { min: '-50', max: '50' },
      { min: '0', max: '1000' },
      { min: '20', max: '40' },
      { min: '0', max: '10' }
    ];
    
    const random = samples[Math.floor(Math.random() * samples.length)];
    this.minValue = random.min;
    this.maxValue = random.max;
  }

  generate(): void {
    this.isLoading = true;
    try {
      const input: string = `${this.minValue} ${this.maxValue}`;
      const result: string = dataVisualizationColorMapper(input);
      this.resultText = result;
      console.log(result);
      this.message = '✓ 颜色映射生成完成';
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.message = `✗ 错误: ${errorMessage}`;
    } finally {
      this.isLoading = false;
    }
  }

  build() {
    Column() {
      // ===== 顶部标题栏 - 数据绿色主题 =====
      Column() {
        Text('📊 Data Visualization Color Mapper')
          .fontSize(28)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .margin({ bottom: 8 })
        
        Text('Gradient Color Generation Tool')
          .fontSize(13)
          .fontColor('#C8E6C9')
      }
      .width('100%')
      .padding(24)
      .backgroundColor('#2E7D32')
      .alignItems(HorizontalAlign.Start)

      // ===== 主内容区域 =====
      Scroll() {
        Column() {
          // 输入卡片
          Column() {
            Row() {
              Text('📈 Data Range')
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .fontColor('#FFFFFF')
              
              Blank()
              
              Text('🎲 Random')
                .fontSize(12)
                .fontColor(Color.White)
                .padding({ left: 10, right: 10, top: 6, bottom: 6 })
                .backgroundColor('#1B5E20')
                .borderRadius(12)
                .onClick(() => {
                  this.generateNewCase();
                })
            }
            .width('100%')
            .margin({ bottom: 18 })

            // 最小值输入
            TextInput({ placeholder: 'Min Value', text: this.minValue })
              .width('100%')
              .height(50)
              .padding(14)
              .fontSize(15)
              .fontColor('#000000')
              .placeholderColor('#999999')
              .border({ width: 2, color: '#2E7D32' })
              .borderRadius(12)
              .backgroundColor('#E8F5E9')
              .onChange((value: string) => {
                this.minValue = value;
              })
              .margin({ bottom: 14 })

            // 最大值输入
            TextInput({ placeholder: 'Max Value', text: this.maxValue })
              .width('100%')
              .height(50)
              .padding(14)
              .fontSize(15)
              .fontColor('#000000')
              .placeholderColor('#999999')
              .border({ width: 2, color: '#2E7D32' })
              .borderRadius(12)
              .backgroundColor('#E8F5E9')
              .onChange((value: string) => {
                this.maxValue = value;
              })
              .margin({ bottom: 20 })

            // 生成按钮
            Button(this.isLoading ? 'Generating...' : 'Generate Mapping')
              .width('100%')
              .height(54)
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .fontColor(Color.White)
              .backgroundColor(this.isLoading ? '#1B5E20' : '#2E7D32')
              .borderRadius(14)
              .onClick(() => {
                if (!this.isLoading) {
                  this.generate();
                }
              })
          }
          .width('90%')
          .padding(20)
          .backgroundColor('#FFFFFF')
          .borderRadius(16)
          .margin({ top: 20, bottom: 20, left: 'auto', right: 'auto' })
          .border({ width: 2, color: '#2E7D32' })

          // 状态提示卡片
          if (this.message !== '准备就绪') {
            Row() {
              Text(this.message.startsWith('✓') ? '✅' : '⚠️')
                .fontSize(20)
                .margin({ right: 12 })

              Text(this.message)
                .fontSize(14)
                .fontColor(this.message.startsWith('✓') ? '#4ECDC4' : '#FF6B6B')
                .fontWeight(FontWeight.Bold)
                .layoutWeight(1)
            }
            .width('90%')
            .padding(16)
            .backgroundColor(this.message.startsWith('✓') ? '#1a3a3a' : '#3a1a1a')
            .border({ width: 2, color: this.message.startsWith('✓') ? '#4ECDC4' : '#FF6B6B' })
            .borderRadius(14)
            .margin({ bottom: 20, left: 'auto', right: 'auto' })
            .alignItems(VerticalAlign.Center)
          }

          // 结果卡片
          if (this.resultText) {
            Column() {
              Row() {
                Text('📊 Color Mapping')
                  .fontSize(14)
                  .fontWeight(FontWeight.Bold)
                  .fontColor('#2E7D32')
              }
              .width('100%')
              .padding(14)
              .backgroundColor('#E8F5E9')
              .borderRadius(12)
              .margin({ bottom: 14 })
              .border({ width: 1, color: '#2E7D32' })

              Text(this.resultText)
                .fontSize(12)
                .fontFamily('monospace')
                .fontColor('#1B5E20')
                .width('100%')
                .padding(14)
                .backgroundColor('#E8F5E9')
                .borderRadius(12)
                .border({ width: 1, color: '#4CAF50' })
            }
            .width('90%')
            .padding(16)
            .backgroundColor('#E8F5E9')
            .borderRadius(16)
            .margin({ bottom: 20, left: 'auto', right: 'auto' })
            .border({ width: 2, color: '#2E7D32' })
          }

          // 底部提示
          Column() {
            Row() {
              Text('💡')
                .fontSize(18)
                .margin({ right: 10 })
              
              Text('📊 Visualization Tips')
                .fontSize(14)
                .fontWeight(FontWeight.Bold)
                .fontColor('#2E7D32')
            }
            .width('100%')
            .margin({ bottom: 12 })

            Text('• Enter data range (min and max)\n• Generate multiple color schemes\n• Choose suitable mapping for your data\n• Consider accessibility needs')
              .fontSize(12)
              .fontColor('#1B5E20')
              .lineHeight(1.6)
          }
          .width('90%')
          .padding(16)
          .backgroundColor('#E8F5E9')
          .borderRadius(16)
          .margin({ bottom: 20, left: 'auto', right: 'auto' })
          .border({ width: 2, color: '#2E7D32' })

          Blank()
            .height(20)
        }
        .width('100%')
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#E8F5E9')
  }
}

ArkTS 代码详解

这个 ArkTS 组件实现了数据可视化颜色映射工具的用户界面。组件使用了 OpenHarmony 的 ArkTS 语言,提供了一个现代化的、数据绿色主题的用户界面。

组件定义了两个 @State 属性来存储数据范围的最小值和最大值。这些属性与输入框绑定,当用户输入数据时,这些属性会自动更新。

generateNewCase() 方法生成随机的数据范围样本,帮助用户快速测试应用。用户可以点击"Random"按钮来生成随机数据。

generate() 方法调用 Kotlin 编译的 JavaScript 函数 dataVisualizationColorMapper(),并将数据范围作为参数传递。函数返回的颜色映射会显示在结果卡片中。

用户界面包括两个输入框(最小值、最大值)、一个生成按钮、一个状态提示卡片、一个结果卡片和一个提示卡片。所有元素都使用了数据绿色主题。


实战案例

案例 1:温度数据映射(0-100°C)

输入:0 100

系统生成的颜色映射:

  • 蓝-红渐变:10 个步骤,从蓝色(0°C)到红色(100°C)
  • 热力图映射:5 个关键点(蓝 → 青 → 黄 → 红)
  • 灰度映射:5 个灰度级别
  • 应用:温度地图、天气可视化

案例 2:财务数据映射(-50 到 50)

输入:-50 50

系统生成的颜色映射:

  • 蓝-红渐变:从蓝色(-50,损失)到红色(50,收益)
  • 热力图映射:从冷色(负值)到暖色(正值)
  • 灰度映射:从黑色(负值)到白色(正值)
  • 应用:收益/损失可视化、增长率分析

案例 3:性能监控映射(0-100%)

输入:0 100

系统生成的颜色映射:

  • 蓝-红渐变:从蓝色(低使用率)到红色(高使用率)
  • 热力图映射:多个颜色阶段表示不同的性能水平
  • 灰度映射:简洁的黑白表示
  • 应用:CPU、内存、网络使用率监控

最佳实践

1. 选择合适的色彩空间

不同的色彩空间适用于不同的应用场景:

  • RGB:计算机显示,但不感知均匀
  • HSL:直观,但不感知均匀
  • LAB:感知均匀,推荐用于数据可视化
  • Viridis:专为数据可视化设计

2. 避免常见的错误

数据可视化中的常见错误:

  • 使用彩虹色:容易误导用户,因为颜色变化不均匀
  • 忽视色盲用户:提供多种映射方案
  • 过度使用颜色:使用太多颜色会降低可读性
  • 缺乏图例:始终提供颜色与数据的对应关系

3. 考虑色盲用户

为色盲用户提供替代方案:

  • 提供多种映射:蓝-红、热力图、灰度
  • 使用图案或纹理:结合颜色使用图案
  • 使用文字标签:为颜色编码的元素添加文字标签
  • 测试工具:使用色盲模拟工具测试

4. 提供清晰的图例

图例是数据可视化的重要组成部分:

  • 颜色范围:显示颜色与数据值的对应关系
  • 单位标注:清楚地标注数据单位
  • 关键值:突出显示关键的数据值
  • 可读性:确保图例易于理解

5. 测试和验证

在不同条件下测试颜色映射:

  • 不同显示设备:在不同的屏幕上测试
  • 不同照明条件:在不同的光线下测试
  • 色盲模拟:使用色盲模拟工具测试
  • 用户反馈:收集用户对颜色映射的反馈

总结

数据可视化中的颜色映射 - 渐变色生成工具展示了如何使用 Kotlin Multiplatform 技术创建一个功能丰富、跨端兼容的颜色映射应用。通过提供多种映射方案和最佳实践指导,系统能够帮助数据分析师和可视化设计师创建更加有效的数据可视化。

这个案例不仅展示了 KMP 的强大功能,还演示了如何将色彩科学和数据可视化知识转化为实用的应用功能。无论是地图热力图、财务数据分析还是性能监控,数据分析师都可以使用这个工具来快速生成合适的颜色映射,提高数据可视化的质量和效果。

通过使用这个颜色映射工具,数据分析师可以确保他们的可视化在视觉上清晰、准确且易于理解,为用户提供更好的数据洞察体验。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐