QT下使用QChart绘制曲线

目录

    • 头文件内容
    • 构造函数
    • AddSeries方法
    • UpdateSeries方法
    • AppendSeriesData方法
    • SetLegendVisiable
    • SetRubberBand
    • CPP内容
    • 测试函数

在这里插入图片描述

需要用到的头文件:

#include <QtCharts/QChart>
#include <QtCharts/QChartView>
#include <QtCharts/QValueAxis>
#include <QPoint>
#include <QtCharts/QLineSeries>
#include <QString>
#include <QGridLayout>
#include <QLegendMarker>

直白一点说明,QChart用来存放曲线坐标轴和曲线,QChartView用来存放QChart,QChartView是一个Widget,可以独立show或者和其他widget做布局。

QLineSeries是直线,上图可以算是一个折线图,Qt还有散点图、光滑的曲线图、条形图、饼状图等等。

QValueAxis是坐标轴。

头文件内容

/*!* \file curve_charts.h* \date 2023/11/18 23:08** \author * Contact:** \brief ** 基于Qt的曲线图** \note
*/#pragma once#include <unordered_map>#include <QWidget>
#include <QtCharts/QChart>
#include <QtCharts/QChartView>
#include <QtCharts/QValueAxis>
#include <QPoint>
#include <QtCharts/QLineSeries>
#include <QString>
#include <QGridLayout>
#include <QLegendMarker>
#include <QScatterSeries>#define		QString2StdString(x)	((x).toStdString())
#define		StdString2QString(x)	(QString::fromLocal8Bit(std::string(x).c_str()))QT_CHARTS_USE_NAMESPACEclass CurveCharts : public QWidget
{Q_OBJECTpublic:CurveCharts(QWidget *parent = nullptr);~CurveCharts();/*!* @func:  void AddSeries(const std::string _series_name, QPen _series_pen);* * @date:  2023/11/18* * @author:叫牌* * @brief: 添加一条曲线,如果已经有这条曲线名称添加失败** @param _series_name: 曲线名称* @param _series_pen:  曲线颜色* * @return: true添加成功,false添加失败*/bool AddSeries(const std::string& _series_name, QPen _series_pen);/*!* @func:  void UpdateSeries(const std::string _series_name, std::vector<QPoint> _charts_data);** @date:  2023/11/18** @author:叫牌** @brief: 通过曲线名称更新曲线** @param _series_name: 曲线名称* @param _charts_data: 曲线数据** @return: true更新成功,false更新失败*/bool UpdateSeries(const std::string& _series_name, std::vector<QPoint> _charts_data);/*!* @func:  void AppendSeriesData(const std::string& _series_name, std::vector<QPoint> _chart_data);** @date:  2023/11/18** @author:叫牌** @brief: 通过曲线名称追加曲线数据** @param _series_name: 曲线名称* @param _charts_data: 曲线数据** @return: true更新成功,false更新失败*/bool AppendSeriesData(const std::string& _series_name, std::vector<QPoint> _chart_data);/*!* @func:  void SetTitle(const std::string _title);** @date:  2023/11/18** @author:叫牌** @brief: 设置曲线标题** @param _title: 曲线标题** @return: 无*/void SetTitle(const std::string& _title);/*!* @func:  std::string GetTitle();** @date:  2023/11/18** @author:叫牌** @brief: 获取曲线标题** @return: 曲线标题*/std::string GetTitle();/*!* @func:  void SetXAxisRange(qreal _x_min, qreal _x_max);** @date:  2023/11/18** @author:叫牌** @brief: 设置X轴范围** @return: 无*/void SetXAxisRange(qreal _x_min, qreal _x_max);/*!* @func:  void SetYAxisRange(qreal _y_min, qreal _y_max);** @date:  2023/11/18** @author:叫牌** @brief: 设置Y轴范围** @return: 无*/void SetYAxisRange(qreal _y_min, qreal _y_max);/*!* @func:  void SetTitle(const std::string& _XTitle, const std::string& _YTitle);** @date:  2023/11/18** @author:叫牌** @brief: 设置Y轴范围* * @param _XTitle: X坐标轴标题* @param _YTitle: Y坐标轴标题** @return: 无*/void setAxisTitles(const std::string& _XTitle, const std::string& _YTitle);/*!* @func:  void SetAxisRanges(bool _flag);** @date:  2023/11/18** @author:叫牌** @brief: 设置坐标轴自适应** @param _flag: true表示自适应,false表示不自适应** @return: 无*/void SetAxisRanges(const bool& _flag);/*!* @func:  void SetLegendVisiable(const bool& _flag);** @date:  2023/11/18** @author:叫牌** @brief: 设置图例显隐** @param _flag: true表示显示,false表示隐藏** @return: 无*/void SetLegendVisiable(const bool& _flag);/*!* @func:  void SetRubberBand(const bool& _hor, const bool& _ver);** @date:  2023/11/18** @author:叫牌** @brief: 设置垂直或水平缩放** @param _hor: true表示打开水平缩放,false表示关闭* @param _ver: true表示打开垂直缩放,false表示关闭** @return: 无* * @note: 垂直和水平缩放只能打开一个,都打开默认选择水平缩放*/void SetRubberBand(const bool& _hor, const bool& _ver);private:QChartView* chart_view_;QChart* chart_;// X轴范围QValueAxis* x_axis_;// Y轴范围QValueAxis* y_axis_;// 存放所有的曲线// <曲线名称,对应的曲线指针>std::unordered_map<std::string, QLineSeries*> charts_series_;// 曲线数据的X和Y最小值QPoint axis_min_;// 曲线数据的X和Y轴最大值QPoint axis_max_;// 坐标轴是否自适应bool is_adaption_;// 图例是否显隐bool is_legend_;
};

