【D3.js in Action 3 精译_040】4.4 D3 弧形图的绘制方法
当前内容所在位置:
- 第四章 直线、曲线与弧线的绘制 ✔️
- 4.1 坐标轴的创建(上篇)
- 4.1.1 D3 中的边距约定(中篇)
- 4.1.2 坐标轴的生成(中篇)
- 4.1.2.1 比例尺的声明(中篇)
- 4.1.2.2 坐标轴的添加(下篇)
- 4.1.2.3 轴标签的添加(下篇)
- 4.2 D3 折线图的绘制
- 4.2.1 直线生成工具的使用
- 4.2.2 对数据点作曲线插值处理
- 4.3 D3 面积图的绘制
- 4.3.1 面积图生成工具的用法
- 4.3.2 用标签提高图表的可读性
- 4.4 D3 弧形图的绘制 ✔️
- 4.4.1 D3 中的极坐标系 ✔️
- 4.4.2 圆弧生成器的使用 ✔️
- 4.4.3 圆弧形心的计算 ✔️
- 4.4.4 人物专访:Francis Gagnon、Patricia Angkiriwang 和 Olivia Gélinas
- 4.5 本章小结
文章目录
- 4.4 D3 弧形图的绘制 Drawing arcs
- 4.4.1 D3 中的极坐标系 The polar coordinate system
- 4.4.2 圆弧生成器的使用 Using the arc generator
- 4.4.3 圆弧形心的计算 Calculating the centroid of an arc
《D3.js in Action》全新第三版封面
译者按
终于来到了第四章的最后一节——弧形图的绘制。有了前面几节的知识储备,看似云遮雾绕的 D3 弧形图绘制也可以立马手到擒来。这也是 D3 可视化的另一个强大之处——掌握相关基础知识后可以快速触类旁通其他图表类型!
4.4 D3 弧形图的绘制 Drawing arcs
在本章最后一节,一起再来看看 D3 弧形图的绘制方法。弧形是数据可视化中的常见形状,经常用于绘制饼图、旭日图(sunburst diagrams)和南丁格尔玫瑰图(Nightingale rose charts)等,用于呈现目标数量与总量之间的关系。此外还可以在自定义的径向可视化作品(custom radial visualizations)中见到它们的身影。
与折线图和面积图一样,弧形图也是通过 SVG 路径元素绘制的。可能您已经猜到了,D3 内置了一个便捷的弧形生成工具专门用于计算弧形路径的 d
属性。在详细介绍弧形生成器之前,先要做好示例项目的相应准备工作。本节要绘制的弧形图,即本章最开始介绍的图 4.1 中右边的“降水天数”环形图,也可以在该图形的线上版本进行查看(详见 http://mng.bz/5orB)。其中蓝色弧线表示 2021 年纽约市全年降水天数的百分比(35%),灰色弧线则表示无降水天数。
首先打开 arc.js
文件,本节后续实现逻辑都将写到这里。同往常一样,这里需要加载一个数据集,即 data
文件夹下的降水量数据文件 daily_precipitation.csv
。查看该 CSV 文件,会看到当中只包含两列,其中 date
列为 2021 年的每一天,而 total_precip_in
列则为每一天的总降水量,单位为英寸。
在下面的代码段中,我们使用 d3.csv()
读取数据集,并利用格式转换函数 d3.autoType
得到正确的日期和数字;然后链式调用 Promise
的 then
方法,并将得到的数据集输出到控制台:
d3.csv("./data/daily_precipitation.csv", d3.autoType).then(data => {console.log("precipitation data", data);
});
注意
这里不会展开讨论
d3.csv()
方法的细节,相关内容详见第三章,或者参考本章 4.1 小节了解d3.autoType
函数的用法。
如果查看控制台中的数据,就会看到日期和数字的格式都是正确的。接下来就可以将处理好的数据集传入 drawArc()
函数。该函数已经事先在 arcs.js
中定义好了(译注:只是不完整):
d3.csv("../data/daily_precipitation.csv", d3.autoType).then(data => {console.log("precipitation data", data);drawArc(data);
});
在 drawArc()
函数中,可以添加一个新的 SVG 容器,如以下代码所示。先指定 SVG 容器的宽高为 300px
,并添加到一个 ID 为 arc
的 div
元素中。该 ID 值已在 index.html
文件中声明。这里利用第一章介绍的知识将 SVG 元素设为响应式容器:忽略其 width
和 height
属性,直接指定 viewBox
属性并传入指定的宽高。这样,SVG 容器就能自适应父容器的大小,并保持恒定纵横比不变。最后,再将 SVG 容器的选择集赋给常量 svg
备用:
const pieChartWidth = 300;
const pieChartHeight = 300;
const svg = d3.select("#arc").append("svg").attr("viewBox", [0, 0, pieChartWidth, pieChartHeight]);
4.4.1 D3 中的极坐标系 The polar coordinate system
回顾 4.1 小节介绍的内容,当时的图表是绘制在一个 SVG 分组元素中并通过平移到达容器指定位置;而本节的实现策略不太一样,由于无需为坐标轴和标签预留足够空间,因此边距约定环节可以省略。但与目前创建的所有可视化效果不同,弧形图是基于极坐标系绘制的,并非之前的直角坐标系。
如图 4.24 所示,SVG 容器的坐标系为直角坐标系(也称笛卡尔坐标系)。它通过两个相互垂直的维度 x
和 y
来描述二维平面空间中的位置;而平面极坐标系也有两个维度:半径与角度。其中半径为坐标原点与空间中某个点之间的距离,而角度则基于 12 点方向沿顺时针算得。这种空间坐标的描述方式在处理圆弧时特别管用。
【图 4.24 直角坐标系的两个维度相互垂直,而极坐标系通过半径和角度来描述空间中的方位】
由于元素在极坐标系中相对于原点定位,因此我们可以说,待绘制的弧形可视化效果的原点位于 SVG 容器的中心,如图 4.25 所示。
【图 4.25 通过在 SVG 容器的分组元素中绘制弧形图,然后平移至容器正中,可以很方便地实现弧形图的绘制。此时各圆弧相对于图表中心定位,也就是极坐标系的原点位置。】
以下代码片段将在 SVG 容器内添加一个分组元素,然后平移至容器正中,并将该选择集赋给常量 innerChart
:
const innerChart = svg.append("g").attr("transform", `translate(${pieChartWidth/2}, ${pieChartHeight/2})`);
要绘制圆弧,还需要计算弧形图中降水天数对应的角度值。使用 D3 创建饼图或环形图时,通常使用饼图布局生成工具(即 pie layout generator)来处理相关计算,该生成器工具将在下一章中重点介绍。本节只涉及两条弧线,因此计算起来很简单。
首先,通过数据集的 length
属性,我们知道了 2021 年全年数据点的总天数为 365
天。接着筛选出降水量大于 0 的天数,即 126
天,从而得到当年有降水记录的天数。最后用降水天数除以总天数,得到 35%
的占比:
const numberOfDays = data.length;
const numberOfDaysWithPrecipitation = data.filter(d => d.total_precip_in > 0).length;
const percentageDaysWithPrecipitation = Math.round(numberOfDaysWithPrecipitation / numberOfDays * 100);
接下来需要计算降水天数对应的角度,用占比乘以 360 度(即一整圈的度数),得到 126 度。用角度进行计算更加直观,但使用时需转换为弧度值,即用角度值乘以 π/180
,算得弧度约为 2.2。最后将该结果赋给常量 angleDaysWithPrecipitation_rad
。
之所以需要转换,是因为后续会用到的弧形生成器需要弧度制单位而非角度单位。根据经验,在处理角度时 JavaScript 通常使用弧度制,而 CSS 样式表中则采用角度制计量:
const angleDaysWithPrecipitation_deg = percentageDaysWithPrecipitation * 360 / 100;
const angleDaysWithPrecipitation_rad = angleDaysWithPrecipitation_deg * Math.PI / 180;
4.4.2 圆弧生成器的使用 Using the arc generator
终于讲到最有意思的部分:圆弧的生成了!首先需要像折线图和面积图那样,声明一个圆弧生成器(arc generator)。圆弧生成器函数 d3.arc()
位于 d3-shape
模块;本例中需要两个关键的访问器函数(accessor functions):圆弧的内圆半径和外圆半径,分别通过 innerRadius()
函数和 outerRadius()
函数进行设置,传入参数分别为 80px
和 120px
。如果内圆半径为 0,则会得到一个饼图。
const arcGenerator = d3.arc().innerRadius(80).outerRadius(120);
如图 4.26 所示,可以调用访问器函数 padAngle()
设置圆弧的填充角来定制圆弧形状。该函数接受一个弧度单位的角度值。这里用的是 0.02
弧度,相当于 1° 多一点点。此外还可以调用 cornerRadius()
函数对圆弧的拐角作圆化处理,其参数为一个基于像素的数字。该访问器函数的效果于 CSS 中的 border-radius
属性类似:
const arcGenerator = d3.arc().innerRadius(80).outerRadius(120).padAngle(0.02).cornerRadius(6);
【图 4.26 圆弧生成器利用多个访问器函数计算弧形的 d 属性。图中声明生成器时分别指定了内圆半径、外圆半径、填充角及拐角半径。添加路径元素时需要传入每个圆弧的起始角与终止角。】
您也许会问,为什么不使用访问器函数来处理圆弧覆盖的角度呢?本例中的角度值是手动计算的,因此在添加路径时将其直接传给圆弧生成器会更简单。在下一章中,我们还将介绍另一些不同的情况。
下面来添加代表降水天数的弧线。在以下代码片段中,先往内部图表的选择集内添加一个 path
元素;接着通过调用前面声明的圆弧生成器来指定其 d
属性。
注意观察,绘制圆弧时需要向生成器中传入一个包含起始角与终止角的配置对象:起始角 startAngle
的值为 0
,对应 12 点钟方向;终止角 endAngle
的值为前面算好的降水天数对应的弧度值。最后指定圆弧的填充色为青蓝色 #6EB7C2
:
innerChart.append("path").attr("d", () => {return arcGenerator({startAngle: 0,endAngle: angleDaysWithPrecipitation_rad});}).attr("fill", "#6EB7C2");
同理可添加第二段圆弧。此时弧线从上一条圆弧的终止位置开始,并在整个圆的终止处结束(对应的弧度为 2*Pi
)。接着再给第二段圆弧指定填充色 #DCE2E2
,即更接近灰色的颜色,表明这些日子没有降水:
innerChart.append("path").attr("d", () => {return arcGenerator({startAngle: angleDaysWithPrecipitation_rad,endAngle: 2 * Math.PI});}).attr("fill", "#DCE2E2");
【图 4.27 用以展示降水天数与无降水天数对比情况的弧线图效果】
保存项目后,本地页面的弧形图应该与图 4.27 中的版本类似。您可以自行尝试变换传入圆弧生成器各访问器函数中的参数值,例如半径和拐角尺寸,观察它们对圆弧外观的影响。
如图 4.28 所示,弧形图的绘制过程与折线图及面积图类似,主要区别在于,弧线在平面空间中的位置坐标是通过极坐标描述的,并非之前的直角坐标系。这一点在圆弧生成器的访问函数中也有所体现。
【图 4.28 弧形图的绘制步骤】
4.4.3 圆弧形心的计算 Calculating the centroid of an arc
饼图和环形图近期在数据可视化领域可谓负面新闻不断,主要原因时人们发现肉眼并不擅长估算角度所代表的比例大小。不过,在包含少量数据类别时,这些图表的表现还是可圈可点的;但我们绝对可以通过添加标签来提高它们的可读性,这就是本节要实现的目标。
在表示降水天数的圆弧上,我们希望添加一个 “35%” 的标签,即之前算出的降水天数占比。该标签的最佳位置应该在圆弧的中心处,即形心(centroid)位置(也叫质心,即 center of mass)。该位置坐标可通过圆弧生成器计算得到。
在下面的代码片段中,我们调用了此前声明的圆弧生成器上的方法。此时,起始角与终止角也可以通过链式调用 startAngle()
和 endAngle()
这两个访问器函数进行设置,最后再链式调用形心计算方法 centroid()
,得到该圆弧的中点坐标:
const centroid = arcGenerator.startAngle(0).endAngle(angleDaysWithPrecipitation_rad).centroid();
将中点坐标输出到控制台,可以看到形心为包含两个坐标值的数组组成,分别为形心的水平与垂直坐标值,本例即为 [89, -45]
。
在以下代码片段中,我们向内部图表选择集添加了一个 text
元素来创建文本标签。为了让标签值带有百分号 %
,这里用到了 D3 的格式化方法 d3.format(".0%")
,然后在后面的括号中传入指定的数值。该方法可以轻松实现数字的各种格式化表示,如货币、百分比及指数形式;也可以为数字添加指定的后缀,如表示百万的 M
以及表示微米数量级的 μ
。具体的格式转换列表详见 d3-format
模块的官方文档。
接着,我们使用 centroid()
方法返回的坐标数组完成 x
和 y
属性的设置。注意,这里还指定了 text-anchor
属性和 dominant-baseline
属性,以确保文本标签在水平与垂直方向均相对 x
和 y
属性居中渲染。
最后,将标签的字体颜色改为白色,粗细设为 500
,以提高标签的可读性。保存项目后,带文本标签的弧形图效果应该与图 4.29 一致:
【图 4.29 带文本标签的弧形图最终效果】
innerChart.append("text").text(d => d3.format(".0%")(percentageDaysWithPrecipitation/100)).attr("x", centroid[0]).attr("y", centroid[1]).attr("text-anchor", "middle").attr("dominant-baseline", "middle").attr("fill", "white").style("font-weight", 500);
至此,我们已经掌握了 D3 折线图、面积图以及弧形图的绘制方法。下一章,我们将利用布局生成工具(layout generators)让这些图形的绘制再提高一个档次!
另附:专栏文章连载期间 完全免费,后续 不排除 调整为收费专栏。对 D3.js 感兴趣、或者想要从零开始彻底掌握 D3 的朋友们强烈建议及时关注本专栏,一起学习交流,共同进步!
目前译好的其他章节内容如下(可进入专栏查看详情):
- 第一部分 D3.js 基础知识
- 第一章 D3.js 简介(已完结)
- 1.1 何为 D3.js?
- 1.2 D3 生态系统——入门须知
- 1.3 数据可视化最佳实践(上)
- 1.3 数据可视化最佳实践(下)
- 1.4 本章小结
- 第二章 DOM 的操作方法(已完结)
- 2.1 第一个 D3 可视化图表
- 2.2 环境准备
- 2.3 用 D3 选中页面元素
- 2.4 向选择集添加元素
- 2.5 用 D3 设置与修改元素属性
- 2.6 用 D3 设置与修改元素样式
- 2.7 本章小结
- 第三章 数据的处理(已完结)
- 3.1 理解数据
- 3.2 准备数据
- 3.3 将数据绑定到 DOM 元素
- 3.3.1 利用数据给 DOM 属性动态赋值
- 3.4 让数据适应屏幕
- 3.4.1 比例尺简介(上篇)
- 3.4.2 线性比例尺(中篇)
- 3.4.2.1 基于 Mocha 测试 D3 线性比例尺(DIY 实战)
- 3.4.3 分段比例尺(下篇)
- 3.4.3.1 使用 Observable 在线绘制 D3 条形图(DIY 实战)
- 3.5 加注图表标签(上篇)
- 3.5.1 人物专访:Krisztina Szűcs(下篇)
- 3.6 本章小结
相关文章:

【D3.js in Action 3 精译_040】4.4 D3 弧形图的绘制方法
当前内容所在位置: 第四章 直线、曲线与弧线的绘制 ✔️ 4.1 坐标轴的创建(上篇) 4.1.1 D3 中的边距约定(中篇)4.1.2 坐标轴的生成(中篇) 4.1.2.1 比例尺的声明(中篇)4.1…...
C++设计模式:抽象工厂模式(风格切换案例)
抽象工厂模式(Abstract Factory)是一种创建型设计模式,其核心思想是:为一组相关或相互依赖的对象提供一个创建接口,而无需指定它们具体的类。简单来说,就是一个工厂可以生产一系列相关的对象。 我们接下来…...
搜维尔科技:Xsens随时随地捕捉,在任何环境下实时录制或捕捉
Xsens随时随地捕捉,在任何环境下实时录制或捕捉 搜维尔科技:Xsens随时随地捕捉,在任何环境下实时录制或捕捉...

爬虫基础总结 —— 附带爬取案例
Crawler —— Learning experience 数据的传输: 在OSI七层模型中,传输层为源主机和目标主机之间提供可靠的数据传输和通信服务,在该层中,有两个重要的协议—— TCP与 UDP协议。 TCP协议(传输控制协议) …...

图像处理学习笔记-20241118
文章目录 霍夫变换基本原理霍夫变换的步骤使用 OpenCV 实现直线检测示例:标准霍夫变换 示例:概率霍夫变换参数解释霍夫变换检测圆 基于GAN的样本生成GAN的基本原理基于GAN的数据增广流程实现代码示例 同态滤波(Homomorphic Filtering…...

不能打开网页,但能打开QQ、微信(三种方式)
1.VPN错误 下面三个开关全关闭 2.DNS问题 WINR 输入CMD打开命令行 命令行输入 ipconfig/flushdns 重启电脑 3.直接火绒(一键修复)...

使用 start-local 脚本在本地运行 Elasticsearch
警告:请勿将这些说明用于生产部署 本页上的说明仅适用于本地开发。请勿将此配置用于生产部署,因为它不安全。请参阅部署选项以获取生产部署选项列表。 使用 start-local 脚本在 Docker 中快速设置 Elasticsearch 和 Kibana 以进行本地开发或测试。 此设…...

计算机网络:概述知识点及习题练习
网课资源: 湖科大教书匠 1、因特网 网络之间需要路由器进行互联,互联网是网络的网络,因特网是最大的互联网,连接到网络的设备称为主机,一般不叫路由器为主机。 因特网发展:ARPNET->三级结构因特网&am…...

python蓝桥杯刷题2
1.最短路 题解:这个采用暴力枚举,自己数一下就好了 2.门牌制作 题解:门牌号从1到2020,使用for循环遍历一遍,因为range函数无法调用最后一个数字,所以设置成1到2021即可,然后每一次for循环&…...

在openi平台 基于华为顶级深度计算平台 openmind 动手实践
大家可能一直疑问,到底大模型在哪里有用。 本人从事的大模型有几个方向的业务。 基于生成式语言模型的海事航行警告结构化解析。 基于生成式语言模型的航空航行警告结构化解析。 基于生成式生物序列(蛋白质、有机物、rna、dna、mrna)的多模态…...

KF UKF
我需要Kalman 现在,主要是用来处理检测问题情况里的漏检,因为模拟了一段2D, (x,y)的数据,为了看效果,画的线尽量简单一点: import numpy as np import matplotlib.pyplo…...

中伟视界:AI智能分析算法如何针对非煤矿山的特定需求,提供定制化的安全生产解决方案
非煤矿山智能化改造,除了政策文件,上级监管单位需要安装的AI智能分析算法功能之外的,矿方真正关心的,能解决矿方安全生产隐患的AI智能分析算法功能有哪些呢? 经过与矿方的现场交流沟通,收集第一现场人员对安…...

Unity 编辑器下 Android 平台 Addressable 加载模型粉红色,类似材质丢失
Unity 编辑器下 Android 平台 Addressable 加载模型粉红色,类似材质丢失 Addressable Play Mode Script加载模式 选择 Use Existiing Build 1.Unity 切换到 PC 平台,执行 Addressable Build 运行,加载 bundle 内的预制体 显示正常 2.Unit…...

Pytest-Bdd-Playwright 系列教程(10):配置功能文件路径 优化场景定义
Pytest-Bdd-Playwright 系列教程(10):配置功能文件路径 & 优化场景定义 前言一、功能文件路径的配置1.1 全局设置功能文件路径1.2. 在场景中覆盖路径 二、避免重复输入功能文件名2.1 使用方法2.2 functools.partial 的背景 三、应用场景总…...

rust逆向初探
rust 逆向葵花宝典 rust逆向技巧 rust逆向三板斧: [!NOTE] 快速定位关键函数 (真正的main函数):观察输出、输入,字符串搜索,断点等方法。定位关键 加密区 :根据输入的flag,打硬件断点,快速捕获…...
【Linux】apt 关闭 ssl 认证
【注意】apt 关闭 ssl 认证可能会引起软件安装风险,请尽量避免关闭。 执行以下命令可以实现全局关闭 sll 验证。 echo Acquire::https::Verify-Peer "false"; >> /etc/apt/apt.conf.d/99disable-signature-verificationecho Acquire::https::Verif…...
【算法】P5018 对称二叉树
题目 P5018 对称二叉树 https://www.luogu.com.cn/problem/P5018 代码 思路:领接表存储二叉树,unordered_map存储各个节点对应的值。dfs遍历一下各个子树的大小个数,再写个递归判断是否是对称二叉树,如果是就更新全局答案。 #…...

Unifying Top-down and Bottom-up Scanpath Prediction Using Transformers
Abstract 大多数视觉注意力模型旨在预测自上而下或自下而上的控制,这些控制通过不同的视觉搜索和自由观看任务进行研究。本文提出了人类注意力变换器(Human Attention Transformer,HAT),这是一个能够预测两种形式注意力…...

JavaSE(十四)——文件操作和IO
文章目录 文件操作和IO文件相关概念Java操作文件文件系统操作文件内容操作字节流FileOutputStreamFileInputStream代码演示 字符流FileWriterFileReader代码演示 缓冲流转换流 案例练习 文件操作和IO 文件相关概念 文件 通常指的是包含用户数据的文件,如文本文件、…...
【视觉SLAM】4b-特征点法估计相机运动之PnP 3D-2D
文章目录 0. 前言1. PnP求解1.1 直接线性变换DLT1.2 P3P1.3 光束平差法BA2. 实现0. 前言 透视n点(Perspective-n-Point,PnP)问题是计算机视觉领域的经典问题,用于求解3D-2D的点运动。换句话说,当知道 N N N个世界坐标系中3D空间点的坐标以及它们在图像上的投影点像素坐标…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...

Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...

stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...

rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...

AD学习(3)
1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分: (1)PCB焊盘:表层的铜 ,top层的铜 (2)管脚序号:用来关联原理图中的管脚的序号,原理图的序号需要和PCB封装一一…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...