用可视化案例讲Rust编程5.用泛型和特性实现自适配绘制和颜色设置

上一节我们讲了用泛型实现返回结果,这一节我们来讲讲在函数签名里面使用泛型来对输入参数进行自适配。

先看UML设计图:

图片

好吧,看起来有点复杂,我们一个个来解释。

首先定义的是一个生成绘图元素需要的参数结构,并且定义个特性,就叫做构造绘图元素build_trace。

pub struct traceParam<G>{
    pub geometrys:Vec<G>,
    pub colors: Vec<inputColor>,
    pub size: usize,
}

pub trait BuildTrace{
    fn build_trace(&self) -> Vec<Box<ScatterMapbox<f64,f64>>>;
}

绘图元素的参数,定义了三个参数:

  • 第一个参数是输入一个几何要素集合,因为我们最起码有点线面三种几何要素,所以定义的是一个泛型变量G

  • 第二参数是一个颜色集合,这里也可以用泛型,不过我们不需要那么多种颜色定义,这里给了一个枚举型的输入颜色,枚举定义如下:

#[derive(Debug,Clone)]
pub enum inputColor {
    NamedColor(NamedColor),
    Rgba(Rgba),
}

这里支持NameColor和Rgba两种颜色定义即可。

  • 第三个参数是一个size,用来控制点的大小、线的宽度和面要素的边框,当然你也可以设定更多的参数,我这里仅用来说明,就不搞那么麻烦了:

图片

接下去就可以写具体的实现了。

点要素的实现:

impl BuildTrace for traceParam<Point>{
    fn build_trace(&self) -> Vec<Box<ScatterMapbox<f64,f64>>> {
        let mut traces:Vec<Box<ScatterMapbox<f64,f64>>> = Vec::new();
        for (pnt,color) in zip(&self.geometrys,&self.colors) {
            let mut trace: Box<ScatterMapbox<f64, f64>> = ScatterMapbox::new(vec![pnt.y()], vec![pnt.x()]);
            trace = match color {
                inputColor::NamedColor(color) => {
                    MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Point)
                },
                inputColor::Rgba(color) => {
                    MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Point)
                },
                _ => panic!(""),
            };
            traces.push(trace);
        }
        traces
    }
}

线要素的实现:

impl BuildTrace for traceParam<LineString>{
    fn build_trace(&self) -> Vec<Box<ScatterMapbox<f64,f64>>> {
        let mut traces:Vec<Box<ScatterMapbox<f64,f64>>> = Vec::new();
        for (line,color) in zip(&self.geometrys,&self.colors) {
            let mut lat:Vec<f64>= Vec::new();
            let mut lon:Vec<f64>= Vec::new();
            for coord in line.coords(){
                lat.push(coord.y);
                lon.push(coord.x);
            }
            let mut trace: Box<ScatterMapbox<f64, f64>> = ScatterMapbox::new(lat, lon);
            trace = match color {
                inputColor::NamedColor(color) => {
                    MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Line)
                },
                inputColor::Rgba(color) => {
                    MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Line)
                },
                _ => panic!(""),
            };
            traces.push(trace);
        }
        traces
    }
}

面数据的实现:

impl BuildTrace for traceParam<Polygon>{
    fn build_trace(&self) -> Vec<Box<ScatterMapbox<f64,f64>>> {
        let mut traces:Vec<Box<ScatterMapbox<f64,f64>>> = Vec::new();
        for (poly,color) in zip(&self.geometrys,&self.colors) {
            let mut lat:Vec<f64>= Vec::new();
            let mut lon:Vec<f64>= Vec::new();
            for coord in poly.exterior(){
                lat.push(coord.y);
                lon.push(coord.x);
            }
            let mut trace: Box<ScatterMapbox<f64, f64>> = ScatterMapbox::new(lat, lon);
            trace = match color {
                inputColor::NamedColor(color) => {
                    MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Polygon)
                },
                inputColor::Rgba(color) => {
                    MyTrace{color:*color,size:self.size,trace:trace}.set_trace(geo_type::Polygon)
                },
                _ => panic!(""),
            };
            traces.push(trace);
            for ipoly in poly.interiors(){
                let mut ilat:Vec<f64>= Vec::new();
                let mut ilon:Vec<f64>= Vec::new();
                for coord in poly.exterior(){
                    ilat.push(coord.y);
                    ilon.push(coord.x);
                }
                trace = ScatterMapbox::new(ilat, ilon);      
                trace = MyTrace{color:NamedColor::White,size:self.size,trace:trace}.set_trace(geo_type::Polygon);
                traces.push(trace);
            }
        }
        traces
    }
}

