Rust机器学习之Plotters

news2024/11/25 20:45:18

Rust机器学习之Plotters

本文将带领大家学习Plotters的基础用法。重点学习Plotters的图表元素和常用图表的使用。

本文是“Rust替代Python进行机器学习”系列文章的第四篇,其他教程请参考下面表格目录:

Python库Rust替代方案教程
numpyndarrayRust机器学习之ndarray
pandasPolars Rust机器学习之Polars
scikit-learnLinfaRust机器学习之Linfa
matplotlibplottersRust机器学习之plotters
pytorchtch-rsRust机器学习之tch-rs
networkspetgraphRust机器学习之petgraph

数据和算法工程师偏爱Jupyter,为了跟Python保持一致的工作环境,文章中的示例都运行在Jupyter上。因此需要各位搭建Rust交互式编程环境(让Rust作为Jupyter的内核运行在Jupyter上),相关教程请参考 Rust交互式编程环境搭建

文章目录

    • 什么是Plotters
    • 安装Plotters
    • Plotters初探
    • 添加图表元素
      • 添加网格
      • 添加坐标轴
      • 添加图例
    • 常见图表
      • 散点图
      • 折线图
      • 直方图
      • 多图组合
    • 结语

什么是Plotters

Plotters是一个用纯Rust开发的图形库,用于中渲染图形、图表和数据可视化。它支持静态图片渲染和实时渲染,并支持多种后端,包括:位图格式(png、bmp、gif等)、矢量图(svg)、窗口和HTML5 Canvas。

Plotters对不同后端使用统一的高级API,并允许开发者自定义坐标系。在Plotters中,任何类型的图表都被抽象为一系列绘图操作,通过这些绘图操作,开发者可以自由地操控和组合绘图内容。因此Plotters不会限制图表类型,开发者可以组合出任意内容的图表。

在这里插入图片描述

图1. Plotters图表案例

安装Plotters

安装Plotters非常简单。如果是Cargo项目,只需要在Cargo.toml中加入

[dependencies]
plotters = "0.3.4"

如果是在jupyter环境下,可以用evcxr:dep加载依赖,只需要加入下面一句:

:dep plotters = { version = "0.3.4", default_features = false, features = ["evcxr", "all_series", "all_elements"] }

因为evcxr只支持输出SVG格式图片,所以这里不需要其他后端,因此我们需要加上default_features = false关掉plotters原本的后端,同时加上features = ["evcxr", "all_series", "all_elements"],让plotters支持evcxr环境,all_series表示支持所有图表,all_elements表示支持所有的图表元素。

关掉plotters原本的后端能让plotters第一次加载时快很多,但即便这样,初次编译plotters还是需要点时间。但好在jupyter中cell之间是共享环境的,第一次编译加载完后,后面调用都很快。

Plotters初探

安装好plotters后,我们来看一下Plotters的基本用法。

首先需要引入所需的模块,这里最简单的做法是引入preludeprelude 里包含了evcxr绘图所需的evcxr_figure方法。

extern crate plotters;
use plotters::prelude::*;

要想在Jupyter中创建图表,需要使用evcxr_figure方法。evcxr_figure方法接收2个参数,第一个参数是图表的尺寸,第二个参数是一个闭包,用于处理图表的绘制。这里的闭包会带上一个DrawingArea对象,这是plotters的绘图后端,一切绘图操作都在此后端上进行。我们先来看个简单的例子:

evcxr_figure((300, 100), |root| {
    // 绘图逻辑
    root.fill(&BLUE)?;
    // 最后返回OK告诉Plotters画完了
    Ok(())
})

上面的代码会在Jupyter中显示一个用绿色填充的300*100大小的矩形。

在这里插入图片描述

上面的图形太单调了,我们在上面写点文字。

evcxr_figure((300, 100), |root| {
    // 绘图逻辑
    root.fill(&GREEN)?;
    // 绘制文字
    root.draw(&Text::new("Plotters真好用!", (40, 40), ("Arial", 30).into_font()))?;
    // 最后返回OK告诉Plotters画完了
    Ok(())
})

上面的代码在原来代码的基础上加入了一行root.draw(&Text::new("Plotters真好用!", (40, 40), ("Arial", 30).into_font()))?;。这里draw方法用于绘制元素,传入3个参数,第一个参数是绘制的内容,这里我们创建了一个文本(Text)对象;第二个参数是绘制的位置(元素左上角在绘图区的位置);第三个参数是字体对象,可以空值文本的字体和大小。绘制效果如下图:

在这里插入图片描述

Plotters的一大特性是可以通过将绘图区域分割成若干子绘图区域来绘制多个图形,并且这种分割可以递归地进行下去。这个特性使得Plotters实现分型绘图非常简单。我们尝试用Plotters画一个谢尔宾斯基地毯:

use plotters::coord::Shift;

pub fn sierpinski_carpet(
    depth: u32, 
    drawing_area: &DrawingArea<SVGBackend, Shift>) 
-> Result<(), Box<dyn std::error::Error>> {
    if depth > 0 {
        // 将传入地绘图区分割成3*3个子区域
        let sub_areas = drawing_area.split_evenly((3,3));
        // 遍历这3*3个子区域
        for (idx, sub_area) in (0..).zip(sub_areas.iter()) {
            if idx == 4 { // 第5个区域(中心区域)填上白色
                sub_area.fill(&WHITE)?;
            } else { // 其他区域递归地进行绘图
                sierpinski_carpet(depth - 1, sub_area)?;
            }
        }
    }
    Ok(())
}

evcxr_figure((4800,4800), |root| {
    root.fill(&BLACK)?;
    sierpinski_carpet(5, &root)
}).style("width: 400px") // 这里可以CSS来展示输出图片在网页上的显示

在这里插入图片描述

除了绘制各种图形外,Plotters最主要的功能就是绘制图表。Plotters提供了_图表上下文_API让我们可以方便地操作图表的标题、坐标轴、网格、图例等图表元素。下面的例子展示了如何使用图表上下文绘制图表:

evcxr_figure((640, 240), |root| {
    root.fill(&WHITE)?;
    // 创建图表上下文
    let mut chart = ChartBuilder::on(&root)
        .caption("图表标题", ("Arial", 20).into_font())
        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;
    // 将数据绘制到图表上
    chart.draw_series((1..10).map(|x|{
        let x = x as f32/10.0;
        Circle::new((x, x), 5, &RED)
    }))?;
    Ok(())
}).style("width:60%")

上面的代码首先用ChartBuilder::on方法创建图表上下文,这里需要传入绘图区域,将图表上下文绑定在此绘图区域上。然后用caption方法设置图表的标题,用build_cartesian_2d方法设置直角坐标系的取值范围。

创建好图表上下文后,我们就可以调用图表上下文的draw_series方法绘制图表的内容。这里只是简单地画了10个散点,效果如下:

在这里插入图片描述

上面的图表可能不像图表,因为没有将坐标轴画出来。其实图表中有很多元素可以设置,上面的例子只展示了标题和内容,下一节我们会逐个看一下图表都有哪些组成元素以及如何配置他们。

添加图表元素

Plotters允许我们灵活地向图表中添加坐标轴、网格、图例等元素,本节我们就来看一下如何向图表中添加这些元素。

添加网格

我们首先向上一节的图表中加入网格。很简单,只需要加入一句chart.configure_mesh().draw()?;即可:

evcxr_figure((640, 240), |root| {
    root.fill(&WHITE)?;
    // 创建图表上下文
    let mut chart = ChartBuilder::on(&root)
        .caption("带网格的图表", ("Arial", 20).into_font())
        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;
    // 绘制网格
    chart.configure_mesh().draw()?;
    // 将数据绘制到图表上
    chart.draw_series((1..10).map(|x|{
        let x = x as f32/10.0;
        Circle::new((x, x), 5, &RED)
    }))?;
    Ok(())
}).style("width:60%")

在这里插入图片描述

网格支持很多配置可以控制网格的呈现形式。bold_line_stylelight_line_style方法可以控制主/副网格线的颜色和透明度,如果想隐藏网格线可以传入&TRANSPARENTx_labelsy_labels方法可以设置坐标轴的刻度。如果想禁用某个轴上的网格,可以用disable_x_meshdisable_y_mesh方法。下面代码可以实现隐藏x轴向网格,隐藏副网格线,y轴网格显示10个刻度:

chart.configure_mesh()
	.y_labels(10)
	.light_line_style(&TRANSPARENT)
	.disable_x_mesh()

在这里插入图片描述

关于网格的更多配置,请参考MeshStyle in plotters::chart - Rust (docs.rs)

添加坐标轴

其实在我们调用build_cartesian_2d方法时,坐标轴就已经建立好了。那为什么我们看不到图表中有坐标轴呢?这是因为我们没有设置坐标轴的显示区域。Plotters中用x_label_area_sizey_label_area_size来设置横坐标和纵坐标的显示区域。我们只要在创建图表上下文时设置横坐标/纵坐标的高度/宽度即可。

