SwiftUI之深入解析如何使用SwiftUI Charts创建折线图

news2024/9/20 11:47:05

一、简单折线图

  • 苹果在 WWWDC 2022 上推出了 SwiftUI 图表,这使得在 SwiftUI 视图中创建图表变得异常简单。图表是以丰富的格式呈现可视化数据的一种很好的方式,而且易于理解。本文展示了如何用比以前从头开始创建同样的折线图少得多的代码轻松创建折线图,此外自定义图表的外观和感觉以及使图表中的信息易于访问也是非常容易的。
  • 从包含王者荣耀全部英雄的登场率开始,类似于在 SwiftUI 中创建折线图中使用的数据,定义一个结构来保存英雄和登场率的步数,并创建一个数组:
struct KingHeroWinRate: Identifiable {
    
    let id = UUID()
    let hero: String
    let winRate: Double
    
    init(hero: String, winRate: Double) {
        self.hero = hero;
        self.winRate = winRate;
    }
}

let currentHero: [KingHeroWinRate] = [
    KingHeroWinRate(hero: "孙悟空", winRate: 0.140),
    KingHeroWinRate(hero: "玄奘", winRate: 0.186),
    KingHeroWinRate(hero: "猪八戒", winRate: 0.111),
    KingHeroWinRate(hero: "嫦娥", winRate: 0.187),
    KingHeroWinRate(hero: "杨戬", winRate: 0.084)
]
  • 要创建一个折线图,为英雄登场率数据中的每个元素创建一个带有 LineMark 的图表,在 LineMark 的 X 值中指定英雄,在 Y 值中指定登场率,需要注意的是需要导入 Charts 框架。这就为英雄登场率数据创建了一个线形图,由于只有一个系列的数据,ForEach 可以省略,数据可以直接传递给 Chart 初始化器,两个部分都产生相同的折线图:
import SwiftUI
import Charts

struct ContentView: View {

    var body: some View {
        VStack {
            GroupBox("王者荣耀英雄登场率排行") {
                Chart {
                    ForEach(currentHero) {
                        LineMark(
                            x: .value("英雄", $0.hero),
                            y: .value("胜率", $0.winRate)
                        )
                    }
                }
            }
            
            GroupBox("王者荣耀英雄登场率排行") {
                Chart(currentHero) {
                    LineMark(
                        x: .value("英雄", $0.hero),
                        y: .value("胜率", $0.winRate)
                    )
                    
                }
            }
		}
    }
}
  • 使用 SwiftUI Charts 创建折线图显示英雄登场率的效果如下:

在这里插入图片描述

二、其它图表

  • SwiftUI Charts 有许多可用的图表选项,这些可以通过将图表标记从 LineMark 改为其他类型的标记(如 BarMark)来生成条形图:
struct ContentView: View {

    var body: some View {
        VStack {
            GroupBox("王者荣耀英雄登场率排行") {
                Chart {
                    ForEach(currentHero) {
                        LineMark(
                            x: .value("英雄", $0.hero),
                            y: .value("胜率", $0.winRate)
                        )
                    }
                }
            }
            GroupBox ("王者荣耀英雄登场率排行") {
                Chart(currentHero) {
                    BarMark(
                        x: .value("英雄", $0.hero),
                        y: .value("胜率", $0.winRate)
                    )
                }
            }
            GroupBox ("王者荣耀英雄登场率排行") {
                Chart(currentHero) {
                    PointMark(
                        x: .value("英雄", $0.hero),
                        y: .value("胜率", $0.winRate)
                    )
                }
            }
            GroupBox ("王者荣耀英雄登场率排行") {
                Chart(currentHero) {
                    RectangleMark(
                        x: .value("英雄", $0.hero),
                        y: .value("胜率", $0.winRate)
                    )
                }
            }
            GroupBox ("王者荣耀英雄登场率排行") {
                Chart(currentHero) {
                    AreaMark(
                        x: .value("英雄", $0.hero),
                        y: .value("胜率", $0.winRate)
                    )
                }
            }
        }
    }
}
  • 效果如下:

在这里插入图片描述

