如何在C++中优雅地绘制图表

如何在C++项目中优雅地绘制图表

  • matplotlib
    • prepare
    • matplotlibcpp.h
    • python3
    • vs configure
    • test
  • Gnuplot
    • prepare
    • gnuplot
    • gnuplot-iostream.h
    • boost
    • vs configure
    • test
  • MathGL

在C++项目中,在进行一些数据分析时往往不够直观,若能借助图表进行分析可以达到事半功倍的效果,通常可以将数据写出到文本,再在excel或python上进行图表绘制和分析,那为什么不直接在像python一样,借助三方库进行图表绘制呢?以下将介绍简单易行的方法,尝试在C++中优雅地绘制图表(测试环境:Windows+VS2019)。


matplotlib

实际上是调用Python中的matplotlib提供的C++ API,无需编译,直接包含头文件然后在C++中配置相应python环境就可以,对于熟悉python的伙伴来说几乎没有学习成本(其本身语法也很简单)。

prepare

  1. 可访问github的网络
  2. git(非必须)
  3. python3(< 3.11)
  4. vs环境

matplotlibcpp.h

有git的直接clone到本地:

 git clone https://github.com/lava/matplotlib-cpp.git

没有git可以下载代码或者直接在线复制 matplotlibcpp.h

matplotlibcpp.h 作如下修改:

新版的matplotlibcpp.h中支持了C++17语法,将其改回C++11,且有重定义,需要注释。

将353行至356行代码用以下代码覆盖:

static_assert(sizeof(long long) == 8, "long type must occupy 8 bytes");
//template <> struct select_npy_type<long long> { const static NPY_TYPES type = NPY_INT64; };
static_assert(sizeof(unsigned long long) == 8, "long type must occupy 8 bytes");
//template <> struct select_npy_type<unsigned long long> { const static NPY_TYPES type = NPY_UINT64; };

python3

matplotlibcpp.h 语法与python3.11以上版本不兼容,报错如下:

1>matpoltlibTest.cpp
1>D:\Program Files\MatplotlibCpp\matplotlibcpp.h(174): error C4996: 'Py_SetProgramName': deprecated in 3.11
1>d:\programdata\anaconda3\include\pylifecycle.h(37): note: 参见“Py_SetProgramName”的声明
1>D:\Program Files\MatplotlibCpp\matplotlibcpp.h(182): error C4996: 'PySys_SetArgv': deprecated in 3.11
1>d:\programdata\anaconda3\include\sysmodule.h(13): note: 参见“PySys_SetArgv”的声明

使用3.11以下的python版本即可,这里我创建一个新的虚拟环境:

(base)>conda create -n Env310 python=3.10.16
(base)>conda activate Env310
(Env310)>conda install matplotlib numpy

将 复制到 D:\Program Files\MatplotlibCpp 下(非必须)。


vs configure

创建一个vs项目,切换为Release x64平台,在属性管理器的【Release | 64】下中新增一个属性表:

在这里插入图片描述
双击该属性表,开始配置:

【通用属性】-【VC++目录】-【包含目录】添加:

D:\Program Files\MatplotlibCpp
D:\ProgramData\anaconda3\envs\Env310\include
D:\ProgramData\anaconda3\envs\Env310\Lib\site-packages\numpy\_core\include

在这里插入图片描述
注意:不同版本的numpy包含目录所在路径可能不同,可通过以下代码确定:

import numpy
print(numpy.get_include())

【通用属性】-【VC++目录】-【库目录】添加:

D:\ProgramData\anaconda3\envs\Env310\libs

在这里插入图片描述
【通用属性】-【链接器】-【常规】-【附加库目录】添加:

D:\ProgramData\anaconda3\envs\Env310

在这里插入图片描述

【通用属性】-【链接器】-【输入】-【附加依赖项】添加:

python3.lib

在这里插入图片描述

保存属性表,在解决方案管理器中右击,更改属性:
【配置属性】-【调试】-【工作目录】更改为:

D:\ProgramData\anaconda3\envs\Env310

在这里插入图片描述

test

添加C++测试代码,如:

#include <cmath>
#include "matplotlibcpp.h"namespace plt = matplotlibcpp;#define M_PI 3.141592653589793238432643int main()
{// Prepare data.int n = 5000; // number of data pointsstd::vector<double> x(n), y(n);for (int i = 0; i < n; ++i){double t = 2 * M_PI * i / n;x.at(i) = 16 * sin(t) * sin(t) * sin(t);y.at(i) = 13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t);}// plot() takes an arbitrary number of (x,y,format)-triples.// x must be iterable (that is, anything providing begin(x) and end(x)),// y must either be callable (providing operator() const) or iterable.plt::plot(x, y, "r-", x, [](double d){return 12.5 + abs(sin(d));}, "k-");// show plotsplt::show();
}