我封装了接口供外部直接调用。

构造函数

CurveCharts::CurveCharts(QWidget* parent): QWidget(parent), chart_view_(new QChartView), chart_(new QChart), x_axis_(new QValueAxis), y_axis_(new QValueAxis), is_adaption_(false), is_legend_(false)
{// 布局,栅格布局,把QChartView对象之间放进去,在main函数实例化对象调用show方法。QGridLayout* layout = new QGridLayout;this->setLayout(layout);layout->addWidget(chart_view_);// 窗口标题setWindowTitle(StdString2QString("曲线视图"));// 设置QChartchart_view_->setChart(chart_);// 设置X和Y坐标轴标题的显示位置,X轴标题在最小面,Y轴标题在左侧chart_->addAxis(x_axis_, Qt::AlignBottom);chart_->addAxis(y_axis_, Qt::AlignLeft);// 用于平滑图形的边缘和曲线,减少锯齿状的边缘chart_view_->setRenderHint(QPainter::Antialiasing);// 初始化最小最大值,方便记录X轴和Y轴所有曲线数据的最大最小值axis_min_.setX(INT_MAX);axis_min_.setY(INT_MAX);axis_max_.setX(INT_MIN);axis_max_.setY(INT_MIN);
}

构造函数里对各种成员变量初始化,进行布局,将QChartView对象通过栅格布局,设置X和Y轴的标题。

AddSeries方法

bool CurveCharts::AddSeries(const std::string& _series_name, QPen _series_pen)
{// 如果找到了就说明这个曲线的名称已经添加过了,不能重复添加或者覆盖if (charts_series_.find(_series_name) != charts_series_.end())return false;// 定义一个折线对象QLineSeries* line_series = new QLineSeries;charts_series_[_series_name] = line_series;// 添加到QChartchart_->addSeries(line_series);// 给这条折线添加颜色line_series->setPen(_series_pen);// 设置X轴line_series->attachAxis(x_axis_);// 设置Y轴line_series->attachAxis(y_axis_);// 设置这条折线的名字line_series->setName(StdString2QString(_series_name));// 为true表示显示图例if(is_legend_)chart_->legend()->markers(line_series)[0]->setLabel(StdString2QString(_series_name));return true;
}

这是一个添加曲线的函数,我们通过实例化该类的对象调用,参数就是你要添加曲线的名字,还有你想要它是什么颜色。

图例:
在这里插入图片描述

UpdateSeries方法

bool CurveCharts::UpdateSeries(const std::string& _series_name, std::vector<QPoint> _charts_data)
{// 找不到说明没有这条曲线if (charts_series_.find(_series_name) == charts_series_.end())return false;// 这是更新,所以得把之前这条曲线的数据清空charts_series_[_series_name]->clear();// 添加曲线数据,同时将最大最小值替换for (const auto& point : _charts_data){qreal y_min = point.y() < axis_min_.y() ? point.y() : axis_min_.y();qreal y_max = point.y() > axis_max_.y() ? point.y() : axis_max_.y();qreal x_min = point.x() < axis_min_.x() ? point.x() : axis_min_.x();qreal x_max = point.x() > axis_max_.x() ? point.x() : axis_max_.x();axis_min_.setX(x_min);axis_min_.setY(y_min);axis_max_.setX(x_max);axis_max_.setY(y_max);charts_series_[_series_name]->append(point.x(), point.y());}// 如果是坐标轴自适应数据,那就通过设置坐标轴范围进行设置if (is_adaption_){SetXAxisRange(axis_min_.x(), axis_max_.x());SetYAxisRange(axis_min_.y(), axis_max_.y());}return true;
}