里面三个方法都用了一个处理trace的方法,实现如下:

struct MyTrace<T>{
    color:T,
    size:usize,
    trace:Box<ScatterMapbox<f64,f64>>
}

enum geo_type{
    Point,
    Line,
    Polygon,
}
trait SetTrace<T> {
    fn set_trace(&self,geo_type:geo_type)->Box<ScatterMapbox<f64,f64>>;
}

impl SetTrace<NamedColor> for MyTrace<NamedColor>{
    fn set_trace(&self,geo_type:geo_type)->Box<ScatterMapbox<f64,f64>> {
        match geo_type{
            geo_type::Point =>{
                let t = *self.trace.to_owned()
                .marker(Marker::new().color(self.color)).show_legend(false);
                Box::new(t)
            },

            geo_type::Line =>{
                let t = *self.trace.to_owned()
                .line(Line::new().width(self.size as f64).color(self.color)).show_legend(false);
                Box::new(t)
            },

            geo_type::Polygon=> {
                let t = *self.trace.to_owned()
                .fill(plotly::scatter_mapbox::Fill::ToSelf).fill_color(self.color).show_legend(false);
                Box::new(t)
            },
            _ => panic!("")
        }
    }
}

impl SetTrace<Rgba> for MyTrace<Rgba>{
    fn set_trace(&self,geo_type:geo_type)->Box<ScatterMapbox<f64,f64>> {
        match geo_type{
            geo_type::Point =>{
                let t = *self.trace.to_owned()
                .marker(Marker::new().color(self.color)).show_legend(false);
                Box::new(t)
            },

            geo_type::Line =>{
                let t = *self.trace.to_owned()
                .line(Line::new().width(self.size as f64).color(self.color)).show_legend(false);
                Box::new(t)
            },

            geo_type::Polygon=> {
                let t = *self.trace.to_owned()
                .fill(plotly::scatter_mapbox::Fill::ToSelf).fill_color(self.color).show_legend(false);
                Box::new(t)
            },
            _ => panic!("")
        }
    }
}

这两个方法,几乎99%是想同的,只是输入的颜色类型不一样,这样就是静态语言的麻烦之处了,只要函数签名不一致,就相当于两个方法,看到这里,大家可能想问,上一节讲过的泛型,在这里能用么?答案当然可以,不过就算用泛型,最终编译出来的代码也会因为编译器的处理,而实现函数单态化,即编译器会针对具体情况,编译出多个静态函数出来。所以这里如果继续抽象,也不是不行,但是算做过度设计了。

之后,就可以写一个绘制函数,然后进行调用了:

pub fn plot_draw_trace(traces:Vec<Box<ScatterMapbox<f64,f64>>>,outimg: Option<&str>){
    let mut plot = Plot::new();
    for t in traces{
        plot.add_trace(t);
    }
    let layout = _get_layout(1024, 800, Center::new(39.9, 116.3),MapboxStyle::Dark);
    plot.set_layout(layout);
    match outimg {
        Some(out) => plot.write_image(out, ImageFormat::PNG, 1200, 900, 1.0),
        None => plot.show(),
    }
}

//这个是一个内部函数,用来初始化构造制图参数的。
fn  _get_layout(width:usize, height:usize,cnt:Center,ms:MapboxStyle) -> Layout{
    Layout::new()
        .drag_mode(DragMode::Zoom)
        .margin(Margin::new().top(10).left(10).bottom(10).right(10))
        .width(width)
        .height(height)
        .mapbox(
            Mapbox::new()
                .style(ms)
                .access_token("pk.eyJ1IjoiYWxsZW5sdTIwMDgiLCJhIjoiY2xxZjNsaGtmMDd0ZTJqcWM1MzRmemx1NCJ9.TbiPQB6j1w9ilBP4pFHRRw")
                .center(cnt)
                .zoom(10),
        )
}

最后我们写一个测试调用方法,来绘制一下百度地图:

// 因为在Html里面绘制比较慢,所以我这里就仅画三个图层
#[test]
fn draw_bd_style(){
    let shp1 = "./data/shp/北京行政区划.shp";
    let poly1:Vec<Polygon> = readShapefile::shp::read_shp(shp1);
    let colors:Vec<inputColor> = (0..poly1.len())
    .map(|x|inputColor::Rgba(Rgba::new(240,243,250,1.0))).collect();
    let mut t1 = traceParam{geometrys:poly1,colors:colors,size:0}.build_trace();
    
    let shp2 = "./data/shp/面状水系.shp";
    let poly2:Vec<Polygon> = readShapefile::shp::read_shp(&shp2);
    let colors:Vec<inputColor> = (0..poly2.len())
    .map(|x|inputColor::Rgba(Rgba::new(108,213,250,1.0))).collect();
    let mut t2 = traceParam{geometrys:poly2,colors:colors,size:0}.build_trace();

    let shp3 = "./data/shp/高速.shp";
    let line1:Vec<LineString> = readShapefile::shp::read_shp(&shp3);
    let colors:Vec<inputColor> = (0..line1.len())
    .map(|x|inputColor::Rgba(Rgba::new(255,182,118,1.0))).collect();
    let mut t3 = traceParam{geometrys:line1,colors:colors,size:1}.build_trace();
    
    t1.append(&mut t2);
    t1.append(&mut t3);
    plot_draw_trace(t1,None);
}