运行,可得图片如下,配置完成。

在这里插入图片描述


Gnuplot

类似matplotlib,先安装gnuplot本体,然后通过C++API调用库,不同的是其可通过命令在终端中使用,需要一定学习成本。

prepare

  1. 可访问github的网络
  2. git(非必须)
  3. boost
  4. vs环境

gnuplot

在官网 可找到最新稳定版下载页面,下载编译好的二进制文件。

在这里插入图片描述
解压后长这个样子:
在这里插入图片描述
bin文件夹下双击打开gnupolt.exe,输入测试代码如下:

plot [-6:6] [-3:3] sin(x),cos(x)

可得:
在这里插入图片描述

将整个gunplot文件夹剪切至D:\Program Files\下,并重命名为Gnuplot(个人喜好),然后将D:\Program Files\Gnuplot\bin添加至系统环境变量Path中,通过重启或者其他方式确保环境变量生效(打开任意终端,输入gunplot未报错即可)。

在这里插入图片描述

那么同样可以在c++代码中调用该exe:

#include <stdio.h>void main()
{FILE* pipe = _popen("gnuplot", "w");if (pipe == NULL){exit(-1);}fprintf(pipe, "set terminal wxt size 600, 400\n");fprintf(pipe, "unset border\n");fprintf(pipe, "set dummy u, v\n");fprintf(pipe, "set angles degrees\n");fprintf(pipe, "set parametric\n");fprintf(pipe, "set view 60, 136, 1.22, 1.26\n");fprintf(pipe, "set samples 64, 64\n");fprintf(pipe, "set isosamples 13, 13\n");fprintf(pipe, "set mapping spherical\n");fprintf(pipe, "set style data lines\n");fprintf(pipe, "unset xtics\n");fprintf(pipe, "unset ytics\n");fprintf(pipe, "unset ztics\n");fprintf(pipe, "set title 'Labels colored by GeV plotted in spherical coordinate system'\n");fprintf(pipe, "set urange [ -90.0000 : 90.0000 ] noreverse nowriteback\n");fprintf(pipe, "set vrange [ 0.00000 : 360.000 ] noreverse nowriteback\n");fprintf(pipe, "set xrange [ * : * ] noreverse writeback\n");fprintf(pipe, "set x2range [ * : * ] noreverse writeback\n");fprintf(pipe, "set yrange [ * : * ] noreverse writeback\n");fprintf(pipe, "set y2range [ * : * ] noreverse writeback\n");fprintf(pipe, "set zrange [ * : * ] noreverse writeback\n");fprintf(pipe, "set cblabel 'GeV'\n");fprintf(pipe, "set cbrange [ 0.00000 : 8.00000 ] noreverse nowriteback\n");fprintf(pipe, "set rrange [ * : * ] noreverse writeback\n");fprintf(pipe, "set colorbox user\n");fprintf(pipe, "set colorbox vertical origin screen 0.9, 0.2 size screen 0.02, 0.75 front  noinvert bdefault\n");fprintf(pipe, "NO_ANIMATION = 1\n");fprintf(pipe, "splot cos(u)*cos(v),cos(u)*sin(v),sin(u) notitle with lines lt 5\n");fprintf(pipe, "pause mouse\n");_pclose(pipe);
}

结果如下:
在这里插入图片描述
但是,以这种方式,如果要批量绘制自定义的数据,仍需要先存数据为文本,然后再读取,这不是我想要的直接绘制的效果。但是不慌,再做一些简单配置就可以实现了。


gnuplot-iostream.h

有git的直接clone到本地

 git clone https://github.com/dstahlke/gnuplot-iostream.git

没有git可以下载代码或者直接在线复制 gnuplot-iostream.h

gnuplot-iostream.h 作如下修改

新版的gnuplot-iostream.h中支持了C++17语法,将其改回C++11,跟上面的matplotlibcpp.h是同样类型的改动

168-169行:

static_assert( is_like_stl_container<std::vector<int>>);
static_assert(!is_like_stl_container<int>);

改为:

static_assert(is_like_stl_container<std::vector<int>>, "Should be STL-like container");
static_assert(!is_like_stl_container<int>, "int is not STL-like container");

186行:

static_assert(is_boost_tuple_nulltype<boost::tuples::null_type>);

