├── lib └── Graph.lib ├── projects ├── Test │ ├── res │ │ └── Test.qrc │ ├── src │ │ ├── main_window.cpp │ │ ├── main.cpp │ │ ├── main_window.h │ │ └── main_window.ui │ ├── Test.vcxproj.filters │ └── Test.vcxproj └── Graph │ ├── src │ ├── chart │ │ ├── axis_config.cpp │ │ ├── chart_config.cpp │ │ ├── series_config.cpp │ │ ├── axis_config.h │ │ ├── series_config.h │ │ ├── chart_config.h │ │ ├── series_config.ui │ │ ├── table.h │ │ ├── color_plot.h │ │ ├── line_plot.h │ │ ├── pie_plot.h │ │ ├── scatter_plot.h │ │ ├── tool_tip.h │ │ ├── density_plot.h │ │ ├── pareto_plot.h │ │ ├── bar_plot.h │ │ ├── color_bar.h │ │ ├── stock_plot.h │ │ ├── radial_plot.h │ │ ├── qq_plot.h │ │ ├── probability_plot.h │ │ ├── plot.h │ │ ├── pie_plot.cpp │ │ ├── histogram_plot.h │ │ ├── interval_plot.h │ │ ├── boxbar_plot.h │ │ ├── chart_view.h │ │ ├── bar_plot.cpp │ │ ├── radar_plot.h │ │ ├── data.h │ │ ├── radial_plot..cpp │ │ ├── line_plot.cpp │ │ ├── waterfall_plot.h │ │ ├── scatter_plot.cpp │ │ ├── color_plot.cpp │ │ ├── table.cpp │ │ ├── density_plot.cpp │ │ ├── pareto_plot.cpp │ │ ├── SizeGripItem.h │ │ ├── plot.cpp │ │ ├── interval_plot.cpp │ │ ├── radar_plot.cpp │ │ ├── boxbar_plot.cpp │ │ ├── qq_plot.cpp │ │ ├── tool_tip.cpp │ │ ├── probability_plot.cpp │ │ ├── waterfall_plot.cpp │ │ ├── histogram_plot.cpp │ │ ├── stock_plot.cpp │ │ ├── SizeGripItem.cpp │ │ ├── color_bar.cpp │ │ ├── chart_view.cpp │ │ └── chart_config.ui │ ├── graph_global.h │ ├── util │ │ ├── math_define.h │ │ ├── util.h │ │ └── util.cpp │ └── graph │ │ ├── graphics_item.cpp │ │ ├── graphics_item.h │ │ ├── poly_line.h │ │ ├── poly_line_preview.h │ │ ├── chart_view_preview.h │ │ ├── poly_line_preview.cpp │ │ ├── chart_view_preview.cpp │ │ └── poly_line.cpp │ ├── Graph.vcxproj.filters │ └── Graph.vcxproj ├── Chart.sln ├── README.md ├── .gitattributes └── .gitignore /lib/Graph.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haomehaode/QtChart/HEAD/lib/Graph.lib -------------------------------------------------------------------------------- /projects/Test/res/Test.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/Test/src/main_window.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haomehaode/QtChart/HEAD/projects/Test/src/main_window.cpp -------------------------------------------------------------------------------- /projects/Test/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main_window.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.showMaximized(); 9 | return a.exec(); 10 | } 11 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/axis_config.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "axis_config.h" 4 | 5 | AxisConfig::AxisConfig(QWidget *parent) 6 | : QDialog(parent) 7 | { 8 | ui.setupUi(this); 9 | } 10 | 11 | AxisConfig::~AxisConfig() 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/chart_config.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "chart_config.h" 4 | 5 | ChartConfig::ChartConfig(QWidget *parent) 6 | : QDialog(parent) 7 | { 8 | ui.setupUi(this); 9 | } 10 | 11 | ChartConfig::~ChartConfig() 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/series_config.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "series_config.h" 4 | 5 | SeriesConfig::SeriesConfig(QWidget *parent) 6 | : QDialog(parent) 7 | { 8 | ui.setupUi(this); 9 | } 10 | 11 | SeriesConfig::~SeriesConfig() 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /projects/Graph/src/graph_global.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPH_GLOBAL_H 2 | #define GRAPH_GLOBAL_H 3 | 4 | #include 5 | 6 | #ifndef BUILD_STATIC 7 | # if defined(GRAPH_LIB) 8 | # define GRAPH_EXPORT Q_DECL_EXPORT 9 | # else 10 | # define GRAPH_EXPORT Q_DECL_IMPORT 11 | # endif 12 | #else 13 | # define GRAPH_EXPORT 14 | #endif 15 | 16 | #endif // GRAPH_GLOBAL_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/axis_config.h: -------------------------------------------------------------------------------- 1 | #ifndef AXIS_CONFIG_H 2 | #define AXIS_CONFIG_H 3 | 4 | #include 5 | #include "ui_axis_config.h" 6 | 7 | class AxisConfig : public QDialog 8 | { 9 | Q_OBJECT 10 | 11 | public: 12 | AxisConfig(QWidget *parent = Q_NULLPTR); 13 | ~AxisConfig(); 14 | 15 | private: 16 | Ui::AxisConfig ui; 17 | }; 18 | 19 | #endif // AXIS_CONFIG_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/series_config.h: -------------------------------------------------------------------------------- 1 | #ifndef SERIES_CONFIG_H 2 | #define SERIES_CONFIG_H 3 | 4 | #include 5 | #include "ui_series_config.h" 6 | 7 | class SeriesConfig : public QDialog 8 | { 9 | Q_OBJECT 10 | 11 | public: 12 | SeriesConfig(QWidget *parent = Q_NULLPTR); 13 | ~SeriesConfig(); 14 | 15 | private: 16 | Ui::SeriesConfig ui; 17 | }; 18 | 19 | #endif // SERIES_CONFIG_H -------------------------------------------------------------------------------- /projects/Graph/src/util/math_define.h: -------------------------------------------------------------------------------- 1 | #ifndef MATH_DEFINE_H 2 | #define MATH_DEFINE_H 3 | 4 | /** Π 和 2Π */ 5 | #define PI 3.141592653589793 6 | #define PIx2 6.283185307179586 7 | 8 | /** 公差,作为临界值 */ 9 | #define TOLERANCE 1.0e-5 10 | 11 | /** 一弧度等于多少度 */ 12 | #define ARAD 57.29577951308232 13 | 14 | /** 一度等于多少弧度 */ 15 | #define ADEGREE 0.0174532925199433 16 | 17 | #endif // MATH_DEFINE_H 18 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/chart_config.h: -------------------------------------------------------------------------------- 1 | #ifndef CHART_CONFIG_H 2 | #define CHART_CONFIG_H 3 | 4 | #include 5 | #include "ui_chart_config.h" 6 | #include "graph_global.h" 7 | 8 | class GRAPH_EXPORT ChartConfig : public QDialog 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | ChartConfig(QWidget *parent = Q_NULLPTR); 14 | ~ChartConfig(); 15 | 16 | private: 17 | Ui::ChartConfig ui; 18 | }; 19 | 20 | #endif // CHART_CONFIG_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/series_config.ui: -------------------------------------------------------------------------------- 1 | 2 | SeriesConfig 3 | 4 | 5 | SeriesConfig 6 | 7 | 8 | 9 | 0 10 | 0 11 | 400 12 | 300 13 | 14 | 15 | 16 | SeriesConfig 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /projects/Graph/src/graph/graphics_item.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "graphics_item.h" 4 | #include "chart_view.h" 5 | 6 | GraphicsItem::GraphicsItem() 7 | { 8 | 9 | } 10 | 11 | void GraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) 12 | { 13 | apply(); 14 | painter->setRenderHint(QPainter::Antialiasing, true); 15 | on_paint(painter); 16 | } 17 | 18 | void GraphicsItem::apply() 19 | { 20 | on_apply(); 21 | } 22 | 23 | void GraphicsItem::set_view(ChartView* view) 24 | { 25 | m_view = view; 26 | } 27 | 28 | ChartView* GraphicsItem::view() 29 | { 30 | return m_view; 31 | } 32 | 33 | QRectF GraphicsItem::boundingRect() const 34 | { 35 | return QRectF(0, 0, 1, 1); 36 | } 37 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/table.h: -------------------------------------------------------------------------------- 1 | #ifndef TABLE_H 2 | #define TABLE_H 3 | 4 | #include "graph_global.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class GRAPH_EXPORT Table : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | 16 | Table(QWidget* parent = nullptr); 17 | 18 | ~Table(); 19 | 20 | public: 21 | 22 | void add_data(QList& list, const QString& name); 23 | 24 | void add_data(QList& list, const QString& name); 25 | 26 | void add_data(QList& list, const QString& name); 27 | 28 | void delete_data(const QString& name); 29 | 30 | private: 31 | 32 | QTableWidget* m_table = nullptr; 33 | 34 | QStringList m_head_list; 35 | 36 | }; 37 | 38 | #endif // TABLE_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/color_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef COLOR_PLOT_H 2 | #define COLOR_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include "data.h" 7 | #include 8 | #include 9 | 10 | class ColorBar; 11 | 12 | class GRAPH_EXPORT ColorPlot : public Plot 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | 18 | ColorPlot(QWidget* parent = nullptr); 19 | 20 | ~ColorPlot(); 21 | 22 | public: 23 | 24 | void set_data(QList& value_list); 25 | 26 | void clear_data(); 27 | 28 | virtual void init_chart() override; 29 | 30 | virtual void init_axis() override; 31 | 32 | virtual void init_series() override; 33 | 34 | private: 35 | /** 颜色条 */ 36 | ColorBar* m_color_item = nullptr; 37 | /** X 轴 */ 38 | QValueAxis* m_axisX = nullptr; 39 | /** Y 轴 */ 40 | QValueAxis* m_axisY = nullptr; 41 | /** Z 值和散点 */ 42 | QMap value2series; 43 | }; 44 | 45 | #endif // COLOR_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/line_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef LINE_PLOT_H 2 | #define LINE_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include 7 | #include 8 | #include 9 | 10 | class GRAPH_EXPORT LinePlot : public Plot 11 | { 12 | 13 | public: 14 | 15 | LinePlot(QWidget *parent = Q_NULLPTR); 16 | 17 | ~LinePlot(); 18 | 19 | public: 20 | 21 | void add_line(QList& poslist, const QString &name ); 22 | 23 | void delete_line(const QString& name); 24 | 25 | virtual void init_chart() override; 26 | 27 | virtual void init_axis() override; 28 | 29 | virtual void init_series() override; 30 | 31 | 32 | private: 33 | /** 数据计算 */ 34 | void prepare_data(QList& poslist); 35 | 36 | private: 37 | /** 名称和系列映射 */ 38 | QMap m_name2series; 39 | /** X 轴 */ 40 | QValueAxis* m_axisX = nullptr; 41 | /** Y 轴 */ 42 | QValueAxis* m_axisY = nullptr; 43 | /** 记录坐标轴范围 */ 44 | QStack m_range[4]; 45 | }; 46 | 47 | #endif // LINE_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/pie_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef PIE_PLOT_H 2 | #define PIE_PLOT_H 3 | 4 | #include "graph_global.h" 5 | #include "plot.h" 6 | #include "data.h" 7 | #include 8 | #include 9 | 10 | 11 | class GRAPH_EXPORT PiePlot : public Plot 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | 17 | PiePlot(QWidget* parent = nullptr); 18 | 19 | ~PiePlot(); 20 | 21 | public slots: 22 | /** 鼠标提示 */ 23 | virtual void slot_tool_tip(QPieSlice* slice, bool state); 24 | 25 | public: 26 | 27 | void set_data(QList& valuelist); 28 | 29 | void add_pie(double value, const QString& name); 30 | 31 | void delete_pie(const QString& name); 32 | 33 | virtual void init_chart() override; 34 | 35 | virtual void init_axis() override; 36 | 37 | virtual void init_series() override; 38 | 39 | private: 40 | 41 | void update_label(); 42 | 43 | private: 44 | /** 名称和系列映射 */ 45 | QMap m_name2series; 46 | 47 | QPieSeries* m_series = nullptr; 48 | 49 | }; 50 | 51 | #endif // PIE_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/scatter_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef SCATTER_PLOT_H 2 | #define SCATTER_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include 7 | #include 8 | #include 9 | 10 | class GRAPH_EXPORT ScatterPlot: public Plot 11 | { 12 | 13 | public: 14 | 15 | ScatterPlot(QWidget* parent = nullptr); 16 | 17 | ~ScatterPlot(); 18 | 19 | public: 20 | 21 | void add_scatter(QList& poslist, const QString& name); 22 | 23 | void delete_scatter(const QString& name); 24 | 25 | virtual void init_chart() override; 26 | 27 | virtual void init_axis() override; 28 | 29 | virtual void init_series() override; 30 | 31 | private: 32 | /** 数据计算 */ 33 | void prepare_data(QList& poslist); 34 | 35 | private: 36 | /** 名称和系列映射 */ 37 | QMap m_name2series; 38 | /** X 轴 */ 39 | QValueAxis* m_axisX = nullptr; 40 | /** Y 轴 */ 41 | QValueAxis* m_axisY = nullptr; 42 | /** 记录坐标轴范围 */ 43 | QStack m_range[4]; 44 | }; 45 | 46 | #endif // SCATTER_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/graph/graphics_item.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHICS_ITEM_H 2 | #define GRAPHICS_ITEM_H 3 | 4 | #include "QGraphicsItem" 5 | #include "graph_global.h" 6 | 7 | class ChartView; 8 | 9 | class GRAPH_EXPORT GraphicsItem : public QGraphicsObject 10 | { 11 | public: 12 | /** 构造函数 */ 13 | GraphicsItem(); 14 | /** 设置所属视图 */ 15 | void set_view(ChartView* view); 16 | /** 获取所属视图 */ 17 | ChartView* view(); 18 | /** 19 | * 图元数据变更时可手动调用该接口以应用新的数据, 20 | * 图元绘制前会自动调用该接口以便显示正确的形状。 21 | */ 22 | void apply(); 23 | 24 | protected: 25 | /** 绘图区域 */ 26 | virtual QRectF boundingRect() const override; 27 | /** 绘图函数 */ 28 | virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; 29 | /** 克隆,由子类实现 */ 30 | virtual GraphicsItem* clone() { return nullptr; } 31 | /** 数据更新计算包围盒,由子类实现 */ 32 | virtual void on_apply() {} 33 | /** 绘制图像,由子类实现 */ 34 | virtual void on_paint(QPainter* painter) {} 35 | 36 | private: 37 | /** 所属视图 */ 38 | ChartView* m_view = nullptr; 39 | }; 40 | 41 | #endif // GRAPHICS_ITEM_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/tool_tip.h: -------------------------------------------------------------------------------- 1 | #ifndef TOOL_TIP_H 2 | #define TOOL_TIP_H 3 | 4 | #include "graph_global.h" 5 | #include 6 | #include 7 | 8 | using namespace QtCharts; 9 | 10 | class QGraphicsSceneMouseEvent; 11 | 12 | class GRAPH_EXPORT ToolTip : public QGraphicsItem 13 | { 14 | 15 | public: 16 | 17 | ToolTip(QChart* chart, QWidget* parent = nullptr); 18 | 19 | ~ToolTip(); 20 | 21 | void setText(const QString& text); 22 | 23 | void setAnchor(QPointF point); 24 | 25 | void updateGeometry(); 26 | 27 | QRectF boundingRect() const; 28 | 29 | void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget); 30 | 31 | protected: 32 | 33 | void mousePressEvent(QGraphicsSceneMouseEvent* event); 34 | 35 | void mouseMoveEvent(QGraphicsSceneMouseEvent* event); 36 | 37 | private: 38 | 39 | QString m_text; 40 | 41 | QRectF m_textRect; 42 | 43 | QRectF m_rect; 44 | 45 | QPointF m_anchor; 46 | 47 | QFont m_font; 48 | 49 | QChart* m_chart = nullptr; 50 | 51 | QWidget* m_widget = nullptr; 52 | }; 53 | 54 | #endif // TOOL_TIP_H -------------------------------------------------------------------------------- /projects/Test/Test.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {d43ef1c5-b190-43e0-940d-64f79ea661cc} 6 | 7 | 8 | {3cc5815c-1f83-4006-a37e-4d20fdc44e63} 9 | 10 | 11 | 12 | 13 | res 14 | 15 | 16 | 17 | 18 | src 19 | 20 | 21 | src 22 | 23 | 24 | 25 | 26 | src 27 | 28 | 29 | 30 | 31 | src 32 | 33 | 34 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/density_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef DENSITY_PLOT_H 2 | #define DENSITY_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include "data.h" 7 | #include 8 | #include 9 | 10 | class ColorBar; 11 | 12 | class GRAPH_EXPORT DensityPlot : public Plot 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | 18 | DensityPlot(QWidget* parent = nullptr); 19 | 20 | ~DensityPlot(); 21 | 22 | public: 23 | 24 | void set_data(QList& pos_list); 25 | 26 | void clear_data(); 27 | 28 | virtual void init_chart() override; 29 | 30 | virtual void init_axis() override; 31 | 32 | virtual void init_series() override; 33 | 34 | private: 35 | 36 | double squareDistance(DensityPoint a, DensityPoint b); 37 | 38 | void calculateDensity(QVector& dataset, float Eps); 39 | 40 | 41 | private: 42 | /** 颜色条 */ 43 | ColorBar* m_color_item = nullptr; 44 | /** X 轴 */ 45 | QValueAxis* m_axisX = nullptr; 46 | /** Y 轴 */ 47 | QValueAxis* m_axisY = nullptr; 48 | /** 密度值和散点 */ 49 | QMap value2series; 50 | /** 密度半径 */ 51 | double radius = 1; 52 | }; 53 | 54 | #endif // DENSITY_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/graph/poly_line.h: -------------------------------------------------------------------------------- 1 | #ifndef POLY_LINE_H 2 | #define POLY_LINE_H 3 | 4 | #include "chart_view.h" 5 | #include "graphics_item.h" 6 | 7 | /////////////////////////////////////////////////////////////////////////////// 8 | //多段线 9 | class PolyLine : public GraphicsItem 10 | { 11 | public: 12 | 13 | PolyLine(); 14 | 15 | public: 16 | 17 | QList get_points() const; 18 | 19 | void set_points(const QList& points); 20 | 21 | void append_point(const QPointF& point); 22 | 23 | QPointF get_last_point() const; 24 | 25 | void set_last_point(const QPointF& point); 26 | 27 | virtual GraphicsItem* clone() override; 28 | 29 | protected: 30 | 31 | QRectF boundingRect() const override; 32 | 33 | void on_paint(QPainter* painter) override; 34 | 35 | protected: 36 | 37 | QList m_points; 38 | 39 | }; 40 | 41 | /////////////////////////////////////////////////////////////////////////////// 42 | //箭头线 43 | class Arrows : public PolyLine 44 | { 45 | public: 46 | 47 | Arrows(); 48 | 49 | virtual GraphicsItem* clone() override; 50 | 51 | protected: 52 | 53 | void on_paint(QPainter* painter) override; 54 | }; 55 | 56 | 57 | #endif // POLY_LINE_H 58 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/pareto_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef PARETO_PLOT_H 2 | #define PARETO_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include "data.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class GRAPH_EXPORT ParetoPlot : public Plot 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | 20 | ParetoPlot(QWidget *parent=nullptr); 21 | 22 | ~ParetoPlot(); 23 | 24 | public: 25 | 26 | void set_data(QList& value_list); 27 | 28 | void clear_data(); 29 | 30 | virtual void init_chart() override; 31 | 32 | virtual void init_axis() override; 33 | 34 | virtual void init_series() override; 35 | 36 | private: 37 | /** 数据计算 */ 38 | QList& prepare_data(QList& value_list); 39 | 40 | private: 41 | 42 | QBarCategoryAxis* m_axisX = nullptr; 43 | 44 | QValueAxis* m_axisY_1 = nullptr; 45 | 46 | QValueAxis* m_axisY_2 = nullptr; 47 | 48 | QBarSeries* m_bar = nullptr; 49 | 50 | QBarSet* m_set = nullptr; 51 | 52 | QLineSeries* m_line = nullptr; 53 | 54 | QScatterSeries* m_scatter = nullptr; 55 | 56 | QStringList m_axisy_list; 57 | }; 58 | 59 | #endif // PARETO_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/bar_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef BAR_PLOT_H 2 | #define BAR_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include "data.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class GRAPH_EXPORT BarPlot : public Plot 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | 20 | BarPlot(QWidget* parent = nullptr); 21 | 22 | ~BarPlot(); 23 | 24 | public: 25 | 26 | void set_axis(QList list); 27 | 28 | void add_bar(QList& value_list, const QString& name); 29 | 30 | void delete_bar(const QString& name); 31 | 32 | virtual void init_chart() override; 33 | 34 | virtual void init_axis() override; 35 | 36 | virtual void init_series() override; 37 | 38 | 39 | private: 40 | /** 数据计算 */ 41 | void prepare_data(QList& value_list); 42 | 43 | private: 44 | /** 名称和系列映射 */ 45 | QMap m_name2series; 46 | 47 | QBarSeries* m_series = nullptr; 48 | /** X 轴刻度集合 */ 49 | QStringList m_axisx_list; 50 | /** X 轴 */ 51 | QBarCategoryAxis* m_axisX =nullptr; 52 | /** Y 轴 */ 53 | QValueAxis* m_axisY = nullptr; 54 | /** 记录坐标轴范围 */ 55 | QStack m_range[2]; 56 | 57 | }; 58 | 59 | #endif // BAR_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/color_bar.h: -------------------------------------------------------------------------------- 1 | #ifndef COLOR_BAR_H 2 | #define COLOR_BAR_H 3 | 4 | #include "chart_view.h" 5 | #include "graphics_item.h" 6 | #include 7 | 8 | enum ColorBarType 9 | { 10 | Gray, 11 | Jet, 12 | Hsv, 13 | Hot 14 | }; 15 | 16 | enum LocationType 17 | { 18 | Top, 19 | Bottom, 20 | Left, 21 | Right 22 | }; 23 | 24 | class ColorBar : public GraphicsItem 25 | { 26 | 27 | public: 28 | 29 | ColorBar(); 30 | 31 | void set_dock_area(LocationType area); 32 | 33 | void set_value_range(double min, double max); 34 | 35 | QColor getColor(double value); 36 | 37 | void set_chart(QChart* chart); 38 | 39 | void set_type(ColorBarType type); 40 | 41 | protected: 42 | 43 | QRectF boundingRect() const override; 44 | 45 | void on_paint(QPainter* painter) override; 46 | 47 | void draw_color_bar(QPainter* painter, QRectF rect); 48 | 49 | void draw_color_title(QPainter* painter, QRectF rect); 50 | 51 | void init_colors(); 52 | 53 | private: 54 | 55 | LocationType m_area = Right; 56 | 57 | double m_min = 0; 58 | 59 | double m_max = 100; 60 | 61 | QVector gray_colors; 62 | 63 | QVector jet_colors; 64 | 65 | QVector hsv_colors; 66 | 67 | QVector hot_colors; 68 | 69 | QChart* m_chart = nullptr; 70 | 71 | ColorBarType m_type = Jet; 72 | }; 73 | 74 | #endif // COLOR_BAR_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/stock_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef STOCK_PLOT_H 2 | #define STOCK_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include "data.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class GRAPH_EXPORT StockPlot : public Plot 16 | { 17 | 18 | public: 19 | 20 | StockPlot(QWidget* parent = nullptr); 21 | 22 | ~StockPlot(); 23 | 24 | public slots: 25 | /** 鼠标提示 */ 26 | virtual void slot_tool_tip(bool status, QCandlestickSet* set); 27 | 28 | public: 29 | 30 | void add_stock(QList& data_list, const QString& name); 31 | 32 | void delete_stock(const QString& name); 33 | 34 | virtual void init_chart() override; 35 | 36 | virtual void init_axis() override; 37 | 38 | virtual void init_series() override; 39 | 40 | 41 | private: 42 | /** 数据计算 */ 43 | void prepare_data(QList& data_list); 44 | 45 | private: 46 | /** 名称和系列映射 */ 47 | QMap m_name2series; 48 | /** X 轴 */ 49 | QBarCategoryAxis* m_axisX = nullptr; 50 | /** Y 轴 */ 51 | QValueAxis* m_axisY = nullptr; 52 | /** 记录坐标轴范围 */ 53 | QStack m_range[4]; 54 | /** X 轴时间 */ 55 | QStringList m_axisx_list; 56 | }; 57 | 58 | #endif // STOCK_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/graph/poly_line_preview.h: -------------------------------------------------------------------------------- 1 | #ifndef POLYLINE_PREVIEW_H 2 | #define POLYLINE_PREVIEW_H 3 | 4 | #include "chart_view_preview.h" 5 | 6 | class PolyLine; 7 | class ChartView; 8 | 9 | //多段线预览类 10 | class PolyLinePreview : public ChartViewPreview 11 | { 12 | public: 13 | PolyLinePreview(ChartView* view); 14 | 15 | protected: 16 | /** 17 | * \brief 绘制进度推进 18 | * @param point 鼠标在场景的坐标 19 | */ 20 | void on_advance_preview(QPointF& point) override; 21 | 22 | /** 完成图元绘制 */ 23 | void on_finish_preview() override; 24 | 25 | /** 鼠标在图元所在的图形视图窗口中移动 */ 26 | void on_mouse_move(QPointF& point) override; 27 | 28 | virtual PolyLine* new_polyline(); 29 | 30 | private: 31 | /** 32 | * \brief 完成步骤操作 33 | * @param step 步骤 34 | * @param point 鼠标在场景的位置 35 | */ 36 | void confirm_step(int step, QPointF& point); 37 | 38 | protected: 39 | enum StepType 40 | { 41 | START_POINT, //第一个点 42 | NEXT_POINT //后续的点 43 | }; 44 | 45 | PolyLine* m_pPolyLine = nullptr; 46 | QPointF m_last_confirm_point; 47 | }; 48 | 49 | /////////////////////////////////////////////////////////////////////////////// 50 | //箭头线预览类 51 | class ArrowsPreview : public PolyLinePreview 52 | { 53 | 54 | public: 55 | 56 | ArrowsPreview(ChartView* view); 57 | 58 | private: 59 | 60 | PolyLine* new_polyline() override; 61 | }; 62 | 63 | 64 | #endif //!POLYLINE_PREVIEW_H 65 | 66 | 67 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/radial_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef RADIAL_PLOT_H 2 | #define RADIAL_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "data.h" 6 | #include "graph_global.h" 7 | #include 8 | #include 9 | 10 | class GRAPH_EXPORT RadialPlot : public Plot 11 | { 12 | struct RadialData 13 | { 14 | RadialData(QString name,double value, QPieSeries* pie) 15 | { 16 | m_name = name; 17 | m_value = value; 18 | m_pie = pie; 19 | }; 20 | QString m_name; 21 | double m_value; 22 | QPieSeries* m_pie; 23 | }; 24 | 25 | public: 26 | 27 | RadialPlot(QWidget* parent = nullptr); 28 | 29 | ~RadialPlot(); 30 | 31 | public slots: 32 | /** 鼠标提示 */ 33 | virtual void slot_tool_tip(QPieSlice* slice, bool state); 34 | 35 | private: 36 | 37 | void update_location(); 38 | 39 | public: 40 | 41 | void set_data(QList& valuelist); 42 | 43 | void add_pie(double value, const QString& name); 44 | 45 | void delete_pie(const QString& name); 46 | 47 | virtual void init_chart() override; 48 | 49 | virtual void init_axis() override; 50 | 51 | virtual void init_series() override; 52 | 53 | private: 54 | 55 | QList m_pie_series; 56 | 57 | QPieSeries* m_series = nullptr; 58 | /** 中心圆圈大小 */ 59 | double m_radial_min = 0.25; 60 | /** 外围圆圈大小 */ 61 | double m_radial_max = 0.85; 62 | /** 径向长度 */ 63 | double m_radial_length = 0.6; 64 | 65 | }; 66 | 67 | #endif // RADIAL_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/qq_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef QQ_PLOT_H 2 | #define QQ_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "data.h" 11 | 12 | class GRAPH_EXPORT QQPlot : public Plot 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | 18 | QQPlot(QWidget* parent = nullptr); 19 | 20 | ~QQPlot(); 21 | 22 | public slots: 23 | 24 | void slot_tool_tip(QPointF point, bool state) override; 25 | 26 | public: 27 | 28 | void add_data(QList& list, const QString& name); 29 | 30 | virtual void init_chart() override; 31 | 32 | virtual void init_axis() override; 33 | 34 | virtual void init_series() override; 35 | 36 | private: 37 | /** 数据计算 */ 38 | void prepare_data(QList& list); 39 | /** 理论CDF */ 40 | double calculate_cdf(int index, int n); 41 | 42 | private: 43 | /** 平均值 */ 44 | double m_mean; 45 | /** 方差 */ 46 | double m_variance; 47 | /** 标准差 */ 48 | double m_sigma; 49 | /** 样本数 */ 50 | int m_n; 51 | 52 | private: 53 | 54 | QLineSeries* m_line_center = nullptr; 55 | 56 | QLineSeries* m_line_top = nullptr; 57 | 58 | QLineSeries* m_line_bottom = nullptr; 59 | 60 | QScatterSeries* m_scatter = nullptr; 61 | 62 | QValueAxis* m_axisX = nullptr; 63 | 64 | QValueAxis* m_axisY = nullptr; 65 | 66 | QList m_probability_list; 67 | 68 | ScoreType m_score_type = Benard; 69 | }; 70 | 71 | #endif // QQ_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/probability_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef PROBABILITY_PLOT_H 2 | #define PROBABILITY_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "data.h" 11 | 12 | 13 | class GRAPH_EXPORT ProbabilityPlot : public Plot 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | 19 | ProbabilityPlot(QWidget* parent = nullptr); 20 | 21 | ~ProbabilityPlot(); 22 | 23 | public slots: 24 | 25 | void slot_tool_tip(QPointF point, bool state) override; 26 | 27 | public: 28 | 29 | void add_data(QList& list, const QString& name); 30 | 31 | virtual void init_chart() override; 32 | 33 | virtual void init_axis() override; 34 | 35 | virtual void init_series() override; 36 | 37 | protected: 38 | /** 数据计算 */ 39 | void prepare_data(QList& list); 40 | /** 理论CDF */ 41 | double calculate_cdf(int index, int n); 42 | 43 | protected: 44 | /** 平均值 */ 45 | double m_mean; 46 | /** 方差 */ 47 | double m_variance; 48 | /** 标准差 */ 49 | double m_sigma; 50 | /** 样本数 */ 51 | int m_n; 52 | 53 | protected: 54 | 55 | QLineSeries* m_line_center =nullptr ; 56 | 57 | QLineSeries* m_line_top = nullptr; 58 | 59 | QLineSeries* m_line_bottom = nullptr; 60 | 61 | QScatterSeries* m_scatter = nullptr; 62 | 63 | QValueAxis* m_axisX = nullptr; 64 | 65 | QCategoryAxis* m_axisY = nullptr; 66 | 67 | QList m_probability_list; 68 | 69 | ScoreType m_score_type = Benard; 70 | 71 | }; 72 | 73 | #endif // PROBABILITY_PLOT_H -------------------------------------------------------------------------------- /Chart.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32228.430 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "projects\Test\Test.vcxproj", "{8C814C96-3D0C-40C4-BF44-47EADC42B3A5}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Graph", "projects\Graph\Graph.vcxproj", "{052877BA-DD5E-4B0A-9259-62F40345A8AE}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {8C814C96-3D0C-40C4-BF44-47EADC42B3A5}.Debug|x64.ActiveCfg = Debug|x64 17 | {8C814C96-3D0C-40C4-BF44-47EADC42B3A5}.Debug|x64.Build.0 = Debug|x64 18 | {8C814C96-3D0C-40C4-BF44-47EADC42B3A5}.Release|x64.ActiveCfg = Release|x64 19 | {8C814C96-3D0C-40C4-BF44-47EADC42B3A5}.Release|x64.Build.0 = Release|x64 20 | {052877BA-DD5E-4B0A-9259-62F40345A8AE}.Debug|x64.ActiveCfg = Debug|x64 21 | {052877BA-DD5E-4B0A-9259-62F40345A8AE}.Debug|x64.Build.0 = Debug|x64 22 | {052877BA-DD5E-4B0A-9259-62F40345A8AE}.Release|x64.ActiveCfg = Release|x64 23 | {052877BA-DD5E-4B0A-9259-62F40345A8AE}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {3A6D25EA-341D-43C1-9483-B721FA4C76E0} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /projects/Graph/src/graph/chart_view_preview.h: -------------------------------------------------------------------------------- 1 | #ifndef CHART_VIEW_PREVIEW_H 2 | #define CHART_VIEW_PREVIEW_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class ChartView; 9 | class QMouseEvent; 10 | 11 | /** 开始预览 */ 12 | #define BEGIN_PREVIEW -1 13 | 14 | class ChartViewPreview 15 | { 16 | 17 | public: 18 | 19 | virtual ~ChartViewPreview(); 20 | /** 是否正在预览 */ 21 | static bool is_previewing(ChartView* view); 22 | /** 完成并退出所有的绘制 */ 23 | static void finish_all(ChartView* view); 24 | 25 | static void on_mouse_move(ChartView* view, QMouseEvent* event); 26 | 27 | static void on_mouse_release(ChartView* view, QMouseEvent* event); 28 | 29 | public: 30 | /** 31 | * \brief 子类实现,绘制进度推进 32 | * @param point 鼠标在场景的坐标 33 | */ 34 | virtual void on_advance_preview(QPointF& point) {} 35 | /** 子类实现,完成图元绘制 */ 36 | virtual void on_finish_preview() {} 37 | 38 | protected: 39 | /** 设置数据,开始预览 */ 40 | void begin_preview(ChartView* view); 41 | /** 42 | * \brief 子类实现,鼠标在所属的图形视图窗口移动 43 | * @param point 鼠标在场景的坐标 44 | */ 45 | virtual void on_mouse_move(QPointF& point) {} 46 | /** 获取预览步骤 */ 47 | int step() const { return m_step; } 48 | /** 设置预览步骤 */ 49 | void set_step(int step); 50 | 51 | private: 52 | /** 完成绘制操作 */ 53 | void finish_preview(); 54 | /** 推进绘制进度 */ 55 | void advance_preview(const QPoint& point); 56 | /** 鼠标在视图中移动 */ 57 | void on_mouse_move(QMouseEvent* event); 58 | 59 | protected: 60 | 61 | ChartView* m_view = nullptr; 62 | 63 | private: 64 | //正在绘制的图元,key 视图, value 预览图元 65 | static QMap s_view2preview; 66 | //已完成的步骤 67 | int m_step; 68 | }; 69 | 70 | #endif // CHART_VIEW_PREVIEW_H -------------------------------------------------------------------------------- /projects/Test/src/main_window.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_WINDOW_H 2 | #define MAIN_WINDOW_H 3 | 4 | #include 5 | #include "ui_main_window.h" 6 | 7 | class LinePlot; 8 | class ScatterPlot; 9 | class PiePlot; 10 | class ProbabilityPlot; 11 | class QQPlot; 12 | class ParetoPlot; 13 | class StockPlot; 14 | class BarPlot; 15 | class Table; 16 | class RadialPlot; 17 | class BoxBarPlot; 18 | class IntervalPlot; 19 | class ColorPlot; 20 | class DensityPlot; 21 | class RadarPlot; 22 | class HistogramPlot; 23 | class WaterfallPlot; 24 | 25 | class MainWindow : public QMainWindow 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | MainWindow(QWidget *parent = Q_NULLPTR); 31 | ~MainWindow(); 32 | 33 | public slots: 34 | void slot_add_line(); 35 | void slot_delete_line(); 36 | void slot_draw_line(); 37 | void slot_draw_arrows(); 38 | void slot_vertical_splitter(); 39 | void slot_horizontal_splitter(); 40 | void slot_delete_splitter(); 41 | void slot_add_label(); 42 | 43 | private: 44 | 45 | void init_chart(); 46 | private: 47 | Ui::MainWindow ui; 48 | LinePlot* line = nullptr; 49 | ScatterPlot* scatter = nullptr; 50 | PiePlot* pie = nullptr; 51 | ProbabilityPlot* probability = nullptr; 52 | QQPlot* qq = nullptr; 53 | ParetoPlot* pareto = nullptr; 54 | StockPlot* stock = nullptr; 55 | BarPlot* bar = nullptr; 56 | Table* table = nullptr; 57 | RadialPlot* radial = nullptr; 58 | BoxBarPlot* boxbar = nullptr; 59 | IntervalPlot* interval = nullptr; 60 | ColorPlot* color = nullptr; 61 | DensityPlot* density = nullptr; 62 | RadarPlot* radar = nullptr; 63 | HistogramPlot* histogram = nullptr; 64 | WaterfallPlot* waterfall = nullptr; 65 | }; 66 | 67 | #endif // MAIN_WINDOW_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/plot.h: -------------------------------------------------------------------------------- 1 | #ifndef PLOT_H 2 | #define PLOT_H 3 | 4 | #include "graph_global.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace QtCharts; 12 | 13 | class ChartView; 14 | class ToolTip; 15 | 16 | class GRAPH_EXPORT Plot : public QWidget 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | 22 | Plot(bool IsPolar=false, QWidget *parent = nullptr); 23 | 24 | ~Plot(); 25 | 26 | public slots: 27 | /** 鼠标提示 */ 28 | virtual void slot_tool_tip(QPointF point, bool state); 29 | /** 图例点击 */ 30 | void slot_handle_marker_clicked(); 31 | 32 | public: 33 | /** 图表标题 */ 34 | void add_title(const QString& name); 35 | /** 连接图例 */ 36 | void connect_markers(); 37 | /** 取消图例连接 */ 38 | void disconnect_markers(); 39 | /** 开始画线 */ 40 | void draw_line(); 41 | /** 开始画箭头 */ 42 | void draw_arrows(); 43 | 44 | protected: 45 | /** 初始化图表 */ 46 | virtual void init_chart() = 0; 47 | /** 初始化坐标轴 */ 48 | virtual void init_axis() = 0; 49 | /** 初始化系列 */ 50 | virtual void init_series() = 0; 51 | 52 | protected: 53 | virtual void resizeEvent(QResizeEvent* event) override; 54 | 55 | protected: 56 | /** 图表 */ 57 | QChart* m_chart = nullptr; 58 | /** 视图 */ 59 | ChartView* m_chartview = nullptr; 60 | /** 鼠标提示 */ 61 | ToolTip* m_tooltip = nullptr; 62 | /** X 最小值 */ 63 | double m_min_x = DBL_MAX; 64 | /** X 最大值 */ 65 | double m_max_x = DBL_MIN; 66 | /** Y 最小值 */ 67 | double m_min_y = DBL_MAX; 68 | /** Y 最大值 */ 69 | double m_max_y = DBL_MIN; 70 | /** Z 最小值 */ 71 | double m_min_z = DBL_MAX; 72 | /** Z 最大值 */ 73 | double m_max_z = DBL_MIN; 74 | }; 75 | 76 | #endif // PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/pie_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "pie_plot.h" 4 | 5 | PiePlot::PiePlot(QWidget* parent) 6 | : Plot(parent) 7 | { 8 | init_series(); 9 | init_chart(); 10 | init_axis(); 11 | } 12 | 13 | PiePlot::~PiePlot() 14 | { 15 | } 16 | 17 | void PiePlot::slot_tool_tip(QPieSlice* slice, bool state) 18 | { 19 | slice->setLabelVisible(state); 20 | slice->setExploded(state); 21 | } 22 | 23 | void PiePlot::set_data(QList& valuelist) 24 | { 25 | for (auto& item : valuelist) 26 | add_pie(item.m_value, item.m_name); 27 | } 28 | 29 | void PiePlot::add_pie(double value, const QString& name) 30 | { 31 | QPieSlice* pie = new QPieSlice(name , value); 32 | m_series->append(pie); 33 | m_name2series[name] = pie; 34 | update_label(); 35 | } 36 | 37 | void PiePlot::delete_pie(const QString& name) 38 | { 39 | if (!m_name2series.contains(name)) 40 | return; 41 | m_series->remove(m_name2series[name]); 42 | m_name2series.remove(name); 43 | } 44 | 45 | void PiePlot::init_chart() 46 | { 47 | m_chart->addSeries(m_series); 48 | m_chart->legend()->setVisible(true); 49 | m_chart->legend()->setAlignment(Qt::AlignRight); 50 | } 51 | 52 | void PiePlot::init_axis() 53 | { 54 | 55 | } 56 | 57 | void PiePlot::init_series() 58 | { 59 | m_series = new QPieSeries(); 60 | connect(m_series, &QPieSeries::hovered, this, &PiePlot::slot_tool_tip); 61 | } 62 | 63 | void PiePlot::update_label() 64 | { 65 | // 设置块标签 66 | for (int sNum = 0; sNum < m_series->slices().count(); sNum++) 67 | { 68 | QPieSlice* slice = m_series->slices().at(sNum); 69 | QString tagText = QString("%1 %2%") 70 | .arg(slice->label().split(' ')[0]) 71 | .arg(QString::number(slice->percentage() * 100)); 72 | slice->setLabel(tagText); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/histogram_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef HISTOGRAM_PLOT_H 2 | #define HISTOGRAM_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include "graphics_item.h" 7 | #include 8 | #include 9 | 10 | ////////////////////////////////////////////////////////////////////////////// 11 | /// 直方图 12 | class HistogramItem :public GraphicsItem 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | HistogramItem(); 18 | void set_chart(QChart* chart); 19 | void set_data(QVector data); 20 | void set_index(int index); 21 | 22 | signals: 23 | void signal_prepare_path() const; 24 | 25 | public slots: 26 | void slot_prepare_path(); 27 | 28 | protected: 29 | QRectF boundingRect() const override; 30 | void on_paint(QPainter* painter) override; 31 | 32 | private: 33 | QChart* m_chart = nullptr; 34 | QVector m_data; 35 | int m_index = 0; 36 | QPainterPath m_shape; 37 | }; 38 | 39 | struct Histogram 40 | { 41 | int m_index; 42 | QList m_list; 43 | QList m_value; 44 | QScatterSeries* m_series = nullptr; 45 | }; 46 | 47 | class GRAPH_EXPORT HistogramPlot : public Plot 48 | { 49 | Q_OBJECT 50 | 51 | public: 52 | 53 | HistogramPlot(QWidget* parent = nullptr); 54 | 55 | ~HistogramPlot(); 56 | 57 | void add_histogram(QList& value_list, const QString& name); 58 | 59 | void delete_histogram(const QString& name); 60 | 61 | protected: 62 | 63 | virtual void init_chart() override; 64 | 65 | virtual void init_axis() override; 66 | 67 | virtual void init_series() override; 68 | 69 | QList> prepare_data(QList& list); 70 | 71 | 72 | private: 73 | /** 名称和系列映射 */ 74 | QMap m_name2itemlist; 75 | /** X 轴 */ 76 | QValueAxis* m_axisX = nullptr; 77 | /** Y 轴 */ 78 | QValueAxis* m_axisY = nullptr; 79 | /** 间距 */ 80 | double m_interval = 2; 81 | /** 总数 */ 82 | int m_count = 0; 83 | }; 84 | 85 | #endif // HISTOGRAM_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/interval_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERVAL_PLOT_H 2 | #define INTERVAL_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "data.h" 6 | #include "graph_global.h" 7 | #include "graphics_item.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | ////////////////////////////////////////////////////////////////////////////// 14 | /// 间隔图 15 | class IntervalItem :public GraphicsItem 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | IntervalItem(); 21 | void set_chart(QChart* chart); 22 | void set_data(BoxData& data, int index); 23 | double get_max(); 24 | double get_min(); 25 | 26 | signals: 27 | void signal_prepare_path() const; 28 | 29 | public slots: 30 | void slot_prepare_path(); 31 | 32 | protected: 33 | QRectF boundingRect() const override; 34 | void on_paint(QPainter* painter) override; 35 | 36 | private: 37 | QChart* m_chart = nullptr; 38 | QList m_list; 39 | QString m_name; 40 | QPointF m_min ; 41 | QPointF m_max ; 42 | QPointF m_mean; 43 | QPointF m_sum ; 44 | QPainterPath m_shape; 45 | }; 46 | 47 | class GRAPH_EXPORT IntervalPlot : public Plot 48 | { 49 | Q_OBJECT 50 | 51 | public: 52 | 53 | IntervalPlot(QWidget* parent = nullptr); 54 | 55 | ~IntervalPlot(); 56 | 57 | public: 58 | 59 | void set_data(QList& list); 60 | 61 | void add_interval(BoxData& data, int index, double& y_min, double& y_max); 62 | 63 | virtual void init_chart() override; 64 | 65 | virtual void init_axis() override; 66 | 67 | virtual void init_series() override; 68 | 69 | private: 70 | /** 名称和系列映射 */ 71 | QMap m_name2item; 72 | /** X 轴 */ 73 | QBarCategoryAxis* m_axisX = nullptr; 74 | /** X 轴刻度 */ 75 | QStringList m_axisx_list; 76 | /** Y 轴 */ 77 | QValueAxis* m_axisY = nullptr; 78 | /** 记录坐标轴范围 */ 79 | QStack m_range[4]; 80 | /** 参考点 */ 81 | QScatterSeries* m_series = nullptr; 82 | }; 83 | 84 | #endif // INTERVAL_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/boxbar_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef BOXBAR_PLOT_H 2 | #define BOXBAR_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include "data.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "graphics_item.h" 12 | 13 | 14 | ////////////////////////////////////////////////////////////////////////////// 15 | /// 条形图 16 | class BoxBarItem :public GraphicsItem 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | BoxBarItem(); 22 | void set_chart(QChart* chart); 23 | void set_data(double mean, double sum, double min, double max, int index); 24 | 25 | signals: 26 | void signal_prepare_path() const; 27 | 28 | public slots: 29 | void slot_prepare_path(); 30 | 31 | protected: 32 | QRectF boundingRect() const override; 33 | void on_paint(QPainter* painter) override; 34 | 35 | private: 36 | QChart* m_chart = nullptr; 37 | QPointF m_min; 38 | QPointF m_max; 39 | QPointF m_mean; 40 | QPointF m_sum; 41 | QPainterPath m_shape; 42 | }; 43 | 44 | 45 | class GRAPH_EXPORT BoxBarPlot : public Plot 46 | { 47 | Q_OBJECT 48 | 49 | public: 50 | 51 | BoxBarPlot(QWidget* parent = nullptr); 52 | 53 | ~BoxBarPlot(); 54 | 55 | void set_type(BoxBarType type); 56 | 57 | public: 58 | 59 | void set_data(QList &list); 60 | 61 | void add_boxbar(BoxData& data, int size, int index); 62 | 63 | void delete_boxbar(const QString& name); 64 | 65 | virtual void init_chart() override; 66 | 67 | virtual void init_axis() override; 68 | 69 | virtual void init_series() override; 70 | 71 | private: 72 | /** 名称和系列映射 */ 73 | QMap m_name2series; 74 | /** 名称和条形图映射 */ 75 | QMap m_name2item; 76 | /** X 轴 */ 77 | QBarCategoryAxis* m_axisX = nullptr; 78 | /** Y 轴 */ 79 | QValueAxis* m_axisY = nullptr; 80 | /** X 轴 */ 81 | QStringList m_axisx_list; 82 | /** 条形图 */ 83 | QStackedBarSeries* m_series = nullptr; 84 | /** 绘画模式 */ 85 | BoxBarType m_boxbartype = MEAN; 86 | 87 | }; 88 | 89 | #endif // BOX_BAR_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/chart_view.h: -------------------------------------------------------------------------------- 1 | #ifndef CHART_VIEW_H 2 | #define CHART_VIEW_H 3 | 4 | #include "graph_global.h" 5 | #include "graphics_item.h" 6 | 7 | #include 8 | #include 9 | 10 | 11 | using namespace QtCharts; 12 | 13 | class GRAPH_EXPORT ChartView : public QGraphicsView 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | 19 | ChartView(QChart* chart, QWidget* parent = nullptr); 20 | 21 | public: 22 | /** 重绘场景 */ 23 | void redraw(); 24 | /** \brief 保存图片*/ 25 | bool save_picture(const QString& filename, const QSize& size = QSize(3050, 2050)); 26 | /** 返回视图的widget */ 27 | QWidget* widget(); 28 | /** 智能设置视图的光标 */ 29 | void set_cursor_auto(); 30 | /** 将视图坐标转换到场景坐标 */ 31 | QPointF map_to_scene(const QPoint& pos); 32 | /** 将场景坐标转换到视图坐标 */ 33 | QPoint map_from_scene(const QPointF& pos); 34 | /** 将视图坐标转换到屏幕坐标 */ 35 | QPoint map_to_global(const QPoint& pos); 36 | /** 添加图元 */ 37 | void add_item(GraphicsItem* item); 38 | /** 删除图元 */ 39 | void delete_item(GraphicsItem* item); 40 | /** 正在绘图 */ 41 | bool is_previewing(); 42 | 43 | public slots: 44 | 45 | void slot_chart_config(); 46 | 47 | void slot_series_config(); 48 | 49 | void slot_axis_config(); 50 | 51 | protected: 52 | 53 | virtual void resizeEvent(QResizeEvent* event) override; 54 | 55 | virtual void mousePressEvent(QMouseEvent* event) override; 56 | 57 | virtual void mouseMoveEvent(QMouseEvent* event) override; 58 | 59 | virtual void mouseReleaseEvent(QMouseEvent* event) override; 60 | 61 | virtual void keyPressEvent(QKeyEvent* event) override; 62 | 63 | virtual void wheelEvent(QWheelEvent* event) override; 64 | 65 | virtual void mouseDoubleClickEvent(QMouseEvent* event) override; 66 | 67 | private: 68 | /** 图表 */ 69 | QChart* m_chart = nullptr; 70 | /** 框选开始点 */ 71 | QPoint m_begin_point; 72 | /** 框选结束点 */ 73 | QPoint m_end_point; 74 | /** 拖拽点 */ 75 | QPoint m_old_point; 76 | /** 是否拖拽 */ 77 | bool m_isTranslate = false; 78 | /** 拖拽记录*/ 79 | QPointF m_translate_pos; 80 | }; 81 | 82 | #endif // CHART_VIEW_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/bar_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "bar_plot.h" 4 | 5 | BarPlot::BarPlot(QWidget *parent) 6 | : Plot(parent) 7 | { 8 | init_series(); 9 | init_chart(); 10 | init_axis(); 11 | } 12 | 13 | BarPlot::~BarPlot() 14 | { 15 | 16 | } 17 | 18 | void BarPlot::set_axis(QList list) 19 | { 20 | m_axisx_list = list; 21 | m_axisX->append(m_axisx_list); 22 | } 23 | 24 | void BarPlot::add_bar(QList& value_list, const QString& name) 25 | { 26 | if (m_name2series.contains(name)) 27 | return; 28 | 29 | prepare_data(value_list); 30 | 31 | QBarSet* set = new QBarSet(name); 32 | set->append(value_list); 33 | m_series->append(set); 34 | 35 | m_name2series[name] = set; 36 | 37 | m_axisY->setRange(m_min_y - 1, m_max_y + 1); 38 | 39 | //connect(series, &QLineSeries::hovered, this, &Plot::slot_tool_tip); 40 | //connect_markers(); 41 | } 42 | 43 | void BarPlot::delete_bar(const QString& name) 44 | { 45 | if (!m_name2series.contains(name)) 46 | return; 47 | m_series->remove(m_name2series[name]); 48 | m_name2series.remove(name); 49 | 50 | m_range[0].pop(); 51 | m_range[1].pop(); 52 | 53 | m_min_y = m_range[0].top(); 54 | m_max_y = m_range[1].top(); 55 | 56 | m_axisY->setRange(m_min_y - 1, m_max_y + 1); 57 | } 58 | 59 | void BarPlot::init_chart() 60 | { 61 | m_chart->addSeries(m_series); 62 | } 63 | 64 | void BarPlot::init_axis() 65 | { 66 | m_axisX = new QBarCategoryAxis(); 67 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 68 | m_series->attachAxis(m_axisX); 69 | 70 | m_axisY = new QValueAxis(); 71 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 72 | m_series->attachAxis(m_axisY); 73 | } 74 | 75 | void BarPlot::init_series() 76 | { 77 | m_series = new QBarSeries(); 78 | } 79 | 80 | void BarPlot::prepare_data(QList& value_list) 81 | { 82 | for (auto& value : value_list) 83 | { 84 | if (value < m_min_y) 85 | m_min_y = value; 86 | if (value > m_max_y) 87 | m_max_y = value; 88 | } 89 | m_range[0].push(m_min_y); 90 | m_range[1].push(m_max_y); 91 | } 92 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/radar_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef RADAR_PLOT_H 2 | #define RADAR_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include "graphics_item.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | enum RadarType 14 | { 15 | Radar = 0, //雷达图 16 | Spider //蜘蛛网图 17 | }; 18 | 19 | enum DrawTpye 20 | { 21 | Scatter = 0, //散点图 22 | Line, //连线图 23 | Area //区域图 24 | }; 25 | 26 | ////////////////////////////////////////////////////////////////////////////// 27 | /// 雷达图 28 | class RadarItem :public GraphicsItem 29 | { 30 | Q_OBJECT 31 | 32 | public: 33 | RadarItem(); 34 | void set_chart(QChart* chart); 35 | void set_radial(int radial); 36 | void set_angular(int angular); 37 | 38 | protected: 39 | QRectF boundingRect() const override; 40 | void on_paint(QPainter* painter) override; 41 | 42 | private: 43 | QChart* m_chart = nullptr; 44 | /** 雷达项数 */ 45 | int m_angular = 5; 46 | /** 雷达圈数 */ 47 | int m_radial = 6; 48 | }; 49 | 50 | 51 | class GRAPH_EXPORT RadarPlot : public Plot 52 | { 53 | Q_OBJECT 54 | 55 | public: 56 | 57 | RadarPlot(QWidget* parent = nullptr); 58 | 59 | ~RadarPlot(); 60 | 61 | void set_radar(QStringList& lablelist); 62 | 63 | void add_radar(QList& valuelist, const QString& name); 64 | 65 | void delete_radar(const QString& name); 66 | 67 | void set_radar_type(RadarType type); 68 | 69 | 70 | protected: 71 | 72 | virtual void init_chart() override; 73 | 74 | virtual void init_axis() override; 75 | 76 | virtual void init_series() override; 77 | 78 | private: 79 | /** 蜘蛛网图 */ 80 | RadarItem* item = nullptr; 81 | /** 角度值/雷达项 */ 82 | QCategoryAxis* m_angularAxis = nullptr; 83 | /** 雷达值/雷达圈数 */ 84 | QValueAxis* m_radialAxis = nullptr; 85 | /** 图类型 */ 86 | RadarType m_radartype = Spider; 87 | /** 线类型 */ 88 | DrawTpye m_drawtype = Line; 89 | /** 雷达项数 */ 90 | int count = 0; 91 | /** 名称和系列映射 */ 92 | QMap m_name2series; 93 | }; 94 | 95 | #endif // RADAR_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/data.h: -------------------------------------------------------------------------------- 1 | #ifndef DATA_H 2 | #define DATA_H 3 | 4 | /** 概率结构 */ 5 | struct Probability 6 | { 7 | /** 分位数 */ 8 | int index; 9 | /** 理论值 */ 10 | double theory; 11 | /** 理论CDF */ 12 | double theory_cdf; 13 | /** 理论Z值 */ 14 | double theory_z; 15 | /** 实际值 */ 16 | double reality; 17 | /** 实际CDF */ 18 | double reality_cdf; 19 | /** 实际Z值 */ 20 | double reality_z; 21 | }; 22 | 23 | /** 评分方法 */ 24 | enum ScoreType 25 | { 26 | Blom, 27 | Benard, 28 | Hazen, 29 | VanDerWaerden, 30 | KaplanMeier 31 | }; 32 | 33 | /** 股票图数据 */ 34 | struct CandlestickData 35 | { 36 | CandlestickData(double timestamp, double open, double high, double low, double close) 37 | { 38 | m_timestamp = timestamp; 39 | m_open = open; 40 | m_high = high; 41 | m_low = low; 42 | m_close = close; 43 | } 44 | double m_timestamp; 45 | double m_open; 46 | double m_high; 47 | double m_low; 48 | double m_close; 49 | }; 50 | 51 | /** 柱状图数据 */ 52 | struct PieData 53 | { 54 | PieData(QString name, double value) 55 | { 56 | m_name = name; 57 | m_value = value; 58 | } 59 | QString m_name; 60 | double m_value; 61 | }; 62 | 63 | /** 帕累托图数据 */ 64 | struct ParetoData 65 | { 66 | ParetoData(QString name, double value) 67 | { 68 | m_name = name; 69 | m_value = value; 70 | } 71 | QString m_name; 72 | double m_value; 73 | double m_percent; 74 | }; 75 | 76 | /** 3d数据 */ 77 | struct ThirdDData 78 | { 79 | ThirdDData(double x, double y,double z) 80 | { 81 | m_x = x; 82 | m_y = y; 83 | m_z = z; 84 | } 85 | double m_x; 86 | double m_y; 87 | double m_z; 88 | }; 89 | 90 | /** 箱型图数据 */ 91 | struct BoxData 92 | { 93 | QString m_name; 94 | QList m_value_list; 95 | }; 96 | 97 | /** 条形图 */ 98 | enum BoxBarType 99 | { 100 | MEAN, 101 | SUM, 102 | MAX, 103 | MIN 104 | }; 105 | 106 | /** 密度点 */ 107 | struct DensityPoint 108 | { 109 | DensityPoint(double a, double b) 110 | { 111 | x = a; 112 | y = b; 113 | } 114 | qreal x; 115 | qreal y; 116 | int pts = 1; 117 | }; 118 | #endif //DATA_H 119 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/radial_plot..cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "radial_plot.h" 4 | #include "QPieSeries" 5 | 6 | RadialPlot::RadialPlot(QWidget* parent) 7 | : Plot(parent) 8 | { 9 | init_series(); 10 | init_chart(); 11 | init_axis(); 12 | } 13 | 14 | RadialPlot::~RadialPlot() 15 | { 16 | } 17 | 18 | void RadialPlot::slot_tool_tip(QPieSlice* slice, bool state) 19 | { 20 | slice->setLabelVisible(state); 21 | //slice->setExploded(state); 22 | } 23 | 24 | void RadialPlot::update_location() 25 | { 26 | const QStringList colorNames = QColor::colorNames(); 27 | double sum = 360 / m_pie_series.size(); 28 | double start = 0; 29 | for (int i=0;i< m_pie_series.size();i++) 30 | { 31 | QPieSeries* series = m_pie_series[i].m_pie; 32 | 33 | QList slices = series->slices(); 34 | for (QPieSlice* slice : slices) 35 | slice->setColor(QColor(colorNames[(i+10)%148])); 36 | 37 | series->setHoleSize(m_radial_min - 0.0001); 38 | double length = m_radial_min + m_radial_length * m_pie_series[i].m_value / m_max_x; 39 | series->setPieSize(length); 40 | series->setPieStartAngle(start); 41 | start += sum; 42 | series->setPieEndAngle(start); 43 | } 44 | } 45 | 46 | void RadialPlot::set_data(QList& valuelist) 47 | { 48 | for (auto& item : valuelist) 49 | add_pie(item.m_value, item.m_name); 50 | } 51 | 52 | void RadialPlot::add_pie(double value, const QString& name) 53 | { 54 | if (value < m_min_x) 55 | m_min_x = value; 56 | if (value > m_max_x) 57 | m_max_x = value; 58 | 59 | QPieSeries* series = new QPieSeries(); 60 | series->append(name + " " + QString::number(value), value); 61 | m_chart->addSeries(series); 62 | connect(series, &QPieSeries::hovered, this, &RadialPlot::slot_tool_tip); 63 | 64 | m_pie_series.append(RadialData(name, value, series)); 65 | 66 | update_location(); 67 | } 68 | 69 | void RadialPlot::delete_pie(const QString& name) 70 | { 71 | 72 | } 73 | 74 | void RadialPlot::init_chart() 75 | { 76 | //m_chart->legend()->setVisible(true); 77 | m_chart->legend()->setAlignment(Qt::AlignRight); 78 | } 79 | 80 | void RadialPlot::init_axis() 81 | { 82 | 83 | } 84 | 85 | void RadialPlot::init_series() 86 | { 87 | 88 | } 89 | -------------------------------------------------------------------------------- /projects/Graph/src/graph/poly_line_preview.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "poly_line_preview.h" 4 | 5 | #include "util.h" 6 | #include "chart_view.h" 7 | #include "poly_line.h" 8 | 9 | PolyLinePreview::PolyLinePreview(ChartView* view) 10 | { 11 | begin_preview(view); 12 | } 13 | 14 | void PolyLinePreview::on_finish_preview() 15 | { 16 | if (m_pPolyLine != nullptr) 17 | { 18 | auto points = m_pPolyLine->get_points(); 19 | points.pop_back(); 20 | if (points.size() >= 2) 21 | { 22 | m_pPolyLine->set_points(points); 23 | m_view->add_item(m_pPolyLine->clone()); 24 | } 25 | m_view->delete_item(m_pPolyLine); 26 | DELETE_PTR(m_pPolyLine); 27 | } 28 | } 29 | 30 | void PolyLinePreview::on_advance_preview(QPointF& point) 31 | { 32 | if (step() == BEGIN_PREVIEW) 33 | set_step(START_POINT); 34 | else if (step() == START_POINT) 35 | set_step(NEXT_POINT); 36 | 37 | confirm_step(step(), point);; 38 | } 39 | 40 | void PolyLinePreview::on_mouse_move(QPointF& point) 41 | { 42 | //将鼠标点坐标更新到直线的最后一个点 43 | if (step() >= START_POINT && step() <= NEXT_POINT) 44 | { 45 | if (QLineF(m_last_confirm_point, point).length() > 0.001) 46 | { 47 | if (m_pPolyLine->view() == nullptr) 48 | { 49 | m_pPolyLine->append_point(point); 50 | m_view->add_item(m_pPolyLine); 51 | } 52 | m_pPolyLine->set_last_point(point); 53 | } 54 | } 55 | } 56 | 57 | PolyLine* PolyLinePreview::new_polyline() 58 | { 59 | return new PolyLine(); 60 | } 61 | 62 | void PolyLinePreview::confirm_step(int step, QPointF& point) 63 | { 64 | //确定第一个点 65 | if (step == START_POINT) 66 | { 67 | m_pPolyLine = new_polyline(); 68 | m_pPolyLine->append_point(point); 69 | m_last_confirm_point = point; 70 | } 71 | //确定后续的点 72 | else if (step == NEXT_POINT) 73 | { 74 | if (QLineF(m_last_confirm_point, point).length() > 0.001) 75 | { 76 | m_pPolyLine->append_point(point); 77 | m_last_confirm_point = point; 78 | } 79 | } 80 | } 81 | 82 | /////////////////////////////////////////////////////////////////////////////// 83 | ///箭头线 84 | ArrowsPreview::ArrowsPreview(ChartView* view) 85 | :PolyLinePreview(view) 86 | { 87 | 88 | } 89 | 90 | PolyLine* ArrowsPreview::new_polyline() 91 | { 92 | return new Arrows(); 93 | } 94 | -------------------------------------------------------------------------------- /projects/Graph/src/util/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #include "math_define.h" 5 | #include "graph_global.h" 6 | 7 | #include 8 | #include 9 | 10 | //宏定义:销毁指针 11 | #define DELETE_PTR(p) if(p){delete p; p = nullptr;} 12 | #define DELETE_PTR_LIST(list) { for (auto x : list) delete x; list.clear();} 13 | 14 | //宏定义:double是否相等 15 | #define DOUBLE_EQUAL(d1, d2) (fabs((d1)-(d2)) <= TOLERANCE) 16 | 17 | 18 | class GRAPH_EXPORT Util 19 | { 20 | public: 21 | 22 | static QRectF bounding_rect(const QList& points); 23 | 24 | static void bounding_rect(const QList& points, double& xmin, double& xmax, double& ymin, double& ymax); 25 | 26 | static QRectF bounding_rect(const QList& rects); 27 | 28 | static void bounding_rect(const QRectF& rect, double& xmin, double& xmax, double& ymin, double& ymax); 29 | 30 | /** 31 | * 基于x轴向右,y轴向上,逆时针为正, 32 | * 计算向量p1p2的角度,范围是[0, 360) 33 | */ 34 | static double angle(const QPointF& p1, const QPointF& p2); 35 | 36 | /** 37 | * 基于x轴向右,y轴向上,逆时针为正, 38 | * 基于坐标原点旋转点p,angle的范围是[0, 360) 39 | */ 40 | static QPointF rotated(const QPointF& p, double angle); 41 | 42 | /** 求平均值*/ 43 | static double average(QList& list); 44 | 45 | /** 求最大值*/ 46 | static double max(QList& list); 47 | 48 | /** 求最小值*/ 49 | static double min(QList& list); 50 | 51 | static void cal_list(QList& list,double &mean,double &sum,double &max,double &min); 52 | 53 | /** 求方差 */ 54 | //若n个数据为总体,则求总体标准差,标准差公式根号内除以n;若n个数据为样本,则求样本标准差,标准差公式根号内除以(n - 1)。 55 | static double variance(QList& list,double mean= DBL_MIN); 56 | 57 | /** 求标准差 */ 58 | static double standard_deviation(QList& list,double sigma2 = DBL_MIN); 59 | 60 | 61 | //计算正态累积分布函数 62 | //https://blog.csdn.net/weixin_42112208/article/details/81292610 63 | //https://stackoverflow.com/questions/2328258/cumulative-normal-distribution-function-in-c-c 64 | //注意负号,但是算的是左侧累积量,(1-该值)*2 //这算的是标准差为1 均值为0 的 65 | static double normal_cdf(double value); 66 | 67 | static double normal_z(double value); 68 | 69 | static double normsdist(double z); 70 | 71 | static double normsinv(double p); 72 | }; 73 | #endif //UTIL_H 74 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/line_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "line_plot.h" 4 | #include 5 | 6 | LinePlot::LinePlot(QWidget* parent) 7 | : Plot(parent) 8 | { 9 | init_series(); 10 | init_chart(); 11 | init_axis(); 12 | } 13 | 14 | LinePlot::~LinePlot() 15 | { 16 | } 17 | 18 | void LinePlot::add_line(QList& poslist, const QString& name) 19 | { 20 | if (m_name2series.contains(name)) 21 | return; 22 | 23 | prepare_data(poslist); 24 | 25 | QLineSeries* series = new QLineSeries(); 26 | series->append(poslist); 27 | series->setName(name); 28 | m_chart->addSeries(series); 29 | m_name2series[name] = series; 30 | series->attachAxis(m_axisX); 31 | series->attachAxis(m_axisY); 32 | m_axisX->setRange(m_min_x, m_max_x); 33 | m_axisY->setRange(m_min_y, m_max_y); 34 | 35 | connect(series, &QLineSeries::hovered, this, &Plot::slot_tool_tip); 36 | connect_markers(); 37 | } 38 | 39 | void LinePlot::delete_line(const QString& name) 40 | { 41 | if (!m_name2series.contains(name)) 42 | return; 43 | m_chart->removeSeries(m_name2series[name]); 44 | m_name2series.remove(name); 45 | 46 | m_range[0].pop(); 47 | m_range[1].pop(); 48 | m_range[2].pop(); 49 | m_range[3].pop(); 50 | 51 | m_min_x=m_range[0].top(); 52 | m_max_x=m_range[1].top(); 53 | m_min_y=m_range[2].top(); 54 | m_max_y=m_range[3].top(); 55 | 56 | m_axisX->setRange(m_min_x , m_max_x ); 57 | m_axisY->setRange(m_min_y , m_max_y ); 58 | } 59 | 60 | void LinePlot::init_chart() 61 | { 62 | //m_chart->legend()->hide(); 63 | } 64 | 65 | void LinePlot::init_axis() 66 | { 67 | m_axisX = new QValueAxis(); 68 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 69 | 70 | m_axisY = new QValueAxis(); 71 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 72 | } 73 | 74 | void LinePlot::init_series() 75 | { 76 | m_name2series.clear(); 77 | } 78 | 79 | void LinePlot::prepare_data(QList& poslist) 80 | { 81 | for (auto& pos : poslist) 82 | { 83 | if (pos.x() < m_min_x) 84 | m_min_x = pos.x(); 85 | if (pos.x() > m_max_x) 86 | m_max_x = pos.x(); 87 | if (pos.y() < m_min_y) 88 | m_min_y = pos.y(); 89 | if (pos.y() > m_max_y) 90 | m_max_y = pos.y(); 91 | } 92 | m_range[0].push(m_min_x); 93 | m_range[1].push(m_max_x); 94 | m_range[2].push(m_min_y); 95 | m_range[3].push(m_max_y); 96 | } 97 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/waterfall_plot.h: -------------------------------------------------------------------------------- 1 | #ifndef WATERFALL_PLOT_H 2 | #define WATERFALL_PLOT_H 3 | 4 | #include "plot.h" 5 | #include "graph_global.h" 6 | #include "data.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "graphics_item.h" 12 | 13 | ////////////////////////////////////////////////////////////////////////////// 14 | /// 瀑布图 15 | class WaterfallItem :public GraphicsItem 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | WaterfallItem(); 21 | void set_chart(QChart* chart); 22 | void set_data(QList data); 23 | void set_series(QBarSet* series); 24 | 25 | signals: 26 | void signal_prepare_path() const; 27 | 28 | public slots: 29 | void slot_prepare_path(); 30 | 31 | protected: 32 | QRectF boundingRect() const override; 33 | void on_paint(QPainter* painter) override; 34 | 35 | private: 36 | QChart* m_chart = nullptr; 37 | QList m_data; 38 | QBarSet* m_series = nullptr; 39 | QPainterPath m_shape; 40 | }; 41 | 42 | class GRAPH_EXPORT WaterfallPlot : public Plot 43 | { 44 | Q_OBJECT 45 | 46 | public: 47 | 48 | WaterfallPlot(QWidget *parent = nullptr); 49 | 50 | ~WaterfallPlot(); 51 | 52 | public: 53 | 54 | void set_data(QList& value_list); 55 | 56 | void clear_data(); 57 | 58 | protected: 59 | 60 | virtual void init_chart() override; 61 | 62 | virtual void init_axis() override; 63 | 64 | virtual void init_series() override; 65 | 66 | void init_item(); 67 | 68 | private: 69 | /** 名称和系列映射 */ 70 | //QMap m_name2itemlist; 71 | /** X 轴 */ 72 | QBarCategoryAxis* m_axisX = nullptr; 73 | /** Y 轴 */ 74 | QValueAxis* m_axisY = nullptr; 75 | /** Y 轴刻度 */ 76 | QStringList m_axis_list; 77 | 78 | QBarSeries* m_bar = nullptr; 79 | 80 | QBarSet* m_bar_start = nullptr; 81 | 82 | QBarSet* m_bar_end = nullptr; 83 | 84 | QBarSet* m_bar_add = nullptr; 85 | 86 | QBarSet* m_bar_low = nullptr; 87 | 88 | WaterfallItem* m_item_start = nullptr; 89 | 90 | WaterfallItem* m_item_end = nullptr; 91 | 92 | WaterfallItem* m_item_add = nullptr; 93 | 94 | WaterfallItem* m_item_low = nullptr; 95 | 96 | /** 起始值 */ 97 | double start_value = 0; 98 | }; 99 | 100 | #endif // WATERFALL_PLOT_H -------------------------------------------------------------------------------- /projects/Graph/src/chart/scatter_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "scatter_plot.h" 4 | 5 | ScatterPlot::ScatterPlot(QWidget* parent) 6 | : Plot(parent) 7 | { 8 | init_series(); 9 | init_chart(); 10 | init_axis(); 11 | } 12 | 13 | ScatterPlot::~ScatterPlot() 14 | { 15 | 16 | } 17 | 18 | void ScatterPlot::add_scatter(QList& poslist, const QString& name) 19 | { 20 | if (m_name2series.contains(name)) 21 | return; 22 | 23 | prepare_data(poslist); 24 | 25 | QScatterSeries* series = new QScatterSeries(); 26 | series->append(poslist); 27 | series->setName(name); 28 | m_chart->addSeries(series); 29 | m_name2series[name] = series; 30 | series->attachAxis(m_axisX); 31 | series->attachAxis(m_axisY); 32 | m_axisX->setRange(m_min_x, m_max_x); 33 | m_axisY->setRange(m_min_y, m_max_y); 34 | 35 | connect(series, &QScatterSeries::hovered, this, &Plot::slot_tool_tip); 36 | connect_markers(); 37 | } 38 | 39 | void ScatterPlot::delete_scatter(const QString& name) 40 | { 41 | if (!m_name2series.contains(name)) 42 | return; 43 | m_chart->removeSeries(m_name2series[name]); 44 | m_name2series.remove(name); 45 | 46 | m_range[0].pop(); 47 | m_range[1].pop(); 48 | m_range[2].pop(); 49 | m_range[3].pop(); 50 | 51 | m_min_x = m_range[0].top(); 52 | m_max_x = m_range[1].top(); 53 | m_min_y = m_range[2].top(); 54 | m_max_y = m_range[3].top(); 55 | 56 | m_axisX->setRange(m_min_x, m_max_x); 57 | m_axisY->setRange(m_min_y, m_max_y); 58 | } 59 | 60 | void ScatterPlot::init_chart() 61 | { 62 | //m_chart->legend()->hide(); 63 | } 64 | 65 | void ScatterPlot::init_axis() 66 | { 67 | m_axisX = new QValueAxis(); 68 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 69 | 70 | m_axisY = new QValueAxis(); 71 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 72 | } 73 | 74 | void ScatterPlot::init_series() 75 | { 76 | m_name2series.clear(); 77 | } 78 | 79 | void ScatterPlot::prepare_data(QList& poslist) 80 | { 81 | for (auto& pos : poslist) 82 | { 83 | if (pos.x() < m_min_x) 84 | m_min_x = pos.x(); 85 | if (pos.x() > m_max_x) 86 | m_max_x = pos.x(); 87 | if (pos.y() < m_min_y) 88 | m_min_y = pos.y(); 89 | if (pos.y() > m_max_y) 90 | m_max_y = pos.y(); 91 | } 92 | m_range[0].push(m_min_x); 93 | m_range[1].push(m_max_x); 94 | m_range[2].push(m_min_y); 95 | m_range[3].push(m_max_y); 96 | } 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | QtChart 2 | 3 | 基于QChart的部分封装二维数据可视化。 4 | 5 | ![image](https://user-images.githubusercontent.com/32051731/160572847-576edff7-eb3c-44c9-8f29-5d0daec5765a.png) 6 | 7 | 曲线 8 | 9 | ![image](https://user-images.githubusercontent.com/32051731/159616847-0aca5f39-045f-4977-b6f8-9548b28df541.png) 10 | 11 | 散点 12 | 13 | ![image](https://user-images.githubusercontent.com/32051731/159616994-0baa2d4f-6fc3-4a04-9f31-518727ea822a.png) 14 | 15 | 正态概率图 16 | 17 | ![image](https://user-images.githubusercontent.com/32051731/159617075-b341e6fc-e7e6-4ee4-81e7-5058c2d5ed9d.png) 18 | 19 | QQ图 20 | 21 | ![image](https://user-images.githubusercontent.com/32051731/159617300-9347286f-7478-4764-bb16-764287bfbe0c.png) 22 | 23 | 帕累托图 24 | 25 | ![image](https://user-images.githubusercontent.com/32051731/160242340-21c25f1b-45fa-4d35-8692-0230033b5794.png) 26 | 27 | 饼图 28 | 29 | ![image](https://user-images.githubusercontent.com/32051731/159617243-cfc63bb2-3d1a-477a-91aa-2595b2b6ee7d.png) 30 | 31 | 股票图 32 | 33 | ![image](https://user-images.githubusercontent.com/32051731/159617365-22450c30-736a-408c-9322-6fff751a7777.png) 34 | 35 | 柱状图 36 | 37 | ![image](https://user-images.githubusercontent.com/32051731/159617430-96d0c20b-f30e-4099-a41a-7805489b1532.png) 38 | 39 | 表格 40 | 41 | ![image](https://user-images.githubusercontent.com/32051731/159617496-cf7e932e-5d44-4f86-8945-b8003f3609f3.png) 42 | 43 | 径向图 44 | 45 | ![image](https://user-images.githubusercontent.com/32051731/160572467-44db6528-96bb-45bb-8e1b-ed711598bd9a.png) 46 | 47 | 统计条形图 48 | 49 | ![image](https://user-images.githubusercontent.com/32051731/160572582-8d3dd7fe-0b71-454f-ab1b-0298d780de46.png) 50 | 51 | 自定义绘制 52 | 53 | ![image](https://user-images.githubusercontent.com/32051731/159877859-430dc7ac-2e62-4cca-afdf-ad51bda12b92.png) 54 | 55 | 彩色点图(计算效率需要优化) 56 | 57 | ![image](https://user-images.githubusercontent.com/32051731/159877245-f5b7c5c1-2f27-4d35-a9d5-9a51f7c6769e.png) 58 | 59 | 密度点图(计算效率需要优化) 60 | 61 | ![image](https://user-images.githubusercontent.com/32051731/159877443-1f42bb66-74da-4910-882a-aa544d413a39.png) 62 | 63 | 雷达图 64 | 65 | ![image](https://user-images.githubusercontent.com/32051731/160069776-01773325-6b68-45a2-877d-0da19467ed15.png) 66 | 67 | 直方图 68 | 69 | ![image](https://user-images.githubusercontent.com/32051731/160572666-e0fe4b00-e5e5-4727-9cd0-84e67f59e968.png) 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/color_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "color_plot.h" 4 | #include "color_bar.h" 5 | 6 | ColorPlot::ColorPlot(QWidget *parent) 7 | : Plot(parent) 8 | { 9 | init_series(); 10 | init_chart(); 11 | init_axis(); 12 | } 13 | 14 | ColorPlot::~ColorPlot() 15 | { 16 | 17 | } 18 | 19 | void ColorPlot::set_data(QList& value_list) 20 | { 21 | for (auto& item : value_list) 22 | { 23 | if (m_min_x > item.m_x) 24 | m_min_x = item.m_x; 25 | if (m_max_x < item.m_x) 26 | m_max_x = item.m_x; 27 | if (m_min_y > item.m_y) 28 | m_min_y = item.m_y; 29 | if (m_max_y < item.m_y) 30 | m_max_y = item.m_y; 31 | if (m_min_z > item.m_z) 32 | m_min_z = item.m_z; 33 | if (m_max_z < item.m_z) 34 | m_max_z = item.m_z; 35 | 36 | if (value2series.contains(item.m_z)) 37 | value2series[item.m_z]->append(QPointF(item.m_x, item.m_y)); 38 | else 39 | { 40 | QScatterSeries* scatter = new QScatterSeries; //散点图 41 | scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); 42 | scatter->setMarkerSize(3.0); 43 | scatter->setBorderColor(Qt::transparent); 44 | scatter->append(QPointF(item.m_x, item.m_y)); 45 | value2series[item.m_z] = scatter; 46 | } 47 | } 48 | 49 | m_axisX->setRange(m_min_x, m_max_x); 50 | m_axisY->setRange(m_min_y, m_max_y); 51 | m_color_item->set_value_range(m_min_z, m_max_z); 52 | 53 | for (auto it = value2series.begin(); it != value2series.end(); ++it) 54 | { 55 | m_chart->addSeries(it.value()); 56 | it.value()->attachAxis(m_axisX); 57 | it.value()->attachAxis(m_axisY); 58 | it.value()->setBrush(m_color_item->getColor(it.key())); 59 | it.value()->setUseOpenGL(true); 60 | } 61 | } 62 | 63 | void ColorPlot::clear_data() 64 | { 65 | value2series.clear(); 66 | m_chart->series().clear(); 67 | } 68 | 69 | void ColorPlot::init_chart() 70 | { 71 | m_chart->legend()->hide(); 72 | 73 | m_color_item = new ColorBar(); 74 | m_color_item->set_chart(m_chart); 75 | m_chartview->add_item(m_color_item); 76 | } 77 | 78 | void ColorPlot::init_axis() 79 | { 80 | m_axisX = new QValueAxis(); 81 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 82 | m_axisX->setGridLineVisible(false); 83 | 84 | m_axisY = new QValueAxis(); 85 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 86 | m_axisY->setGridLineVisible(false); 87 | } 88 | 89 | void ColorPlot::init_series() 90 | { 91 | value2series.clear(); 92 | } 93 | -------------------------------------------------------------------------------- /projects/Graph/src/graph/chart_view_preview.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "chart_view_preview.h" 4 | #include "util.h" 5 | #include "chart_view.h" 6 | 7 | #include 8 | #include 9 | 10 | QMap ChartViewPreview::s_view2preview; 11 | 12 | ChartViewPreview::~ChartViewPreview() 13 | { 14 | //清理全局预览对象 15 | s_view2preview.remove(m_view); 16 | //恢复鼠标形状 17 | m_view->set_cursor_auto(); 18 | } 19 | 20 | bool ChartViewPreview::is_previewing(ChartView* view) 21 | { 22 | return s_view2preview.contains(view); 23 | } 24 | 25 | void ChartViewPreview::finish_all(ChartView* view) 26 | { 27 | auto preview = s_view2preview.take(view); 28 | if (preview != nullptr) 29 | { 30 | preview->finish_preview(); 31 | delete preview; 32 | } 33 | } 34 | 35 | void ChartViewPreview::begin_preview(ChartView* view) 36 | { 37 | m_view = view; 38 | 39 | //一个视图窗口只能有一个预览 40 | finish_all(m_view); 41 | 42 | //记录预览图元 43 | s_view2preview[m_view] = this; 44 | 45 | //显示cad光标 46 | m_view->set_cursor_auto(); 47 | 48 | set_step(BEGIN_PREVIEW); 49 | } 50 | 51 | void ChartViewPreview::finish_preview() 52 | { 53 | set_step(BEGIN_PREVIEW); 54 | on_finish_preview(); 55 | } 56 | 57 | void ChartViewPreview::advance_preview(const QPoint& point) 58 | { 59 | QPointF pos = m_view->map_to_scene(point); 60 | on_advance_preview(pos); 61 | } 62 | 63 | void ChartViewPreview::on_mouse_move(ChartView* view, QMouseEvent* event) 64 | { 65 | if (s_view2preview.contains(view)) 66 | { 67 | s_view2preview[view]->on_mouse_move(event); 68 | } 69 | } 70 | 71 | void ChartViewPreview::on_mouse_move(QMouseEvent* event) 72 | { 73 | QPointF pos = m_view->map_to_scene(event->pos()); 74 | on_mouse_move(pos); 75 | m_view->redraw(); 76 | } 77 | 78 | void ChartViewPreview::set_step(int step) 79 | { 80 | m_step = step; 81 | } 82 | 83 | void ChartViewPreview::on_mouse_release(ChartView* view, QMouseEvent* event) 84 | { 85 | if (!s_view2preview.contains(view)) return; 86 | 87 | auto preview = s_view2preview[view]; 88 | 89 | if (event->button() == Qt::LeftButton) 90 | { 91 | preview->advance_preview(event->pos()); 92 | } 93 | else if (event->button() == Qt::RightButton) 94 | { 95 | if (preview->step() == BEGIN_PREVIEW) 96 | delete preview; 97 | else preview->finish_preview(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/table.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "table.h" 4 | 5 | Table::Table(QWidget *parent) 6 | : QWidget(parent) 7 | { 8 | m_table = new QTableWidget(); 9 | m_table->setEditTriggers(QAbstractItemView::NoEditTriggers); 10 | 11 | QHBoxLayout* layout = new QHBoxLayout; 12 | layout->setMargin(0); 13 | layout->setSpacing(0); 14 | layout->addWidget(m_table); 15 | setLayout(layout); 16 | } 17 | 18 | Table::~Table() 19 | { 20 | 21 | } 22 | 23 | void Table::add_data(QList& list, const QString& name) 24 | { 25 | m_head_list.append(name); 26 | m_table->setColumnCount(m_head_list.size()); 27 | m_table->setHorizontalHeaderLabels(m_head_list); 28 | for (int i = 0; i < list.size(); i++) 29 | { 30 | int count = m_table->rowCount(); 31 | if (i < count) 32 | m_table->setItem(i, m_head_list.size()-1,new QTableWidgetItem(QString::number(list[i]))); 33 | else 34 | { 35 | m_table->setRowCount(count + 1); 36 | m_table->setItem(count, m_head_list.size() - 1, new QTableWidgetItem(QString::number(list[i]))); 37 | } 38 | } 39 | } 40 | 41 | void Table::add_data(QList& list, const QString& name) 42 | { 43 | m_head_list.append(name); 44 | m_table->setColumnCount(m_head_list.size()); 45 | m_table->setHorizontalHeaderLabels(m_head_list); 46 | for (int i = 0; i < list.size(); i++) 47 | { 48 | int count = m_table->rowCount(); 49 | if (i < count) 50 | m_table->setItem(i, m_head_list.size() - 1, new QTableWidgetItem(QString::number(list[i]))); 51 | else 52 | { 53 | m_table->setRowCount(count + 1); 54 | m_table->setItem(count, m_head_list.size() - 1, new QTableWidgetItem(QString::number(list[i]))); 55 | } 56 | } 57 | } 58 | 59 | void Table::add_data(QList& list, const QString& name) 60 | { 61 | m_head_list.append(name); 62 | m_table->setColumnCount(m_head_list.size()); 63 | m_table->setHorizontalHeaderLabels(m_head_list); 64 | for (int i = 0; i < list.size(); i++) 65 | { 66 | int count = m_table->rowCount(); 67 | if (i < count) 68 | m_table->setItem(i, m_head_list.size() - 1, new QTableWidgetItem(list[i])); 69 | else 70 | { 71 | m_table->setRowCount(count + 1); 72 | m_table->setItem(count, m_head_list.size() - 1, new QTableWidgetItem(list[i])); 73 | } 74 | } 75 | } 76 | 77 | void Table::delete_data(const QString& name) 78 | { 79 | m_head_list.removeOne(name); 80 | m_table->setColumnCount(m_head_list.size()); 81 | m_table->setHorizontalHeaderLabels(m_head_list); 82 | } 83 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/density_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "density_plot.h" 4 | #include "color_bar.h" 5 | 6 | DensityPlot::DensityPlot(QWidget *parent) 7 | : Plot(parent) 8 | { 9 | init_series(); 10 | init_chart(); 11 | init_axis(); 12 | } 13 | 14 | DensityPlot::~DensityPlot() 15 | { 16 | 17 | } 18 | 19 | void DensityPlot::set_data(QList& pos_list) 20 | { 21 | QVector dataset; 22 | 23 | for (auto& item : pos_list) 24 | { 25 | if (m_min_x > item.x()) 26 | m_min_x = item.x(); 27 | if (m_max_x < item.x()) 28 | m_max_x = item.x(); 29 | if (m_min_y > item.y()) 30 | m_min_y = item.y(); 31 | if (m_max_y < item.y()) 32 | m_max_y = item.y(); 33 | 34 | dataset.push_back(DensityPoint(item.x(), item.y())); 35 | } 36 | 37 | calculateDensity(dataset, radius); 38 | 39 | for (int i = 0; i < dataset.size(); i++) 40 | { 41 | auto pos = dataset.at(i); 42 | int zi = pos.pts; 43 | qreal x = pos.x; 44 | qreal y = pos.y; 45 | if (value2series.contains(zi)) 46 | value2series[zi]->append(x, y); 47 | else 48 | { 49 | QScatterSeries* scatter = new QScatterSeries; //散点图 50 | //scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); 51 | scatter->setMarkerSize(3.0); 52 | scatter->setBorderColor(Qt::transparent); 53 | scatter->append(x, y); 54 | value2series[zi] = scatter; 55 | } 56 | } 57 | 58 | m_axisX->setRange(m_min_x, m_max_x); 59 | m_axisY->setRange(m_min_y, m_max_y); 60 | m_color_item->set_value_range(1.0, value2series.size()); 61 | 62 | for (auto it = value2series.begin(); it != value2series.end(); ++it) 63 | { 64 | m_chart->addSeries(it.value()); 65 | it.value()->attachAxis(m_axisX); 66 | it.value()->attachAxis(m_axisY); 67 | it.value()->setBrush(m_color_item->getColor(it.key())); 68 | it.value()->setUseOpenGL(true); 69 | } 70 | } 71 | 72 | void DensityPlot::clear_data() 73 | { 74 | value2series.clear(); 75 | m_chart->series().clear(); 76 | } 77 | 78 | void DensityPlot::init_chart() 79 | { 80 | m_chart->legend()->hide(); 81 | 82 | m_color_item = new ColorBar(); 83 | m_color_item->set_chart(m_chart); 84 | m_chartview->add_item(m_color_item); 85 | } 86 | 87 | void DensityPlot::init_axis() 88 | { 89 | m_axisX = new QValueAxis(); 90 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 91 | m_axisX->setGridLineVisible(false); 92 | 93 | m_axisY = new QValueAxis(); 94 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 95 | m_axisY->setGridLineVisible(false); 96 | } 97 | 98 | void DensityPlot::init_series() 99 | { 100 | value2series.clear(); 101 | } 102 | 103 | double DensityPlot::squareDistance(DensityPoint a, DensityPoint b) 104 | { 105 | return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); 106 | } 107 | 108 | void DensityPlot::calculateDensity(QVector& dataset, float Eps) 109 | { 110 | int len = dataset.size(); 111 | 112 | for (int i = 0; i < len; i++) 113 | { 114 | for (int j = i + 1; j < len; j++) 115 | { 116 | if (squareDistance(dataset[i], dataset[j]) <= Eps) 117 | { 118 | dataset[i].pts++; 119 | dataset[j].pts++; 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/pareto_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "pareto_plot.h" 4 | #include 5 | using namespace std; 6 | 7 | ParetoPlot::ParetoPlot(QWidget *parent) 8 | : Plot(parent) 9 | { 10 | init_series(); 11 | init_chart(); 12 | init_axis(); 13 | } 14 | 15 | ParetoPlot::~ParetoPlot() 16 | { 17 | 18 | } 19 | 20 | void ParetoPlot::set_data(QList& value_list) 21 | { 22 | QList data = prepare_data(value_list); 23 | 24 | QVector line_center_poslist; 25 | QVector scatter_poslist; 26 | 27 | for (int i = 0; i < data.size(); i++) 28 | { 29 | m_axisy_list.append(data[i].m_name); 30 | m_set->append(data[i].m_value); 31 | 32 | line_center_poslist.append(QPointF(i, data[i].m_percent)); 33 | scatter_poslist.append(QPointF(i, data[i].m_percent)); 34 | } 35 | 36 | m_line->replace(line_center_poslist); 37 | m_scatter->replace(scatter_poslist); 38 | 39 | m_axisY_1->setRange(1, 60); 40 | m_axisX->append(m_axisy_list); 41 | m_axisX->setRange(m_axisy_list.first(), m_axisy_list.last()); 42 | 43 | //connect(m_scatter, &QScatterSeries::hovered, this, &Plot::slot_tool_tip); 44 | } 45 | 46 | void ParetoPlot::clear_data() 47 | { 48 | m_line->clear(); 49 | m_scatter->clear(); 50 | m_bar->clear(); 51 | } 52 | 53 | void ParetoPlot::init_chart() 54 | { 55 | m_chart->legend()->hide(); 56 | m_chart->addSeries(m_bar); 57 | m_chart->addSeries(m_line); 58 | m_chart->addSeries(m_scatter); 59 | } 60 | 61 | void ParetoPlot::init_axis() 62 | { 63 | m_axisX = new QBarCategoryAxis(); 64 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 65 | m_line->attachAxis(m_axisX); 66 | m_bar->attachAxis(m_axisX); 67 | m_scatter->attachAxis(m_axisX); 68 | 69 | m_axisY_1 = new QValueAxis(); 70 | m_axisY_1->setTitleText("计数"); 71 | m_chart->addAxis(m_axisY_1, Qt::AlignLeft); 72 | m_bar->attachAxis(m_axisY_1); 73 | 74 | m_axisY_2 = new QValueAxis(); 75 | m_axisY_2->setTitleText("累积频率"); 76 | m_axisY_2->setTickCount(12); 77 | m_axisY_2->setRange(0, 110); 78 | m_axisY_2->setLabelFormat("%.1f%"); 79 | m_axisY_2->setGridLineVisible(false); //隐藏背景网格Y轴框线 80 | m_chart->addAxis(m_axisY_2, Qt::AlignRight); 81 | m_line->attachAxis(m_axisY_2); 82 | m_scatter->attachAxis(m_axisY_2); 83 | } 84 | 85 | void ParetoPlot::init_series() 86 | { 87 | m_set = new QBarSet(""); 88 | m_bar = new QBarSeries(); 89 | m_bar->append(m_set); 90 | 91 | m_line = new QLineSeries(); 92 | m_line->append(QPointF(0, 0)); 93 | 94 | m_scatter = new QScatterSeries(); 95 | m_scatter->append(QPointF(0, 0)); 96 | m_scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); 97 | m_scatter->setMarkerSize(10); 98 | m_scatter->setPointLabelsVisible(); 99 | m_scatter->setPointLabelsFormat("@yPoint%"); 100 | m_scatter->setPointLabelsClipping(false); 101 | } 102 | 103 | QList& ParetoPlot::prepare_data(QList& value_list) 104 | { 105 | qSort(value_list.begin(), value_list.end(), 106 | [](const ParetoData& data1,const ParetoData& data2) 107 | { 108 | return data1.m_value > data2.m_value; 109 | }); 110 | double sum = accumulate(value_list.begin(), value_list.end(), 0, 111 | [](double a, ParetoData b) 112 | { 113 | return a + b.m_value; 114 | }); 115 | double result = 0; 116 | for (auto& item :value_list) 117 | { 118 | result += item.m_value; 119 | item.m_percent = result / sum * 100; 120 | } 121 | return value_list; 122 | } 123 | 124 | 125 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/SizeGripItem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SizeGripItem - A size grip QGraphicsItem for interactive resizing. 3 | * 4 | * Copyright (c) 2011 Cesar L. B. Silveira 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a 7 | * copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, including without limitation 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included 14 | * in all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | * IN THE SOFTWARE. 23 | */ 24 | 25 | #ifndef SIZEGRIPITEM_H 26 | #define SIZEGRIPITEM_H 27 | 28 | #include 29 | #include 30 | 31 | class SizeGripItem : public QGraphicsItem 32 | { 33 | private: 34 | enum 35 | { 36 | Top = 0x1, 37 | Bottom = 0x2, 38 | Left = 0x4, 39 | TopLeft = Top | Left, 40 | BottomLeft = Bottom | Left, 41 | Right = 0x8, 42 | TopRight = Top | Right, 43 | BottomRight = Bottom | Right 44 | }; 45 | 46 | class HandleItem : public QGraphicsRectItem 47 | { 48 | public: 49 | HandleItem(int positionFlags, SizeGripItem* parent); 50 | int positionFlags() const; 51 | 52 | protected: 53 | virtual QVariant itemChange(GraphicsItemChange change, 54 | const QVariant &value); 55 | 56 | private: 57 | QPointF restrictPosition(const QPointF& newPos); 58 | 59 | int positionFlags_; 60 | SizeGripItem* parent_; 61 | }; 62 | 63 | public: 64 | class Resizer 65 | { 66 | public: 67 | virtual void operator()(QGraphicsItem* item, 68 | const QRectF& rect) = 0; 69 | }; 70 | 71 | SizeGripItem(Resizer* resizer = 0, QGraphicsItem* parent = 0); 72 | virtual ~SizeGripItem(); 73 | virtual QRectF boundingRect() const; 74 | virtual void paint(QPainter* painter, 75 | const QStyleOptionGraphicsItem* option, 76 | QWidget* widget = 0); 77 | void setTopLeft(const QPointF& pos); 78 | void setTop(qreal y); 79 | void setTopRight(const QPointF& pos); 80 | void setRight(qreal x); 81 | void setBottomRight(const QPointF& pos); 82 | void setBottom(qreal y); 83 | void setBottomLeft(const QPointF& pos); 84 | void setLeft(qreal x); 85 | 86 | private: 87 | void doResize(); 88 | void updateHandleItemPositions(); 89 | 90 | QList handleItems_; 91 | QRectF rect_; 92 | Resizer* resizer_; 93 | }; 94 | 95 | #endif // SIZEGRIPITEM_H 96 | -------------------------------------------------------------------------------- /projects/Graph/src/graph/poly_line.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "poly_line.h" 4 | #include "util.h" 5 | #include 6 | #include 7 | 8 | PolyLine::PolyLine() 9 | : GraphicsItem() 10 | { 11 | setZValue(1); 12 | setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); 13 | } 14 | 15 | QList PolyLine::get_points() const 16 | { 17 | return m_points; 18 | } 19 | 20 | void PolyLine::set_points(const QList& points) 21 | { 22 | m_points = points; 23 | } 24 | 25 | void PolyLine::append_point(const QPointF& point) 26 | { 27 | m_points.append(point); 28 | } 29 | 30 | QPointF PolyLine::get_last_point() const 31 | { 32 | QPointF lpt; 33 | if (!m_points.isEmpty()) 34 | lpt = m_points.last(); 35 | return lpt; 36 | } 37 | 38 | void PolyLine::set_last_point(const QPointF& point) 39 | { 40 | m_points.pop_back(); 41 | append_point(point); 42 | } 43 | 44 | QRectF PolyLine::boundingRect() const 45 | { 46 | auto points = get_points(); 47 | for (auto& p : points) p.setY(-p.y()); 48 | QRectF rect = Util::bounding_rect(points); 49 | return rect; 50 | } 51 | 52 | void PolyLine::on_paint(QPainter* painter) 53 | { 54 | auto points = get_points().toVector(); 55 | for (int i = 0; i < points.size() - 1; ++i) 56 | { 57 | auto p1 = points[i]; 58 | auto p2 = points[i + 1]; 59 | if ((p1 - p2).manhattanLength() > TOLERANCE) 60 | { 61 | p1.setY(-p1.y()); 62 | p2.setY(-p2.y()); 63 | painter->drawLine(p1, p2); 64 | } 65 | } 66 | } 67 | 68 | GraphicsItem* PolyLine::clone() 69 | { 70 | PolyLine* line = new PolyLine(); 71 | line->set_points(m_points); 72 | return line; 73 | } 74 | 75 | /////////////////////////////////////////////////////////////////////////////// 76 | //箭头线 77 | Arrows::Arrows() 78 | { 79 | 80 | } 81 | 82 | GraphicsItem* Arrows::clone() 83 | { 84 | Arrows* arrows = new Arrows(); 85 | arrows->set_points(m_points); 86 | return arrows; 87 | } 88 | 89 | void Arrows::on_paint(QPainter* painter) 90 | { 91 | auto points = get_points().toVector(); 92 | for (int i = 0; i < points.size() - 1; ++i) 93 | { 94 | auto p1 = points[i]; 95 | auto p2 = points[i + 1]; 96 | if ((p1 - p2).manhattanLength() > TOLERANCE) 97 | { 98 | p1.setY(-p1.y()); 99 | p2.setY(-p2.y()); 100 | painter->drawLine(p1, p2); 101 | 102 | if (i + 1 == points.size() - 1) 103 | { 104 | QLineF line(p1, p2); 105 | double angle = std::atan2(-line.dy(), line.dx()); 106 | qreal arrowSize = 10; 107 | QPointF arrowP1 = line.p2() - QPointF(sin(angle + PI / 3) * arrowSize, 108 | cos(angle + PI / 3) * arrowSize); 109 | QPointF arrowP2 = line.p2() - QPointF(sin(angle + PI - PI / 3) * arrowSize, 110 | cos(angle + PI - PI / 3) * arrowSize); 111 | QPolygonF arrowHead; 112 | arrowHead << line.p2() << arrowP2 << arrowP1; 113 | painter->drawLine(p2, arrowP1); 114 | painter->drawLine(p2, arrowP2); 115 | } 116 | } 117 | else 118 | { 119 | auto p1 = points[i - 1]; p1.setY(-p1.y()); 120 | auto p2 = points[i]; p2.setY(-p2.y()); 121 | QLineF line(p1, p2); 122 | double angle = std::atan2(-line.dy(), line.dx()); 123 | qreal arrowSize = 10; 124 | QPointF arrowP1 = line.p2() - QPointF(sin(angle + PI / 3) * arrowSize, 125 | cos(angle + PI / 3) * arrowSize); 126 | QPointF arrowP2 = line.p2() - QPointF(sin(angle + PI - PI / 3) * arrowSize, 127 | cos(angle + PI - PI / 3) * arrowSize); 128 | QPolygonF arrowHead; 129 | arrowHead << line.p2() << arrowP2 << arrowP1; 130 | painter->drawLine(p2, arrowP1); 131 | painter->drawLine(p2, arrowP2); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "plot.h" 4 | #include "tool_tip.h" 5 | #include "chart_view.h" 6 | #include "poly_line_preview.h" 7 | 8 | Plot::Plot(bool IsPolar, QWidget *parent) 9 | : QWidget(parent) 10 | { 11 | if (IsPolar) 12 | m_chart = new QPolarChart(); 13 | else 14 | m_chart = new QChart(); 15 | m_chartview = new ChartView(m_chart); 16 | 17 | QHBoxLayout* layout = new QHBoxLayout; 18 | layout->setMargin(0); 19 | layout->setSpacing(0); 20 | layout->addWidget(m_chartview); 21 | setLayout(layout); 22 | } 23 | 24 | Plot::~Plot() 25 | { 26 | } 27 | 28 | void Plot::slot_tool_tip(QPointF point, bool state) 29 | { 30 | if (m_tooltip == nullptr) 31 | m_tooltip = new ToolTip(m_chart); 32 | if (state) { 33 | m_tooltip->setText(QString("X: %1 \nY: %2 ").arg(point.x()).arg(point.y())); 34 | m_tooltip->setAnchor(point); 35 | m_tooltip->setZValue(11); 36 | m_tooltip->updateGeometry(); 37 | m_tooltip->show(); 38 | } 39 | else 40 | m_tooltip->hide(); 41 | } 42 | 43 | void Plot::add_title(const QString& name) 44 | { 45 | m_chart->setTitle(name); 46 | } 47 | 48 | void Plot::connect_markers() 49 | { 50 | const auto markers = m_chart-> legend()->markers(); 51 | for (QLegendMarker* marker : markers) 52 | { 53 | disconnect(marker, &QLegendMarker::clicked, this, &Plot::slot_handle_marker_clicked); 54 | connect(marker, &QLegendMarker::clicked, this, &Plot::slot_handle_marker_clicked); 55 | } 56 | } 57 | 58 | void Plot::disconnect_markers() 59 | { 60 | const auto markers = m_chart->legend()->markers(); 61 | for (QLegendMarker* marker : markers) 62 | disconnect(marker, &QLegendMarker::clicked, this, &Plot::slot_handle_marker_clicked); 63 | } 64 | 65 | void Plot::draw_line() 66 | { 67 | new PolyLinePreview(m_chartview); 68 | } 69 | 70 | void Plot::draw_arrows() 71 | { 72 | new ArrowsPreview(m_chartview); 73 | } 74 | 75 | void Plot::resizeEvent(QResizeEvent* event) 76 | { 77 | //遍历每一个图例 78 | //const auto markers = m_chart->legend()->markers(); 79 | //for (QLegendMarker* marker : markers) 80 | //{ 81 | // if (marker = markers[1]) 82 | // marker->setVisible(false); 83 | //} 84 | 85 | //QLegend* legend = m_chart->legend(); 86 | //if (legend->isAttachedToChart()) { 87 | // legend->detachFromChart(); 88 | // m_chart->legend()->setGeometry(m_chart->plotArea().x(), m_chart->plotArea().y(), 100, 100); 89 | // m_chart->legend()->setBackgroundVisible(true); 90 | // m_chart->legend()->setBrush(QBrush(QColor(128, 128, 128, 128))); 91 | // m_chart->legend()->setPen(QPen(QColor(192, 192, 192, 192))); 92 | // m_chart->legend()->update(); 93 | //} 94 | } 95 | 96 | void Plot::slot_handle_marker_clicked() 97 | { 98 | QLegendMarker* marker = qobject_cast (sender()); 99 | Q_ASSERT(marker); 100 | 101 | switch (marker->type()) 102 | { 103 | case QLegendMarker::LegendMarkerTypeXY: 104 | { 105 | marker->series()->setVisible(!marker->series()->isVisible()); 106 | marker->setVisible(true); 107 | qreal alpha = 1.0; 108 | 109 | if (!marker->series()->isVisible()) 110 | alpha = 0.5; 111 | 112 | QColor color; 113 | QBrush brush = marker->labelBrush(); 114 | color = brush.color(); 115 | color.setAlphaF(alpha); 116 | brush.setColor(color); 117 | marker->setLabelBrush(brush); 118 | 119 | brush = marker->brush(); 120 | color = brush.color(); 121 | color.setAlphaF(alpha); 122 | brush.setColor(color); 123 | marker->setBrush(brush); 124 | 125 | QPen pen = marker->pen(); 126 | color = pen.color(); 127 | color.setAlphaF(alpha); 128 | pen.setColor(color); 129 | marker->setPen(pen); 130 | break; 131 | } 132 | default: 133 | break; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/interval_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "interval_plot.h" 4 | #include "chart_view.h" 5 | #include "util.h" 6 | #include "color_bar.h" 7 | 8 | IntervalPlot::IntervalPlot(QWidget *parent) 9 | : Plot(parent) 10 | { 11 | init_series(); 12 | init_chart(); 13 | init_axis(); 14 | } 15 | 16 | IntervalPlot::~IntervalPlot() 17 | { 18 | 19 | } 20 | 21 | void IntervalPlot::set_data(QList& list) 22 | { 23 | for (int i = 0; i < list.size(); i++) 24 | { 25 | double min, max; 26 | add_interval(list[i], i, min, max); 27 | m_axisx_list.append(list[i].m_name); 28 | if (max > m_max_y) 29 | m_max_y = max; 30 | if (min < m_min_y) 31 | m_min_y = min; 32 | } 33 | m_axisX->setCategories(m_axisx_list); 34 | m_axisY->setRange(m_min_y * 0.9, m_max_y * 1.1); 35 | } 36 | 37 | void IntervalPlot::add_interval(BoxData& data, int index, double& y_min, double& y_max) 38 | { 39 | if (m_name2item.contains(data.m_name)) 40 | return; 41 | 42 | IntervalItem* item = new IntervalItem(); 43 | item->set_data(data, index); 44 | item->set_chart(m_chart); 45 | y_min = item->get_min(); 46 | y_max = item->get_max(); 47 | m_chartview->add_item(item); 48 | m_name2item[data.m_name] = item; 49 | } 50 | 51 | void IntervalPlot::init_chart() 52 | { 53 | //m_chart->legend()->hide(); 54 | m_chart->addSeries(m_series); 55 | } 56 | 57 | void IntervalPlot::init_axis() 58 | { 59 | m_axisX = new QBarCategoryAxis(); 60 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 61 | m_series->attachAxis(m_axisX); 62 | 63 | m_axisY = new QValueAxis(); 64 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 65 | m_series->attachAxis(m_axisY); 66 | } 67 | 68 | void IntervalPlot::init_series() 69 | { 70 | m_series = new QScatterSeries(); 71 | } 72 | 73 | ////////////////////////////////////////////////////////////////////////////// 74 | /// 间隔图 75 | IntervalItem::IntervalItem() 76 | { 77 | connect(this, &IntervalItem::signal_prepare_path, this, &IntervalItem::slot_prepare_path); 78 | } 79 | 80 | void IntervalItem::set_chart(QChart* chart) 81 | { 82 | m_chart = chart; 83 | } 84 | 85 | void IntervalItem::set_data(BoxData& data, int index) 86 | { 87 | double mean, sum, min, max; 88 | Util::cal_list(data.m_value_list, mean, sum, max, min); 89 | 90 | m_list = data.m_value_list; 91 | m_name = data.m_name; 92 | m_min = QPointF(index, min); 93 | m_max = QPointF(index, max); 94 | m_mean = QPointF(index, mean); 95 | m_sum = QPointF(index, sum); 96 | } 97 | 98 | double IntervalItem::get_max() 99 | { 100 | return m_max.y(); 101 | } 102 | 103 | double IntervalItem::get_min() 104 | { 105 | return m_min.y(); 106 | } 107 | 108 | void IntervalItem::slot_prepare_path() 109 | { 110 | QLineF line(m_chart->mapToPosition(QPointF(0, 0)), m_chart->mapToPosition(QPointF(1, 0))); 111 | double width = line.length(); 112 | QPointF top = m_chart->mapToPosition(m_max); 113 | QPointF buttom = m_chart->mapToPosition(m_min); 114 | QPointF center = m_chart->mapToPosition(m_mean); 115 | QPointF tl = top - QPointF(width * 0.05, 0); 116 | QPointF tr = top + QPointF(width * 0.05, 0); 117 | QPointF bl = buttom - QPointF(width * 0.05, 0); 118 | QPointF br = buttom + QPointF(width * 0.05, 0); 119 | 120 | QPainterPath path; 121 | path.moveTo(top); 122 | path.lineTo(buttom); 123 | path.moveTo(tl); 124 | path.lineTo(tr); 125 | path.moveTo(bl); 126 | path.lineTo(br); 127 | path.addEllipse(center, width * 0.05, width * 0.05); 128 | 129 | m_shape = path; 130 | } 131 | 132 | QRectF IntervalItem::boundingRect() const 133 | { 134 | emit signal_prepare_path(); 135 | return m_chart->plotArea().intersected(m_shape.boundingRect()); 136 | } 137 | 138 | void IntervalItem::on_paint(QPainter* painter) 139 | { 140 | painter->setClipRect(boundingRect()); 141 | painter->drawPath(m_shape); 142 | } 143 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/radar_plot.cpp: -------------------------------------------------------------------------------- 1 | #include "radar_plot.h" 2 | #include 3 | #include "chart_view.h" 4 | #include "math_define.h" 5 | 6 | RadarPlot::RadarPlot(QWidget *parent) 7 | : Plot(true, parent) 8 | { 9 | init_series(); 10 | init_chart(); 11 | init_axis(); 12 | set_radar_type(m_radartype); 13 | } 14 | 15 | RadarPlot::~RadarPlot() 16 | { 17 | } 18 | 19 | void RadarPlot::set_radar(QStringList& lablelist) 20 | { 21 | count = lablelist.size(); 22 | const auto offset = 360 / count; 23 | for (int i = 0; i < count; i++) 24 | m_angularAxis->append(lablelist[i], offset * i); 25 | } 26 | 27 | void RadarPlot::add_radar(QList& valuelist, const QString& name) 28 | { 29 | if (valuelist.size() != count) 30 | return; 31 | if (m_name2series.contains(name)) 32 | return; 33 | QLineSeries* series = new QLineSeries(); 34 | series->setName(name); 35 | for (int i = 0; i < count; i++) 36 | { 37 | if (valuelist[i] < m_min_x) 38 | m_min_x = valuelist[i]; 39 | if (valuelist[i] > m_max_x) 40 | m_max_x = valuelist[i]; 41 | series->append(360 / count * i, valuelist[i]); 42 | } 43 | series->append(360, valuelist.first()); 44 | 45 | m_chart->addSeries(series); 46 | m_name2series[name] = series; 47 | series->attachAxis(m_angularAxis); 48 | series->attachAxis(m_radialAxis); 49 | m_radialAxis->setRange(m_min_x * 0.9, m_max_x * 1.1); 50 | } 51 | 52 | void RadarPlot::delete_radar(const QString& name) 53 | { 54 | if (!m_name2series.contains(name)) 55 | return; 56 | m_chart->removeSeries(m_name2series[name]); 57 | m_name2series.remove(name); 58 | } 59 | 60 | void RadarPlot::set_radar_type(RadarType type) 61 | { 62 | m_radartype = type; 63 | switch (m_radartype) 64 | { 65 | case Radar: 66 | m_radialAxis->setGridLineVisible(true); 67 | m_angularAxis->setLineVisible(true); 68 | item->setVisible(false); 69 | break; 70 | case Spider: 71 | m_radialAxis->setGridLineVisible(false); 72 | m_angularAxis->setLineVisible(false); 73 | item->setVisible(true); 74 | break; 75 | default: 76 | break; 77 | } 78 | } 79 | 80 | void RadarPlot::init_chart() 81 | { 82 | //m_chart->legend()->setVisible(true); 83 | m_chart->legend()->setAlignment(Qt::AlignRight); 84 | item = new RadarItem(); 85 | item->set_chart(m_chart); 86 | m_chartview->add_item(item); 87 | } 88 | 89 | void RadarPlot::init_axis() 90 | { 91 | m_angularAxis = new QCategoryAxis(); 92 | m_angularAxis->setRange(0, 360); 93 | m_angularAxis->setStartValue(0); 94 | m_angularAxis->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue); 95 | dynamic_cast(m_chart)->addAxis(m_angularAxis, QPolarChart::PolarOrientationAngular); 96 | 97 | m_radialAxis = new QValueAxis(); 98 | m_radialAxis->setTickCount(7); 99 | dynamic_cast(m_chart)->addAxis(m_radialAxis, QPolarChart::PolarOrientationRadial); 100 | } 101 | 102 | void RadarPlot::init_series() 103 | { 104 | m_name2series.clear(); 105 | } 106 | 107 | ////////////////////////////////////////////////////////////////////////////// 108 | /// 雷达图 109 | RadarItem::RadarItem() 110 | { 111 | 112 | } 113 | 114 | void RadarItem::set_chart(QChart* chart) 115 | { 116 | m_chart = chart; 117 | } 118 | 119 | void RadarItem::set_radial(int radial) 120 | { 121 | m_radial = radial; 122 | } 123 | 124 | void RadarItem::set_angular(int angular) 125 | { 126 | m_angular = angular; 127 | } 128 | 129 | QRectF RadarItem::boundingRect() const 130 | { 131 | return m_chart->plotArea(); 132 | } 133 | 134 | void RadarItem::on_paint(QPainter* painter) 135 | { 136 | for (int i = 0; i <= m_radial; i++) 137 | { 138 | int rad = i * boundingRect().width() / 2 / m_radial ; 139 | QPolygonF poslist; 140 | for (int j = 0; j < m_angular; j++) 141 | { 142 | QPen pen; 143 | QColor color(Qt::lightGray); 144 | pen.setWidthF(0.4); 145 | painter->setPen(pen); 146 | int x = 360 * j / m_angular; 147 | QPointF pos = boundingRect().center() - QPointF(sin(x * PI / 180) * rad, cos(x * PI / 180) * rad); 148 | poslist.append(pos); 149 | } 150 | painter->drawPolygon(poslist); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/boxbar_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "boxbar_plot.h" 4 | #include "util.h" 5 | #include 6 | #include "chart_view.h" 7 | #include "plot.h" 8 | 9 | BoxBarPlot::BoxBarPlot(QWidget* parent) 10 | : Plot(parent) 11 | { 12 | init_series(); 13 | init_chart(); 14 | init_axis(); 15 | } 16 | 17 | BoxBarPlot::~BoxBarPlot() 18 | { 19 | } 20 | 21 | void BoxBarPlot::set_type(BoxBarType type) 22 | { 23 | switch (type) 24 | { 25 | case MEAN: 26 | break; 27 | case SUM: 28 | break; 29 | case MAX: 30 | break; 31 | case MIN: 32 | break; 33 | default: 34 | break; 35 | } 36 | } 37 | 38 | void BoxBarPlot::set_data(QList& list) 39 | { 40 | for (int i = 0; i < list.size(); i++) 41 | { 42 | if (Util::max(list[i].m_value_list) > m_max_y) 43 | m_max_y = Util::max(list[i].m_value_list); 44 | add_boxbar(list[i],list.size(),i); 45 | } 46 | 47 | m_axisX->setCategories(m_axisx_list); 48 | m_axisY->setRange(0, m_max_y * 1.1); 49 | } 50 | 51 | void BoxBarPlot::add_boxbar(BoxData& data, int size, int index) 52 | { 53 | if (m_name2series.contains(data.m_name)) 54 | return; 55 | 56 | double mean, sum, min, max; 57 | QBarSet* box = new QBarSet(data.m_name); 58 | Util::cal_list(data.m_value_list, mean, sum, max, min); 59 | box->setProperty("mean", mean); 60 | box->setProperty("sum", sum); 61 | box->setProperty("min", max); 62 | box->setProperty("max", min); 63 | box->setProperty("index", index); 64 | 65 | for (int i = 0; i < size; i++) 66 | box->append(0); 67 | box->replace(index, mean); 68 | 69 | m_axisx_list.append(data.m_name); 70 | m_series->append(box); 71 | 72 | 73 | BoxBarItem* item = new BoxBarItem(); 74 | item->set_chart(m_chart); 75 | item->set_data(mean, sum, min, max, index); 76 | m_chartview->add_item(item); 77 | m_name2item[data.m_name] = item; 78 | 79 | m_name2series[data.m_name] = box; 80 | } 81 | 82 | void BoxBarPlot::delete_boxbar(const QString& name) 83 | { 84 | if (!m_name2series.contains(name)) 85 | return; 86 | m_series->remove(m_name2series[name]); 87 | m_name2series.remove(name); 88 | 89 | m_chartview->delete_item(m_name2item[name]); 90 | m_name2item.remove(name); 91 | } 92 | 93 | void BoxBarPlot::init_chart() 94 | { 95 | m_chart->addSeries(m_series); 96 | } 97 | 98 | void BoxBarPlot::init_axis() 99 | { 100 | m_axisX = new QBarCategoryAxis(); 101 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 102 | m_series->attachAxis(m_axisX); 103 | 104 | m_axisY = new QValueAxis(); 105 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 106 | m_series->attachAxis(m_axisY); 107 | } 108 | 109 | void BoxBarPlot::init_series() 110 | { 111 | m_series = new QStackedBarSeries(); 112 | } 113 | 114 | BoxBarItem::BoxBarItem() 115 | { 116 | connect(this, &BoxBarItem::signal_prepare_path, this, &BoxBarItem::slot_prepare_path); 117 | } 118 | 119 | void BoxBarItem::set_chart(QChart* chart) 120 | { 121 | m_chart = chart; 122 | } 123 | 124 | void BoxBarItem::set_data(double mean, double sum, double min, double max, int index) 125 | { 126 | m_min = QPointF(index, min); 127 | m_max = QPointF(index, max); 128 | m_mean = QPointF(index, mean); 129 | m_sum = QPointF(index, sum); 130 | } 131 | 132 | void BoxBarItem::slot_prepare_path() 133 | { 134 | QLineF line(m_chart->mapToPosition(QPointF(0, 0)), m_chart->mapToPosition(QPointF(1, 0))); 135 | double width = line.length(); 136 | QPointF top = m_chart->mapToPosition(m_max); 137 | QPointF buttom = m_chart->mapToPosition(m_min); 138 | QPointF center = m_chart->mapToPosition(m_mean); 139 | QPointF tl = top - QPointF(width * 0.1, 0); 140 | QPointF tr = top + QPointF(width * 0.1, 0); 141 | QPointF bl = buttom - QPointF(width * 0.1, 0); 142 | QPointF br = buttom + QPointF(width * 0.1, 0); 143 | 144 | QPainterPath path; 145 | path.moveTo(top); 146 | path.lineTo(center); 147 | path.moveTo(tl); 148 | path.lineTo(tr); 149 | 150 | m_shape = path; 151 | } 152 | 153 | QRectF BoxBarItem::boundingRect() const 154 | { 155 | emit signal_prepare_path(); 156 | return m_chart->plotArea().intersected(m_shape.boundingRect()); 157 | } 158 | 159 | void BoxBarItem::on_paint(QPainter* painter) 160 | { 161 | painter->setClipRect(boundingRect()); 162 | painter->drawPath(m_shape); 163 | } 164 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/qq_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "qq_plot.h" 4 | #include 5 | #include "util.h" 6 | #include "tool_tip.h" 7 | 8 | QQPlot::QQPlot(QWidget *parent) 9 | : Plot(parent) 10 | { 11 | init_series(); 12 | init_chart(); 13 | init_axis(); 14 | } 15 | 16 | QQPlot::~QQPlot() 17 | { 18 | 19 | } 20 | 21 | void QQPlot::slot_tool_tip(QPointF point, bool state) 22 | { 23 | if (m_tooltip == nullptr) 24 | m_tooltip = new ToolTip(m_chart); 25 | if (state) { 26 | m_tooltip->setText(QString("X: %1 \nY: %2% ").arg(point.x()).arg(point.y())); 27 | m_tooltip->setAnchor(point); 28 | m_tooltip->setZValue(11); 29 | m_tooltip->updateGeometry(); 30 | m_tooltip->show(); 31 | } 32 | else { 33 | m_tooltip->hide(); 34 | } 35 | } 36 | 37 | void QQPlot::add_data(QList& list, const QString& name) 38 | { 39 | prepare_data(list); 40 | 41 | QVector line_center_poslist; 42 | QVector scatter_poslist; 43 | 44 | for (Probability& item : m_probability_list) 45 | { 46 | line_center_poslist.append(QPointF(item.theory, item.theory)); 47 | scatter_poslist.append(QPointF(item.reality, item.theory)); 48 | } 49 | 50 | m_line_center->replace(line_center_poslist); 51 | m_scatter->replace(scatter_poslist); 52 | 53 | m_axisX->setRange(m_min_x - 1, m_max_x + 1); 54 | m_axisY->setRange(m_min_x - 10, m_max_x + 10); 55 | } 56 | 57 | void QQPlot::init_chart() 58 | { 59 | //m_chart->legend()->hide(); 60 | m_chart->addSeries(m_line_center); 61 | m_chart->addSeries(m_scatter); 62 | } 63 | 64 | void QQPlot::init_axis() 65 | { 66 | m_axisX = new QValueAxis(); 67 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 68 | m_line_top->attachAxis(m_axisX); 69 | m_line_center->attachAxis(m_axisX); 70 | m_line_bottom->attachAxis(m_axisX); 71 | m_scatter->attachAxis(m_axisX); 72 | 73 | m_axisY = new QValueAxis(); 74 | m_axisY->setTitleText("期望正态值"); 75 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 76 | m_line_top->attachAxis(m_axisY); 77 | m_line_center->attachAxis(m_axisY); 78 | m_line_bottom->attachAxis(m_axisY); 79 | m_scatter->attachAxis(m_axisY); 80 | } 81 | 82 | void QQPlot::init_series() 83 | { 84 | m_line_center = new QLineSeries(m_chart); 85 | m_line_center->setName("参照线"); 86 | m_line_center->append(QPointF(0, 0)); 87 | 88 | m_line_top = new QLineSeries(m_chart); 89 | m_line_top->setName("上线百分位数"); 90 | m_line_top->append(QPointF(0, 0)); 91 | 92 | m_line_bottom = new QLineSeries(m_chart); 93 | m_line_bottom->setName("下线百分位数"); 94 | m_line_bottom->append(QPointF(0, 0)); 95 | 96 | m_scatter = new QScatterSeries(); 97 | m_scatter->setName("百分数位"); 98 | m_scatter->append(QPointF(0, 0)); 99 | m_scatter->setMarkerSize(10); 100 | m_scatter->setBorderColor(Qt::transparent); 101 | connect(m_scatter, &QScatterSeries::hovered, this, &QQPlot::slot_tool_tip); 102 | } 103 | 104 | void QQPlot::prepare_data(QList& list) 105 | { 106 | if (list.isEmpty()) 107 | return; 108 | 109 | m_n = list.count(); 110 | m_mean = Util::average(list); 111 | m_variance = Util::variance(list, m_mean); 112 | m_sigma = Util::standard_deviation(list, m_variance); 113 | 114 | m_probability_list.clear(); 115 | 116 | qSort(list); 117 | for (int i = 0; i < list.size(); i++) 118 | { 119 | if (list[i] < m_min_x) 120 | m_min_x = list[i]; 121 | if (list[i] > m_max_x) 122 | m_max_x = list[i]; 123 | 124 | Probability pro; 125 | pro.index = i + 1; 126 | pro.theory_cdf = calculate_cdf(pro.index, list.size()); 127 | pro.theory_z = Util::normsinv(pro.theory_cdf); 128 | pro.theory = m_mean + pro.theory_z * m_sigma; 129 | pro.reality = list.at(i); 130 | pro.reality_z = (pro.reality - m_mean) / m_sigma; 131 | pro.reality_cdf = Util::normsdist(pro.reality_z); 132 | m_probability_list.append(pro); 133 | } 134 | } 135 | 136 | double QQPlot::calculate_cdf(int index, int n) 137 | { 138 | double value = DBL_MIN; 139 | switch (m_score_type) 140 | { 141 | case Blom: 142 | value = (index - 0.375) / (n + 0.25); 143 | break; 144 | case Benard: 145 | value = (index - 0.3) / (n + 0.4); 146 | break; 147 | case Hazen: 148 | value = (index - 0.5) / n; 149 | break; 150 | case VanDerWaerden: 151 | value = index / (n + 1); 152 | break; 153 | case KaplanMeier: 154 | value = index / n; 155 | break; 156 | default: 157 | break; 158 | } 159 | return value; 160 | } 161 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/tool_tip.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "tool_tip.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | ToolTip::ToolTip(QChart* chart, QWidget* parent) 11 | : QGraphicsItem(chart), m_chart(chart), m_widget(parent) 12 | { 13 | 14 | } 15 | 16 | ToolTip::~ToolTip() 17 | { 18 | 19 | } 20 | 21 | void ToolTip::setText(const QString& text) 22 | { 23 | m_text = text; 24 | QFontMetrics metrics(m_font); 25 | m_textRect = metrics.boundingRect(QRect(0, 0, 150, 150), Qt::AlignLeft, m_text); 26 | m_textRect.translate(5, 5); 27 | prepareGeometryChange(); 28 | m_rect = m_textRect.adjusted(-5, -5, 5, 5); 29 | } 30 | 31 | void ToolTip::setAnchor(QPointF point) 32 | { 33 | m_anchor = point; 34 | } 35 | 36 | void ToolTip::updateGeometry() 37 | { 38 | prepareGeometryChange(); 39 | if (m_widget == nullptr) 40 | setPos(m_chart->mapToPosition(m_anchor) + QPoint(10, -50)); 41 | else 42 | setPos(m_anchor + QPoint(10, -50)); 43 | } 44 | 45 | QRectF ToolTip::boundingRect() const 46 | { 47 | QPointF anchor; 48 | if (m_widget == nullptr) 49 | anchor = mapFromParent(m_chart->mapToPosition(m_anchor)); 50 | else 51 | anchor = m_anchor; 52 | QRectF rect; 53 | rect.setLeft(qMin(m_rect.left(), anchor.x())); 54 | rect.setRight(qMax(m_rect.right(), anchor.x())); 55 | rect.setTop(qMin(m_rect.top(), anchor.y())); 56 | rect.setBottom(qMax(m_rect.bottom(), anchor.y())); 57 | return rect; 58 | } 59 | 60 | void ToolTip::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) 61 | { 62 | Q_UNUSED(option); 63 | Q_UNUSED(widget); 64 | QPainterPath path; 65 | path.addRoundedRect(m_rect, 5, 5); 66 | 67 | QPointF anchor; 68 | if (m_widget == nullptr) 69 | anchor = mapFromParent(m_chart->mapToPosition(m_anchor)); 70 | else 71 | anchor = m_anchor; 72 | if (!m_rect.contains(anchor) && !m_anchor.isNull()) { 73 | QPointF point1, point2; 74 | 75 | // establish the position of the anchor point in relation to m_rect 76 | bool above = anchor.y() <= m_rect.top(); 77 | bool aboveCenter = anchor.y() > m_rect.top() && anchor.y() <= m_rect.center().y(); 78 | bool belowCenter = anchor.y() > m_rect.center().y() && anchor.y() <= m_rect.bottom(); 79 | bool below = anchor.y() > m_rect.bottom(); 80 | 81 | bool onLeft = anchor.x() <= m_rect.left(); 82 | bool leftOfCenter = anchor.x() > m_rect.left() && anchor.x() <= m_rect.center().x(); 83 | bool rightOfCenter = anchor.x() > m_rect.center().x() && anchor.x() <= m_rect.right(); 84 | bool onRight = anchor.x() > m_rect.right(); 85 | 86 | // get the nearest m_rect corner. 87 | qreal x = (onRight + rightOfCenter) * m_rect.width(); 88 | qreal y = (below + belowCenter) * m_rect.height(); 89 | bool cornerCase = (above && onLeft) || (above && onRight) || (below && onLeft) || (below && onRight); 90 | bool vertical = qAbs(anchor.x() - x) > qAbs(anchor.y() - y); 91 | 92 | qreal x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * !vertical * (onLeft * 10 - onRight * 20); 93 | qreal y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (above * 10 - below * 20);; 94 | point1.setX(x1); 95 | point1.setY(y1); 96 | 97 | qreal x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * !vertical * (onLeft * 20 - onRight * 10);; 98 | qreal y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (above * 20 - below * 10);; 99 | point2.setX(x2); 100 | point2.setY(y2); 101 | 102 | if (m_widget == nullptr) 103 | { 104 | path.moveTo(point1); 105 | path.lineTo(anchor); 106 | path.lineTo(point2); 107 | path = path.simplified(); 108 | } 109 | //else 110 | //{ 111 | // path.moveTo(point1); 112 | // path.lineTo(anchor); 113 | // path.lineTo(point2); 114 | // path = path.simplified(); 115 | //} 116 | } 117 | painter->setBrush(QColor(255, 255, 255)); 118 | painter->drawPath(path); 119 | painter->drawText(m_textRect, m_text); 120 | } 121 | 122 | void ToolTip::mousePressEvent(QGraphicsSceneMouseEvent* event) 123 | { 124 | event->setAccepted(true); 125 | } 126 | 127 | void ToolTip::mouseMoveEvent(QGraphicsSceneMouseEvent* event) 128 | { 129 | if (event->buttons() & Qt::LeftButton) { 130 | setPos(mapToParent(event->pos() - event->buttonDownPos(Qt::LeftButton))); 131 | event->setAccepted(true); 132 | } 133 | else { 134 | event->setAccepted(false); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/probability_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "probability_plot.h" 4 | #include 5 | #include "util.h" 6 | #include "tool_tip.h" 7 | 8 | ProbabilityPlot::ProbabilityPlot(QWidget *parent) 9 | : Plot(parent) 10 | { 11 | init_series(); 12 | init_chart(); 13 | init_axis(); 14 | } 15 | 16 | ProbabilityPlot::~ProbabilityPlot() 17 | { 18 | } 19 | 20 | void ProbabilityPlot::slot_tool_tip(QPointF point, bool state) 21 | { 22 | if (m_tooltip == nullptr) 23 | m_tooltip = new ToolTip(m_chart); 24 | if (state) { 25 | m_tooltip->setText(QString("X: %1 \nY: %2% ").arg(point.x()).arg(Util::normsdist(point.y())*100)); 26 | m_tooltip->setAnchor(point); 27 | m_tooltip->setZValue(11); 28 | m_tooltip->updateGeometry(); 29 | m_tooltip->show(); 30 | } 31 | else { 32 | m_tooltip->hide(); 33 | } 34 | } 35 | 36 | void ProbabilityPlot::add_data(QList& list, const QString& name) 37 | { 38 | prepare_data(list); 39 | 40 | QVector line_center_poslist; 41 | QVector scatter_poslist; 42 | 43 | for (Probability &item : m_probability_list) 44 | { 45 | line_center_poslist.append(QPointF(item.theory,item.theory_z)); 46 | scatter_poslist.append(QPointF(item.reality, item.theory_z)); 47 | } 48 | 49 | m_line_center->replace(line_center_poslist); 50 | m_scatter->replace(scatter_poslist); 51 | 52 | m_axisX->setRange(m_min_x - 1, m_max_x + 1); 53 | } 54 | 55 | void ProbabilityPlot::init_chart() 56 | { 57 | //m_chart->legend()->hide(); 58 | m_chart->addSeries(m_line_center); 59 | m_chart->addSeries(m_scatter); 60 | } 61 | 62 | void ProbabilityPlot::init_axis() 63 | { 64 | m_axisX = new QValueAxis(); 65 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 66 | m_line_top->attachAxis(m_axisX); 67 | m_line_center->attachAxis(m_axisX); 68 | m_line_bottom->attachAxis(m_axisX); 69 | m_scatter->attachAxis(m_axisX); 70 | 71 | m_axisY = new QCategoryAxis(); 72 | m_axisY->setTitleText("百分比"); 73 | m_axisY->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue); 74 | m_axisY->setMin(-3.09); 75 | m_axisY->setMax(3.09); 76 | m_axisY->setStartValue(-3.71); 77 | m_axisY->append("0.1", -3.09); 78 | m_axisY->append("1", -2.33); 79 | m_axisY->append("5", -1.64); 80 | m_axisY->append("10", -1.28); 81 | m_axisY->append("20", -0.84); 82 | m_axisY->append("30", -0.52); 83 | m_axisY->append("40", -0.25); 84 | m_axisY->append("50", 0); 85 | m_axisY->append("60", 0.25); 86 | m_axisY->append("70", 0.52); 87 | m_axisY->append("80", 0.84); 88 | m_axisY->append("90", 1.28); 89 | m_axisY->append("95", 1.64); 90 | m_axisY->append("99", 2.33); 91 | m_axisY->append("99.9", 3.09); 92 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 93 | m_line_top->attachAxis(m_axisY); 94 | m_line_center->attachAxis(m_axisY); 95 | m_line_bottom->attachAxis(m_axisY); 96 | m_scatter->attachAxis(m_axisY); 97 | } 98 | 99 | void ProbabilityPlot::init_series() 100 | { 101 | m_line_center = new QLineSeries(m_chart); 102 | m_line_center->setName("参照线"); 103 | m_line_center->append(QPointF(0, 0)); 104 | 105 | m_line_top = new QLineSeries(m_chart); 106 | m_line_top->setName("上线百分位数"); 107 | m_line_top->append(QPointF(0, 0)); 108 | 109 | m_line_bottom = new QLineSeries(m_chart); 110 | m_line_bottom->setName("下线百分位数"); 111 | m_line_bottom->append(QPointF(0, 0)); 112 | 113 | m_scatter = new QScatterSeries(); 114 | m_scatter->setName("百分数位"); 115 | m_scatter->append(QPointF(0, 0)); 116 | m_scatter->setMarkerSize(10); 117 | m_scatter->setBorderColor(Qt::transparent); 118 | connect(m_scatter, &QScatterSeries::hovered, this, &ProbabilityPlot::slot_tool_tip); 119 | } 120 | 121 | void ProbabilityPlot::prepare_data(QList& list) 122 | { 123 | if (list.isEmpty()) 124 | return; 125 | 126 | m_n = list.count(); 127 | m_mean = Util::average(list); 128 | m_variance = Util::variance(list, m_mean); 129 | m_sigma = Util::standard_deviation(list, m_variance); 130 | 131 | m_probability_list.clear(); 132 | 133 | qSort(list); 134 | for (int i = 0; i < list.size(); i++) 135 | { 136 | if (list[i] < m_min_x) 137 | m_min_x = list[i]; 138 | if (list[i] > m_max_x) 139 | m_max_x = list[i]; 140 | 141 | Probability pro; 142 | pro.index = i + 1; 143 | pro.theory_cdf = calculate_cdf(pro.index, list.size()); 144 | pro.theory_z = Util::normsinv(pro.theory_cdf); 145 | pro.theory = m_mean + pro.theory_z * m_sigma; 146 | pro.reality = list.at(i); 147 | pro.reality_z = (pro.reality - m_mean) / m_sigma; 148 | //pro.reality_cdf = Util::normsdist(pro.reality_z); 149 | m_probability_list.append(pro); 150 | } 151 | } 152 | 153 | double ProbabilityPlot::calculate_cdf(int index, int n) 154 | { 155 | double value = DBL_MIN; 156 | switch (m_score_type) 157 | { 158 | case Blom: 159 | value= (index - 0.375) / (n + 0.25); 160 | break; 161 | case Benard: 162 | value = (index - 0.3) / (n + 0.4); 163 | break; 164 | case Hazen: 165 | value = (index - 0.5) / n; 166 | break; 167 | case VanDerWaerden: 168 | value = index / (n + 1); 169 | break; 170 | case KaplanMeier: 171 | value = index / n; 172 | break; 173 | default: 174 | break; 175 | } 176 | return value; 177 | } 178 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/waterfall_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "waterfall_plot.h" 4 | #include "chart_view.h" 5 | #include "plot.h" 6 | #include 7 | 8 | WaterfallPlot::WaterfallPlot(QWidget *parent) 9 | : Plot(parent) 10 | { 11 | init_series(); 12 | init_chart(); 13 | init_axis(); 14 | init_item(); 15 | } 16 | 17 | WaterfallPlot::~WaterfallPlot() 18 | { 19 | 20 | } 21 | 22 | void WaterfallPlot::set_data(QList& value_list) 23 | { 24 | QList start_pos, end_pos, add_pos, low_pos; 25 | 26 | double sum = start_value; 27 | m_axis_list.append(tr("起始值")); 28 | start_pos.append(QPointF(0, 0)); 29 | start_pos.append(QPointF(0, sum)); 30 | 31 | m_max_y = m_min_y = start_value; 32 | for (int i = 0; i < value_list.size(); i++) 33 | { 34 | if (value_list[i].m_value >= 0) 35 | { 36 | add_pos.append(QPointF(i + 1, sum + value_list[i].m_value)); 37 | add_pos.append(QPointF(i + 1, sum)); 38 | } 39 | else 40 | { 41 | low_pos.append(QPointF(i + 1, sum)); 42 | low_pos.append(QPointF(i + 1, sum - value_list[i].m_value)); 43 | } 44 | sum += value_list[i].m_value; 45 | 46 | if (sum > m_max_y) 47 | m_max_y = sum; 48 | if (sum < m_min_y) 49 | m_min_y = sum; 50 | 51 | m_axis_list.append(value_list[i].m_name); 52 | } 53 | 54 | m_axis_list.append(tr("累计值")); 55 | end_pos.append(QPointF(value_list.size() + 1, 0)); 56 | end_pos.append(QPointF(value_list.size() + 1, sum)); 57 | 58 | m_item_start->set_data(start_pos); 59 | m_item_end->set_data(end_pos); 60 | m_item_add->set_data(add_pos); 61 | m_item_low->set_data(low_pos); 62 | 63 | m_axisX->append(m_axis_list); 64 | m_axisX->setRange(m_axis_list.first(), m_axis_list.last()); 65 | m_axisY->setRange(m_min_y * 0.9, m_max_y * 1.1); 66 | } 67 | 68 | void WaterfallPlot::clear_data() 69 | { 70 | 71 | } 72 | 73 | void WaterfallPlot::init_chart() 74 | { 75 | m_chart->addSeries(m_bar); 76 | } 77 | 78 | void WaterfallPlot::init_axis() 79 | { 80 | m_axisX = new QBarCategoryAxis(); 81 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 82 | m_bar->attachAxis(m_axisX); 83 | 84 | m_axisY = new QValueAxis(); 85 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 86 | m_bar->attachAxis(m_axisY); 87 | } 88 | 89 | void WaterfallPlot::init_series() 90 | { 91 | m_bar = new QBarSeries(); 92 | m_bar_start = new QBarSet(tr("起始")); 93 | m_bar_add = new QBarSet(tr("增加")); 94 | m_bar_low = new QBarSet(tr("降低")); 95 | m_bar_end = new QBarSet(tr("累计")); 96 | m_bar->append(m_bar_start); 97 | m_bar->append(m_bar_add); 98 | m_bar->append(m_bar_low); 99 | m_bar->append(m_bar_end); 100 | } 101 | 102 | void WaterfallPlot::init_item() 103 | { 104 | m_item_start = new WaterfallItem(); 105 | m_item_start->set_chart(m_chart); 106 | m_item_start->set_series(m_bar_start); 107 | m_chartview->add_item(m_item_start); 108 | 109 | m_item_end = new WaterfallItem(); 110 | m_item_end->set_chart(m_chart); 111 | m_item_end->set_series(m_bar_end); 112 | m_chartview->add_item(m_item_end); 113 | 114 | m_item_add = new WaterfallItem(); 115 | m_item_add->set_chart(m_chart); 116 | m_item_add->set_series(m_bar_add); 117 | m_chartview->add_item(m_item_add); 118 | 119 | m_item_low = new WaterfallItem(); 120 | m_item_low->set_chart(m_chart); 121 | m_item_low->set_series(m_bar_low); 122 | m_chartview->add_item(m_item_low); 123 | } 124 | 125 | ////////////////////////////////////////////////////////////////////////////// 126 | /// 瀑布图 127 | WaterfallItem::WaterfallItem() 128 | { 129 | connect(this, &WaterfallItem::signal_prepare_path, this, &WaterfallItem::slot_prepare_path); 130 | } 131 | 132 | void WaterfallItem::set_chart(QChart* chart) 133 | { 134 | m_chart = chart; 135 | } 136 | 137 | void WaterfallItem::set_data(QList data) 138 | { 139 | m_data = data; 140 | } 141 | 142 | void WaterfallItem::set_series(QBarSet* series) 143 | { 144 | m_series = series; 145 | } 146 | 147 | void WaterfallItem::slot_prepare_path() 148 | { 149 | QPainterPath path; 150 | 151 | QLineF line(m_chart->mapToPosition(QPointF(0, 0)), m_chart->mapToPosition(QPointF(1, 0))); 152 | double width = line.length(); 153 | for (int i = 0; i < m_data.size(); i=i+2) 154 | { 155 | QPointF top = m_data[i].y()>= m_data[i + 1].y() ? m_chart->mapToPosition(m_data[i]) : m_chart->mapToPosition(m_data[i + 1]); 156 | QPointF buttom = m_data[i].y() < m_data[i + 1].y() ? m_chart->mapToPosition(m_data[i]) : m_chart->mapToPosition(m_data[i + 1]); 157 | QPointF tl = top - QPointF(width * 0.05, 0); 158 | QPointF tr = top + QPointF(width * 0.05, 0); 159 | QPointF bl = buttom - QPointF(width * 0.05, 0); 160 | QPointF br = buttom + QPointF(width * 0.05, 0); 161 | QRectF rect(tl, br); 162 | path.addRect(rect); 163 | } 164 | 165 | m_shape = path; 166 | } 167 | 168 | QRectF WaterfallItem::boundingRect() const 169 | { 170 | emit signal_prepare_path(); 171 | return m_chart->plotArea().intersected(m_shape.boundingRect()); 172 | } 173 | 174 | void WaterfallItem::on_paint(QPainter* painter) 175 | { 176 | painter->setClipRect(boundingRect()); 177 | 178 | QColor color = m_series->color(); 179 | 180 | //QPen pen; 181 | //pen.setColor(color); 182 | //pen.setStyle(Qt::SolidLine); 183 | //painter->setPen(pen); 184 | 185 | QBrush brush; 186 | brush.setStyle(Qt::SolidPattern); 187 | brush.setColor(color); 188 | painter->setBrush(brush); 189 | 190 | painter->drawPath(m_shape); 191 | } 192 | -------------------------------------------------------------------------------- /projects/Graph/src/util/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include 4 | #include 5 | #include "qmath.h" 6 | 7 | QRectF Util::bounding_rect(const QList& points) 8 | { 9 | double xmin, xmax, ymin, ymax; 10 | bounding_rect(points, xmin, xmax, ymin, ymax); 11 | return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax)); 12 | } 13 | 14 | void Util::bounding_rect(const QList& points, double& xmin, double& xmax, double& ymin, double& ymax) 15 | { 16 | xmin = INT_MAX; 17 | xmax = INT_MIN; 18 | ymin = INT_MAX; 19 | ymax = INT_MIN; 20 | 21 | for (auto& p : points) 22 | { 23 | if (p.x() < xmin) xmin = p.x(); 24 | if (p.x() > xmax) xmax = p.x(); 25 | if (p.y() < ymin) ymin = p.y(); 26 | if (p.y() > ymax) ymax = p.y(); 27 | } 28 | if (xmin == xmax) 29 | xmax += 0.01; 30 | if (ymin == ymax) 31 | ymax += 0.01; 32 | } 33 | 34 | QRectF Util::bounding_rect(const QList& rects) 35 | { 36 | QList pts; 37 | for (auto r : rects) 38 | { 39 | pts.append(r.topLeft()); 40 | pts.append(r.bottomRight()); 41 | } 42 | return Util::bounding_rect(pts); 43 | } 44 | 45 | void Util::bounding_rect(const QRectF& rect, 46 | double& xmin, double& xmax, double& ymin, double& ymax) 47 | { 48 | QList pts; 49 | pts.append(rect.topLeft()); 50 | pts.append(rect.bottomRight()); 51 | bounding_rect(pts, xmin, xmax, ymin, ymax); 52 | } 53 | 54 | 55 | double Util::angle(const QPointF& p1, const QPointF& p2) 56 | { 57 | //QLineF基于y轴向下,而我们是y轴向上,所以需要变化y轴的方向 58 | QPointF _p1 = QPointF(p1.x(), -p1.y()); 59 | QPointF _p2 = QPointF(p2.x(), -p2.y()); 60 | return QLineF(_p1, _p2).angle(); 61 | } 62 | 63 | QPointF Util::rotated(const QPointF& p, double angle) 64 | { 65 | double rad = angle * ADEGREE; 66 | QMatrix mat(cos(rad),sin(rad), -sin(rad), cos(rad),0,0); 67 | return mat.map(p); 68 | } 69 | 70 | double Util::average(QList& list) 71 | { 72 | double sum = 0; 73 | for (int i = 0; i < list.size(); i++) // 求和 74 | sum += list[i]; 75 | return sum / list.size(); 76 | } 77 | 78 | double Util::max(QList& list) 79 | { 80 | double max = DBL_MIN; 81 | for (auto& item : list) 82 | { 83 | if (max < item) 84 | max = item; 85 | } 86 | return max; 87 | } 88 | 89 | double Util::min(QList& list) 90 | { 91 | double min = DBL_MAX; 92 | for (auto& item : list) 93 | { 94 | if (min > item) 95 | min = item; 96 | } 97 | return min; 98 | } 99 | 100 | void Util::cal_list(QList& list, double& mean, double& sum, double& max, double& min) 101 | { 102 | min = DBL_MAX; max = DBL_MIN; sum = 0; 103 | for (int i = 0; i < list.size(); i++) // 求和 104 | { 105 | if (max < list[i]) 106 | max = list[i]; 107 | if (min > list[i]) 108 | min = list[i]; 109 | sum += list[i]; 110 | } 111 | mean = sum / list.size(); 112 | } 113 | 114 | double Util::variance(QList& list, double mean/*= DBL_MIN*/) 115 | { 116 | double sum = 0; 117 | double average = mean != DBL_MIN ? mean : Util::average(list); 118 | for (int i = 0; i < list.size(); i++) 119 | sum += pow(list[i] - average, 2); 120 | return sum / (list.size() - 1); 121 | } 122 | 123 | double Util::standard_deviation(QList& list, double sigma2 /*= DBL_MIN*/) 124 | { 125 | double variance = sigma2 != DBL_MIN ? sigma2 : Util::variance(list); 126 | return sqrt(variance); 127 | } 128 | 129 | double Util::normal_cdf(double value) 130 | { 131 | return 0.5 * erfc(-value * M_SQRT1_2); 132 | } 133 | 134 | double Util::normal_z(double value) 135 | { 136 | const double A1 = 0.31938153; 137 | const double A2 = -0.356563782; 138 | const double A3 = 1.781477937; 139 | const double A4 = -1.821255978; 140 | const double A5 = 1.330274429; 141 | const double RSQRT2PI = 0.39894228040143267793994605993438; 142 | 143 | double 144 | K = 1.0 / (1.0 + 0.2316419 * fabs(value)); 145 | 146 | double 147 | cnd = RSQRT2PI * exp(-0.5 * value * value) * 148 | (K * (A1 + K * (A2 + K * (A3 + K * (A4 + K * A5))))); 149 | 150 | if (value > 0) 151 | cnd = 1.0 - cnd; 152 | 153 | return cnd; 154 | } 155 | 156 | double Util::normsdist(double z) 157 | { 158 | if (z > 6) 159 | return 1; 160 | if (z < -6) 161 | return 0; 162 | double gamma = 0.231641900, a1 = 0.319381530, a2 = -0.356563782, a3 = 1.781477973, a4 = -1.821255978, a5 = 1.330274429; 163 | double x = abs(z); 164 | double t = 1 / (1 + gamma * x); 165 | double n = 1 - (1 / (sqrt(2 * PI)) * exp(-z * z / 2)) * (a1 * t + a2 * pow(t, 2) + a3 * pow(t, 3) + a4 * pow(t, 4) + a5 * pow(t, 5)); 166 | if (z < 0) 167 | return 1.0 - n; 168 | return n; 169 | } 170 | 171 | double Util::normsinv(double p) 172 | { 173 | double LOW = 0.02425; 174 | double HIGH = 0.97575; 175 | double a[] = { -3.969683028665376e+01, 2.209460984245205e+02,-2.759285104469687e+02, 1.383577518672690e+02,-3.066479806614716e+01, 2.506628277459239e+00 }; 176 | double b[] = { -5.447609879822406e+01, 1.615858368580409e+02,-1.556989798598866e+02, 6.680131188771972e+01,-1.328068155288572e+01 }; 177 | double c[] = { -7.784894002430293e-03, -3.223964580411365e-01,-2.400758277161838e+00, -2.549732539343734e+00,4.374664141464968e+00, 2.938163982698783e+00 }; 178 | double d[] = { 7.784695709041462e-03, 3.224671290700398e-01,2.445134137142996e+00, 3.754408661907416e+00 }; 179 | double q, r; 180 | if (p < LOW) { 181 | q = sqrt(-2 * log(p)); 182 | return (((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1); 183 | } 184 | else if (p > HIGH) { 185 | q = sqrt(-2 * log(1 - p)); 186 | return -(((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1); 187 | } 188 | else { 189 | q = p - 0.5; 190 | r = q * q; 191 | return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q / (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/histogram_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "histogram_plot.h" 4 | #include "chart_view.h" 5 | #include 6 | #include 7 | 8 | HistogramPlot::HistogramPlot(QWidget *parent) 9 | : Plot(parent) 10 | { 11 | init_series(); 12 | init_chart(); 13 | init_axis(); 14 | } 15 | 16 | HistogramPlot::~HistogramPlot() 17 | { 18 | 19 | } 20 | 21 | void HistogramPlot::add_histogram(QList& value_list, const QString& name) 22 | { 23 | if (m_name2itemlist.contains(name)) 24 | return; 25 | 26 | QList> list = prepare_data(value_list); 27 | 28 | Histogram* his = new Histogram; 29 | his->m_index = m_name2itemlist.size() + 1; 30 | his->m_value = value_list; 31 | QScatterSeries *series = new QScatterSeries(); 32 | series->setName(name); 33 | series->setColor(QColor::colorNames()[m_name2itemlist.size() + 5]); 34 | m_chart->addSeries(series); 35 | series->attachAxis(m_axisX); 36 | series->attachAxis(m_axisY); 37 | his->m_series = series; 38 | for (int i = 0; i < list.size(); i++) 39 | { 40 | if (list[i][2] > m_count) 41 | m_count = list[i][2]; 42 | QVector ver; 43 | ver.append(list[i][0]); //开始 44 | ver.append(list[i][1]); //结束 45 | ver.append(list[i][2]); //总数 46 | 47 | HistogramItem* item = new HistogramItem(); 48 | item->set_chart(m_chart); 49 | item->set_data(ver); 50 | item->set_index(his->m_index); 51 | m_chartview->add_item(item); 52 | his->m_list.append(item); 53 | } 54 | m_name2itemlist[name] = his; 55 | 56 | m_chart->setProperty("sum", m_name2itemlist.size()); 57 | 58 | m_axisX->setTickCount(list.size()+1); 59 | m_max_x = m_min_x + list.size() * m_interval; 60 | m_axisX->setRange(m_min_x, m_max_x); 61 | m_axisY->setTickCount(m_count+2); 62 | m_axisY->setRange(0, m_count+1); 63 | } 64 | 65 | void HistogramPlot::delete_histogram(const QString& name) 66 | { 67 | if (!m_name2itemlist.contains(name)) 68 | return; 69 | m_chart->removeSeries(m_name2itemlist[name]->m_series); 70 | DELETE_PTR_LIST(m_name2itemlist[name]->m_list); 71 | DELETE_PTR(m_name2itemlist[name]); 72 | m_name2itemlist.remove(name); 73 | } 74 | 75 | void HistogramPlot::init_chart() 76 | { 77 | //m_chart->legend()->hide(); 78 | //m_chart->addSeries(m_series); 79 | } 80 | 81 | void HistogramPlot::init_axis() 82 | { 83 | m_axisX = new QValueAxis(); 84 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 85 | //m_series->attachAxis(m_axisX); 86 | 87 | m_axisY = new QValueAxis(); 88 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 89 | //m_series->attachAxis(m_axisY); 90 | } 91 | 92 | void HistogramPlot::init_series() 93 | { 94 | //m_series = new QScatterSeries(); 95 | } 96 | 97 | QList> HistogramPlot::prepare_data(QList& list) 98 | { 99 | if (m_name2itemlist.isEmpty()) 100 | { 101 | for (auto& item : list) 102 | { 103 | if (item < m_min_x) 104 | m_min_x = item; 105 | if (item > m_max_x) 106 | m_max_x = item; 107 | } 108 | 109 | if ((floor((m_max_x - m_min_x) / m_interval)) * m_interval + m_min_x >= m_max_x) 110 | m_max_x = m_max_x + m_interval; 111 | 112 | QList> histogram_list; 113 | for (double i = m_min_x; i < m_max_x; i = i + m_interval) 114 | { 115 | QVector vect(3); 116 | vect[0] = i; 117 | vect[1] = i + m_interval; 118 | vect[2] = 0; 119 | histogram_list.append(vect); 120 | } 121 | 122 | for (int i = 0; i < list.size(); i++) 123 | { 124 | int index = floor((list[i] - m_min_x) / m_interval); 125 | if (index * m_interval + m_min_x < list[i]) 126 | histogram_list[index--][2]++; 127 | else 128 | histogram_list[index][2]++; 129 | } 130 | return histogram_list; 131 | } 132 | else 133 | { 134 | double min = m_min_x, max = m_max_x; 135 | for (auto& item : list) 136 | { 137 | if (item < min) 138 | min = item; 139 | if (item > max) 140 | max = item; 141 | } 142 | while ( min< m_min_x) 143 | m_min_x -= m_interval; 144 | while (max>= m_max_x) 145 | m_max_x += m_interval; 146 | 147 | QList> histogram_list; 148 | for (double i = m_min_x; i < m_max_x; i = i + m_interval) 149 | { 150 | QVector vect(3); 151 | vect[0] = i; 152 | vect[1] = i + m_interval; 153 | vect[2] = 0; 154 | histogram_list.append(vect); 155 | } 156 | 157 | for (int i = 0; i < list.size(); i++) 158 | { 159 | int index = floor((list[i] - m_min_x) / m_interval); 160 | if (index * m_interval + m_min_x < list[i]) 161 | histogram_list[index--][2]++; 162 | else 163 | histogram_list[index][2]++; 164 | } 165 | return histogram_list; 166 | } 167 | } 168 | 169 | ////////////////////////////////////////////////////////////////////////////// 170 | /// 直方图 171 | HistogramItem::HistogramItem() 172 | { 173 | connect(this, &HistogramItem::signal_prepare_path, this, &HistogramItem::slot_prepare_path); 174 | } 175 | 176 | void HistogramItem::set_chart(QChart* chart) 177 | { 178 | m_chart = chart; 179 | } 180 | 181 | void HistogramItem::set_data(QVector data) 182 | { 183 | m_data = data; 184 | } 185 | 186 | void HistogramItem::set_index(int index) 187 | { 188 | m_index = index - 1; 189 | } 190 | 191 | void HistogramItem::slot_prepare_path() 192 | { 193 | QPainterPath path; 194 | 195 | int size = m_chart->property("sum").toInt(); 196 | double width = (m_data[1] - m_data[0]) / size; 197 | double start = m_data[0] + width * m_index; 198 | double end = start + width; 199 | QPointF tl = m_chart->mapToPosition(QPointF(start, m_data[2])); 200 | QPointF br = m_chart->mapToPosition(QPointF(end, 0)); 201 | QRectF rect(tl, br); 202 | path.addRect(rect); 203 | 204 | m_shape = path; 205 | } 206 | 207 | QRectF HistogramItem::boundingRect() const 208 | { 209 | emit signal_prepare_path(); 210 | return m_chart->plotArea().intersected(m_shape.boundingRect()); 211 | } 212 | 213 | void HistogramItem::on_paint(QPainter* painter) 214 | { 215 | painter->setClipRect(boundingRect()); 216 | 217 | QColor color(QColor::colorNames()[m_index + 5]); 218 | 219 | //QPen pen; 220 | //pen.setColor(color); 221 | //pen.setStyle(Qt::SolidLine); 222 | //painter->setPen(pen); 223 | 224 | QBrush brush; 225 | brush.setStyle(Qt::SolidPattern); 226 | brush.setColor(color); 227 | painter->setBrush(brush); 228 | 229 | painter->drawPath(m_shape); 230 | } 231 | -------------------------------------------------------------------------------- /projects/Test/src/main_window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 549 10 | 456 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 549 25 | 23 26 | 27 | 28 | 29 | 30 | 31 | TopToolBarArea 32 | 33 | 34 | false 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 线 49 | 50 | 51 | 52 | 53 | 删除 54 | 55 | 56 | 57 | 58 | 线 59 | 60 | 61 | 线 62 | 63 | 64 | 65 | 66 | 箭头 67 | 68 | 69 | 70 | 71 | 水平分割 72 | 73 | 74 | 75 | 76 | 垂直分割 77 | 78 | 79 | 80 | 81 | 删除分割 82 | 83 | 84 | 85 | 86 | 添加Label 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | action_add_line 95 | triggered() 96 | MainWindow 97 | slot_add_line() 98 | 99 | 100 | -1 101 | -1 102 | 103 | 104 | 199 105 | 149 106 | 107 | 108 | 109 | 110 | action_delete_line 111 | triggered() 112 | MainWindow 113 | slot_delete_line() 114 | 115 | 116 | -1 117 | -1 118 | 119 | 120 | 199 121 | 149 122 | 123 | 124 | 125 | 126 | action_draw_arrows 127 | triggered() 128 | MainWindow 129 | slot_draw_arrows() 130 | 131 | 132 | -1 133 | -1 134 | 135 | 136 | 274 137 | 227 138 | 139 | 140 | 141 | 142 | action_draw_line 143 | triggered() 144 | MainWindow 145 | slot_draw_line() 146 | 147 | 148 | -1 149 | -1 150 | 151 | 152 | 274 153 | 227 154 | 155 | 156 | 157 | 158 | horizontal_action 159 | triggered() 160 | MainWindow 161 | slot_horizontal_splitter() 162 | 163 | 164 | -1 165 | -1 166 | 167 | 168 | 274 169 | 227 170 | 171 | 172 | 173 | 174 | vertical_action 175 | triggered() 176 | MainWindow 177 | slot_vertical_splitter() 178 | 179 | 180 | -1 181 | -1 182 | 183 | 184 | 274 185 | 227 186 | 187 | 188 | 189 | 190 | action_add 191 | triggered() 192 | MainWindow 193 | slot_add_label() 194 | 195 | 196 | -1 197 | -1 198 | 199 | 200 | 274 201 | 227 202 | 203 | 204 | 205 | 206 | delete_action 207 | triggered() 208 | MainWindow 209 | slot_delete_splitter() 210 | 211 | 212 | -1 213 | -1 214 | 215 | 216 | 274 217 | 227 218 | 219 | 220 | 221 | 222 | 223 | slot_add_line() 224 | slot_delete_line() 225 | slot_draw_line() 226 | slot_draw_arrows() 227 | slot_vertical_splitter() 228 | slot_horizontal_splitter() 229 | slot_delete_splitter() 230 | slot_add_label() 231 | 232 | 233 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/stock_plot.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "stock_plot.h" 4 | #include 5 | #include "tool_tip.h" 6 | #include "chart_view.h" 7 | 8 | StockPlot::StockPlot(QWidget *parent) 9 | : Plot(parent) 10 | { 11 | init_series(); 12 | init_chart(); 13 | init_axis(); 14 | } 15 | 16 | StockPlot::~StockPlot() 17 | { 18 | //QCandlestickSeries常用函数: 19 | //append(self, set):将由set指定的单个烛台条目添加到烛台图中,并获得其所有权。如果该项为空或已在系列中,则不会附加该项。如果添加成功返回True,否则返回False。 20 | //clear(self) : 永久删除图中的所有条目。 21 | //remove(self, set):从烛台图中删除set指定的条目。 22 | //take(self, set):从图中获取由set指定的单个条目。但不删除该条目。 23 | //setBodyOutlineVisible(self, bodyOutlineVisible):设置烛台轮廓是否可见。 24 | //setBodyWidth(self, bodyWidth):设置烛台条目的相对宽度,范围为0.0到1.0。 25 | //setBrush(self, brush):设置烛台条目的画刷。 26 | //setPen(self, pen):设置烛台条目线条的画笔。 27 | //setCapsVisible(self, capsVisible):设置烛台条目盖是否可见。 28 | //setCapsWidth(self, capsWidth): 设置烛台条目盖的宽度。 29 | //setDecreasingColor(self, decreasingColor):设置烛台条目递减颜色。 30 | //setIncreasingColor(self, increasingColor):设置烛台条目递增颜色。 31 | //setMaximumColumnWidth(self, maximumColumnWidth):设置烛台条目的最大宽度(以像素为单位。设置为负值表示没有最大宽度。所有负值都将转换为 - 1.0)。 32 | //setMinimumColumnWidth(self, minimumColumnWidth):设置烛台条目的最小宽度(以像素为单位。设置为负值表示没有最大宽度。所有负值都将转换为 - 1.0)。 33 | 34 | //QCandlestickSeries常用信号: 35 | //bodyOutlineVisibilityChanged(self):烛台条目主体轮廓的可见性更改时,将发出此信号。 36 | //bodyWidthChanged(self):烛台条目的宽度更改时,将发出此信号。 37 | //brushChanged(self):烛台条目画刷更改时,将发出此信号。 38 | //candlestickSetsAdded(self, sets):当sets指定的烛台条目添加到烛台图中时,将发出此信号。 39 | //candlestickSetsRemoved(self, sets):从烛台图中删除sets指定的烛台条目时,将发出此信号。 40 | //capsVisibilityChanged(self):烛台条目盖的可见属性更改时,将发出此信号。 41 | //capsWidthChanged(self) : 烛台条目盖的宽度更改时,将发出此信号。 42 | //clicked(self, set) : 单击图表上由set指定的烛台条目时,将发出此信号。 43 | //countChanged(self):当烛台图中中烛台条目的数量发生更改时,将发出此信号。 44 | //decreasingColorChanged(self) : 当烛台条目的颜色减少时,将发出此信号。 45 | //doubleClicked(self, set):双击图表上由set指定的烛台条目时,将发出此信号。 46 | //hovered(self, status, set):当鼠标悬停在所指定的烛台条目set时,这个信号被发射。当鼠标移至该条目上方时,state变为True,而当鼠标再次移开时,state变为False。 47 | //increasingColorChanged(self):烛台条目颜色增加时,将发出此信号。 48 | //maximumColumnWidthChanged(self) : 烛台条目的最大列宽发生变化时,将发出此信号。 49 | //minimumColumnWidthChanged(self):烛台条目的最小列宽发生变化时,将发出此信号。 50 | //penChanged(self):烛台图的画笔发生更改时会发出此信号。 51 | //pressed(self, set):当用户单击set指定的烛台条目并按住鼠标按钮时,将发出此信号。 52 | //released(self, set):当用户释放set所指定的烛台条目上的鼠标时,将发出此信号。 53 | 54 | //QCandlestickSet常用函数: 55 | //setBrush(self, brush):设置条目的画刷为brush。 56 | //setPen(self, pen):设置条目的画笔为pen。 57 | //setClose(self, close):设置条目的收盘价为close。 58 | //setHigh(self, high):设置条目的上限值为high。 59 | //setLow(self, low):设置条目的下限值为low。 60 | //setOpen(self, open):设置条目的开盘价。 61 | //setTimestamp(self, timestamp):设置条目的时间戳。 62 | 63 | //QCandlestickSet常用信号: 64 | //brushChanged(self):更改时画刷,将发出此信号。 65 | //penChanged(self):更改画笔时,将发出此信号。 66 | //clicked(self):单击条目时,将发出此信号。 67 | //doubleClicked(self):双击条目时,将发出此信号。 68 | //hovered(self, status):当鼠标悬停在条目上时,将发出此信号。 69 | //pressed(self):当用户单击条并按住鼠标按钮时,将发出此信号。 70 | //released(self):当用户释放对条目的释放鼠标时,将发出此信号。 71 | //closeChanged(self):条目收盘价发生改变时发出此信号。 72 | //highChanged(self):条目上限值更改时,将发出此信号。 73 | //lowChanged(self):条目下限值更改时,将发出此信号。 74 | //openChanged(self):条目开盘价变化时发出此信号。 75 | //timestampChanged(self):当条目时间戳更改时,将发出此信号。 76 | } 77 | 78 | void StockPlot::slot_tool_tip(bool status, QCandlestickSet* set) 79 | { 80 | if (m_tooltip == nullptr) 81 | m_tooltip = new ToolTip(m_chart,this); 82 | if (status) { 83 | m_tooltip->setText(QString("开盘: %1 \n收盘: %2\n最高: %3\n最低: %4 ") 84 | .arg(set->open()).arg(set->close()).arg(set->high()).arg(set->low())); 85 | QPointF point = m_chartview->mapFromGlobal(QCursor::pos()); 86 | m_tooltip->setAnchor(point); 87 | m_tooltip->setZValue(11); 88 | m_tooltip->updateGeometry(); 89 | m_tooltip->show(); 90 | } 91 | else 92 | m_tooltip->hide(); 93 | } 94 | 95 | void StockPlot::add_stock(QList& data_list, const QString& name) 96 | { 97 | if (m_name2series.contains(name)) 98 | return; 99 | 100 | prepare_data(data_list); 101 | 102 | QCandlestickSeries* series = new QCandlestickSeries(); 103 | series->setName(name); 104 | series->setIncreasingColor(QColor(Qt::green)); 105 | series->setDecreasingColor(QColor(Qt::red)); 106 | 107 | for (auto& item : data_list) 108 | { 109 | QCandlestickSet* set = new QCandlestickSet(item.m_timestamp); 110 | set->setProperty("parent", name); 111 | set->setOpen(item.m_open); 112 | set->setHigh(item.m_high); 113 | set->setLow(item.m_low); 114 | set->setClose(item.m_close); 115 | series->append(set); 116 | m_axisx_list << QDateTime::fromMSecsSinceEpoch(set->timestamp()).toString("dd"); 117 | } 118 | 119 | m_chart->addSeries(series); 120 | m_name2series[name] = series; 121 | series->attachAxis(m_axisX); 122 | series->attachAxis(m_axisY); 123 | m_axisX->setCategories(m_axisx_list); 124 | m_axisY->setRange(m_min_y, m_max_y); 125 | 126 | connect(series, &QCandlestickSeries::hovered, this, &StockPlot::slot_tool_tip); 127 | //connect_markers(); 128 | } 129 | 130 | void StockPlot::delete_stock(const QString& name) 131 | { 132 | if (!m_name2series.contains(name)) 133 | return; 134 | m_chart->removeSeries(m_name2series[name]); 135 | m_name2series.remove(name); 136 | 137 | m_range[0].pop(); 138 | m_range[1].pop(); 139 | m_range[2].pop(); 140 | m_range[3].pop(); 141 | 142 | m_min_x = m_range[0].top(); 143 | m_max_x = m_range[1].top(); 144 | m_min_y = m_range[2].top(); 145 | m_max_y = m_range[3].top(); 146 | 147 | m_axisX->setRange(QString::number(m_min_x), QString::number(m_max_x)); 148 | m_axisY->setRange(m_min_y * 0.99, m_max_y * 1.01); 149 | } 150 | 151 | void StockPlot::init_chart() 152 | { 153 | //m_chart->legend()->hide(); 154 | } 155 | 156 | void StockPlot::init_axis() 157 | { 158 | m_axisX = new QBarCategoryAxis(); 159 | m_chart->addAxis(m_axisX, Qt::AlignBottom); 160 | 161 | m_axisY = new QValueAxis(); 162 | m_chart->addAxis(m_axisY, Qt::AlignLeft); 163 | } 164 | 165 | void StockPlot::init_series() 166 | { 167 | m_name2series.clear(); 168 | } 169 | 170 | void StockPlot::prepare_data(QList& data_list) 171 | { 172 | for (auto& data : data_list) 173 | { 174 | if (data.m_timestamp < m_min_x) 175 | m_min_x = data.m_timestamp; 176 | if (data.m_timestamp > m_max_x) 177 | m_max_x = data.m_timestamp; 178 | if (data.m_low < m_min_y) 179 | m_min_y = data.m_low; 180 | if (data.m_high > m_max_y) 181 | m_max_y = data.m_high; 182 | } 183 | m_range[0].push(m_min_x); 184 | m_range[1].push(m_max_x); 185 | m_range[2].push(m_min_y); 186 | m_range[3].push(m_max_y); 187 | } 188 | -------------------------------------------------------------------------------- /projects/Test/Test.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {8C814C96-3D0C-40C4-BF44-47EADC42B3A5} 28 | QtVS_v304 29 | 10.0.19041.0 30 | 10.0.19041.0 31 | $(MSBuildProjectDirectory)\QtMsBuild 32 | 33 | 34 | 35 | Application 36 | v143 37 | 38 | 39 | Application 40 | v143 41 | 42 | 43 | 44 | 45 | 46 | 47 | 5.15.2_msvc2019_64 48 | core;gui;widgets;charts 49 | debug 50 | 51 | 52 | 5.15.2_msvc2019_64 53 | core;gui;widgets 54 | release 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | $(SolutionDir)projects\Graph\src\graph;$(SolutionDir)projects\Graph\src\chart;$(SolutionDir)projects\Graph\src;.\src;%(AdditionalIncludeDirectories) 77 | 78 | 79 | $(SolutionDir)lib 80 | Graph.lib;%(AdditionalDependencies) 81 | 82 | 83 | copy $(SolutionDir)$(IntDir)$(TargetFileName) $(SolutionDir)bin 84 | 85 | 86 | 87 | 88 | .\src;%(AdditionalIncludeDirectories) 89 | 90 | 91 | 92 | 93 | true 94 | true 95 | ProgramDatabase 96 | Disabled 97 | MultiThreadedDebugDLL 98 | 99 | 100 | Windows 101 | true 102 | 103 | 104 | 105 | 106 | true 107 | true 108 | None 109 | MaxSpeed 110 | MultiThreadedDLL 111 | 112 | 113 | Windows 114 | false 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/SizeGripItem.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "SizeGripItem.h" 4 | #include 5 | 6 | SizeGripItem::HandleItem::HandleItem(int positionFlags, SizeGripItem* parent) 7 | : QGraphicsRectItem(-4, -4, 8, 8, parent), 8 | positionFlags_(positionFlags), 9 | parent_(parent) 10 | { 11 | setBrush(QBrush(Qt::lightGray)); 12 | setFlag(ItemIsMovable); 13 | setFlag(ItemIsSelectable); 14 | //setFlag(ItemSendsGeometryChanges); 15 | } 16 | 17 | int SizeGripItem::HandleItem::positionFlags() const 18 | { 19 | return positionFlags_; 20 | } 21 | 22 | QVariant SizeGripItem::HandleItem::itemChange(GraphicsItemChange change,const QVariant &value) 23 | { 24 | QVariant retVal = value; 25 | 26 | if (change == ItemPositionChange) 27 | { 28 | retVal = restrictPosition(value.toPointF()); 29 | } 30 | else if (change == ItemPositionHasChanged) 31 | { 32 | QPointF pos = value.toPointF(); 33 | 34 | switch (positionFlags_) 35 | { 36 | case TopLeft: 37 | parent_->setTopLeft(pos); 38 | break; 39 | case Top: 40 | parent_->setTop(pos.y()); 41 | break; 42 | case TopRight: 43 | parent_->setTopRight(pos); 44 | break; 45 | case Right: 46 | parent_->setRight(pos.x()); 47 | break; 48 | case BottomRight: 49 | parent_->setBottomRight(pos); 50 | break; 51 | case Bottom: 52 | parent_->setBottom(pos.y()); 53 | break; 54 | case BottomLeft: 55 | parent_->setBottomLeft(pos); 56 | break; 57 | case Left: 58 | parent_->setLeft(pos.x()); 59 | break; 60 | } 61 | } 62 | 63 | return retVal; 64 | } 65 | 66 | QPointF SizeGripItem::HandleItem::restrictPosition(const QPointF& newPos) 67 | { 68 | QPointF retVal = pos(); 69 | 70 | if (positionFlags_ & Top || positionFlags_ & Bottom) 71 | retVal.setY(newPos.y()); 72 | 73 | if (positionFlags_ & Left || positionFlags_ & Right) 74 | retVal.setX(newPos.x()); 75 | 76 | if (positionFlags_ & Top && retVal.y() > parent_->rect_.bottom()) 77 | retVal.setY(parent_->rect_.bottom()); 78 | else if (positionFlags_ & Bottom && retVal.y() < parent_->rect_.top()) 79 | retVal.setY(parent_->rect_.top()); 80 | 81 | if (positionFlags_ & Left && retVal.x() > parent_->rect_.right()) 82 | retVal.setX(parent_->rect_.right()); 83 | else if (positionFlags_ & Right && retVal.x() < parent_->rect_.left()) 84 | retVal.setX(parent_->rect_.left()); 85 | 86 | return retVal; 87 | } 88 | 89 | SizeGripItem::SizeGripItem(Resizer* resizer, QGraphicsItem* parent) 90 | : QGraphicsItem(parent), 91 | resizer_(resizer) 92 | { 93 | if (parentItem()) 94 | rect_ = parentItem()->boundingRect(); 95 | 96 | handleItems_.append(new HandleItem(TopLeft, this)); 97 | handleItems_.append(new HandleItem(Top, this)); 98 | handleItems_.append(new HandleItem(TopRight, this)); 99 | handleItems_.append(new HandleItem(Right, this)); 100 | handleItems_.append(new HandleItem(BottomRight, this)); 101 | handleItems_.append(new HandleItem(Bottom, this)); 102 | handleItems_.append(new HandleItem(BottomLeft, this)); 103 | handleItems_.append(new HandleItem(Left, this)); 104 | updateHandleItemPositions(); 105 | } 106 | 107 | SizeGripItem::~SizeGripItem() 108 | { 109 | if (resizer_) 110 | delete resizer_; 111 | } 112 | 113 | QRectF SizeGripItem::boundingRect() const 114 | { 115 | return rect_; 116 | } 117 | 118 | void SizeGripItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) 119 | { 120 | //if (parentItem()->isSelected()) 121 | //{ 122 | // foreach(HandleItem * item, handleItems_) 123 | // item->setVisible(true); 124 | //} 125 | //else 126 | //{ 127 | // foreach(HandleItem * item, handleItems_) 128 | // item->setVisible(false); 129 | //} 130 | } 131 | 132 | void SizeGripItem::setTopLeft(const QPointF& pos) 133 | { 134 | rect_.setTopLeft(pos); 135 | doResize(); 136 | } 137 | 138 | void SizeGripItem::setTop(qreal y) 139 | { 140 | rect_.setTop(y); 141 | doResize(); 142 | } 143 | 144 | void SizeGripItem::setTopRight(const QPointF& pos) 145 | { 146 | rect_.setTopRight(pos); 147 | doResize(); 148 | } 149 | 150 | void SizeGripItem::setRight(qreal x) 151 | { 152 | rect_.setRight(x); 153 | doResize(); 154 | } 155 | 156 | void SizeGripItem::setBottomRight(const QPointF& pos) 157 | { 158 | rect_.setBottomRight(pos); 159 | doResize(); 160 | } 161 | 162 | void SizeGripItem::setBottom(qreal y) 163 | { 164 | rect_.setBottom(y); 165 | doResize(); 166 | } 167 | 168 | void SizeGripItem::setBottomLeft(const QPointF& pos) 169 | { 170 | rect_.setBottomLeft(pos); 171 | doResize(); 172 | } 173 | 174 | void SizeGripItem::setLeft(qreal x) 175 | { 176 | rect_.setLeft(x); 177 | doResize(); 178 | } 179 | 180 | void SizeGripItem::doResize() 181 | { 182 | if (resizer_) 183 | { 184 | (*resizer_)(parentItem(), rect_); 185 | updateHandleItemPositions(); 186 | } 187 | } 188 | 189 | void SizeGripItem::updateHandleItemPositions() 190 | { 191 | foreach (HandleItem* item, handleItems_) 192 | { 193 | item->setFlag(ItemSendsGeometryChanges, false); 194 | 195 | switch (item->positionFlags()) 196 | { 197 | case TopLeft: 198 | item->setPos(rect_.topLeft()); 199 | break; 200 | case Top: 201 | item->setPos(rect_.left() + rect_.width() / 2 - 1, rect_.top()); 202 | break; 203 | case TopRight: 204 | item->setPos(rect_.topRight()); 205 | break; 206 | case Right: 207 | item->setPos(rect_.right(), rect_.top() + rect_.height() / 2 - 1); 208 | break; 209 | case BottomRight: 210 | item->setPos(rect_.bottomRight()); 211 | break; 212 | case Bottom: 213 | item->setPos(rect_.left() + rect_.width() / 2 - 1, rect_.bottom()); 214 | break; 215 | case BottomLeft: 216 | item->setPos(rect_.bottomLeft()); 217 | break; 218 | case Left: 219 | item->setPos(rect_.left(), 220 | rect_.top() + rect_.height() / 2 - 1); 221 | break; 222 | } 223 | 224 | item->setFlag(ItemSendsGeometryChanges, true); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /projects/Graph/src/chart/color_bar.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "color_bar.h" 4 | #include 5 | 6 | ColorBar::ColorBar() 7 | : GraphicsItem() 8 | { 9 | init_colors(); 10 | } 11 | 12 | void ColorBar::set_dock_area(LocationType area) 13 | { 14 | m_area = area; 15 | QMargins margin = m_chart->margins(); 16 | switch (m_area) 17 | { 18 | case Top: 19 | margin.setTop(50); 20 | break; 21 | case Bottom: 22 | margin.setBottom(50); 23 | break; 24 | case Left: 25 | margin.setLeft(100); 26 | break; 27 | case Right: 28 | margin.setRight(100); 29 | break; 30 | default: 31 | break; 32 | } 33 | m_chart->setMargins(margin); 34 | } 35 | 36 | void ColorBar::set_value_range(double min, double max) 37 | { 38 | m_min = min; 39 | m_max = max; 40 | } 41 | 42 | QColor ColorBar::getColor(double value) 43 | { 44 | QVector colors; 45 | switch (m_type) 46 | { 47 | case Gray: 48 | colors = gray_colors; 49 | break; 50 | case Jet: 51 | colors = jet_colors; 52 | break; 53 | case Hsv: 54 | colors = hsv_colors; 55 | break; 56 | case Hot: 57 | colors = hot_colors; 58 | break; 59 | default: 60 | break; 61 | } 62 | if (value >= m_max) 63 | return colors.last(); 64 | if (value <= m_min) 65 | return colors.first(); 66 | int index = ((value - m_min) / (m_max - m_min)) * colors.size(); 67 | return colors.at(index); 68 | } 69 | 70 | void ColorBar::set_chart(QChart* chart) 71 | { 72 | m_chart = chart; 73 | set_dock_area(m_area); 74 | } 75 | 76 | void ColorBar::set_type(ColorBarType type) 77 | { 78 | m_type = type; 79 | } 80 | 81 | QRectF ColorBar::boundingRect() const 82 | { 83 | QRectF rect = m_chart->plotArea(); 84 | 85 | switch (m_area) 86 | { 87 | case Top: 88 | return QRectF(rect.topLeft(), rect.topRight() + QPointF(0, -100)); 89 | break; 90 | case Bottom: 91 | return QRectF(rect.bottomLeft(), rect.bottomRight() + QPointF(0,100)); 92 | break; 93 | case Left: 94 | return QRectF(rect.topLeft(), rect.bottomLeft() + QPointF(-100, 0)); 95 | break; 96 | case Right: 97 | return QRectF(rect.topRight(), rect.bottomLeft() + QPointF(100, 0)); 98 | break; 99 | default: 100 | return QRectF(0, 0, 1, 1); 101 | break; 102 | } 103 | } 104 | 105 | void ColorBar::on_paint(QPainter* painter) 106 | { 107 | QRectF rect = boundingRect(); 108 | switch (m_area) 109 | { 110 | case Top: 111 | { 112 | QRectF bar_rect = rect; 113 | bar_rect.setHeight(-25); 114 | draw_color_bar(painter, bar_rect); 115 | QRectF title_rect = rect; 116 | title_rect.setTopLeft(QPointF(rect.topLeft().x(), rect.topLeft().y() - 30)); 117 | draw_color_title(painter, title_rect); 118 | } 119 | break; 120 | case Bottom: 121 | { 122 | QRectF bar_rect = rect; 123 | bar_rect.setHeight(25); 124 | draw_color_bar(painter, bar_rect); 125 | QRectF title_rect = rect; 126 | title_rect.setTopLeft(QPointF(rect.topLeft().x(), rect.topLeft().y() + 30)); 127 | draw_color_title(painter, title_rect); 128 | } 129 | break; 130 | case Left: 131 | { 132 | QRectF bar_rect = rect; 133 | bar_rect.setBottomRight(QPointF(rect.topLeft().x() - 25, rect.bottomRight().y())); 134 | draw_color_bar(painter, bar_rect); 135 | QRectF title_rect = rect; 136 | title_rect.setTopLeft(QPointF(rect.topLeft().x() - 30, rect.topLeft().y())); 137 | draw_color_title(painter, title_rect); 138 | } 139 | break; 140 | case Right: 141 | { 142 | QRectF bar_rect = rect; 143 | bar_rect.setWidth(25); 144 | draw_color_bar(painter, bar_rect); 145 | QRectF title_rect = rect; 146 | title_rect.setTopLeft(QPointF(rect.topLeft().x() + 30, rect.topLeft().y())); 147 | draw_color_title(painter, title_rect); 148 | } 149 | break; 150 | default: 151 | break; 152 | } 153 | } 154 | 155 | void ColorBar::draw_color_bar(QPainter* painter,QRectF rect) 156 | { 157 | QVector colors; 158 | switch (m_type) 159 | { 160 | case Gray: 161 | colors = gray_colors; 162 | break; 163 | case Jet: 164 | colors = jet_colors; 165 | break; 166 | case Hsv: 167 | colors = hsv_colors; 168 | break; 169 | case Hot: 170 | colors = hot_colors; 171 | break; 172 | default: 173 | break; 174 | } 175 | 176 | double numIntervalls; 177 | if (m_area == Right|| m_area == Left) 178 | numIntervalls = rect.height() / colors.size(); 179 | else 180 | numIntervalls = rect.width() / colors.size(); 181 | 182 | for (int i = 0; i < colors.size(); i++) { 183 | QRectF section; 184 | if (m_area == Right || m_area == Left) 185 | section.setRect(rect.bottomLeft().x(), rect.bottomLeft().y() - i * numIntervalls, rect.width(), numIntervalls); 186 | else 187 | section.setRect(rect.x() + i * numIntervalls, rect.y(), numIntervalls, rect.height()); 188 | 189 | painter->fillRect(section, colors.at(i)); 190 | } 191 | } 192 | 193 | void ColorBar::draw_color_title(QPainter* painter, QRectF rect) 194 | { 195 | for (int i = 0; i < 6; i++) { 196 | QString str = QString().sprintf("%.2f", m_min + i * (m_max - m_min) / 5); 197 | QFontMetrics fm = painter->fontMetrics(); 198 | switch (m_area) 199 | { 200 | case Top: 201 | { 202 | QPointF pos(rect.topLeft().x() + (rect.width() / 5) * i - fm.width(str) / 2, rect.topLeft().y()); 203 | painter->drawText(pos, str); 204 | } 205 | break; 206 | case Bottom: 207 | { 208 | QPointF pos(rect.topLeft().x() + (rect.width() / 5) * i - fm.width(str) / 2, rect.topLeft().y()+fm.ascent()); 209 | painter->drawText(pos, str); 210 | } 211 | break; 212 | case Left: 213 | { 214 | QPointF pos(rect.topLeft().x() - fm.width(str), rect.bottomLeft().y() - (rect.height() / 5) * i + fm.ascent() / 2); 215 | painter->drawText(pos, str); 216 | } 217 | break; 218 | case Right: 219 | { 220 | QPointF pos(rect.topLeft().x(), rect.bottomLeft().y() - (rect.height() / 5) * i + fm.ascent() / 2); 221 | painter->drawText(pos, str); 222 | } 223 | break; 224 | default: 225 | break; 226 | } 227 | } 228 | } 229 | 230 | void ColorBar::init_colors() 231 | { 232 | QColor color; 233 | float colorBarLength = 343.0;//设置颜色条的长度 234 | 235 | //------设置为gray颜色条---------// 236 | for (int i = 0; i <= colorBarLength; i++)// gray 237 | { 238 | color.setHsv(0, 0, (colorBarLength - i) / colorBarLength * 255); 239 | gray_colors.append(color); 240 | } 241 | 242 | //------设置为jet颜色条---------// 243 | float tempLength = colorBarLength / 4; 244 | for (int i = 0; i < tempLength / 2; i++) 245 | { 246 | color.setRgbF(0, 0, (tempLength / 2 + i) / tempLength); 247 | jet_colors.append(color); 248 | } 249 | for (int i = tempLength / 2 + 1; i < tempLength / 2 + tempLength; i++) 250 | { 251 | color.setRgbF(0, (i - tempLength / 2) / tempLength, 1); 252 | jet_colors.append(color); 253 | } 254 | for (int i = tempLength / 2 + tempLength + 1; i < tempLength / 2 + 2 * tempLength; i++) 255 | { 256 | color.setRgbF((i - tempLength - tempLength / 2) / tempLength, 1, (tempLength * 2 + tempLength / 2 - i) / tempLength); 257 | jet_colors.append(color); 258 | } 259 | for (int i = tempLength / 2 + 2 * tempLength + 1; i < tempLength / 2 + 3 * tempLength; i++) 260 | { 261 | color.setRgbF(1, (tempLength * 3 + tempLength / 2 - i) / tempLength, 0); 262 | jet_colors.append(color); 263 | } 264 | for (int i = tempLength / 2 + 3 * tempLength + 1; i < colorBarLength; i++) 265 | { 266 | color.setRgbF((colorBarLength - i + tempLength / 2) / (tempLength), 0, 0); 267 | jet_colors.append(color); 268 | } 269 | //------设置为hsv颜色条---------// 270 | for (int i = 0; i <= colorBarLength; i++) 271 | { 272 | color.setHsvF(i / colorBarLength, 1, 1); 273 | hsv_colors.append(color); 274 | } 275 | //------设置为hot颜色条---------// 276 | tempLength = colorBarLength / 2.5; 277 | for (int i = 0; i < tempLength / 2; i++) 278 | { 279 | color.setRgbF((tempLength / 2 + i) / tempLength, 0, 0); 280 | hot_colors.append(color); 281 | } 282 | for (int i = tempLength / 2 + 1; i < tempLength / 2 + tempLength; i++) 283 | { 284 | color.setRgbF(1, (i - tempLength / 2) / tempLength, 0); 285 | hot_colors.append(color); 286 | } 287 | for (int i = tempLength / 2 + tempLength + 1; i < colorBarLength; i++) 288 | { 289 | color.setRgbF(1, 1, (i - tempLength / 2 - tempLength) / (colorBarLength - tempLength / 2 - tempLength + 20)); 290 | hot_colors.append(color); 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /projects/Graph/Graph.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {1d944975-c53b-4168-9198-4c3d6b45bdf8} 6 | 7 | 8 | {aa37d10d-5484-46b2-a459-ae17d38bbdb1} 9 | 10 | 11 | {4346b31c-4b32-490a-9ccc-0322b3de8e08} 12 | 13 | 14 | {755af64f-0683-4696-9d91-b454ed35f3e1} 15 | 16 | 17 | 18 | 19 | src 20 | 21 | 22 | src\chart 23 | 24 | 25 | src\chart 26 | 27 | 28 | src\chart 29 | 30 | 31 | src\chart 32 | 33 | 34 | src\chart 35 | 36 | 37 | src\chart 38 | 39 | 40 | src\chart 41 | 42 | 43 | src\util 44 | 45 | 46 | src\util 47 | 48 | 49 | src\graph 50 | 51 | 52 | src\graph 53 | 54 | 55 | src\graph 56 | 57 | 58 | src\graph 59 | 60 | 61 | src\chart 62 | 63 | 64 | 65 | 66 | src\chart 67 | 68 | 69 | src\chart 70 | 71 | 72 | src\chart 73 | 74 | 75 | src\chart 76 | 77 | 78 | src\chart 79 | 80 | 81 | src\chart 82 | 83 | 84 | src\chart 85 | 86 | 87 | src\chart 88 | 89 | 90 | src\chart 91 | 92 | 93 | src\chart 94 | 95 | 96 | src\chart 97 | 98 | 99 | src\chart 100 | 101 | 102 | src\chart 103 | 104 | 105 | src\chart 106 | 107 | 108 | src\chart 109 | 110 | 111 | src\chart 112 | 113 | 114 | src\chart 115 | 116 | 117 | src\chart 118 | 119 | 120 | src\chart 121 | 122 | 123 | src\chart 124 | 125 | 126 | src\util 127 | 128 | 129 | src\graph 130 | 131 | 132 | src\graph 133 | 134 | 135 | src\graph 136 | 137 | 138 | src\graph 139 | 140 | 141 | src\chart 142 | 143 | 144 | src\chart 145 | 146 | 147 | src\chart 148 | 149 | 150 | src\chart 151 | 152 | 153 | src\chart 154 | 155 | 156 | 157 | 158 | src\chart 159 | 160 | 161 | src\chart 162 | 163 | 164 | src\chart 165 | 166 | 167 | src\chart 168 | 169 | 170 | src\chart 171 | 172 | 173 | src\chart 174 | 175 | 176 | src\chart 177 | 178 | 179 | src\chart 180 | 181 | 182 | src\chart 183 | 184 | 185 | src\chart 186 | 187 | 188 | src\chart 189 | 190 | 191 | src\chart 192 | 193 | 194 | src\chart 195 | 196 | 197 | src\chart 198 | 199 | 200 | src\chart 201 | 202 | 203 | src\chart 204 | 205 | 206 | src\chart 207 | 208 | 209 | src\chart 210 | 211 | 212 | 213 | 214 | src\chart 215 | 216 | 217 | src\chart 218 | 219 | 220 | src\chart 221 | 222 | 223 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/chart_view.cpp: -------------------------------------------------------------------------------- 1 | #pragma execution_character_set("utf-8") 2 | 3 | #include "chart_view.h" 4 | #include "QGraphicsView" 5 | #include "QAbstractScrollArea" 6 | #include "qmath.h" 7 | #include "QMenu" 8 | #include "axis_config.h" 9 | #include "series_config.h" 10 | #include "chart_config.h" 11 | #include 12 | #include "chart_view_preview.h" 13 | 14 | 15 | namespace 16 | { 17 | class RectResizer : public SizeGripItem::Resizer 18 | { 19 | public: 20 | virtual void operator()(QGraphicsItem* item, const QRectF& rect) 21 | { 22 | QGraphicsRectItem* rectItem =dynamic_cast(item); 23 | if (rectItem) 24 | rectItem->setRect(rect); 25 | } 26 | }; 27 | 28 | class EllipseResizer : public SizeGripItem::Resizer 29 | { 30 | public: 31 | virtual void operator()(QGraphicsItem* item, const QRectF& rect) 32 | { 33 | QGraphicsEllipseItem* ellipseItem = dynamic_cast(item); 34 | if (ellipseItem) 35 | ellipseItem->setRect(rect); 36 | } 37 | }; 38 | } 39 | 40 | 41 | ChartView::ChartView(QChart* chart, QWidget* parent) 42 | : QGraphicsView(new QGraphicsScene, parent), m_chart(chart), m_old_point(0, 0), m_translate_pos(0, 0) 43 | { 44 | setRenderHint(QPainter::Antialiasing); 45 | 46 | //使能接收到鼠标在视图窗口移动的事件 47 | setMouseTracking(true); 48 | 49 | setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 50 | setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 51 | setViewportUpdateMode(FullViewportUpdate); 52 | 53 | m_chart->setZValue(0); 54 | m_chart->setSelected(true); 55 | scene()->addItem(m_chart); 56 | 57 | //QGraphicsEllipseItem* item = new QGraphicsEllipseItem(0, 0, 100, 100);//x,y 为左上角的图元局部坐标,图元中心点为0,0 58 | //item->setFlags(QGraphicsItem::ItemIsMovable| QGraphicsItem::ItemIsSelectable); 59 | //item->setZValue(1); 60 | //item->setPos(10, 10); 61 | //item->setSelected(true); 62 | //scene()->addItem(item); 63 | 64 | //QGraphicsRectItem* rectItem = new QGraphicsRectItem(QRectF(0, 0, 320, 240)); 65 | //rectItem->setBrush(Qt::red); 66 | //rectItem->setPen(Qt::NoPen); 67 | //rectItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); 68 | //scene()->addItem(rectItem); 69 | 70 | //QGraphicsEllipseItem* ellipseItem = 71 | // new QGraphicsEllipseItem(QRectF(0, 0, 200, 200)); 72 | //ellipseItem->setBrush(Qt::blue); 73 | //ellipseItem->setPen(Qt::NoPen); 74 | //ellipseItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); 75 | //scene()->addItem(ellipseItem); 76 | 77 | //SizeGripItem* rectSizeGripItem =new SizeGripItem(new RectResizer, rectItem); 78 | //SizeGripItem* ellipseSizeGripItem =new SizeGripItem(new EllipseResizer, ellipseItem); 79 | 80 | } 81 | 82 | 83 | void ChartView::redraw() 84 | { 85 | viewport()->update(); 86 | } 87 | 88 | bool ChartView::save_picture(const QString& filename, const QSize& size ) 89 | { 90 | return true; 91 | } 92 | 93 | QWidget* ChartView::widget() 94 | { 95 | return this; 96 | } 97 | 98 | void ChartView::slot_chart_config() 99 | { 100 | ChartConfig dlg; 101 | dlg.setModal(false); 102 | dlg.exec(); 103 | } 104 | 105 | void ChartView::slot_series_config() 106 | { 107 | SeriesConfig dlg; 108 | dlg.setModal(false); 109 | dlg.exec(); 110 | } 111 | 112 | void ChartView::slot_axis_config() 113 | { 114 | AxisConfig dlg; 115 | dlg.setModal(false); 116 | dlg.exec(); 117 | } 118 | 119 | void ChartView::resizeEvent(QResizeEvent* event) 120 | { 121 | if (scene()) { 122 | scene()->setSceneRect(QRect(QPoint(0, 0), event->size())); 123 | m_chart->resize(event->size()); 124 | } 125 | QGraphicsView::resizeEvent(event); 126 | } 127 | 128 | void ChartView::mousePressEvent(QMouseEvent* event) 129 | { 130 | //鼠标左键按下,记录beginPoint 131 | if (event->button() == Qt::LeftButton) 132 | m_begin_point = event->pos(); 133 | else if (event->button() == Qt::MiddleButton) 134 | { 135 | m_isTranslate = true; 136 | m_old_point = event->pos(); 137 | set_cursor_auto(); 138 | } 139 | //else if (event->button() == Qt::RightButton) 140 | //{ 141 | // QPointF pointScene = mapToScene(event->pos()); //转换到Scene坐标 142 | // QGraphicsItem* item = NULL; 143 | // item = scene()->itemAt(pointScene, transform()); //获取光标下的绘图项 144 | // auto lost= scene()->items(pointScene); 145 | 146 | // QMenu menu(this); 147 | // menu.addAction(tr("图表设置"), this, SLOT(slot_chart_config())); 148 | // menu.addAction(tr("曲线设置"), this, SLOT(slot_series_config())); 149 | // menu.addAction(tr("坐标轴设置"), this, SLOT(slot_axis_config())); 150 | // menu.addSeparator(); 151 | // menu.addAction(tr("导出图片")); 152 | // menu.addAction(tr("打印")); 153 | // menu.exec(QCursor::pos()); 154 | //} 155 | QGraphicsView::mousePressEvent(event); 156 | } 157 | 158 | void ChartView::mouseMoveEvent(QMouseEvent* event) 159 | { 160 | if (is_previewing()) 161 | ChartViewPreview::on_mouse_move(this, event); 162 | else if (m_isTranslate) 163 | { 164 | QPointF delta = event->pos() - m_old_point; 165 | m_translate_pos += QPointF(-delta.x(), delta.y()); 166 | m_chart->scroll(-delta.x(), delta.y()); 167 | m_old_point = event->pos(); 168 | } 169 | QGraphicsView::mouseMoveEvent(event); 170 | } 171 | 172 | void ChartView::mouseReleaseEvent(QMouseEvent* event) 173 | { 174 | if (event->button() == Qt::LeftButton) 175 | { 176 | //鼠标左键释放,获取矩形框的endPoint,进行缩放 177 | m_end_point = event->pos(); 178 | //QRectF rectF; 179 | //rectF.setTopLeft(this->m_begin_point); 180 | //rectF.setBottomRight(this->m_end_point); 181 | //m_chart->zoomIn(rectF); 182 | } 183 | else if (event->button() == Qt::RightButton) 184 | { 185 | m_chart->zoomReset(); //鼠标右键释放,resetZoom 186 | m_chart->scroll(-m_translate_pos.x(), -m_translate_pos.y()); 187 | m_translate_pos.setX(0); 188 | m_translate_pos.setY(0); 189 | } 190 | else if (event->button() == Qt::MiddleButton) 191 | { 192 | m_isTranslate = false; 193 | set_cursor_auto(); 194 | } 195 | if (is_previewing()) 196 | ChartViewPreview::on_mouse_release(this, event); 197 | QGraphicsView::mouseReleaseEvent(event); 198 | } 199 | 200 | void ChartView::keyPressEvent(QKeyEvent* event) 201 | { 202 | switch (event->key()) { 203 | case Qt::Key_Plus: 204 | m_chart->zoomIn(); 205 | break; 206 | case Qt::Key_Minus: 207 | m_chart->zoomOut(); 208 | break; 209 | case Qt::Key_Left: 210 | m_chart->scroll(-10, 0); 211 | break; 212 | case Qt::Key_Right: 213 | m_chart->scroll(10, 0); 214 | break; 215 | case Qt::Key_Up: 216 | m_chart->scroll(0, 10); 217 | break; 218 | case Qt::Key_Down: 219 | m_chart->scroll(0, -10); 220 | break; 221 | default: 222 | QGraphicsView::keyPressEvent(event); 223 | break; 224 | } 225 | } 226 | 227 | void ChartView::wheelEvent(QWheelEvent* event) 228 | { 229 | // 设置比例 230 | qreal ratio = std::pow(0.999, event->delta()); 231 | // 1. 读取视图基本信息 232 | QRectF rect = m_chart->plotArea(); 233 | QPointF pos = rect.center(); 234 | // 2. 水平调整 235 | rect.setWidth(rect.width() * ratio); 236 | // 3. 竖直调整 237 | rect.setHeight(rect.height() * ratio); 238 | // 4. 计算视点,让鼠标点击的位置尽量保持不动(等比换算,存在一点误差) 239 | QPointF center(2 * pos - event->pos() - (pos - event->pos()) / ratio); 240 | // 5. 设置视点 241 | rect.moveCenter(center); 242 | // 6. 提交缩放调整 243 | m_chart->zoomIn(rect); 244 | 245 | QGraphicsView::wheelEvent(event); 246 | 247 | } 248 | 249 | void ChartView::mouseDoubleClickEvent(QMouseEvent* event) 250 | { 251 | if (event->button() == Qt::LeftButton) 252 | { 253 | //QPointF pointScene = mapToScene(event->pos()); //转换到Scene坐标 254 | //QGraphicsItem* item = NULL; 255 | //item = scene()->itemAt(pointScene, transform()); //获取光标下的绘图项 256 | //auto lost = scene()->items(pointScene); 257 | 258 | //QMenu menu(this); 259 | //menu.addAction(tr("图表设置")); 260 | //menu.addAction(tr("曲线设置")); 261 | //menu.addAction(tr("坐标轴设置")); 262 | //menu.addSeparator(); 263 | //menu.addAction(tr("导出图片")); 264 | //menu.addAction(tr("打印")); 265 | //menu.exec(QCursor::pos()); 266 | //scene()->clearSelection(); 267 | } 268 | QGraphicsView::mouseDoubleClickEvent(event); 269 | } 270 | 271 | void ChartView::set_cursor_auto() 272 | { 273 | if (m_isTranslate) 274 | setCursor(Qt::ClosedHandCursor); 275 | else if (ChartViewPreview::is_previewing(this)) 276 | setCursor(Qt::CrossCursor); 277 | else 278 | setCursor(Qt::ArrowCursor); 279 | } 280 | 281 | QPointF ChartView::map_to_scene(const QPoint& pos) 282 | { 283 | QPointF pt = mapToScene(pos); 284 | pt.setY(-pt.y()); 285 | return pt; 286 | } 287 | 288 | QPoint ChartView::map_from_scene(const QPointF& pos) 289 | { 290 | QPointF p(pos.x(), -pos.y()); 291 | return mapFromScene(p); 292 | } 293 | 294 | QPoint ChartView::map_to_global(const QPoint& pos) 295 | { 296 | return mapToGlobal(pos); 297 | } 298 | 299 | void ChartView::add_item(GraphicsItem* item) 300 | { 301 | item->apply(); 302 | item->set_view(this); 303 | scene()->addItem(dynamic_cast(item)); 304 | } 305 | 306 | void ChartView::delete_item(GraphicsItem* item) 307 | { 308 | scene()->removeItem(dynamic_cast (item)); 309 | } 310 | 311 | bool ChartView::is_previewing() 312 | { 313 | return ChartViewPreview::is_previewing(this); 314 | } 315 | -------------------------------------------------------------------------------- /projects/Graph/src/chart/chart_config.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ChartConfig 4 | 5 | 6 | 7 | 0 8 | 0 9 | 263 10 | 187 11 | 12 | 13 | 14 | 图表设置 15 | 16 | 17 | 18 | 19 | 20 | 0 21 | 22 | 23 | 24 | 标题 25 | 26 | 27 | 28 | 29 | 30 | 显示标题 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 图例 42 | 43 | 44 | 45 | 46 | 47 | 显示图例 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 位置 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 顶部 65 | 66 | 67 | 68 | 69 | 底部 70 | 71 | 72 | 73 | 74 | 左侧 75 | 76 | 77 | 78 | 79 | 右侧 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 边距 91 | 92 | 93 | 94 | 95 | 96 | 左边距 97 | 98 | 99 | Qt::AlignCenter 100 | 101 | 102 | 103 | 104 | 105 | 106 | 10 107 | 108 | 109 | 500 110 | 111 | 112 | 113 | 114 | 115 | 116 | 右边距 117 | 118 | 119 | Qt::AlignCenter 120 | 121 | 122 | 123 | 124 | 125 | 126 | 10 127 | 128 | 129 | 500 130 | 131 | 132 | 133 | 134 | 135 | 136 | 上边距 137 | 138 | 139 | Qt::AlignCenter 140 | 141 | 142 | 143 | 144 | 145 | 146 | 10 147 | 148 | 149 | 500 150 | 151 | 152 | 153 | 154 | 155 | 156 | 下边距 157 | 158 | 159 | Qt::AlignCenter 160 | 161 | 162 | 163 | 164 | 165 | 166 | 10 167 | 168 | 169 | 500 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 动画效果 178 | 179 | 180 | 181 | 182 | 183 | 动画效果 184 | 185 | 186 | Qt::AlignCenter 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | NoAnimation 195 | 196 | 197 | 198 | 199 | GridAxisAnimations 200 | 201 | 202 | 203 | 204 | SeriesAnimations 205 | 206 | 207 | 208 | 209 | AllAnimations 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 主 题 218 | 219 | 220 | Qt::AlignCenter 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | Light 229 | 230 | 231 | 232 | 233 | BlueCerulean 234 | 235 | 236 | 237 | 238 | Dark 239 | 240 | 241 | 242 | 243 | BrownSand 244 | 245 | 246 | 247 | 248 | BlueNcs 249 | 250 | 251 | 252 | 253 | HighContrast 254 | 255 | 256 | 257 | 258 | BlueIcy 259 | 260 | 261 | 262 | 263 | Qt 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | Qt::Horizontal 278 | 279 | 280 | 281 | 40 282 | 20 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 确定 291 | 292 | 293 | 294 | 295 | 296 | 297 | 取消 298 | 299 | 300 | 301 | 302 | 303 | 304 | 应用 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | -------------------------------------------------------------------------------- /projects/Graph/Graph.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | {052877BA-DD5E-4B0A-9259-62F40345A8AE} 87 | QtVS_v304 88 | 10.0.19041.0 89 | 10.0.19041.0 90 | $(MSBuildProjectDirectory)\QtMsBuild 91 | 92 | 93 | 94 | DynamicLibrary 95 | v143 96 | 97 | 98 | DynamicLibrary 99 | v143 100 | 101 | 102 | 103 | 104 | 105 | 106 | 5.15.2_msvc2019_64 107 | core;gui;widgets;charts 108 | debug 109 | 110 | 111 | 5.15.2_msvc2019_64 112 | core 113 | release 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | copy $(SolutionDir)$(IntDir)$(TargetName).dll $(SolutionDir)bin 136 | copy $(SolutionDir)$(IntDir)$(TargetName).lib $(SolutionDir)lib 137 | 138 | 139 | .\src\chart;.\src\graph;.\src\util;.\src;.\;.;%(AdditionalIncludeDirectories) 140 | 141 | 142 | $(SolutionDir)lib;%(AdditionalLibraryDirectories) 143 | %(AdditionalDependencies) 144 | 145 | 146 | 147 | 148 | .\src;.\;.\src\graph;.\src\extend;.\src\chart;%(AdditionalIncludeDirectories) 149 | 150 | 151 | 152 | 153 | true 154 | true 155 | ProgramDatabase 156 | Disabled 157 | MultiThreadedDebugDLL 158 | GRAPH_LIB;%(PreprocessorDefinitions) 159 | 160 | 161 | Windows 162 | true 163 | 164 | 165 | 166 | 167 | true 168 | true 169 | None 170 | MaxSpeed 171 | MultiThreadedDLL 172 | GRAPH_LIB;%(PreprocessorDefinitions) 173 | 174 | 175 | Windows 176 | false 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | --------------------------------------------------------------------------------