三、增加折线图的可访问性

  • 将图表植入 SwiftUI 的一个好处是,可以很容易地使用可访问性修饰符使图表变得可访问。为 KingHeroWinRate 添加一个计算属性,将数据返回为一个字符串,可由 accessibilityLabel 使用,然后为图表中的每个标记添加可访问性标签和值:
struct KingHeroWinRate: Identifiable {
    
    let id = UUID()
    let hero: String
    let winRate: Double
    
    init(hero: String, winRate: Double) {
        self.hero = hero;
        self.winRate = winRate;
    }
    
    var heroNameString: String {
        return hero;
    }
}
  • 第一次尝试添加这两个系列的数据没有按预期显示:
struct ContentView: View {

    var body: some View {
        VStack {
            GroupBox("王者荣耀英雄登场率排行") {
                Chart {
                    ForEach(heroData, id: \.period) {
                        ForEach($0.data) {
                            LineMark(
                                x: .value("英雄", $0.hero),
                                y: .value("登场率", $0.winRate)
                            )
                            .accessibilityLabel($0.heroNameString)
                            .accessibilityValue("\($0.winRate) winRate")
                        }
                    }
                }
            }
        }
    }
}

在这里插入图片描述

四、为折线图添加多个数据序列

  • 折线图是比较两个不同系列数据的好方法,创建第二个系列,即另外一组英雄的登场率,并将这两个系列添加到折线图中:
let previousHero: [KingHeroWinRate] = [
    KingHeroWinRate(hero: "刘备", winRate: 0.063),
    KingHeroWinRate(hero: "关羽", winRate: 0.071),
    KingHeroWinRate(hero: "赵云", winRate: 0.079),
    KingHeroWinRate(hero: "张飞", winRate: 0.061),
    KingHeroWinRate(hero: "黄忠", winRate: 0.061)
]

let currentHero: [KingHeroWinRate] = [
    KingHeroWinRate(hero: "孙悟空", winRate: 0.140),
    KingHeroWinRate(hero: "玄奘", winRate: 0.186),
    KingHeroWinRate(hero: "猪八戒", winRate: 0.111),
    KingHeroWinRate(hero: "嫦娥", winRate: 0.187),
    KingHeroWinRate(hero: "杨戬", winRate: 0.084)
]

let heroData = [
    (period: "Current Hero", data: currentHero),
    (period: "Previous Hero", data: previousHero)
]
  • 第一次尝试添加这两个系列的数据没有按预期显示:
        GroupBox("王者荣耀英雄登场率排行") {
            Chart {
                ForEach(heroData, id: \.period) {
                    ForEach($0.data) {
                        LineMark(
                            x: .value("英雄", $0.heroBranching),
                            y: .value("登场率", $0.winRate)
                        )
                        .accessibilityLabel($0.heroBranching)
                        .accessibilityValue("\($0.winRate) winRate")
                    }
                }
            }
        }

在这里插入图片描述

五、显示登场率系列

  • 在折线图中显示多个基于英雄的登场率系列,最初尝试在折线图中显示多组数据的问题是 X 轴使用了英雄,当前的英雄紧接着上一部分英雄,因此每一个点都是沿着 X 轴线性递增绘制的。有必要只用分路作为 X 轴的数值,这样所有的英雄都在同一个 X 坐标上绘制。
  • 在 KingHeroWinRate 中添加另一个计算属性,以便以字符串格式返回英雄的分路:
struct KingHeroWinRate: Identifiable {
    
    let id = UUID()
    let hero: String
    let winRate: Double
    
    init(hero: String, winRate: Double) {
        self.hero = hero;
        self.winRate = winRate;
    }
    
    var heroNameString: String {
        return hero;
    }
    
    var heroBranching: String {
        if (heroNameString == "孙悟空" || heroNameString == "刘备") {
            return "打野";
        } else if (heroNameString == "玄奘" || heroNameString == "关羽") {
            return "中路";
        } else if (heroNameString == "猪八戒" || heroNameString == "赵云") {
            return "上路";
        } else if (heroNameString == "嫦娥" || heroNameString == "张飞") {
            return "辅助";
        } else if (heroNameString == "杨戬" || heroNameString == "黄忠") {
            return "下路";
        } else {
            return "";
        }
   }
    
}
  • 此 heroBranching 用于图表中 LineMarks 的 x 值。另外,前景的样式设置为基于 KingHeroWinRate 数组的周期,折线图使用 x 轴的分路来显示英雄,以便在分路之间进行比较:
struct ContentView: View {

    var body: some View {       
        VStack {
            GroupBox("王者荣耀英雄登场率排行") {
                Chart {
                    ForEach(heroData, id: \.period) { hero in
                        ForEach(hero.data) {
                            LineMark(
                                x: .value("英雄", $0.heroBranching),
                                y: .value("登场率", $0.winRate)
                            )
                            .foregroundStyle(by: .value("branch", hero.period))
                            .accessibilityLabel($0.heroBranching)
                            .accessibilityValue("\($0.winRate) winRate")
                        }
                    }
                }
                .frame(height:400)
            }
            .padding()
            Spacer()
        }
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1381910.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android WiFi Service启动-Android13

Android WiFi Service启动 - Android13 1、SystemServer中入口2、WifiService启动2.1 关键类概要2.2 启动时序图 Android WiFi基础概览 AOSP > 文档 > 心主题 > WiFi概览 1、SystemServer中入口 编译生成对应的jar包:"/apex/com.android.wifi/javalib…

十三、QPalette的简单使用(Qt5 GUI系列)

目录 一、设计需求 二、实现代码 三、代码解析 四、总结 一、设计需求 在实际应用中,经常需要改变某个控件的颜色外观,如背景、文字颜色等。Qt提供的调色板类 QPalette 专门用于管理对话框的外观显示。QPalette 类相当于对话框或是控件的调色板&…

1222. 密码脱落(dp划分)

题目&#xff1a; 1222. 密码脱落 - AcWing题库 思路&#xff1a; 代码&#xff1a; #include<cstdio> #include<cstring> using namespace std; const int N1010; int f[N][N];//表示以L和R为两端点的字符串的“最长”回文序列长度 char s[N];//存储输入的字符串…

【Docker篇】使用Docker操作镜像

文章目录 &#x1f6f8;镜像&#x1f33a;基本操作⭐docker --help⭐docker pull [ 参数 ]⭐docker images⭐docker save -- 导出⭐docker rmi -- 删除⭐docker load -- 导入 &#x1f6f8;镜像 镜像是指在计算机领域中&#xff0c;通过复制和创建一个与原始对象相似的副本的过…

js逆向第20例:猿人学第19题乌拉乌拉乌拉

文章目录 一、前言二、定位关键参数1、JA3/TLS指纹怎么查看2、加密值长度对比三、代码实现四、参考文献一、前言 任务十九:抓取这5页的数字,计算加和并提交结果 此题在以前用python写逆向代码是存在缺陷的,直到今年有个大佬开源了curl_cffi库,并且支持 JA3/TLS 和 http2 指…

计算机组成原理 CPU的功能和基本结构和指令执行过程

文章目录 CPU的功能和基本结构CPU的功能CPU的基本结构 指令执行过程指令周期概念指令执行方案指令数据流取周期数据流析指周期数据流执行周期数据流中断周期数据流 数据通路的功能和基本结构数据通路的功能数据通路的结构单总线 CPU的功能和基本结构 #mermaid-svg-jr0QOEyC6Q92…

二分图最大匹配——匈牙利算法详解

文章目录 零、前言一、红娘牵线二、二分图最大匹配2.1概念2.2交替路2.3增广路2.4匈牙利算法2.4.1算法原理2.4.2算法示例2.4.3代码实现 3.OJ练习3.1模板3.2棋盘覆盖3.3車的放置 零、前言 关于二分图的基本知识见&#xff1a;二分图及染色法判定 一、红娘牵线 一位红娘近日遇到一…

leetcode 每日一题 2024年01月14日 删除排序链表中的重复元素

题目 83. 删除排序链表中的重复元素 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例 2&#xff1a; 输入&#xff…

通信入门系列——微积分中极限、连续、导数、微分、积分

本节目录 一、极限 1、数列极限 2、函数极限 二、连续 三、导数 四、微分 五、积分本节内容 一、极限 1、数列极限 数列极限&#xff1a;设{xn}为一个实数列&#xff0c;A为一个定数。若对任意给定的ε>0&#xff0c;总存在正整数N,使得当n>N时&#xff0c;有|xn-A|<…

探索商超货架场景目标检测性能,基于YOLOv8【n/s/m/l/x】全系列参数模型开发构建商超货架场景下亨氏米粉食品种类检测识别系统

在前面的系列博文中&#xff0c;我们陆续应用实践开发了很多有趣的项目&#xff0c;但是在密集排布场景下如商超购物场所内货架上货物种类目标检测模型的开发我们则少有涉及&#xff0c;正值周末&#xff0c;本文的主要目的就是想要实践构建这一场景下的目标检测模型&#xff0…

云原⽣组件Nacos新型红队手法研究

组件简介 Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称&#xff0c;一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集&#xff0c;帮助您快…

canvas设置圆锥形渐变

查看专栏目录 canvas示例教程100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

【QT】多层QTreeWidget与QStackedWidget的关联操作

通过点击多层QTreeWidget来控制QStackedWidget中的page页面切换 treeWidget设计 treeWidget设计&#xff1a; // treeWidget设计ui->treeWidget->clear();ui->treeWidget->setColumnCount(1);//第一层QStringList l;l<<"管理系统";QTreeWid…

数据仓库(2)-认识数仓

1、数据仓库是什么 数据仓库 &#xff0c;由数据仓库之父比尔恩门&#xff08;Bill Inmon&#xff09;于1990年提出&#xff0c;主要功能仍是将组织透过资讯系统之联机事务处理(OLTP)经年累月所累积的大量资料&#xff0c;透过数据仓库理论所特有的资料储存架构&#xff0c;做…

DHCP中继【新华三】

理论【DHCP服务器可以对其直连的网段中的pc&#xff0c;分配其IP地址等服务&#xff0c;但是&#xff0c;对于跨网段进行分配IP地址&#xff0c;需要中间有DHCP中继进行传达&#xff0c;由DHCP中继指定DHCP服务器的位置&#xff0c;可以很好的对其跨网段分配IP地址起到指引的作…

第 2 课 ROS 系统安装和环境搭建

第 2 课 ROS 系统安装和环境搭建 1.版本选择 不同的 Ubuntu 安装的 ROS 版本不同&#xff0c;其中 Ubuntu18.04 的 ROS 对应版本为Melodic。 Ubuntu版本ROS版本Ubuntu16.04KineticUbuntu18.04MelodicUbuntu20.04Noetic 2.检查 Ubuntu 的软件和更新源 找到系统中的“软件和…

数据模型/数据建模的含义

我们可以从以下四个方面来了解 &#xff08;1&#xff09;、业务模型 &#xff08;2&#xff09;、构建表关系/表链接 &#xff08;3&#xff09;、数学模型 &#xff08;4&#xff09;、算法模型 业务模型 建立业务模型的重点是懂业务&#xff0c;即了解业务的整个过…

Java项目:07 Springboot的客户管理系统

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 springboot客户管理系统 功能模块&#xff1a;登录修改密码客户列表充值列表消费记录客户类型 环境&#xff1a;IDEAjdk1.8Tomcat9MySQL5.7maven3.6…

RK3568笔记八: Display子系统

modetest 是由 libdrm 提供的测试程序&#xff0c;可以查询显示设备的特性&#xff0c;进行基本的显示测试&#xff0c;以及设置显示的模式。 我们可以借助该工具来学习 Linux DRM 应用编程&#xff0c;另外为了深入分析 Rockchip DRM driver&#xff0c;有必要先了解一下这个…

用C语言采集亚马逊amazon产品数据

上一篇文章我是用C写的一个爬取亚马逊的爬虫程序&#xff0c;相信大家已经看过了&#xff0c;这次呢&#xff0c;我依然使用C语言来写一个爬虫&#xff0c;大体上思路是和之前一样&#xff0c;只是支持的库以及语法有些区别&#xff0c;具体的呢我会一一解释出来&#xff0c;方…