绘制效果如下:

图片

注意:plotly.rs的JS引用的是Mapbox,所以网络访问上可能会有一些障碍,有可能需要科学上网……

打完收工。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

紫外线吸收剂为光稳定剂代表产品 塑料及化妆品领域为其主要需求端

紫外线吸收剂为光稳定剂代表产品 塑料及化妆品领域为其主要需求端 紫外线吸收剂指能吸收阳光及荧光光源中的紫外线部分的一种光稳定剂。紫外线吸收剂具有热稳定性好、可吸收紫外线、化学稳定性好、能增强目标物色泽稳定性、毒性低等优势&#xff0c;在塑料、化妆品、纺织品、涂…

大厂级别交互设计秘籍:一篇读懂

交互式设计属于UI设计之一&#xff0c;也是当今流行的设计之一。许多大型工厂非常需要交互式设计人才&#xff0c;这一趋势也引起了许多毕业生和UI设计爱好者的广泛关注&#xff0c;那么你知道大型工厂设计师必要的交互式设计是什么吗&#xff1f;这篇文章将带你了解。 什么是…

【PFA树脂交换柱】实验室高纯PFA材质过滤柱耐受电子级氢氟酸含氟树脂层析柱

PFA离子交换柱&#xff0c;也叫PFA层析柱、PFA过滤柱等&#xff0c;其原理是利用吸附剂对不同化合物有不同吸附作用和不同化合物在溶剂中的不同溶解度&#xff0c;用适应溶剂使混合物在填有吸附剂的柱内通过&#xff0c;使复杂的混合物达到分离和提纯的目的。 柱体为透明PFA材…

再生式收音机填坑记

年前踩坑再生式收音机&#xff0c;还是得找机会把坑填上&#xff0c;最终选定了K8TND的方案&#xff0c;其实与Mr. Kitchen的也基本差不多。电路图如下&#xff1a; 实物图如下&#xff1a; 实际接收效果还不错&#xff0c;但是感觉频段上哪哪都是中国之声&#xff0c;对这种…

牛仔裤什么牌子的好?国产质量最好牛仔裤大汇总

现在的裤子款式多到可以每天不重样&#xff0c;但大家总是买不到合适。现在虽然裤子款式非常多&#xff0c;但是大部分的裤子版型设计有很多问题&#xff0c;甚至还有一些商家为了利润而不断压缩成本&#xff0c;采用劣质面料&#xff0c;导致出现各种问题。 今天我就结合我的专…

openGauss 6.0.0-RC1 版本正式发布!

openGauss 6.0.0-RC1版本正式上线&#xff01; openGauss 6.0.0-RC1是社区最新发布的创新版本&#xff0c;版本生命周期为0.5年。&#xff08;创新版本命名&#xff1a;由原方案 XX.1.0 Preview (例&#xff1a;5.1.0 preview&#xff09;&#xff0c;调整为现方案 XX.0.0-RCx&…

scRNA+bulk+MR:动脉粥样硬化五个GEO数据集+GWAS,工作量十分到位

今天给大家分享一篇JCR一区&#xff0c;单细胞bulkMR的文章&#xff1a;An integrative analysis of single-cell and bulk transcriptome and bidirectional mendelian randomization analysis identified C1Q as a novel stimulated risk gene for Atherosclerosis 标题&…

营业执照印章检测识别技术落地项目

项目效果演示&#xff1a; 输入图片&#xff0c;对电子版和拍摄版都具体良好的效果 示例一&#xff1a; 印章识别 示例二&#xff1a; 拍摄版本&#xff0c;清晰度差 识别结果 训练模型样本数量&#xff1a;一万张印章样本训练 样本上准确率99% 印章文字识别率100% 印章文…

前端对数据进行分组和计数处理

js对数组数据的处理&#xff0c;添加属性&#xff0c;合并表格数据。 let data[{id:1,group_id:111},{id:2,group_id:111},{id:3,group_id:111},{id:4,group_id:222},{id:5,group_id:222} ]let tempDatadata; tempDatatempData.reduce((arr,item)>{let findarr.find(i>i…