evcxr_figure((640, 240), |root| {
    root.fill(&WHITE)?;
    // 创建图表上下文
    let mut chart = ChartBuilder::on(&root)
        .caption("带坐标轴和网格的图表", ("Arial", 20).into_font())
    	.x_label_area_size(40) // x轴显示区域(高度)
        .y_label_area_size(40) // y轴显示区域(宽度)
        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;
    // 绘制网格
    chart.configure_mesh()
        .y_labels(10)
        .light_line_style(&TRANSPARENT)
        .disable_x_mesh()
        .draw()?;
    // 将数据绘制到图表上
    chart.draw_series((1..10).map(|x|{
        let x = x as f32/10.0;
        Circle::new((x, x), 5, &RED)
    }))?;
    Ok(())
}).style("width:60%")

在这里插入图片描述

我们还可以调用MeshStyle的x_descy_desc方法为坐标轴设置描述:

chart.configure_mesh()
    .x_desc("X轴描述")
    .y_desc("Y轴描述")
	...

在这里插入图片描述

添加图例

如果图表中有多个图线,一般我们需要添加图例加以区分。Plotters中可以在绘制图线后用label方法设置图例名称,用legend绘制图例。由于图例是单独的元素,设置好后需要调用configure_series_labels().draw()才能绘制出来,请看下面的代码:

chart.draw_series((1..10).map(|x|{
        let x = x as f32/10.0;
        Circle::new((x, x), 5, &RED)
    }))?
    .label("y=x")
    .legend(|(x, y)| Circle::new((x+20, y), 4, &RED));
    
    chart.configure_series_labels().draw()?;

在这里插入图片描述

常见图表

与其他图标库不同,Plotters并没有内置任何形式的图表,而是将图表抽象为一个叫series的概念。这样做最大的好处是灵活,可以方便地将两种不同类型的图组合在一起。

为了使用方便,Plotters内置了几个常用的series,分别是:

  • 散点图
  • 折线图
  • 直方图

我们也可以定义自己的serires,然后根据数据在图上的坐标绘制任意图形,灵活程度非常高。

散点图

我们先来随机创建一些点:

:dep rand = { version = "0.6.5" }
extern crate rand;

use rand::distributions::Normal;
use rand::distributions::Distribution;
use rand::thread_rng;
let sd = 0.13;
let random_points:Vec<(f64,f64)> = {
    let mut norm_dist = Normal::new(0.5, sd);
    let (mut x_rand, mut y_rand) = (thread_rng(), thread_rng());
    let x_iter = norm_dist.sample_iter(&mut x_rand);
    let y_iter = norm_dist.sample_iter(&mut y_rand);
    x_iter.zip(y_iter).take(1000).collect()
};

这里我们用正态分布生成了1000个点。

用Plotters绘制散点图很简单。只需要传入坐标序列即可。下面的示例显示了如何制作2D正态分布图。红色矩形是 2 σ 2\sigma 2σ面积,红色十字是平均值。

evcxr_figure((640, 480), |root| {
    root.fill(&WHITE)?;
    // The following code will create a chart context
    let mut chart = ChartBuilder::on(&root)
        .caption("随机正态分布散点图", ("Arial", 20).into_font())
        .x_label_area_size(40)
        .y_label_area_size(40)
        .build_ranged(0f64..1f64, 0f64..1f64)?;
    
    chart.configure_mesh()
        .disable_x_mesh() // 隐藏网格
        .disable_y_mesh() // 隐藏网格
        .draw()?;
    
    // 绘制散点
    chart.draw_series(random_points.iter().map(|(x,y)| Circle::new((*x,*y), 3, GREEN.filled())));
    
    // 绘制红色矩形,框住2σ区域
    let area = chart.plotting_area();
    let two_sigma = sd * 2.0;
    area.draw(&Rectangle::new(
        [(0.5 - two_sigma, 0.5 - two_sigma), (0.5 + two_sigma, 0.5 + two_sigma)], 
        RED.mix(0.3).filled())
    )?;
    // 标出均值位置
    area.draw(&Cross::new((0.5, 0.5), 5, &RED))?;
    
    Ok(())
}).style("width:60%")

在这里插入图片描述

折线图

Plotters提供了LineSeries用于绘制折线图,只需要传入一系列坐标点序列,Plotters就能将这些点连成折线。下面示例展示了如何用LineSeries绘制正弦曲线和余弦曲线:

evcxr_figure((640, 480), |root| {
    let x_axis = (-3.4f32..3.4).step(0.01);
    root.fill(&WHITE)?;
    let mut chart = ChartBuilder::on(&root)
        .margin(5)
        .set_all_label_area_size(50)
        .caption("正弦曲线和余弦曲线", ("sans-serif", 20))
        .build_cartesian_2d(-3.4f32..3.4, -1.2f32..1.2f32)?;
    
    chart.configure_mesh()
        .x_labels(20)
        .y_labels(10)
        .disable_mesh()
        .x_label_formatter(&|v| format!("{:.1}", v))
        .y_label_formatter(&|v| format!("{:.1}", v))
        .draw()?;
    
    // 绘制正弦曲线
    chart.draw_series(LineSeries::new(x_axis.values().map(|x| (x, x.sin())), &RED))?
        .label("正弦")
        .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));
    
    // 绘制余弦曲线
    chart.draw_series(LineSeries::new(
        x_axis.values().map(|x| (x, x.cos())),
        &BLUE,
    ))?
    .label("余弦")
    .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));

    chart.configure_series_labels().border_style(&BLACK).draw()?;
    
    Ok(())
}).style("width:60%")

在这里插入图片描述

直方图

在数据可视化中直方图也是用的最多的一种图。Plotters提供了Histogram生成直方图series。下面的代码分别统计了散点图中随机点在x轴和y轴上的分布:

evcxr_figure((640, 480), |root| {
    let areas = root.split_evenly((2,1));
    let mut charts = vec![];
    root.fill(&WHITE)?;
   for (area, name) in areas.iter().zip(["X", "Y"].into_iter()) {
        let mut chart = ChartBuilder::on(&area)
            .caption(format!("{}轴直方图", name), ("Arial", 20).into_font())
            .x_label_area_size(40)
            .y_label_area_size(40)
            .build_cartesian_2d(0u32..100u32, 0f64..0.5f64)?;
        chart.configure_mesh()
            .disable_x_mesh()
            .disable_y_mesh()
            .y_labels(5)
            .x_label_formatter(&|x| format!("{:.1}", *x as f64 / 100.0))
            .y_label_formatter(&|y| format!("{}%", (*y * 100.0) as u32))
            .draw()?;
        charts.push(chart);
    }
    
    let hist_x = Histogram::vertical(&charts[0])
        .style(RED.filled())
        .margin(0)
        .data(random_points.iter().map(|(x,_)| ((x*100.0) as u32, 0.01)));
    
    let hist_y = Histogram::vertical(&charts[0])
        .style(GREEN.filled())
        .margin(0)
        .data(random_points.iter().map(|(_,y)| ((y*100.0) as u32, 0.01)));
    
    charts[0].draw_series(hist_x);
    charts[1].draw_series(hist_y);
    
    Ok(())
}).style("width:60%")

在这里插入图片描述

多图组合

Plotter最强大的地方就是可以通过分割子图将多个图表组合在一起。我们可以将随机点的散点图和各轴上的分布直方图组合在一起:

evcxr_figure((640, 480), |root| {
    root.fill(&WHITE)?;
    let root = root.titled("散点图组合直方图", ("Arial", 20).into_font())?;
    let areas = root.split_by_breakpoints([560], [80]);
    let mut x_hist_ctx = ChartBuilder::on(&areas[0])
        .y_label_area_size(40)
        .build_cartesian_2d(0u32..100u32, 0f64..0.5f64)?;
    let mut y_hist_ctx = ChartBuilder::on(&areas[3])
        .x_label_area_size(40)
        .build_cartesian_2d(0f64..0.5f64, 0..100u32)?;
    let mut scatter_ctx = ChartBuilder::on(&areas[2])
        .x_label_area_size(40)
        .y_label_area_size(40)
        .build_cartesian_2d(0f64..1f64, 0f64..1f64)?;
    scatter_ctx.configure_mesh()
        .disable_x_mesh()
        .disable_y_mesh()
        .draw()?;
    scatter_ctx.draw_series(random_points.iter().map(|(x,y)| Circle::new((*x,*y), 3, BLUE.filled())))?;
    let x_hist = Histogram::vertical(&x_hist_ctx)
        .style(RED.filled())
        .margin(0)
        .data(random_points.iter().map(|(x,_)| ((x*100.0) as u32, 0.01)));
    let y_hist = Histogram::horizontal(&y_hist_ctx)
        .style(GREEN.filled())
        .margin(0)
        .data(random_points.iter().map(|(_,y)| ((y*100.0) as u32, 0.01)));
    x_hist_ctx.draw_series(x_hist)?;
    y_hist_ctx.draw_series(y_hist)?;
    
    Ok(())
}).style("width:60%")