这是更新曲线数据,所谓更新就是把之前的清空,是新一份数据,参数是要更新的曲线名称和数据。

AppendSeriesData方法

bool CurveCharts::AppendSeriesData(const std::string& _series_name, std::vector<QPoint> _chart_data)
{if (charts_series_.find(_series_name) == charts_series_.end())return false;for (const auto& point : _chart_data){qreal y_min = point.y() < axis_min_.y() ? point.y() : axis_min_.y();qreal y_max = point.y() > axis_max_.y() ? point.y() : axis_max_.y();qreal x_min = point.x() < axis_min_.x() ? point.x() : axis_min_.x();qreal x_max = point.x() > axis_max_.x() ? point.x() : axis_max_.x();axis_min_.setX(x_min);axis_min_.setY(y_min);axis_max_.setX(x_max);axis_max_.setY(y_max);charts_series_[_series_name]->append(point.x(), point.y());}if (is_adaption_){SetXAxisRange(axis_min_.x(), axis_max_.x());SetYAxisRange(axis_min_.y(), axis_max_.y());}return true;
}

追加曲线数据,我们需要在外部给某条曲线数据追加时,和更新的区别在于更新需要清空,而追加不需要,沿用之前的数据。

SetLegendVisiable

void CurveCharts::SetLegendVisiable(const bool& _flag)
{is_legend_ = _flag;if (is_legend_){for (auto it = charts_series_.begin(); it != charts_series_.end(); it++)chart_->legend()->markers(it->second)[0]->setLabel(StdString2QString(it->first));}
}

设置是否显示图例,true表示显示,false表示不显示

SetRubberBand

void CurveCharts::SetRubberBand(const bool& _hor, const bool& _ver)
{if (_hor)chart_view_->setRubberBand(QChartView::HorizontalRubberBand);else if (_ver)chart_view_->setRubberBand(QChartView::VerticalRubberBand);
}

设置垂直缩放和水平缩放,但是这两个只能生效一个,不能同时生效。

剩下的方法就很简单,不做说明,直接贴源码。

CPP内容