【技巧】压缩文件如何设置“自动加密”?

很多人会在压缩文件的时候&#xff0c;同时设置密码&#xff0c;以此保护私密文件。如果经常需要压缩文件并设置密码&#xff0c;不妨使用解压缩软件的“自动加密”功能&#xff0c;更省时省力。 下面介绍WinRAR解压缩软件的两种“自动加密”的方法&#xff0c;一起来看看吧&a…

九河云携手华为云推出海外电商解决方案,一体化解决出海问题

随着国内竞争的日益激烈&#xff0c;国内企业的出海热情正在逐步提高。国外尤其是东南亚等地区&#xff0c;正在成为企业营收的新增长点。九河云携手华为云为客户带来了海外电商部署方案。华为云作为增长最快的云服务提供商&#xff0c;秉持着为客户提供最优质服务的原则&#…

手把手写深度学习(26):统计视频数据集的基本特性(帧数、帧率、长度)和预处理(切分)的自动化脚本

手把手写深度学习(0)&#xff1a;专栏文章导航 前言&#xff1a;当算法工程师拿到一个新的视频数据集的时候&#xff0c;需要首先查看一下这个数据集的基本特性&#xff0c;方便后续处理和模型训练。这篇博客提供自动化脚本&#xff0c;帮助统计视频数据集的基本特性&#xff0…

C++入门(以c为基础)——学习笔记

1.前言 首先&#xff0c;c兼容c语言百分之九十八、九十九的内容&#xff0c;可以认为这是两种不分家的语言 c的语法几乎能在c上都能跑 在一个后缀为.cpp的文件中&#xff0c;我们以面向过程的思考&#xff08;C语言的逻辑&#xff09;写下如下代码&#xff1a; #include <s…

基于STM32CubeMX移植freeModbus RTU(从站)-避坑篇

基于STM32CubeMX移植freeModbus RTU&#xff08;从站&#xff09;-避坑篇 &#xff08;重点&#xff09;Chapter0 移植Freemodbus到STM32(基于CubeMX,HAL库)-避坑篇&#xff08;1&#xff09;Freemodbus移植到TTL的USART1可行&#xff0c;但改为485的USART2不行&#xff08;2&a…

科研学习|论文解读——情感对感知偶然信息遭遇的影响研究(JASIST,2022)

原文题目 Investigating the impact of emotions on perceiving serendipitous information encountering 一、引言 serendipity一词最初是由霍勒斯沃波尔创造的&#xff0c;他将其定义为“通过意外和睿智发现你并不追求的事物”。信息研究中大多数现有的偶然性定义从几个角度看…

深度学习理解及学习推荐(持续更新)

主推YouTuBe和Bilibili 深度学习博主推荐&#xff1a; Umar Jamil - YouTubehttps://www.youtube.com/umarjamilai StatQuest with Josh Starmer - YouTubehttps://www.youtube.com/statquest RNN Illustrated Guide to Recurrent Neural Networks: Understanding the Int…

Java基础入门--面向对象课后题(1)

某公司正进行招聘工作&#xff0c;被招聘人员需要填写个人信息&#xff0c;编写“个人简历”的封装类Resume&#xff0c;并编写测试类进行实现。类图及输出效果如下。 类名&#xff1a;Resumename : String (private)sex : String (private)age : int (private)Resume( ) // 没…

【产品设计】四句口诀,搞懂支付交易设计

01 支付交易介绍 支付是交易的一部分&#xff0c;订单是信息流支付是资金流&#xff0c;交易系统通过信息和资金的匹配来完成交易履约。这么说有点抽象&#xff0c;我们通过大家熟悉的电商购物流程来介绍下。 1.1、交易链路 我们做交易设计的时候听到最多的就是“要掌握交易…

数据结构八大常见的排序

数据结构八大常见的排序 常见排序算法分类1.插入排序2.希尔排序(缩小增量排序)3.选择排序4.堆排序5.冒泡排序6.快速排序7.归并排序归并排序非递归的实现8.计数排序 常见排序算法分类 1.插入排序 基本思想&#xff1a;把待排序的数组按大小逐个插入到一个已经排好序的有序序列中…

结构体与位段的定义以及在内存中的存储

目录 结构体的声明 完全声明 不完全声明 结构体变量的定义和初始化 结构体的嵌套 结构体成员的直接访问和间接访问 结构体的自引用 typedef对结构体类型重命名 结构体内存对齐 对齐规则 练习 为什么存在内存对齐 修改默认对齐数 结构体传参 结构体实现位段 位段…