【D3.js in Action 3 精译_046】DIY 实战:在 Observable 平台利用饼图布局函数实现 D3 多个环形图的绘制

当前内容所在位置:

  • 第五章 饼图布局与堆叠布局 ✔️
    • 5.1 饼图和环形图的创建 ✔️
      • 5.1.1 准备阶段(一)
      • 5.1.2 饼图布局生成器(二)
      • 5.1.3 圆弧的绘制(三)
      • 5.1.4 数据标签的添加(四)
      • 5.1.5 DIY-在 Observable 平台实现多个 D3 环形图的绘制 ✔️

文章目录

  • DIY 实战:在 Observable 平台利用饼图布局函数实现 D3 多个环形图的绘制
    • 1. 需求描述
    • 2. 具体步骤
      • 2.1 上传并初始化数据集
      • 2.2 按边距约定声明所需尺寸和常量
      • 2.3 迁移环形图中的比例尺
      • 2.4 绘制环形图模块的迁移
        • 2.4.1 明确总体思路
        • 2.4.2 添加 SVG 容器及内部绘图区
        • 2.4.3 指定年份的遍历逻辑
        • 2.4.4 基于年份生成带注解的环形图数据集
        • 2.4.5 单个环形图容器的绘制
        • 2.4.6 初始化圆弧生成工具
        • 2.4.7 绘制各环形片段的 path 元素
        • 2.4.8 每个环形图数据标签的绘制
        • 2.4.9 为每个环形图添加年份标签
      • 2.5 绘制 HTML 模板并渲染环形图

《D3.js in Action》全新第三版封面

《D3.js in Action》全新第三版封面

DIY 实战:在 Observable 平台利用饼图布局函数实现 D3 多个环形图的绘制


【写在前面】

最近一直在忙着更新我的 CSS 专栏《CSS in Depth 2》,趁着今天冬至顺利进军全书最后一个模块的学习,回头再来复盘一下《D3.js in Action》第五章 5.1 小节的知识点。时隔半月有余,这一节中关于多个拼图的绘制方法已经有所生疏了,真是应了那句 “拳不离手曲不离口” 的老话。没关系,之前有基础,多练练就找回感觉了。

1. 需求描述

将《D3.js in Action》第 3 版 5.1 节中演示的三个环形图,原封不动地迁移到 Observable 平台,如图 1 所示:

图 1 将在 Observable 平台同步实现的 5.1 节多个环形图效果

【图 1 将在 Observable 平台同步实现的 5.1 节多个环形图效果】

2. 具体步骤

2.1 上传并初始化数据集