在这里插入图片描述

结语

尽管Plotters与Python的matplotlib思想和用法不同,但与matplotlib比Plotters有很多优势:

  1. 灵活,Plotters不固定图表类型,而是通过高度抽象的模型和组件元素让开发者可以自由创作任意想要的图表
  2. 快速,得益于Rust的性能,使Plotters可以轻松处理上亿数据的可视化,这在Python和JavaScript中几乎是不可能的。
  3. 支持WebAssembly ,Plotters对wasm支持良好,通过wasm,Plotters可以运行在网页上,替代JavaScript处理大量数据的可视化,提升页面性能,优化使用体验。

Plotters的功能和配置项非常多,本文只选择日常最常用的功能和图表做了讲解和演示,更多内容请阅读Plotters Developer’s Guide。

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

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

相关文章

关于账本数据库:你想知道的这里都有

&#x1f495;前言&#xff1a;十二月份出个openGuass集合专栏&#xff0c;带领大家浅浅的认识一下国产数据库吧&#x1f495; 1. 什么是账本数据库 区块链大家想必都耳熟能详&#xff0c;比特币、以太坊甚至狗狗币等代币&#xff0c;作为区块链的代名词&#xff0c;不仅牵动着…

《歌在飞》在抖音播放7.7亿,歌者苏勒亚其其格用公益让爱心传递

随着短视频的流行&#xff0c;抖音平台也被大家所熟知&#xff0c;很多好听的音乐作品&#xff0c;都是通过抖音平台传唱开来。 曾经有一首《歌在飞》的音乐作品&#xff0c;在抖音平台传唱度很广&#xff0c;截止目前已经有7.7亿的播放量。据悉&#xff0c;《歌在飞》这首歌曲…

基于QPSK的载波同步和定时同步性能仿真,包括Costas环的gardner环

目录 1.算法描述 2.matlab算法仿真效果 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 载波同步是相干解调的基础&#xff0c;不管对于模拟通信还是数字通信来说&#xff0c;只要是相干解调&#xff0c;接收端都必须提供同频同相的载波。当然&#xff0c;若采用基带传输&#…

hadoop 3.x大数据集群搭建系列7-安装Hudi

文章目录编译环境准备一. 下载并解压hudi二. maven的下载和配置2.1 maven的下载和解压2.2 添加环境变量到/etc/profile中2.3 修改为阿里镜像三. 编译hudi3.1 修改pom文件3.2 修改源码兼容hadoop33.3 手动安装Kafka依赖3.4 解决spark模块依赖冲突3.4.1 修改hudi-spark-bundle的p…

pytest + yaml 框架 - 3.全局仅登录一次,在用例中自动在请求头部添加Authentication token认证

前言 我们在使用自动化测试框架的时候&#xff0c;经常会遇到一个需求&#xff0c;希望在全局用例中&#xff0c;仅登录一次&#xff0c;后续所有的用例自动带上请求头部token 或者cookies。 环境准备 Python 3.8版本 Pytest 7.2.0 最新版 pip 安装插件 pip install pytes…

[附源码]Python计算机毕业设计Django的实验填报管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

OSSID: Online Self-Supervised Instance Detection by (And For) Pose Estimation

许多机器人操作算法都需要 实时目标姿态估计。然而&#xff0c;最先进的目标姿态估计方法是针对一组特定的对象进行训练的&#xff1b;因此&#xff0c;这些方法需要 重新训练 以估计每个新对象的姿势。本文提出了 OSSID 框架&#xff0c;利用 慢速零样本 姿态估计器 来 自监督…

OpenGL 图像色调

目录 一.OpenGL 图像色调 1.IOS Object-C 版本1.Windows OpenGL ES 版本2.Windows OpenGL 版本 二.OpenGL 图像色调 GLSL Shader三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录…

Spring | IOC技术之Bean的配置与实例化

&#x1f451; 博主简介&#xff1a;    &#x1f947; Java领域新星创作者    &#x1f947; 阿里云开发者社区专家博主、星级博主、技术博主 &#x1f91d; 交流社区&#xff1a;BoBooY&#xff08;优质编程学习笔记社区&#xff09; 文章目录Bean的基础配置1、id 与 cla…

家电生产线数控机床上下料长臂机器人组设计