改为:

static_assert(is_boost_tuple_nulltype<boost::tuples::null_type>, "Should be boost null type");

197-200行:

static_assert( is_boost_tuple<boost::tuple<int>>);
static_assert( is_boost_tuple<boost::tuple<int, int>>);
static_assert(!is_boost_tuple<std::tuple<int>>);
static_assert(!is_boost_tuple<std::tuple<int, int>>);

改为:

static_assert(is_boost_tuple<boost::tuple<int>>, "Should be boost::tuple");
static_assert(is_boost_tuple<boost::tuple<int, int>>, "Should be boost::tuple");
static_assert(!is_boost_tuple<std::tuple<int>>, "std::tuple is not boost::tuple");
static_assert(!is_boost_tuple<std::tuple<int, int>>, "std::tuple is not boost::tuple");

2436-2437行

static_assert( is_eigen_matrix<Eigen::MatrixXf>);
static_assert(!is_eigen_matrix<int>);

改为

static_assert(is_eigen_matrix<Eigen::MatrixXf>, "Should be Eigen::Matrix");
static_assert(!is_eigen_matrix<int>, "int is not an Eigen::Matrix");

2442行

static_assert(dont_treat_as_stl_container<Eigen::MatrixXf>);

改为

static_assert(dont_treat_as_stl_container<Eigen::MatrixXf>, "Eigen::Matrix should not be treated as an STL container");

然后在上述gnuplot的安装目录D:\Program Files\Gnuplot下新建include文件夹,将改动后的gnuplot-iostream.h拷贝过去。

boost

由于gnuplot的C++调用需要boost支持,这里也介绍一下boost的配置,因为有预编译好的库,所以也比较easy。

在boost官网的下载页面找到预编译好的Windows库:

在这里插入图片描述
根据所需环境选择对应版本。

在这里插入图片描述

这里我根据自己的环境选择较早的1.80.0 VS140版(注意和自己的环境对应)。
在这里插入图片描述
双击运行:
在这里插入图片描述
更改安装目录:
在这里插入图片描述

在这里插入图片描述


vs configure

创建一个vs项目,切换为Release x64平台,在属性中将【平台工具集】改为Visual Studio 2015 (v140),在属性管理器的【Release | 64】下中新增一个属性表【Gnupolt_Release_x64.props】

双击该属性表,开始配置

【通用属性】-【VC++目录】-【包含目录】添加:

D:\Program Files\Gnuplot\include
D:\Program Files\boost_1_80_0\boost

【通用属性】-【VC++目录】-【库目录】添加:

D:\Program Files\boost_1_80_0\lib64-msvc-14.0

在这里插入图片描述

应用,保存属性表。


test

添加C++测试代码,如:


#include <cmath>
#include <vector>
#include <gnuplot-iostream.h>#define M_PI 3.141592653589793238432643int main()
{// 初始化 Gnuplot 对象Gnuplot gp;// 设置标题和样式gp << "set title 'Sharper Heart Shape'\n";gp << "set size ratio -1\n"; // 确保 x 和 y 轴比例一致gp << "set nokey\n";         // 不显示图例gp << "set samples 1000\n";  // 增加采样点使曲线更平滑gp << "set xrange [-20:20]\n"; // 设置 x 轴范围gp << "set yrange [-20:20]\n"; // 设置 y 轴范围// 定义参数化方程的数据点std::vector<std::pair<double, double>> points;const int num_points = 1000; // 数据点数量for (int i = 0; i <= num_points; ++i){double t = 2 * M_PI * i / num_points; // 参数 t 从 0 到 2πdouble x = 16 * pow(sin(t), 3);      // 使用新的 x 方程double y = (13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t)); // 使用新的 y 方程points.emplace_back(x, y);}// 绘制爱心形状gp << "plot '-' with lines lc rgb 'red' lw 2 title 'Heart'\n";for (const auto& point : points){gp << point.first << " " << point.second << "\n";}gp << "e\n"; // 结束数据流return 0;
}

运行,可得图片如下,配置完成。
在这里插入图片描述


MathGL

需要特定的环境和复杂的配置,其发布的库也是Linux平台下的,在Windows需要和其他依赖库一起重新编译。

同样在官网找到最新版下载入口,这里有两个版本,我两个版本都下载并配置了,很不幸都在测试阶段报错了,要么缺少头文件要么缺依赖库。虽然可以拿源码自己重新cmake,但其需要依赖其他可视化库(背离了简单易行的初衷),本着世上无难事只要肯放弃的精神,暂停MathGL的测试。