首先登录 Observable 平台(https://observablehq.com/),并新建一个记事本页面。然后将 5.1 节附带的原始数据集文件(data.csv)上传至平台(随书源码详见我上传到 CSDN 下载频道的 zip压缩包):

图 2:将原始数据集上传至 Observable 平台

【图 2:将原始数据集上传至 Observable 平台】

接着,利用 FileAttachment 语法完成数据集的赋值:

data = await FileAttachment("data.csv").csv({ typed: true })

2.2 按边距约定声明所需尺寸和常量

由于本节的页面复杂度陡然提升,演示案例又没有借助任何前端框架,导致所有的全局变量(比如边距约定需要的 margin 对象等)都只能通过 <script> 标签引入,给项目练习和往 Observable 平台迁移带来的些许不便。因为用不了 import / export 语法,只能来回切换不同的 js 文件:

图 3:主页面 index.html 引入的各个 JavaScript 文件

【图 3:主页面 index.html 引入的各个 JavaScript 文件】

迁移时,我将作者提供的共享常量模块 shared-constants.js 一并放入 D3 边距约定中,并赋给常量 sizes

sizes = {const margin = { top: 50, right: 0, bottom: 50, left: 70 };const width = 1200;const height = 350;const innerWidth = width - margin.left - margin.right;const innerHeight = height - margin.top - margin.bottom;const formatsInfo = [{ id: "vinyl", label: "Vinyl", color: "#76B6C2" },{ id: "eight_track", label: "8-Track", color: "#4CDDF7" },{ id: "cassette", label: "Cassette", color: "#20B9BC" },{ id: "cd", label: "CD", color: "#2F8999" },{ id: "download", label: "Download", color: "#E39F94" },{ id: "streaming", label: "Streaming", color: "#ED7864" },{ id: "other", label: "Other", color: "#ABABAB" }];return {formatsInfo,margin,width,height,innerWidth,innerHeight};
}

这样就完成了两个全局变量的声明:

图 4:完成迁移的原始数据集 data 以及边距约定尺寸对象 sizes

【图 4:完成迁移的原始数据集 data 以及边距约定尺寸对象 sizes】

2.3 迁移环形图中的比例尺

根据作者的思路,环形图比例尺的初始化是在 scales.js 中实现的。有了之前的 data 常量,就可以将环形图需要的两个比例尺——分别用于设置横轴的 D3 分段比例尺,以及定义色阶用到的 D3 序数比例尺 —— 统一放到 scales 常量中备用:

scales = {const xScale = d3.scaleBand().domain(data.map((d) => d.year)).range([0, innerWidth]);const colorScale = d3.scaleOrdinal().domain(sizes.formatsInfo.map((d) => d.id)).range(sizes.formatsInfo.map((d) => d.color));return { xScale, colorScale };
}

这样,就只剩下环形图绘制模块 donut-charts.js 了。这也是迁移过程中最麻烦的一步。

2.4 绘制环形图模块的迁移

由于 Observable 平台无需定义专门的函数来控制 D3 图形渲染的开关,定义好一个单元格,导出的模块即在全局可用。因此,本地示例页中的启动模块(load-data.js)可以直接忽略。不过也可以用于模仿学习其中的命名规范:

// Load data
d3.csv("../data/data.csv", d3.autoType).then(data => {defineScales(data);  // scales.jsdrawDonutCharts(data); // donut-charts.jsdrawStackedBars(data); // 绘制堆积柱状图,与环形图无关,略drawStreamGraph(data); // 绘制流图,与环形图无关,略addLegend(); // 绘制图例,与环形图无关,略
});

而按照最终的环形图绘制模块,需要将 drawDonutCharts(data) 方法完整平移到 Observable 平台。这里先给出迁移前的本地版实现:

const drawDonutCharts = (data) => {/*******************************//*    Append the containers    *//*******************************/// Append the SVG containerconst svg = d3.select("#donut").append("svg").attr("viewBox", `0 0 ${width} ${height}`);// Append the group that will contain the inner chartconst donutContainers = svg.append("g").attr("transform", `translate(${margin.left}, ${margin.top})`);/**********************************//*    Create a donut chart for    *//*    each year of interest       *//**********************************/const years = [1975, 1995, 2013];const formats = data.columns.filter(format => format !== "year");years.forEach(year => {// Append a group for each year// and translate it to the proper positionconst donutContainer = donutContainers.append("g").attr("transform", `translate(${xScale(year)}, ${innerHeight/2})`);// Prepare the data for the pie generatorconst yearData = data.find(d => d.year === year);const formattedData = [];formats.forEach(format => {formattedData.push({ format: format, sales: yearData[format] });});console.log("formattedData", formattedData);// Initialize the pie layout generatorconst pieGenerator = d3.pie().value(d => d.sales);// Call the pie generator to obtain the annotated dataconst annotatedData = pieGenerator(formattedData);console.log("annotatedData", annotatedData)// Initialize the arc generatorconst arcGenerator = d3.arc().startAngle(d => d.startAngle).endAngle(d => d.endAngle).innerRadius(60).outerRadius(100).padAngle(0.02).cornerRadius(3);// Append the arcsconst arcs = donutContainer.selectAll(`.arc-${year}`).data(annotatedData)// .join("path")//   .attr("class", `arc-${year}`)//   .attr("d", arcGenerator)//   .attr("fill", d => colorScale(d.data.format));.join("g").attr("class", `arc-${year}`);arcs.append("path").attr("d", arcGenerator).attr("fill", d => colorScale(d.data.format));arcs.append("text").text(d => {d["percentage"] = (d.endAngle - d.startAngle) / (2 * Math.PI);return d3.format(".0%")(d.percentage);}).attr("x", d => {d["centroid"] = arcGenerator.startAngle(d.startAngle).endAngle(d.endAngle).centroid();return d.centroid[0];}).attr("y", d => d.centroid[1]).attr("text-anchor", "middle").attr("dominant-baseline", "middle").attr("fill", "#f6fafc").attr("fill-opacity", d => d.percentage < 0.05 ? 0 : 1).style("font-size", "16px").style("font-weight", 500);// Append year labelsdonutContainer.append("text").text(year).attr("text-anchor", "middle").attr("dominant-baseline", "middle").style("font-size", "24px").style("font-weight", 500);});
};

可以看到,绘制逻辑还是相当繁琐的。接下来一步步拆分。

2.4.1 明确总体思路

环形图的绘制主要分为以下步骤:

  1. 添加 SVG 容器及内部绘图区(即 SVG 分组元素 g);
  2. 遍历要绘制的三个年份,在循环体中依次绘制每个环形图 ——
    1. 添加单个环形图容器(g 元素);
    2. 数据源及辅助工具准备:
      1. 使用饼图布局函数,获取带标注信息的数据集(annotatedData);
      2. 初始化圆弧生成器(arcGenerator);
    3. 将单个环形图的各个片段归为一组,以便后续分别设置 path 元素与数据标签元素 text——
      1. 添加各环形片段的分组元素(记为 arcs);
      2. 基于 arcs 绘制各段圆弧(添加 path 并确定 d 属性值);
      3. 基于 arcs 绘制各段圆弧的数据标签(添加 text 并确定各标签的横纵坐标)。
    4. 导出 SVG 节点,方便页面其他单元格渲染完整图形。
2.4.2 添加 SVG 容器及内部绘图区

Observable 平台无需 DOM 操作,利用 d3.create('svg') 初始化 SVG 容器后导出即可:

svg = {const svg = d3.create("svg").attr("viewBox", `0 0 ${sizes.width} ${sizes.height}`);// inner containerconst innerContainer = svg.append("g").attr("transform", `translate(${sizes.margin.left}, ${sizes.margin.top})`);return svg;
}
2.4.3 指定年份的遍历逻辑

剩余步骤可按照以下结构先声明再逐步实现:

svg = {// svg & inner container part:// const svg = ...// const innerContainer = ...// annotated dataconst years = [1975, 1995, 2013];years.forEach((year) => {const annotatedData = getAnnotedData(year);// append donut container for each year's donut chartconst donutContainer = appendDonutContainer(innerContainer, year);// arc generatorconst arcGenerator = getArcGenerator();// donut chartconst arcs = donutContainer.selectAll(`.donut-${year}`).data(annotatedData).join("g").attr("class", `donut-${year}`);// slice pathconst slicePaths = appendSlicePaths(arcs, arcGenerator);// labels for each sliceconst sliceLabels = appendSliceLabels(arcs, arcGenerator);// year labelconst yearLabel = appendYearLabel(year, donutContainer);});return svg;
}
2.4.4 基于年份生成带注解的环形图数据集

利用循环遍历的年份 year,筛选出当年的原始数据,然后与饼图布局函数结合,得到带注解的饼图数据集:

function getAnnotedData(year, rawData = data, fmts = formats) {const yearData = rawData.find((d) => d.year === year);const formattedData = fmts.map((format) => ({format,sales: yearData[format]}));// pie generatorconst pieGenerator = d3.pie().value((d) => d.sales);const annotatedData = pieGenerator(formattedData);return annotatedData;
}

这里的 pieGenerator 就是 D3 的饼图布局函数。

2.4.5 单个环形图容器的绘制

按照 2.4.1 确定的总思路,接下来实现每个环形图的容器逻辑:

function appendDonutContainer(innerContainer, year) {const offsetX = scales.xScale(year);const offsetY = sizes.innerHeight / 2;const donutContainer = innerContainer.append("g").attr("transform", `translate(${offsetX}, ${offsetY})`);return donutContainer;
}
2.4.6 初始化圆弧生成工具

即实现 svg 模块中的这一句:

const arcGenerator = getArcGenerator();

其中的 getArcGenerator 由以下单元格定义:

function getArcGenerator() {return d3.arc().startAngle((d) => d.startAngle).endAngle((d) => d.endAngle).innerRadius(60).outerRadius(100).padAngle(0.02).cornerRadius(3);
}

注意:这里回调函数中的 d 是带注解的数据集,不是最初的原始数据集。

2.4.7 绘制各环形片段的 path 元素

这一步即实现:

// slice path
const slicePaths = appendSlicePaths(arcs, arcGenerator);

函数 appendSlicePaths 由以下单元格实现:

function appendSlicePaths(arcs, arcGenerator) {const { colorScale } = scales;const slicePaths = arcs.append("path").attr("d", arcGenerator).attr("fill", (d) => colorScale(d.data.format));return slicePaths;
}
2.4.8 每个环形图数据标签的绘制

即实现:

// labels for each slice
const sliceLabels = appendSliceLabels(arcs, arcGenerator);

其中 appendSliceLabels 定义如下:

function appendSliceLabels(arcs, arcGenerator) {const textFormatter = (d) => {d.percentage = (d.endAngle - d.startAngle) / (2 * Math.PI);const formatter = d3.format(".0%");return formatter(d.percentage);};const showLabelAbove5Pct = (d) => (d.percentage < 0.05 ? 0 : 1);const getCentroidX = initCentroidXAccessor(arcGenerator);const getCentroidY = (d) => d.centroid[1];const sliceLabels = arcs.append("text").text(textFormatter).attr("x", getCentroidX).attr("y", getCentroidY).attr("text-anchor", "middle").attr("dominant-baseline", "middle").attr("fill", "#f6fafc").attr("fill-opacity", showLabelAbove5Pct).style("font-size", "1em").style("font-weight", 500);return sliceLabels;
}

这一步是整个迁移过程中的难点。arcs 其实是一个 g 容器元素,但绑定的数据集是当前年份各环形片段的子数据集,因此第 14 行中的 .append("text") 其实是一次性添加了多个数据标签,数量与环形片段的个数相等。

另外,数据标签的 xy 坐标,均是基于当前片段的形心(这里可以理解为重心)定位的。其中第 10 行使用了一个高阶函数来初始化形心 x 坐标的访问器函数:

function initCentroidXAccessor(arcGenerator) {return (d) => {d.centroid = arcGenerator.startAngle(d.startAngle).endAngle(d.endAngle).centroid();return d.centroid[0];};
}

可见,每个片段都利用了圆弧生成工具 arcGenerator 以及当前绑定的数据项 d 来初始化。

2.4.9 为每个环形图添加年份标签

最后是年份标签的添加,即实现 svg 中的这一行逻辑:

// year label
const yearLabel = appendYearLabel(year, donutContainer);

其中 appendYearLabel 定义如下:

function appendYearLabel(year, container) {const label = container.append("text").text(year).attr("text-anchor", "middle").attr("dominant-baseline", "middle").style("font-size", "1.5em").style("font-weight", 500);return label;
}

这里为了让年份标签具有响应式特征,字号使用了 1.5em 而非参考代码中的 24px

2.5 绘制 HTML 模板并渲染环形图

最后创建一个单元格,用于在 Observable 平台渲染 HTML 模板。Observable 内置了 HTML 模板工具 htl,具体实现如下(HTML 节选自 index.html):

htl.html`
<div class="container"><h1 class="chart">Visualizing 40 Years of Music Industry Sales</h1><div class="intro">This project visualizes the music sales in the United States by format between 1973 and 2019. These formats range from physical supports like <span class="support support-vinyl">vinyl</span>, <span class="support support-eigth-track">8-track</span>, <span class="support support-cassette">cassette</span>, and <span class="support support-cd">cd</span>, to music consumed digitally, with <span class="support support-download">downloads</span> and <span class="support support-streaming">streaming services</span>. The category <span class="support support-other">other</span> includes less prominent sources of revenue like music videos (physical), synchronization, and royalties.</div><div id="donut">${svg}</div><div class="source"><p>Data Source: <a class="demo" href="https://data.world/makeovermonday/2020w21-visualizing-40-years-of-music-industry-sales">MakeoverMonday 2020/W21</a></p><p>Inspiration for the dataviz layout: <a class="demo" href="https://www.makeovermonday.co.uk/week-21-2020/">Submission of Laura Elliot</a></p></div></div>`

注意第 5 行,这里引入了 2.4 步中导出的 svg 节点常量。

关于 CSS 的设置,也可以用类似方法插入一个 <style> 标签(具体内容直接从 base.css 中复制粘贴即可):

htl.html`<style>
/* CSS styles */
</style>`

需要注意的是,通过这种方式设置的 CSS 样式会与 Observable 平台内置的 CSS 样式发生冲突,因此需要根据平台的渲染情况进行微调,比如将基础样式中的链接元素 aa:hovera:focus 调整为 a.demoa.demo:hovera.demo:focus,并同步更新 HTML 模板,添加对应的类名 demo

这样,就大功告成了!

图 5:D3 环形图的最终效果

【图 5:D3 环形图的最终效果】

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

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

相关文章

IP地址查询的背后②:IP地址(IPv4)的构成、类型以及子网划分

自从各大平台将IP地址显示之后&#xff0c;相信广大网友对于IP地址相当不陌生了。而我们见到的IP地址往往只会显示在某市&#xff0c;更仔细的会看到有一段段字节所显示的字符串&#xff0c;而IP地址看似由很简单的1-255之间的数字所组成的四个部分&#xff0c;但其实质上则是二…

使用 DeepSpeed 微调 OPT 基础语言模型

文章目录 OPT 基础语言模型Using OPT with DeepSpeedmain.py 解析1、导入库和模块2、解析命令行参数3、main 函数3.1 设备与分布式初始化3.2 模型与数据准备3.3 定义评估函数3.4 优化器与学习率调度器设置3.5 使用 deepspeed 进行模型等初始化3.6 训练循环3.7 模型保存 4、dsch…

计算机网络-GRE Over IPSec实验

一、概述 前情回顾&#xff1a;上次基于IPsec VPN的主模式进行了基础实验&#xff0c;但是很多高级特性没有涉及&#xff0c;如ike v2、不同传输模式、DPD检测、路由方式引入路由、野蛮模式等等&#xff0c;以后继续学习吧。 前面我们已经学习了GRE可以基于隧道口实现分支互联&…

使用Turtle库实现,鼠标左键绘制路径,用鼠标右键结束绘制,小海龟并沿路径移动

使用Turtle库实现&#xff0c;鼠标左键绘制路径&#xff0c;用鼠标右键结束绘制&#xff0c;小海龟并沿路径移动 Turtle库是Python标准库的一部分&#xff0c;它提供了一种基于命令的图形绘制方式。Turtle模块通过一个“海龟”&#xff08;Turtle&#xff09;对象在屏幕上移动…

《计算机组成及汇编语言原理》阅读笔记:p9-p27

《计算机组成及汇编语言原理》学习第 2 天&#xff0c;p9-p27 总结&#xff0c;总计 19 页。 一、技术总结 1.quantum physics(量子物理学) (1)quantum(量子) quantum的本意是&#xff1a;c. the smallest amount of sth(量子)。 In physics, a quantum is the minimum am…

Qt:QMetaObject::connectSlotsByName实现信号槽自动关联

简介 在Qt中&#xff0c;QMetaObject::connectSlotsByName 是一个便利的方法&#xff0c;它可以根据对象的对象名&#xff08;objectName&#xff09;自动将信号和槽连接起来。但是&#xff0c;要使用这个方法&#xff0c;必须确保&#xff1a; 1 控件&#xff08;如按钮&…

国标GB28181平台EasyGBS在安防视频监控中的信号传输(电源/视频/音频)特性及差异

在现代安防视频监控系统中&#xff0c;国标GB28181协议作为公共安全视频监控联网系统的国家标准&#xff0c;该协议不仅规范了视频监控系统的信息传输、交换和控制技术要求&#xff0c;还为不同厂商设备之间的互联互通提供了统一的框架。EasyGBS平台基于GB28181协议&#xff0c…

概率论得学习和整理29: 用EXCEL 描述二项分布

目录 1 关于二项分布的基本内容 2 二项分布的概率 2.1 核心要素 2.2 成功K次的概率&#xff0c;二项分布公式 2.3 期望和方差 2.4 具体试验 2.5 概率质量函数pmf 和cdf 3 二项分布的pmf图的改进 3.1 改进折线图 3.2 如何生成这种竖线图呢 4 不同的二项分布 4.1 p0.…

长短期记忆网络(LSTM):深度学习中的序列数据处理利器

目录 ​编辑 长短期记忆网络&#xff08;LSTM&#xff09;&#xff1a;深度学习中的序列数据处理利器 引言 LSTM的起源与背景 LSTM的核心机制 LSTM的优势 LSTM的应用案例 LSTM的研究进展 LSTM的变种 LSTM的改进 LSTM的最新研究 结论 长短期记忆网络&#xff08;LST…

2024年前端面试题【基本功篇】

文章目录 前言一、html 相关1.1 行内元素和块级元素分别有哪些&#xff1f;1.2 IE盒子模型和标准盒子模型 二、css 相关2.1 选择器2.2 设置垂直居中的方法2.3 定位的几种方式2.4 清除浮动的几种方式2.5 rem、em、px、vw、vh区别2.6 响应式和自适应布局的区别2.7 元素隐藏的几种…

Excel设置生日自动智能提醒,公式可直接套用!

大家好&#xff0c;我是小鱼。 今天跟大家分享一个WPS表格中根据出生日期&#xff0c;设置生日提醒&#xff0c;并且根据距离生日天数自动标记数据颜色。简单又实用&#xff0c;一个公式轻松搞定&#xff01; 接下来我们先学习一下需要使用到的函数&#xff0c;然后再根据实例让…

【MAC】深入浅出 Homebrew 下 Nginx 的安装与配置指南

硬件&#xff1a;Apple M4 Pro 16寸 系统&#xff1a; macos Sonoma 15.1.1 Nginx 是一款高性能的 Web 服务器和反向代理服务器&#xff0c;广泛应用于全球各地的网站和企业应用中。本文将详细介绍如何在 macOS 环境下使用 Homebrew 安装、启动、管理以及优化配置 Nginx&#x…

安卓环境配置及打开新项目教程,2024年12月20日最新版

1.去官网下载最新的Android Studio&#xff0c;网址&#xff1a;https://developer.android.com/studio?hlzh-cn 2.下载加速器&#xff0c;注册账号&#xff0c;开启加速器。网址&#xff1a;放在文末。 3.下载安卓代码&#xff0c;项目的路径上不能有中文&#xff0c;特别是…

VMware虚拟机Ubuntu 18.04版本 磁盘扩容

一、版本配置 虚拟机版本&#xff1a;VMware WORKSTATION 16 PRO Ubuntu版本&#xff1a;Ubuntu 18.04 二、磁盘大小介绍 目的&#xff1a;磁盘扩容&#xff08;20G----->100G&#xff09;&#xff0c;从20G扩到100G 查看磁盘大小命令&#xff1a;df -h 扩容前的磁盘大小 …

10. 虚拟机VMware Workstation Pro下共享Ubuntu和Win11文件夹

本文记录当前最新版虚拟机VMware Workstation Pro&#xff08;2024.12&#xff09;如何在win11下共享文件&#xff0c;以实现Windows与Ubuntu互传文件的目的。 1. 创建共享文件夹 1.1 先关闭虚拟机的客户机&#xff0c;打开虚拟机设置 1.2 在虚拟机设置界面找到“选项”->“…

HTTP—03

触发 GET 请求 1&#xff09;直接在浏览器 地址栏 输入 URL&#xff0c;此时构成了一个GET请求 2&#xff09;HTML中的一些特殊标签可能会触发 例如 img,a,link,script... 3&#xff09;通过Form表单触发&#xff08;Form本质也是一个HTML标签&#xff09; 4&#xff0…

2024年《网络安全事件应急指南》

在这个信息技术日新月异的时代&#xff0c;网络攻击手段的复杂性与日俱增&#xff0c;安全威胁层出不穷&#xff0c;给企事业单位的安全防护能力带 来了前所未有的挑战。深信服安全应急响应中心&#xff08;以下简称“应急响应中心”&#xff09;编写了《网络安全事件应急指南》…

MobaXterm 连接不上VMware 的Ubuntu 虚拟机

想在window11的笔记本上通过VMWare安装Ubuntu操作系统&#xff0c;但是在两个桌面见来回切换&#xff0c;十分的麻烦&#xff0c;于是通过远程服务访问客户端软件MateXterm来访问虚拟机的Linux系统&#xff0c;但是从CSDN上搜到的教程都没有成功&#xff0c;于是&#xff0c;尝…

MapReduce的shuffle过程详解

文章目录 MapReduce的shuffle过程详解一、引言二、Shuffle过程详解1、Map端Shuffle1.1、分区&#xff08;Partition&#xff09;1.2、排序&#xff08;Sort&#xff09;1.3、分割&#xff08;Spill&#xff09; 2、Reduce端Shuffle 三、使用示例四、总结 MapReduce的shuffle过程…

AI图像生成利器:Stable Diffusion 3.5本地运行与远程出图操作流程

文章目录 前言1. 本地部署ComfyUI2. 下载 Stable Diffusion3.5 模型3. 演示文生图4. 公网使用Stable Diffusion 3.5 大模型4.1 创建远程连接公网地址 5. 固定远程访问公网地址 前言 本篇文章将介绍如何在Windows系统电脑本地部署Stable Diffusion 3.5&#xff0c;并利用cpolar…