Unity中画2D图表(3)——用XChart包绘制复合图表【柱状图 + 折线图】

绘制组合图是一种常见的需求。日常所见的组合图,比如股价走势图,上面有股价图(蜡烛图),还有趋势线(MA5,MA10,MA60等等)。

组合图示例

本文给定三个系列的数据,前两个系列绘制成Bar图,后一个系列绘制成Line图,其中两个Bar用的是同一个Y轴的刻度范围(Y轴1),Line图用的是另一个Y轴的刻度范围。*

一、要画的图(示例)

在这里插入图片描述

  • X轴:月份,从1月到12月

  • Y轴1【左】:温度,

  • Y轴2【右】:温差比值,百分比0% - 100%

  • 数据1:林内温度,刻度用的是Y轴1(左)

  • 数据2:林外温度,刻度用的是Y轴1(左)

  • 数据3:温差比值,刻度用的是Y轴2(右)

二、作图的大概流程(关键步骤)

请添加图片描述

作图的关键步骤

三、代码清单

using Cysharp.Threading.Tasks;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using XCharts.Runtime;

/// <summary>
/// line和bar的合并图表
/// </summary>
public class ExampleComboChart : MonoBehaviour
{
    
    
    /// <summary>
    /// 测试按钮——画线
    /// </summary>
    public Button StartBtn;

    void Start()
    {
    
    
        StartBtn.onClick.AddListener(() =>
        {
    
    
            DrawComboChartFlow();
        });
    }