在这里插入图片描述
测试代码:

#include <mgl2/mgl.h>int main()
{mglGraph gr;gr.SetRange('x', -1, 1);gr.SetRange('y', -1, 1);gr.Axis();gr.FPlot("sin(1.7*2*pi*x) + sin(1.9*2*pi*x)", "r-2");gr.WriteFrame("test.png");return 0;
}

mathgl-8.0.3-ucrt64 报错:

1>D:\Program Files\MathGL2\include\mgl2\data_cf.h(26,10): fatal error C1083: 无法打开包括文件: “gsl/gsl_vector.h”: No such file or directory

mathgl-8.0.3.LGPL-ucrt64 报错:

1>D:\Program Files\MathGL2\include\mgl2\data.h(27,10): fatal error C1083: 无法打开包括文件: “armadillo”: No such file or directory

打完收工。

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

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

相关文章

vue3使用keep-alive缓存组件与踩坑日记

目录 一.了解一下KeepAlive 二.使用keep-alive标签缓存组件 1.声明Home页面名称 三.在路由出口使用keep-alive标签 四.踩坑点1&#xff1a;可能需要配置路由&#xff08;第三点完成后有效可忽略&#xff09; 五.踩坑点2&#xff1a;没有找到正确的路由出口 一.了解一下Kee…

ros通信机制学习——latched持久化机制

点云的地图的发送逻辑中&#xff0c;我发现每次使用rostopic echo 时只会打印一次&#xff0c;然后就不会再打印了。并且rviz中也是始终都会显示的&#xff0c;这里面其实就是用到了latched持久话机制&#xff0c;可以接受这最后一次发布的消息。 我们通过一个具体的项目来学习…

力扣每日打卡 1922. 统计好数字的数目 (中等)

力扣 1922. 统计好数字的数目 中等 前言一、题目内容二、解题方法1. 暴力解法&#xff08;会超时&#xff0c;此法不通&#xff09;2. 快速幂运算3. 组合计数的思维逻辑分析组合计数的推导例子分析思维小结论 4.官方题解4.1 方法一&#xff1a;快速幂 三、快速幂运算快速幂运算…

如何使用通义灵码玩转Docker - AI助手提升开发效率

一、引言 Docker 作为一种流行的虚拟化技术&#xff0c;能够帮助开发者快速搭建所需的运行环境。然而&#xff0c;对于初学者来说&#xff0c;掌握 Docker 的基本概念和使用方法可能会遇到一些挑战。本文将介绍如何利用通义灵码这一智能编码助手&#xff0c;帮助你更高效地学习…

从一到无穷大 #45:InfluxDB MCP Server 构建:从工程实践到价值重构

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 工程实践遇到的问题MCP Host选择开发流程 结果展现可能性展望工作生活带来的变化 MCP…

JAVA SDK通过proxy对接google: GCS/FCM

前言&#xff1a;因为国内调用google相关api需要通过代理访问(不想设置全局代理)&#xff0c;所以在代理这里经常遇到问题&#xff0c;先说一下结论 GCS 需要设置全局代理或自定义代理选择器&#xff0c; FCM sdk admin 在初始化firebaseApp时是支持设置的。 GCS: 开始时尝试在…

【NLP】24. spaCy 教程:自然语言处理核心操作指南(进阶)

spaCy 中文教程&#xff1a;自然语言处理核心操作指南&#xff08;进阶&#xff09; 1. 识别文本中带有“百分号”的数字 import spacy# 创建一个空的英文语言模型 nlp spacy.blank("en")# 处理输入文本 doc nlp("In 1990, more than 60% of people in East…

关于香橙派OrangePi 5 Ultra 这个开源板子,开发Android

我下载了它资料中的开源Android13 系统SDK&#xff0c; 这个SDK连个git 都没有&#xff0c;把这种代码释放能称为开源吗&#xff1f;&#xff1f; 并且也就是说你买了这个板子&#xff0c;里面是没有任何关于RK3588的开发文档&#xff0c;如果你没玩过其他RK平台&#xff0c;估…

WHAT - React Portal 机制:将子组件渲染到 DOM 的指定节点

文章目录 适合场景基本语法示例&#xff1a;Modal 弹窗1. 创建一个简单的 Modal.tsx2. 在 App 中使用 为什么要用 Portal&#xff1f;TypeScript 中 Portal 类型定义&#xff1f; 适合场景 React Portal 是 React 提供的一种机制&#xff0c;让你可以将子组件渲染到 DOM 的指定…