目录 摘 要 I ABSTRCT II 前言 III 1.长臂机器人组概况 1 1.1国内外发展状况 1 1.2研究意义 2 1.2.1长臂机器人组研究现状 2 1.2.2长臂机器人组研究方向 3 1.3本课题意义和目的 4 1.3.1本课题的意义 4 1.3.2本课题的目的 4 2.长臂机器人组的组成分类及设计分析 6 2.1 长臂机器人…

【车载开发系列】UDS诊断---诊断故障清除($0x14)

【车载开发系列】UDS诊断—诊断故障清除&#xff08;$0x14&#xff09; UDS诊断---诊断故障清除&#xff08;$0x14&#xff09;【车载开发系列】UDS诊断---诊断故障清除&#xff08;$0x14&#xff09;一.概念定义二.参数说明三.清除内容方式1&#xff09;清除内容2&#xff09;…

python接口自动化44- requests 库使用 hook 机制

前言 requests 是 Hooks 即钩子方法&#xff0c;用于在某个框架固定的某个流程执行是捎带执行&#xff08;钩上&#xff09;某个自定义的方法。 requests 库只支持一个 response 的钩子&#xff0c;即在响应返回时可以捎带执行我们自定义的某些方法。 可以用于打印一些信息&am…

Unity引擎开发-无人机模拟飞行实现

目 录 摘 要 I Abstract II 一、 绪论 1 &#xff08;一&#xff09; 研究背景和研究意义 1 &#xff08;二&#xff09; 国内外研究现状 1 &#xff08;三&#xff09; 论文组织结构 2 二、 3D游戏技术的知识系统 2 &#xff08;一&#xff09; 3D图形库 2 &#xff08;二&…

UML概述及UML类图详解

一 UML介绍 UML这三个字母的全称是Unified Modeling Language&#xff0c;翻译就是统一建模语言&#xff0c;是一种用于软件系统分析和设计的语言工具&#xff0c;它用于帮助软件开发人员进行思考和记录思路的结果 UML 本身是一套符号的规定&#xff0c;就像数学符号和化学符…

Linux——md5命令

文章目录介绍选项使用案例生成文件md5值文本模式或二进制模式md5值重定向重定向追加md5校验实际开发场景介绍 md5sum命令用于生成和校验文件的md5值。它会逐位对文件的内容进行校验。是文件的内容&#xff0c;与文件名无关&#xff0c;也就是文件内容相同&#xff0c;其md5值相…

CTGU操作系统

CTGU操作系统第一章第二章 Operating-System structures操作系统结构第三章自己看&#xff0c;懒得写了&#xff0c;我也不知道为啥划重点他要把所有PPT过一遍&#xff0c;离谱第一章 第二章 Operating-System structures操作系统结构 第三章自己看&#xff0c;懒得写了&#x…

【能效管理】电力监控系统在某商业数据中心的应用分析

摘要&#xff1a;在电力系统的运行过程中&#xff0c;变电站作为整个电力系统的核心&#xff0c;在保证电力系统可靠的运行方面起着至关重要的作用&#xff0c;基于此需对变电站监控系统的特点进行分析&#xff0c;结合变电站监控系统的功能需求&#xff0c;对变电站电力监控系…

Yoshua Bengio:我的一生

文 | 智商掉了一地2018 年图灵奖获得者、AI 先驱、深度学习三巨头之一、对抗生成网络 GAN、标志性的银灰卷发和浓眉&#xff0c;如果还没猜到的话&#xff0c;当你看到这个封面&#xff0c;一定就会意识到自己在学习的路上&#xff0c;已经或间接或直接地拜读过大佬的著作了。看…

云原生主题学习月|成为社区领学员,解锁专属奖励及超多数量社区学员奖品!

CSDN 已上线亚马逊云科技超过 60 门中文数字化培训课程&#xff0c;希望为学习者提供亚马逊云科技基础技能知识和最佳实践。 每门课程时长从十分钟到几小时不等&#xff0c;由亚马逊云科技专家打造&#xff0c;其中包括最受欢迎的《亚马逊云科技云从业者必修知识》&#xff0c…

为什么 FindFirstFile 会查找短文件名?

FindFirstFile 函数会尝试匹配短文件名和长文件名。这可能会产生一些令人惊讶的结果。例如&#xff0c;如果你查找 “*.htm” &#xff0c;那么它会返回给你文件 “x.html” &#xff0c;因为它的短文件名是 “X~1.HTM”。 这确实比较令人感到意外。 为什么 FindFirstFile 会匹…