    /// <summary>
    /// 绘制复合图的流程
    /// </summary>
    /// <returns></returns>
    private async UniTask DrawComboChartFlow()
    {
    
    
        //【1】添加一个LineChart的组件
        Debug.Log("添加一个组合图表");
        var chart = gameObject.GetComponent<LineChart>();
        if (chart == null)
        {
    
    
            chart = gameObject.AddComponent<LineChart>();
            chart.Init();
        }

        //【2】设置图表的大小:SetSize(x,y)
        Debug.Log("设置图表的大小(580, 300) ");
        chart.SetSize(580, 300);//代码动态设置尺寸

        Debug.Log("2秒后重新设置大小(1102, 519) ");
        await UniTask.Delay(TimeSpan.FromSeconds(2.0f));
        chart.SetSize(1102, 519);

        //【3】设置标题:chart.Title.text|subText = ""
        Debug.Log("2秒后:设置标题 ");
        await UniTask.Delay(TimeSpan.FromSeconds(2.0f));
        var title = chart.GetOrAddChartComponent<Title>();
        title.text = "各月份林内林外温度";            //主标题
        title.subText = "分析对比图";                 //副标题

        //【4】设置提示框【Tooltip】和图例【Legend】是否显示
        //Tooltip - 鼠标悬停在曲线节点上的时候,显示数据信息 
        //Legend  - 图上数据系列的类别信息【例如[red-白天温度]、[black-晚上温度]】
        Debug.Log("2秒后:设置提示框和图例是否显示");
        await UniTask.Delay(TimeSpan.FromSeconds(2.0f));
        var tooltip = chart.GetOrAddChartComponent<Tooltip>();
        tooltip.show = true;                                //在数据节点上,鼠标悬停时显示的信息框
        var legend = chart.GetOrAddChartComponent<Legend>();
        legend.show = true;

        //【5】设置坐标轴的数据刻度信息
        Debug.Log("2秒后:设置坐标轴");
        await UniTask.Delay(TimeSpan.FromSeconds(2.0f));

        //——x轴设置
        var xAxis = chart.GetOrAddChartComponent<XAxis>();
        xAxis.splitNumber = 24;                            //数据的个数-参数硬编码
        xAxis.boundaryGap = true;
        xAxis.type = Axis.AxisType.Category;

        //X轴的坐标轴名称设置
        xAxis.axisName.name = "月份";
        xAxis.axisName.show = true;
        xAxis.axisName.labelStyle.position = LabelStyle.Position.Middle;
        xAxis.axisName.labelStyle.rotate = 0;
        xAxis.axisName.labelStyle.textPadding.top = 100;

        //——y轴设置
        //第一个Y轴设置
        var yAxis1 = chart.GetOrAddChartComponent<YAxis>();
        yAxis1.type = Axis.AxisType.Value;
        yAxis1.axisLabel.formatter = "{value}℃";

        //Y轴1的坐标轴名称设置
        yAxis1.axisName.name = "温度";
        yAxis1.axisName.show = true;
        yAxis1.axisName.labelStyle.position = LabelStyle.Position.End;
        yAxis1.axisName.labelStyle.rotate = 90;
        yAxis1.axisName.labelStyle.textPadding.bottom = 150;

        //第二个Y轴设置       
        var yAxis2 = chart.AddChartComponent<YAxis>();
        yAxis2.minMaxType = Axis.AxisMinMaxType.Custom;
        yAxis2.min = 0;
        yAxis2.max = 100;
        yAxis2.position = Axis.AxisPosition.Right;
        yAxis2.axisLabel.formatter = "{value}%";

        //Y轴2的坐标轴名称设置
        yAxis2.axisName.name = "温差比值";
        yAxis2.axisName.show = true;
        yAxis2.axisName.labelStyle.position = LabelStyle.Position.End;
        yAxis2.axisName.labelStyle.rotate = 90;
        yAxis2.axisName.labelStyle.textPadding.top = 140;

        //【6】清空默认数据,添加Scatter类型的Serie用于接收数据
        Debug.Log("2秒后:清空默认数据,添加Scatter类型的Serie用于接收数据");
        await UniTask.Delay(TimeSpan.FromSeconds(2.0f));
        chart.RemoveData();

        //【7】添加数据:X轴的刻度数据,Y轴的数据
        var serie1 = chart.AddSerie<Bar>("林内温度");     //增加一个Bar系列
        serie1.yAxisIndex = 0;//它的Y轴设定为第一个Y轴

        var serie2 = chart.AddSerie<Bar>("林外温度");     //增加一个Bar系列 
        serie2.yAxisIndex = 0;//它的Y轴设定为第一个Y轴

        var serie3 = chart.AddSerie<Line>("温差比值");    //增加一个Line系列  
        serie3.yAxisIndex = 1;//它的Y轴设定为第二个Y轴

        Debug.Log("2秒后:添加数据");
        await UniTask.Delay(TimeSpan.FromSeconds(2.0f));

        var seriesNums = Enumerable.Range(0, 12).ToList();    //12个数据
        var xTickLabels = new List<string> {
    
     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

        var y1Values = new List<float> {
    
     1,2,3,4,5,6,7,8,9,10,11,12};
        y1Values = seriesNums.Select(x => (float)(UnityEngine.Random.Range(10, 20))).ToList();            //[min,max) 前开后闭

        var y2Values = new List<float> {
    
     2,3,4,5,6,7,8,9,10,11,12,13 };
        y2Values = y1Values.Select(x => (float)(x + UnityEngine.Random.Range(10, 20) / 10.0) ).ToList();  //Y2 = f(Y1) 

        var y3Values = new List<float> {
    
    3,4,5,6,7,8,9,10,11,12,13,14 };
        y3Values = y1Values.Zip(y2Values, (y1, y2) =>  Math.Abs(y1 - y2)/y1 * 100).ToList();              //Y3 = f(Y1,Y2)   

        //数据添加到图表上
        seriesNums.ForEach(idx =>
        {
    
    
            chart.AddXAxisData(xTickLabels[idx]);  //X轴的刻度标签
            chart.AddData(0, y1Values[idx]);       //Y1,第一组数据
            chart.AddData(1, y2Values[idx]);       //Y2,第二组数据
            chart.AddData(2, y3Values[idx]);       //Y3,第二组数据
        });

        //【8】x轴刻度标签旋转(倾斜)设置
        Debug.Log("2秒后:x轴刻度标签旋转设置");
        await UniTask.Delay(TimeSpan.FromSeconds(2.0f));
        xAxis.axisLabel.rotate = 45;

        //【9】设置线条的颜色
        Debug.Log("0.4秒后:线条的颜色设置");
        await UniTask.Delay(TimeSpan.FromSeconds(0.4f));
        chart.series[0].itemStyle.color = Color.red;     //第一组线条的颜色 
        chart.series[1].itemStyle.color = Color.green;   //第二组线条的颜色
        chart.series[2].itemStyle.color = Color.blue;    //第三组线条的颜色

        //【10】线条样式设置:
        await UniTask.Delay(TimeSpan.FromSeconds(2.0f));
        Debug.Log("2秒后:设置Bar的width");
        chart.series[0].barWidth = 20;
        chart.series[0].barType = BarType.Zebra;     //斑马线样式

        chart.series[1].barWidth = 20;
        chart.series[1].barType = BarType.Normal;    //默认样式

        chart.series[2].lineStyle.width = 1;
        chart.series[2].lineType = LineType.Smooth;  //线条设置为平滑

        //刷新所有的组件【不刷新的话,发现不能画直线】
        chart.RefreshAllComponent();
    }

#if UNITY_EDITOR
    [ContextMenu("测试")]
#endif
    void Test()
    {
    
    
        DrawComboChartFlow();
    }
}

猜你喜欢

转载自blog.csdn.net/dzj2021/article/details/129044527