#include "curve_charts.h"CurveCharts::CurveCharts(QWidget* parent): QWidget(parent), chart_view_(new QChartView), chart_(new QChart), x_axis_(new QValueAxis), y_axis_(new QValueAxis), is_adaption_(false), is_legend_(false)
{// 布局,栅格布局,把QChartView对象之间放进去,在main函数实例化对象调用show方法。QGridLayout* layout = new QGridLayout;this->setLayout(layout);layout->addWidget(chart_view_);// 窗口标题setWindowTitle(StdString2QString("曲线视图"));// 设置QChartchart_view_->setChart(chart_);// 设置X和Y坐标轴标题的显示位置,X轴标题在最小面,Y轴标题在左侧chart_->addAxis(x_axis_, Qt::AlignBottom);chart_->addAxis(y_axis_, Qt::AlignLeft);chart_view_->setRenderHint(QPainter::Antialiasing);// 初始化最小最大值,方便记录X轴和Y轴所有曲线数据的最大最小值axis_min_.setX(INT_MAX);axis_min_.setY(INT_MAX);axis_max_.setX(INT_MIN);axis_max_.setY(INT_MIN);
}CurveCharts::~CurveCharts()
{}bool CurveCharts::AddSeries(const std::string& _series_name, QPen _series_pen)
{// 如果找到了就说明这个曲线的名称已经添加过了,不能重复添加或者覆盖if (charts_series_.find(_series_name) != charts_series_.end())return false;// 定义一个折线对象QLineSeries* line_series = new QLineSeries;charts_series_[_series_name] = line_series;// 添加到QChartchart_->addSeries(line_series);// 给这条折线添加颜色line_series->setPen(_series_pen);// 设置X轴line_series->attachAxis(x_axis_);// 设置Y轴line_series->attachAxis(y_axis_);// 设置这条折线的名字line_series->setName(StdString2QString(_series_name));// 为true表示显示图例if(is_legend_)chart_->legend()->markers(line_series)[0]->setLabel(StdString2QString(_series_name));return true;
}bool CurveCharts::UpdateSeries(const std::string& _series_name, std::vector<QPoint> _charts_data)
{// 找不到说明没有这条曲线if (charts_series_.find(_series_name) == charts_series_.end())return false;// 这是更新,所以得把之前这条曲线的数据清空charts_series_[_series_name]->clear();// 添加曲线数据,同时将最大最小值替换for (const auto& point : _charts_data){qreal y_min = point.y() < axis_min_.y() ? point.y() : axis_min_.y();qreal y_max = point.y() > axis_max_.y() ? point.y() : axis_max_.y();qreal x_min = point.x() < axis_min_.x() ? point.x() : axis_min_.x();qreal x_max = point.x() > axis_max_.x() ? point.x() : axis_max_.x();axis_min_.setX(x_min);axis_min_.setY(y_min);axis_max_.setX(x_max);axis_max_.setY(y_max);charts_series_[_series_name]->append(point.x(), point.y());}// 如果是坐标轴自适应数据,那就通过设置坐标轴范围进行设置if (is_adaption_){SetXAxisRange(axis_min_.x(), axis_max_.x());SetYAxisRange(axis_min_.y(), axis_max_.y());}return true;
}bool CurveCharts::AppendSeriesData(const std::string& _series_name, std::vector<QPoint> _chart_data)
{if (charts_series_.find(_series_name) == charts_series_.end())return false;for (const auto& point : _chart_data){qreal y_min = point.y() < axis_min_.y() ? point.y() : axis_min_.y();qreal y_max = point.y() > axis_max_.y() ? point.y() : axis_max_.y();qreal x_min = point.x() < axis_min_.x() ? point.x() : axis_min_.x();qreal x_max = point.x() > axis_max_.x() ? point.x() : axis_max_.x();axis_min_.setX(x_min);axis_min_.setY(y_min);axis_max_.setX(x_max);axis_max_.setY(y_max);charts_series_[_series_name]->append(point.x(), point.y());}if (is_adaption_){SetXAxisRange(axis_min_.x(), axis_max_.x());SetYAxisRange(axis_min_.y(), axis_max_.y());}return true;
}void CurveCharts::SetTitle(const std::string& _title)
{chart_->setTitle(StdString2QString(_title));
}std::string CurveCharts::GetTitle()
{return QString2StdString(chart_->title());
}void CurveCharts::SetXAxisRange(qreal _x_min, qreal _x_max)
{x_axis_->setRange(_x_min, _x_max);
}void CurveCharts::SetYAxisRange(qreal _y_min, qreal _y_max)
{y_axis_->setRange(_y_min, _y_max);
}void CurveCharts::setAxisTitles(const std::string& _XTitle, const std::string& _YTitle)
{x_axis_->setTitleText(StdString2QString(_XTitle));y_axis_->setTitleText(StdString2QString(_YTitle));
}void CurveCharts::SetRubberBand(const bool& _hor, const bool& _ver)
{if (_hor)chart_view_->setRubberBand(QChartView::HorizontalRubberBand);else if (_ver)chart_view_->setRubberBand(QChartView::VerticalRubberBand);
}void CurveCharts::SetAxisRanges(const bool& _flag)
{is_adaption_ = _flag;
}void CurveCharts::SetLegendVisiable(const bool& _flag)
{is_legend_ = _flag;if (is_legend_){for (auto it = charts_series_.begin(); it != charts_series_.end(); it++)chart_->legend()->markers(it->second)[0]->setLabel(StdString2QString(it->first));}
}

测试函数

#include <QtWidgets/QApplication>
#include <QTimer>
#include <random>#include "curve_charts.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);CurveCharts* cure_charts = new CurveCharts;cure_charts->SetTitle("信号曲线");cure_charts->AddSeries("时域", QPen(QColor(Qt::green)));cure_charts->AddSeries("频域", QPen(QColor(Qt::red)));cure_charts->SetAxisRanges(true);cure_charts->SetLegendVisiable(true);cure_charts->SetRubberBand(true, false);cure_charts->setAxisTitles("时间", "幅度");int x = 0;QTimer timer;timer.setInterval(1000); // 设置定时间隔QObject::connect(&timer, &QTimer::timeout, [&]() {std::random_device rd;  // 随机设备,用于产生随机数种子std::mt19937 gen(rd()); // 使用随机设备的随机数引擎std::uniform_int_distribution<int> dist(0, 100); // 定义随机数分布范围为 [0, 100]std::vector<QPoint> temp1;std::vector<QPoint> temp2;int randomNumber1 = dist(gen);int randomNumber2 = dist(gen);QPoint point;point.setX(x);point.setY(randomNumber1);temp1.emplace_back(point);point.setY(randomNumber2);temp2.emplace_back(point);cure_charts->AppendSeriesData("时域", temp1);cure_charts->AppendSeriesData("频域", temp2);x++;});timer.start();cure_charts->show();return a.exec();
}