数据结构---跳表

目录 一、跳表的概念 为什么要使用随机值来确定层高 二、跳表的分析 &#xff08;1&#xff09;查找过程 &#xff08;2&#xff09;性能分析 三、跳表的实现 四、与红黑树哈希表的对比 skiplist本质上也是一种查找结构&#xff0c;用于解决算法中的查找问题&#xff0c…

PCDN通过个人路由器,用更靠近用户的节点来分发内容,从而达到更快地网络反应速度

PCDN&#xff08;P2P CDN&#xff09;的核心思想正是利用个人路由器、家庭宽带设备等分布式边缘节点&#xff0c;通过就近分发内容来降低延迟、提升网络响应速度&#xff0c;同时降低传统CDN的带宽成本。以下是其技术原理和优势的详细分析&#xff1a; 1. 为什么PCDN能更快&…

用excel做九乘九乘法表

公式&#xff1a; IF($A2>B 1 , 1, 1,A2 & “" & B$1 & “” & $A2B$1,”")

凡泰极客亮相QCon2025鸿蒙专场,解析FinClip“技术+生态”双引擎

2025年4月10日&#xff0c;备受瞩目的QCon开发者技术峰会盛大举行&#xff0c;本次活动开设鸿蒙专场以“HarmonyOS NEXT 创新特性与行业实践”为主题&#xff0c;汇聚了众多鸿蒙生态的领军人物与技术专家&#xff0c;共同探讨鸿蒙操作系统的技术创新与行业应用。 凡泰极客CTO徐…

java HttpServletRequest 和 HttpServletResponse

HttpServletRequest 和 HttpServletResponse 详解 1. HttpServletRequest&#xff08;HTTP 请求对象&#xff09; HttpServletRequest 是 Java Servlet API 提供的接口&#xff0c;用于封装客户端的 HTTP 请求信息。它继承自 ServletRequest&#xff0c;并增加了 HTTP 协议相…

HAL TIM PWM产生 蓝桥杯

目录 0.原理 0.1 CNT和CCR关系 0.2 PWM模式1模式2 1. cubemx配置 需求(将PA1输出1Khz的 50&#xff05;占空比的方波) 1.0 PWM的频率计算: 2.代码 0.原理 0.1 CNT和CCR关系 CNT计数器和CCR比较器进行比较,如果是向上计数,CNT逐渐增加,CCR是虚线位置,也是用户自定义的…

python入门:简单介绍和python和pycharm软件安装/学习网址/pycharm设置(改成中文界面,主题,新建文件)

Python 目前是 AI 开发的首选语言 软件安装 python解释器 官网下载 Python |Python.org 勾选 Add python.exe to PATH 将python.exe添加到PATH 勾选这个选项会将Python的可执行文件路径添加到系统的环境变量PATH中。这样做的好处是&#xff0c;你可以在命令行中从任何位置直…

CMD命令行笔记

CMD命令行笔记&#xff0c;涵盖常用命令及实用技巧&#xff0c;适合快速查阅&#xff1a; 一、基础操作 打开CMD Win R → 输入 cmd → 回车管理员模式&#xff1a;右键开始菜单 → 选择“命令提示符&#xff08;管理员&#xff09;” 常用命令 help&#xff1a;查看所有命令…

android中dp和px的关系

关于android的dp和px的关系是我刚开始学习android的第一个知识点&#xff0c;不知不觉学安卓也有一年了&#xff0c;但是偶然间我发现我理解的dp和px的关系一直是错的&#xff0c;真的是有一点搞笑&#xff0c;今天特意写一篇博客纪念一下这个我理解错一年的知识点。 dp和px之间…

(四)机器学习---逻辑回归及其Python实现

之前我们提到了常见的任务和算法&#xff0c;本篇我们使用逻辑回归来进行分类 分类问题回归问题聚类问题各种复杂问题决策树√线性回归√K-means√神经网络√逻辑回归√岭回归密度聚类深度学习√集成学习√Lasso回归谱聚类条件随机场贝叶斯层次聚类隐马尔可夫模型支持向量机高…

【汽车产品开发项目管理——端到端的汽车产品诞生流程】

MPU&#xff1a;集成运算器、寄存器和控制器的中央处理器芯片 MCU&#xff1a;微控制单元&#xff0c;将中央处理器CPU、存储器ROM/RAM、计数器、IO接口及多种外设模块集成在单一芯片上的微型计算机系统。 汽车产品开发项目属性&#xff1a;临时性、独特性、渐进明细性、以目标…