在测试代码中,我们添加了两条曲线,定义了一个定时器,间隔为1秒,每次产生两个0~100的随机值代表两条曲线的Y值,X值是时间。

另外,QChart支持设置背景色、十字线之类的效果,可以自己div。

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

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

相关文章

淘宝详情api(获取主图)2023年11月20日最新版本

返回数据格式&#xff1a; 请求链接 {"item": {"apiStack": [{"name": "esi","value": "{\"delivery\": {\"from\": \"福建莆田\", \"to\": \"全国\", \"com…

酒糟废水处理设备有哪些

酒糟废水处理设备有以下几种&#xff1a; 格栅&#xff1a;用于拦截大颗粒悬浮物&#xff0c;以保护后续处理设备。调节池&#xff1a;用于调节水质和水量&#xff0c;使废水在处理过程中保持稳定。混凝反应池&#xff1a;通过添加混凝剂&#xff0c;使废水中的小颗粒悬浮物凝…

2023年中国吞咽神经和肌肉电刺激仪市场发展趋势分析:产品需求持续增长[图]

吞咽神经和肌肉电刺激仪是通过输出特定的低频脉冲电流对吞咽及构音功能相关的神经和肌肉进行电刺激&#xff0c;改善吞咽、构音肌群的收缩运动功能&#xff0c;缓解神经元麻痹&#xff0c;促进吞咽反射弧的重建与恢复&#xff0c;进而提高患者的吞咽及语言能力。 吞咽神经和肌…

如何定位el-tree中的树节点当父元素滚动时如何定位子元素

使用到的方法 Element 接口的 scrollIntoView() 方法会滚动元素的父容器&#xff0c;使被调用 scrollIntoView() 的元素对用户可见。 参数 alignToTop可选 一个布尔值&#xff1a; 如果为 true&#xff0c;元素的顶端将和其所在滚动区的可视区域的顶端对齐。相应的 scrollIntoV…

axios升级依赖版本后报错SyntaxError: Cannot use import statement outside a module

Axios构建为ES模块&#xff0c;而不是在Node中运行时的CommonJs。Jest的问题是它在Node中运行代码。这就是为什么告诉Jest转换Axios有效的原因。 Axios SDK附带了一个用于Node env的内置CommonJs文件。因此&#xff0c;我们可以通过将以下内容添加到您的package.json来修复它&a…

一步一步教你如何在Windows 10上使用Java,包括下载、安装和配置等

Java开发工具包(JDK)是用于Java编程的软件,与Java虚拟机(JVM)和Java运行时环境(JRE)一起使用。JDK包括编译器和类库,允许开发人员创建可由JVM和JRE执行的Java程序。 在本教程中,你将学习在Windows上安装Java开发工具包。 检查是否安装了Java 在安装Java开发工具包之…

CentOS安装nodejs

查看可安装的版本 dnf module list nodejs选择需要版本安装 dnf module install nodejs:<stream>查看版本

2023年中国地产SaaS分类、产业链及市场规模分析[图]

SaaS是一种基于云计算技术&#xff0c;通过订阅的方式向互联网向客户提供访问权限以获取计算资源的一项软件即服务。地产SaaS则是SaaS的具体应用&#xff0c;提供了一个线上平台&#xff0c;用于协助房地产供应商与购房者、建筑承建商、材料供应商及房地产资产管理公司之间的协…

性能压力测试的优势与重要性

性能压力测试是软件开发过程中至关重要的一环&#xff0c;它通过模拟系统在极限条件下的运行&#xff0c;以评估系统在正常和异常负载下的表现。这种测试为确保软件系统的可靠性、稳定性和可伸缩性提供了关键信息。下面将探讨性能压力测试的优势以及为什么在软件开发中它具有不…

vue安装three.js并创建第一个入门场景

vue安装three.js&#xff0c;并创建第一个入门场景 安装three.js npm install --save three引入three.js import * as THREE from threethree.js结构 three.js坐标 创建一个场景 scene场景&#xff0c;camera相机&#xff0c;renderer渲染器 创建一个场景 this.scene new T…

定时关机软件哪个好?定时关机软件大盘点

在生活和工作中&#xff0c;我们可以使用定时关机软件来定时关闭电脑&#xff0c;以实现对电脑的控制。那么&#xff0c;定时关机软件哪个好呢&#xff1f;下面我们就来了解一下。 定时关机软件的作用 定时关机软件可以帮助用户在预设的时间自动关闭电脑。这对于那些需要在特…

Excel筛选怎么用?6种基本用法帮你提高效率!

“我在使用Excel进行数据处理时&#xff0c;需要对某些数据进行筛选&#xff0c;但是不知道应该如何使用筛选功能&#xff0c;有没有比较简单的使用方法呀&#xff1f;” Excel中的筛选功能是数据处理和分析中的重要工具&#xff0c;能够帮助用户快速找到所需的数据。但是有很多…

IDEA 中设置 File Header 以及自定义类、方法注释模板的方法

目录 1 设置 File Header2 自定义类、方法注释生成类注解模板生成方法注解模板 1 设置 File Header File -> Settings -> File and Code Templates -> Includes -> File Header -> 编辑 2 自定义类、方法注释 File -> Settings -> Live Templates -&g…

squid代理服务器

ginx也可以代理&#xff1a;反向代理 ---- 负载均衡&#xff1b;nginx也可以缓存&#xff0c;但是无法做正向代理&#xff08;proxy_pass 反向代理&#xff09; squid正向代理服务器【VPN】 squid作用&#xff1a;正向代理&#xff0c;可以缓存加速&#xff0c;基于ACL协议可以…

云端援手:智能枢纽应对数字资产挑战 ——华为云11.11应用集成管理与创新专区优惠限时购

现新客3.96元起&#xff0c;下单有机会抽HUAWEI P60 Art 福利仅限双十一 机会唾手可得&#xff0c;立即行动&#xff01; 「有效管理保护应用与数据的同时实现高效互通」——华为云全力满足企业需求&#xff0c;推出全套「应用集成管理与创新」智能解决方案&#xff1a;华为云…

锐捷OSPF认证

一、知识补充 1、基本概述 OSPF区域认证和端口认证是两种不同的认证机制&#xff0c;用于增强OSPF协议的安全性。 OSPF区域认证&#xff08;OSPF Area Authentication&#xff09;&#xff1a;这种认证机制是基于区域的。在OSPF网络中&#xff0c;每个区域都可以配置一个区域…

大学生如何免费认证,下载,安装MATLAB

下载 打开学校图书馆官网 选择版本后&#xff0c;点击下载 注册绑定个人认证 前提&#xff01;需要有学校邮箱【以edu.cn结尾的】 进入mathworks官网 注册账户 安装 下载完后&#xff0c;打开 选择&#xff1a;setup 安装程序 勾选&#xff1a;是&#xff1b;选择&#xf…

2023年中国温热电灸综合治疗仪发展趋势分析:产品渗透率将进一步增长[图]

温热电灸综合治疗仪是传统中医针灸结合现代低频脉冲电刺激和电加热的一款现代化电针灸治疗仪器。其基于传统的艾灸原理及现代神经和肌肉电刺激原理&#xff0c;通过电子加热和磁化作用&#xff0c;充分利用艾草及其它特效药材精炼的高效成分&#xff0c;同时对人体多个穴位进行…

Ultipa Transporter V4.3.22 即将发布,解锁更多易用功能!

Ultipa Graph 作为一款领先的实时图数据库分析平台&#xff0c;即将发布最新版的数据导入/导出工具Ultipa Transporter V4.3.22 以实现对 Neo4j数据源的导入支持。自今年以来&#xff0c;Ultipa Transporter不断增加新功能&#xff0c;除原本支持本地CSV文件导入导出外&#xf…

MR素数测试及 pycryptodome库下 已知MR伪素数以及强伪证 生成指定伪随机数生成器绕过素性检测

MR素数测试在密码学库中应用广泛&#xff0c;通常作为BSPW的一部分来进行素数测试&#xff0c;由于在其算法中&#xff0c;有随机数的使用&#xff08;选择一个随机的base&#xff09;&#xff0c;若一个MR伪素数 n n n&#xff0c;已知其在某一个强伪证 a a a&#xff08;随机…