diff --git a/Modules/Chart/include/QmitkChartWidget.h b/Modules/Chart/include/QmitkChartWidget.h index b26aea11ea..b9a18b2ed4 100644 --- a/Modules/Chart/include/QmitkChartWidget.h +++ b/Modules/Chart/include/QmitkChartWidget.h @@ -1,357 +1,357 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkC3jsWidget_h #define QmitkC3jsWidget_h #include #include #include #include class QmitkChartxyData; /*! \brief QmitkChartWidget is a widget to display various charts based on the javascript chart library plotly. * \details Data is added via AddData1D() or AddData2D().\n * There can be multiple charts (of different types with different properties) created by calling AddData1D or AddData2D multiple times.\n\n * The following chart types are supported: * * line chart * * bar chart * * spline chart * * pie chart * * scatter chart * * area chart * * area spline chart. * * Technical details: The javascript code is embedded in a QWebEngineView. The actual js code is implemented in resource\Chart.js. * \sa https://plot.ly/javascript/ for further information about the used javaScript library. * \ingroup Modules/Chart */ class MITKCHART_EXPORT QmitkChartWidget : public QWidget { Q_OBJECT public: /*! * \brief enum of diagram types. */ enum class ChartType { bar, /*!< bar chart, see https://plot.ly/javascript/bar-charts/ */ line, /*!< line chart, see https://plot.ly/javascript/line-charts/ */ spline, /*!< spline chart (smoothed line chart), see https://plot.ly/~jduelfer/23/spline/#/ */ pie, /*!< pie chart, see https://plot.ly/javascript/pie-charts/ */ area, /*!< area chart, see https://plot.ly/javascript/filled-area-plots/ */ area_spline, /*!< area-spline chart, similar to https://plot.ly/~jduelfer/23/spline/#/ */ scatter /*!< scatter chart, see https://plot.ly/javascript/line-and-scatter/ */ }; /*! * \brief enum of chart style (modifies background and line color). */ enum class ColorTheme { darkstyle, /*!< background color: dark gray, foreground color: white*/ lightstyle /*!< background color: white, foreground color: black */ }; enum class LineStyle { solid, dashed }; enum class MarkerSymbol { circle, diamond, cross, square, pentagon, star, x, diamond_tall, star_diamond, star_triangle_up, star_triangle_down, asterisk, cross_thin, x_thin }; enum class ChartColor { red, orange, yellow, green, blue, purple, brown, magenta, tan, cyan, olive, maroon, navy, aquamarine, turqouise, silver, lime, teal, indigo, violet, pink, black, white, grey }; enum class AxisScale { linear, log }; /*! * \brief enum of legend position. * See https://plot.ly/javascript/legend/ */ enum class LegendPosition { bottomMiddle, bottomRight, topRight, topLeft, middleRight }; explicit QmitkChartWidget(QWidget* parent = nullptr); //for UnitTests explicit QmitkChartWidget(QWidget *parent, bool unitTest); ~QmitkChartWidget() override; /*! * \brief Adds 1D data to the widget * \details internally, the list is converted to a map with increasing integers keys starting at 0. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ void AddData1D(const std::vector& data1D, const std::string& label, ChartType chartType = ChartType::bar); /*! * \brief Updates data of an existing label * \param data1D the 1D data , \sa AddData1D * \param label the (existing) label * \note if the label does not exist, nothing happens */ void UpdateData1D(const std::vector &data1D, const std::string &label); /*! * \sa UpdateData1D * \sa AddData2D */ - void UpdateData2D(const std::map &data2D, const std::string &label); + void UpdateData2D(const std::vector< std::pair > &data2D, const std::string &label); /*! * \brief Adds 2D data to the widget. Call repeatedly for displaying multiple charts. * \details each entry represents a data point: key: value --> x-value: y-value. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ - void UpdateChartExampleData(const std::map& data2D, + void UpdateChartExampleData(const std::vector< std::pair >& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData = 0); - void AddData2D(const std::map &data2D, + void AddData2D(const std::vector< std::pair > &data2D, const std::string &label, ChartType chartType = ChartType::bar); //Add Function for the ChartExample - void AddChartExampleData(const std::map& data2D, + void AddChartExampleData(const std::vector< std::pair >& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& style, const std::string& pieLabelsData = 0); /*! * \brief Removes data from the widget, works for 1D and 2D Data * \param label the name of the data that is also used as identifier. * \note All data can be cleared with ClearDiagram() * \throws Invalid Argument Exception when the label cannot be found */ void RemoveData(const std::string& label); void UpdateLabel(const std::string& existingLabel, const std::string& newLabel); QmitkChartxyData *GetDataElementByLabel(const std::string& label) const; /*! * \brief Sets the color of one data entry (identifier is previously assigned label) * \details the color name can be "red" or a hex number (#FF0000). * \warning Either define all data entries with a color or no data entry. If a mixed approach is used, * plotly choses the color of the data entry (that could be the same as a user defined color). * \note If an unknown label is given, nothing happens. * \sa https://www.w3schools.com/cssref/css_colors.asp */ void SetColor(const std::string& label, const std::string& colorName); /*! * \brief Sets the line style of one data entry (identifier is previously assigned label) * \details two line styles are possible: LineStyle::solid and LineStyle::dashed. * The default line style is solid. * \note If an unknown label is given, nothing happens. * \warning only sets the line style if the current chart type is ChartType::line. * However, the line style remains also if the chart changes (e.g. new chart type) */ void SetLineStyle(const std::string& label, LineStyle style); /*! * \brief Sets the marker style of one data entry (identifier is previously assigned label) * \note If an unknown label is given, nothing happens. */ void SetMarkerSymbol(const std::string &label, MarkerSymbol symbol); /*! * \brief Sets the axis scale to either linear (default) or logarithmic. * \sa https://plot.ly/javascript/log-plot/ */ void SetYAxisScale(AxisScale scale); void SetXAxisLabel(const std::string& label); void SetYAxisLabel(const std::string& label); /*! * \brief Sets labels for pie chart data. * \note in AddData1D, the label still has to be given that acts as a unique id. However, the label is omitted then. */ void SetPieLabels(const std::vector &pieLabels, const std::string &label); /*! * \brief Sets a title for the chart. */ void SetTitle(const std::string &title); /*! * \brief Sets the chart type for a data entry * \details for available types, see ChartType * \note If an unknown label is given, nothing happens. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. * \sa DiagramType for available types */ void SetChartType(const std::string& label, ChartType type); /*! * \brief Sets error bars for data in x direction * \note If only error plus is provided, the error bars are symmetrical * \param label the name of the data that is also used as identifier. * \param errorPlus the error in positive direction * \param errorMinus the error in negative direction. Same as error plus if omitted */ void SetXErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector& errorMinus = std::vector()); /*! * \brief Sets error bars for data in y direction * \details for parameters, see SetXErrorBars * \note If only error plus is provided, the error bars are symmetrical */ void SetYErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus = std::vector()); /*! * \brief Sets the legend position. * \details Default position is bottom. * \sa LegendPosition for available types */ void SetLegendPosition(LegendPosition position); void SetShowLegend(bool show); void SetStackedData(bool stacked); /*! * \brief Displays the chart in the widget * \param showSubChart if a subchart is displayed inside the widget or not. * \note if no data has been provided, (\sa AddData1D AddData2D), an empty chart is displayed. */ void Show(bool showSubChart=false); /*! * \brief Either displays the dataPoints or not * \param showDataPoints if dataPoints are displayed inside the widget or not. * \details: example for not showing points: https://plot.ly/javascript/line-charts/#styling-line-plot * example for showing the points: https://plot.ly/javascript/pointcloud/ */ void SetShowDataPoints(bool showDataPoints); /*! * \brief Clears all data inside and resets the widget. */ void Clear(); /*! * \brief Sets the theme of the widget. * \details default is dark theme as in MITK. * \warning has to be called before Show() or Reload() to work */ void SetTheme(ColorTheme themeEnabled); /*! * \brief Sets whether the subchart shall be shown. * \details Changes the state of the current chart object. * \note Needs to be reloaded with Reload() to display changes. */ void SetShowSubchart(bool showSubChart); /*! * \brief Sets whether the error bars shall be shown. * \details Changes the state of the current chart object. * \note Needs to be reloaded with Reload() to display changes. * \param showErrorBars if error bars are displayed or not. */ void SetShowErrorBars(bool showErrorBars); /*! * \brief Sets the min and max x values of the chart * \details Zooms in to view the values between minValue and maxValue in x direction */ void SetMinMaxValueXView(double minValueX,double maxValueX); /*! * \brief Sets the min and max y values of the chart * \details Zooms in to view the values between minValue and maxValue in y direction */ void SetMinMaxValueYView(double minValueY, double maxValueY); /*! * \brief Reloads the chart in the widget * \details reloading may be needed to display added data in an existing chart */ void Reload(); QSize sizeHint() const override; void SavePlotAsImage(); public slots: void OnLoadFinished(bool isLoadSuccessful); void OnPageSuccessfullyLoaded(); signals: void PageSuccessfullyLoaded(); private: /*! source: https://stackoverflow.com/questions/29383/converting-bool-to-text-in-c*/ std::string convertBooleanValue(bool value) const; class Impl; std::unique_ptr m_Impl; }; #endif diff --git a/Modules/Chart/include/QmitkChartxyData.h b/Modules/Chart/include/QmitkChartxyData.h index 30f71d94fc..8c29ff5d67 100644 --- a/Modules/Chart/include/QmitkChartxyData.h +++ b/Modules/Chart/include/QmitkChartxyData.h @@ -1,171 +1,171 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkC3xyData_h #define QmitkC3xyData_h #include /** /brief This class holds the actual data for the chart generation with C3. * data can be loaded in constructor directly or with SetData * It is derived from QObject, because we need Q_PROPERTIES to send Data via QWebChannel to JavaScript. */ class QmitkChartxyData : public QObject { Q_OBJECT Q_PROPERTY(QVariant m_LabelCount READ GetLabelCount CONSTANT); Q_PROPERTY(QList m_YData READ GetYData WRITE SetYData NOTIFY SignalDataChanged); Q_PROPERTY(QList m_XData READ GetXData WRITE SetXData NOTIFY SignalDataChanged); Q_PROPERTY( QList m_XErrorDataPlus READ GetXErrorDataPlus WRITE SetXErrorDataPlus NOTIFY SignalErrorDataChanged); Q_PROPERTY( QList m_XErrorDataMinus READ GetXErrorDataMinus WRITE SetXErrorDataMinus NOTIFY SignalErrorDataChanged); Q_PROPERTY( QList m_YErrorDataPlus READ GetYErrorDataPlus WRITE SetYErrorDataPlus NOTIFY SignalErrorDataChanged); Q_PROPERTY( QList m_YErrorDataMinus READ GetYErrorDataMinus WRITE SetYErrorDataMinus NOTIFY SignalErrorDataChanged); Q_PROPERTY( QList m_PieLabels READ GetPieLabels WRITE SetPieLabels NOTIFY SignalPieLabelsChanged); Q_PROPERTY(QVariant m_ChartType READ GetChartType WRITE SetChartType NOTIFY SignalDiagramTypeChanged); Q_PROPERTY(QVariant m_Color READ GetColor WRITE SetColor NOTIFY SignalColorChanged); Q_PROPERTY(QVariant m_Label READ GetLabel WRITE SetLabel NOTIFY SignalLabelChanged); Q_PROPERTY(QVariant m_LineStyleName READ GetLineStyle WRITE SetLineStyle NOTIFY SignalLineStyleChanged); Q_PROPERTY(QVariant m_MarkerSymbolName READ GetMarkerSymbol WRITE SetMarkerSymbol NOTIFY SignalMarkerSymbolChanged); public: - explicit QmitkChartxyData(const QMap &data, + explicit QmitkChartxyData(const QList< QPair > &data, const QVariant &label, const QVariant &diagramType, const QVariant &position); // Constructor for Data2D (x:y=1:2, 2:6, 3:7) - void SetData(const QMap &data); + void SetData(const QList< QPair > &data); Q_INVOKABLE QVariant GetLabelCount() const { return m_LabelCount; } Q_INVOKABLE QList GetYData() const { return m_YData; }; Q_INVOKABLE void SetYData(const QList &yData) { m_YData = yData; emit SignalDataChanged(yData); }; Q_INVOKABLE QList GetXData() const { return m_XData; }; Q_INVOKABLE void SetXData(const QList &xData) { m_XData = xData; emit SignalDataChanged(xData); }; Q_INVOKABLE QList GetXErrorDataPlus() const { return m_XErrorDataPlus; }; Q_INVOKABLE void SetXErrorDataPlus(const QList &errorData) { m_XErrorDataPlus = errorData; emit SignalErrorDataChanged(errorData); }; Q_INVOKABLE QList GetXErrorDataMinus() const { return m_XErrorDataMinus; }; Q_INVOKABLE void SetXErrorDataMinus(const QList &errorData) { m_XErrorDataMinus = errorData; emit SignalErrorDataChanged(errorData); }; Q_INVOKABLE QList GetYErrorDataPlus() const { return m_YErrorDataPlus; }; Q_INVOKABLE void SetYErrorDataPlus(const QList &errorData) { m_YErrorDataPlus = errorData; emit SignalErrorDataChanged(errorData); }; Q_INVOKABLE QList GetYErrorDataMinus() const { return m_YErrorDataMinus; }; Q_INVOKABLE void SetYErrorDataMinus(const QList &errorData) { m_YErrorDataMinus = errorData; emit SignalErrorDataChanged(errorData); }; Q_INVOKABLE QVariant GetChartType() const { return m_ChartType; }; Q_INVOKABLE void SetChartType(const QVariant &chartType) { m_ChartType = chartType; emit SignalDiagramTypeChanged(chartType); }; Q_INVOKABLE QVariant GetLabel() const { return m_Label; }; Q_INVOKABLE void SetLabel(const QVariant &label) { m_Label = label; emit SignalLabelChanged(label); }; Q_INVOKABLE QList GetPieLabels() const { return m_PieLabels; }; Q_INVOKABLE void SetPieLabels(const QList &pieLabels) { m_PieLabels = pieLabels; }; Q_INVOKABLE QVariant GetColor() const { return m_Color; }; Q_INVOKABLE void SetColor(const QVariant &color) { m_Color = color; emit SignalColorChanged(color); }; Q_INVOKABLE QVariant GetMarkerSymbol() const { return m_MarkerSymbolName; }; Q_INVOKABLE void SetMarkerSymbol(const QVariant &markerSymbol) { m_MarkerSymbolName = markerSymbol; emit SignalMarkerSymbolChanged(markerSymbol); }; Q_INVOKABLE QVariant GetLineStyle() const { return m_LineStyleName; }; Q_INVOKABLE void SetLineStyle(const QVariant &lineStyle) { m_LineStyleName = lineStyle; emit SignalLineStyleChanged(lineStyle); }; /** * \brief Clears the Data. * * This function clears the data (including error data). */ void ClearData(); QmitkChartxyData() {} signals: void SignalDataChanged(const QList data); void SignalErrorDataChanged(const QList errorData); void SignalDiagramTypeChanged(const QVariant diagramType); void SignalColorChanged(const QVariant color); void SignalLabelChanged(const QVariant label); void SignalPieLabelsChanged(const QList pieLabels); void SignalLineStyleChanged(const QVariant lineStyle); void SignalMarkerSymbolChanged(const QVariant lineStyle); private: /** js needs to know which label position in the list QmitkChartWidget::Impl::m_C3xyData it has for updating the values*/ const QVariant m_LabelCount; QList m_YData; QList m_XData; QList m_XErrorDataPlus; QList m_XErrorDataMinus; QList m_YErrorDataPlus; QList m_YErrorDataMinus; QVariant m_Label; QList m_PieLabels; QVariant m_ChartType; QVariant m_Color; QVariant m_LineStyleName; QVariant m_MarkerSymbolName; }; #endif // QmitkC3xyData_h diff --git a/Modules/Chart/include/mitkChartExampleTestHelper.h b/Modules/Chart/include/mitkChartExampleTestHelper.h index aa11463aba..195212fb24 100644 --- a/Modules/Chart/include/mitkChartExampleTestHelper.h +++ b/Modules/Chart/include/mitkChartExampleTestHelper.h @@ -1,65 +1,65 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITK_CHART_EXAMPLE_TEST_HELPER_H #define MITK_CHART_EXAMPLE_TEST_HELPER_H #include // mitk core #include #include // std includes #include #include #include #include namespace mitk { class MITKCHART_EXPORT ChartExampleTestHelper { public: ////////////////////////////////////////////////////////////////////////// // ACCESS TO DATA SETS ////////////////////////////////////////////////////////////////////////// std::unique_ptr GetDataOne(); std::unique_ptr GetDataTwo(); std::unique_ptr GetDataThree(); std::unique_ptr GetDataFour(); std::unique_ptr GetDataFive(); ////////////////////////////////////////////////////////////////////////// // INSTANCE OF CLASS TO BE TESTED ////////////////////////////////////////////////////////////////////////// QmitkChartWidget qmitkChartWidget; ////////////////////////////////////////////////////////////////////////// // AUXILIARY FUNCTIONS ////////////////////////////////////////////////////////////////////////// QmitkChartWidget::ChartType ReturnChartTypeByString(std::string chartTypeString); QmitkChartWidget::ChartColor ReturnChartColorByString(std::string chartColorString); QmitkChartWidget::LineStyle ReturnChartStyleByString(std::string chartStyleString); void Add(int dataSet); - std::map ToStdMap(QVariantList xData, QVariantList yData); + std::vector > ToStdPairList(QVariantList xData, QVariantList yData); void ClearMemory(); }; // end ChartExampleTestHelper } // end mitk #endif diff --git a/Modules/Chart/src/QmitkChartWidget.cpp b/Modules/Chart/src/QmitkChartWidget.cpp index 3955aa3f2b..43eeb29469 100644 --- a/Modules/Chart/src/QmitkChartWidget.cpp +++ b/Modules/Chart/src/QmitkChartWidget.cpp @@ -1,954 +1,954 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include "mitkExceptionMacro.h" #include #include class CustomPage : public QWebEnginePage { public: CustomPage(QObject *parent = nullptr) : QWebEnginePage(parent) {} virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel /*level*/, const QString &message, int lineNumber, const QString & /*sourceID*/) override { MITK_INFO << "JS > " << lineNumber << ": " << message.toStdString(); } }; class QmitkChartWidget::Impl final { public: explicit Impl(QWidget *parent); ~Impl(); Impl(const Impl &) = delete; Impl &operator=(const Impl &) = delete; void AddData1D(const std::vector &data1D, const std::string &label, QmitkChartWidget::ChartType chartType); - void AddData2D(const std::map &data2D, + void AddData2D(const std::vector< std::pair > &data2D, const std::string &label, QmitkChartWidget::ChartType chartType); - void AddChartExampleData(const std::map& data2D, + void AddChartExampleData(const std::vector< std::pair >& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& style, const std::string& pieLabelsData = 0); void UpdateData1D(const std::vector &data1D, const std::string &label); - void UpdateData2D(const std::map &data2D, const std::string &label); - void UpdateChartExampleData(const std::map& data2D, + void UpdateData2D(const std::vector< std::pair > &data2D, const std::string &label); + void UpdateChartExampleData(const std::vector< std::pair >& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData = 0); void RemoveData(const std::string &label); void UpdateLabel(const std::string &existingLabel, const std::string &newLabel); QmitkChartxyData* GetDataElementByLabel(const std::string& label) const; void ClearData(); void SetColor(const std::string &label, const std::string &colorName); void SetLineStyle(const std::string &label, LineStyle style); void SetMarkerSymbol(const std::string &label, MarkerSymbol symbol); void SetYAxisScale(AxisScale scale); void SetXAxisLabel(const std::string &label); void SetYAxisLabel(const std::string &label); void SetPieLabels(const std::vector &pieLabels, const std::string &label); void SetTitle(const std::string &title); void SetXErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus = std::vector()); void SetYErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus = std::vector()); std::string GetThemeName() const; void SetThemeName(ColorTheme style); void SetLegendPosition(LegendPosition position); void Show(bool showSubChart); void SetShowLegend(bool show); void SetShowErrorBars(bool show); void SetStackedData(bool stacked); void SetShowDataPoints(bool showDataPoints = false); void SetShowSubchart(bool showSubChart); void SetChartType(const std::string &label, QmitkChartWidget::ChartType chartType); void SetMinMaxValueXView(double minValueX, double maxValueX); void SetMinMaxValueYView(double minValueY, double maxValueY); QList ConvertErrorVectorToQList(const std::vector &error); QList ConvertVectorToQList(const std::vector &vec); std::string ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const; void ClearJavaScriptChart(); void InitializeJavaScriptChart(); void CallJavaScriptFuntion(const QString &command); QSize sizeHint() const; void GetImageUrl(); private: using ChartxyDataVector = std::vector>; std::string GetUniqueLabelName(const QList &labelList, const std::string &label) const; QList GetDataLabels(const ChartxyDataVector &c3xyData) const; QWebChannel *m_WebChannel; QWebEngineView *m_WebEngineView; QmitkChartData m_C3Data; ChartxyDataVector m_C3xyData; std::map m_ChartTypeToName; std::map m_ChartColorToName; std::map m_ColorThemeToName; std::map m_LegendPositionToName; std::map m_LineStyleToName; std::map m_MarkerSymbolToName; std::map m_AxisScaleToName; }; QmitkChartWidget::Impl::Impl(QWidget *parent) : m_WebChannel(new QWebChannel(parent)), m_WebEngineView(new QWebEngineView(parent)) { // disable context menu for QWebEngineView m_WebEngineView->setContextMenuPolicy(Qt::NoContextMenu); m_WebEngineView->setPage(new CustomPage()); // Set the webengineview to an initial empty page. The actual chart will be loaded once the data is calculated. m_WebEngineView->load(QUrl(QStringLiteral("qrc:///Chart/empty.html"))); m_WebEngineView->page()->setWebChannel(m_WebChannel); m_WebEngineView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); connect(m_WebEngineView, SIGNAL(loadFinished(bool)), parent, SLOT(OnLoadFinished(bool))); auto layout = new QGridLayout(parent); layout->setMargin(0); layout->addWidget(m_WebEngineView); m_ChartTypeToName.emplace(ChartType::bar, "bar"); m_ChartTypeToName.emplace(ChartType::line, "line"); m_ChartTypeToName.emplace(ChartType::spline, "spline"); m_ChartTypeToName.emplace(ChartType::pie, "pie"); m_ChartTypeToName.emplace(ChartType::area, "area"); m_ChartTypeToName.emplace(ChartType::area_spline, "area-spline"); m_ChartTypeToName.emplace(ChartType::scatter, "scatter"); m_ChartColorToName.emplace(ChartColor::red, "red"); m_ChartColorToName.emplace(ChartColor::orange, "orange"); m_ChartColorToName.emplace(ChartColor::yellow, "yellow"); m_ChartColorToName.emplace(ChartColor::green, "green"); m_ChartColorToName.emplace(ChartColor::blue, "blue"); m_ChartColorToName.emplace(ChartColor::purple, "purple"); m_ChartColorToName.emplace(ChartColor::brown, "brown"); m_ChartColorToName.emplace(ChartColor::magenta, "magenta"); m_ChartColorToName.emplace(ChartColor::tan, "tan"); m_ChartColorToName.emplace(ChartColor::cyan, "cyan"); m_ChartColorToName.emplace(ChartColor::olive, "olive"); m_ChartColorToName.emplace(ChartColor::maroon, "maroon"); m_ChartColorToName.emplace(ChartColor::navy, "navy"); m_ChartColorToName.emplace(ChartColor::aquamarine, "aquamarine"); m_ChartColorToName.emplace(ChartColor::turqouise, "turqouise"); m_ChartColorToName.emplace(ChartColor::silver, "silver"); m_ChartColorToName.emplace(ChartColor::lime, "lime"); m_ChartColorToName.emplace(ChartColor::teal, "teal"); m_ChartColorToName.emplace(ChartColor::indigo, "indigo"); m_ChartColorToName.emplace(ChartColor::violet, "violet"); m_ChartColorToName.emplace(ChartColor::pink, "pink"); m_ChartColorToName.emplace(ChartColor::black, "black"); m_ChartColorToName.emplace(ChartColor::white, "white"); m_ChartColorToName.emplace(ChartColor::grey, "grey"); m_LegendPositionToName.emplace(LegendPosition::bottomMiddle, "bottomMiddle"); m_LegendPositionToName.emplace(LegendPosition::bottomRight, "bottomRight"); m_LegendPositionToName.emplace(LegendPosition::topRight, "topRight"); m_LegendPositionToName.emplace(LegendPosition::topLeft, "topLeft"); m_LegendPositionToName.emplace(LegendPosition::middleRight, "middleRight"); m_LineStyleToName.emplace(LineStyle::solid, "solid"); m_LineStyleToName.emplace(LineStyle::dashed, "dashed"); m_MarkerSymbolToName.emplace(MarkerSymbol::circle, "circle"); m_MarkerSymbolToName.emplace(MarkerSymbol::cross, "cross"); m_MarkerSymbolToName.emplace(MarkerSymbol::diamond, "diamond"); m_MarkerSymbolToName.emplace(MarkerSymbol::pentagon, "pentagon"); m_MarkerSymbolToName.emplace(MarkerSymbol::square, "square"); m_MarkerSymbolToName.emplace(MarkerSymbol::star, "star"); m_MarkerSymbolToName.emplace(MarkerSymbol::x, "x"); m_MarkerSymbolToName.emplace(MarkerSymbol::diamond_tall, "diamond-tall"); m_MarkerSymbolToName.emplace(MarkerSymbol::star_diamond, "star-diamond"); m_MarkerSymbolToName.emplace(MarkerSymbol::star_triangle_up, "star-triangle-up"); m_MarkerSymbolToName.emplace(MarkerSymbol::star_triangle_down, "star-triangle-down"); m_MarkerSymbolToName.emplace(MarkerSymbol::asterisk, "asterisk"); m_MarkerSymbolToName.emplace(MarkerSymbol::cross_thin, "cross-thin"); m_MarkerSymbolToName.emplace(MarkerSymbol::x_thin, "x-thin"); m_AxisScaleToName.emplace(AxisScale::linear, ""); m_AxisScaleToName.emplace(AxisScale::log, "log"); m_ColorThemeToName.emplace(ColorTheme::lightstyle, "light"); m_ColorThemeToName.emplace(ColorTheme::darkstyle, "dark"); } QmitkChartWidget::Impl::~Impl() {} std::string QmitkChartWidget::Impl::GetThemeName() const { - return m_C3Data.GetThemeName().toString().toStdString(); + return m_C3Data.GetThemeName().toString().toStdString(); } std::string CheckForCorrectHex(const std::string &colorName) { std::regex rgx("([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"); std::smatch match; if (!colorName.empty() && colorName.at(0) != '#' && std::regex_search(colorName.begin(), colorName.end(), match, rgx)) { return "#" + colorName; } else { return colorName; } } void QmitkChartWidget::Impl::GetImageUrl() { m_C3Data.EmitSignalImageUrl(); } void QmitkChartWidget::Impl::AddData1D(const std::vector &data1D, const std::string &label, QmitkChartWidget::ChartType type) { - std::map transformedData2D; + std::vector< std::pair > transformedData2D; unsigned int count = 0; // transform the 1D data to 2D data for (const auto &ele : data1D) { - transformedData2D[count] = ele; + transformedData2D.push_back(std::pair(count, ele)); count++; } AddData2D(transformedData2D, label, type); } -void QmitkChartWidget::Impl::AddData2D(const std::map &data2D, +void QmitkChartWidget::Impl::AddData2D(const std::vector< std::pair > &data2D, const std::string &label, QmitkChartWidget::ChartType type) { - QMap data2DConverted; + QList< QPair > data2DConverted; for (const auto &aValue : data2D) { - data2DConverted.insert(aValue.first, aValue.second); + data2DConverted.append(QPair(aValue.first, aValue.second)); } const std::string chartTypeName(m_ChartTypeToName.at(type)); auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, label); unsigned int sizeOfC3xyData = static_cast(m_C3xyData.size()); m_C3xyData.push_back(std::make_unique(data2DConverted, QVariant(QString::fromStdString(uniqueLabel)), QVariant(QString::fromStdString(chartTypeName)), QVariant(sizeOfC3xyData))); } -void QmitkChartWidget::Impl::AddChartExampleData(const std::map& data2D, +void QmitkChartWidget::Impl::AddChartExampleData(const std::vector< std::pair >& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData) { - QMap data2DConverted; - for (const auto& aValue : data2D) - { - data2DConverted.insert(aValue.first, aValue.second); - } + QList< QPair > data2DConverted; + for (const auto& aValue : data2D) + { + data2DConverted.append(QPair(aValue.first, aValue.second)); + } - auto definedLabels = GetDataLabels(m_C3xyData); - auto uniqueLabel = GetUniqueLabelName(definedLabels, label); - if (type == "scatter") - { - SetShowDataPoints(true); - MITK_INFO << "Enabling data points for all because of scatter plot"; - } - unsigned int sizeOfC3xyData = static_cast(m_C3xyData.size()); + auto definedLabels = GetDataLabels(m_C3xyData); + auto uniqueLabel = GetUniqueLabelName(definedLabels, label); + if (type == "scatter") + { + SetShowDataPoints(true); + MITK_INFO << "Enabling data points for all because of scatter plot"; + } + unsigned int sizeOfC3xyData = static_cast(m_C3xyData.size()); - std::unique_ptr chartData = - std::make_unique( - data2DConverted, - QVariant(QString::fromStdString(uniqueLabel)), - QVariant(QString::fromStdString(type)), - QVariant(sizeOfC3xyData)); + std::unique_ptr chartData = + std::make_unique( + data2DConverted, + QVariant(QString::fromStdString(uniqueLabel)), + QVariant(QString::fromStdString(type)), + QVariant(sizeOfC3xyData)); - chartData->SetColor(QVariant(QString::fromStdString(color))); - chartData->SetLineStyle(QVariant(QString::fromStdString(lineStyle))); + chartData->SetColor(QVariant(QString::fromStdString(color))); + chartData->SetLineStyle(QVariant(QString::fromStdString(lineStyle))); - if (pieLabelsData != "") - { - std::string pieLabelsDataWorkingString = pieLabelsData; + if (pieLabelsData != "") + { + std::string pieLabelsDataWorkingString = pieLabelsData; - QList pieLabelsDataList; - while (pieLabelsDataWorkingString.size() != 0) - { - QVariant oneElement = QString::fromStdString(pieLabelsDataWorkingString.substr(0, pieLabelsDataWorkingString.find(";"))); - pieLabelsDataList.push_back(oneElement); - - if (pieLabelsDataWorkingString.find(";") != std::string::npos) - { - pieLabelsDataWorkingString.erase(0, pieLabelsDataWorkingString.find(";") + 1); - } - else - { - pieLabelsDataWorkingString.erase(pieLabelsDataWorkingString.begin(), pieLabelsDataWorkingString.end()); - } - } + QList pieLabelsDataList; + while (pieLabelsDataWorkingString.size() != 0) + { + QVariant oneElement = QString::fromStdString(pieLabelsDataWorkingString.substr(0, pieLabelsDataWorkingString.find(";"))); + pieLabelsDataList.push_back(oneElement); - chartData->SetPieLabels(pieLabelsDataList); + if (pieLabelsDataWorkingString.find(";") != std::string::npos) + { + pieLabelsDataWorkingString.erase(0, pieLabelsDataWorkingString.find(";") + 1); + } + else + { + pieLabelsDataWorkingString.erase(pieLabelsDataWorkingString.begin(), pieLabelsDataWorkingString.end()); + } } - m_C3xyData.push_back(std::move(chartData)); + chartData->SetPieLabels(pieLabelsDataList); + } + + m_C3xyData.push_back(std::move(chartData)); } void QmitkChartWidget::Impl::UpdateData1D(const std::vector &data1D, const std::string &label) { - std::map transformedData2D; + std::vector< std::pair > transformedData2D; unsigned int count = 0; // transform the 1D data to 2D data for (const auto &ele : data1D) { - transformedData2D[count] = ele; + transformedData2D.push_back( std::pair(count, ele) ); count++; } UpdateData2D(transformedData2D, label); } -void QmitkChartWidget::Impl::UpdateData2D(const std::map &data2D, const std::string &label) +void QmitkChartWidget::Impl::UpdateData2D(const std::vector< std::pair > &data2D, const std::string &label) { auto element = GetDataElementByLabel(label); if (element) { - QMap data2DConverted; + QList< QPair > data2DConverted; for (const auto &aValue : data2D) { - data2DConverted.insert(aValue.first, aValue.second); + data2DConverted.append( QPair(aValue.first, aValue.second) ); } element->SetData(data2DConverted); } } -void QmitkChartWidget::Impl::UpdateChartExampleData(const std::map& data2D, +void QmitkChartWidget::Impl::UpdateChartExampleData(const std::vector< std::pair >& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData) { - UpdateData2D(data2D, label); + UpdateData2D(data2D, label); + + auto element = GetDataElementByLabel(label); + if (element) + { + element->SetChartType(QString::fromStdString(type)); + element->SetColor(QString::fromStdString(color)); + element->SetLineStyle(QString::fromStdString(lineStyle)); - auto element = GetDataElementByLabel(label); - if (element) + if (pieLabelsData != "") { - element->SetChartType(QString::fromStdString(type)); - element->SetColor(QString::fromStdString(color)); - element->SetLineStyle(QString::fromStdString(lineStyle)); + std::string pieLabelsDataWorkingString = pieLabelsData; - if (pieLabelsData != "") + QList pieLabelsDataList; + while (pieLabelsDataWorkingString.size() != 0) + { + QVariant oneElement = QString::fromStdString(pieLabelsDataWorkingString.substr(0, pieLabelsDataWorkingString.find(";"))); + pieLabelsDataList.push_back(oneElement); + + if (pieLabelsDataWorkingString.find(";") != std::string::npos) { - std::string pieLabelsDataWorkingString = pieLabelsData; - - QList pieLabelsDataList; - while (pieLabelsDataWorkingString.size() != 0) - { - QVariant oneElement = QString::fromStdString(pieLabelsDataWorkingString.substr(0, pieLabelsDataWorkingString.find(";"))); - pieLabelsDataList.push_back(oneElement); - - if (pieLabelsDataWorkingString.find(";") != std::string::npos) - { - pieLabelsDataWorkingString.erase(0, pieLabelsDataWorkingString.find(";") + 1); - } - else - { - pieLabelsDataWorkingString.erase(pieLabelsDataWorkingString.begin(), pieLabelsDataWorkingString.end()); - } - } - - element->SetPieLabels(pieLabelsDataList); + pieLabelsDataWorkingString.erase(0, pieLabelsDataWorkingString.find(";") + 1); } + else + { + pieLabelsDataWorkingString.erase(pieLabelsDataWorkingString.begin(), pieLabelsDataWorkingString.end()); + } + } + + element->SetPieLabels(pieLabelsDataList); } + } } void QmitkChartWidget::Impl::RemoveData(const std::string &label) { for (ChartxyDataVector::iterator iter = m_C3xyData.begin(); iter != m_C3xyData.end(); ++iter) { if ((*iter)->GetLabel().toString().toStdString() == label) { m_C3xyData.erase(iter); return; } } throw std::invalid_argument("Cannot Remove Data because the label does not exist."); } void QmitkChartWidget::Impl::ClearData() { for (auto &xyData : m_C3xyData) { m_WebChannel->deregisterObject(xyData.get()); } m_C3xyData.clear(); } void QmitkChartWidget::Impl::UpdateLabel(const std::string &existingLabel, const std::string &newLabel) { auto element = GetDataElementByLabel(existingLabel); if (element) { auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, newLabel); element->SetLabel(QString::fromStdString(uniqueLabel)); } } void QmitkChartWidget::Impl::SetColor(const std::string &label, const std::string &colorName) { auto element = GetDataElementByLabel(label); if (element) { auto colorChecked = CheckForCorrectHex(colorName); element->SetColor(QVariant(QString::fromStdString(colorChecked))); } } void QmitkChartWidget::Impl::SetLineStyle(const std::string &label, LineStyle style) { auto element = GetDataElementByLabel(label); const std::string lineStyleName(m_LineStyleToName.at(style)); element->SetLineStyle(QVariant(QString::fromStdString(lineStyleName))); } void QmitkChartWidget::Impl::SetMarkerSymbol(const std::string &label, MarkerSymbol symbol) { auto element = GetDataElementByLabel(label); const std::string markerSymbolName(m_MarkerSymbolToName.at(symbol)); element->SetMarkerSymbol(QVariant(QString::fromStdString(markerSymbolName))); } void QmitkChartWidget::Impl::SetYAxisScale(AxisScale scale) { const std::string axisScaleName(m_AxisScaleToName.at(scale)); m_C3Data.SetYAxisScale(QString::fromStdString(axisScaleName)); } QmitkChartxyData *QmitkChartWidget::Impl::GetDataElementByLabel(const std::string &label) const { for (const auto &qmitkChartxyData : m_C3xyData) { if (qmitkChartxyData->GetLabel().toString() == label.c_str()) { return qmitkChartxyData.get(); } } return nullptr; } QList QmitkChartWidget::Impl::GetDataLabels(const ChartxyDataVector &c3xyData) const { QList dataLabels; for (auto element = c3xyData.begin(); element != c3xyData.end(); ++element) { dataLabels.push_back((*element)->GetLabel()); } return dataLabels; } void QmitkChartWidget::Impl::SetXAxisLabel(const std::string &label) { m_C3Data.SetXAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetYAxisLabel(const std::string &label) { m_C3Data.SetYAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetPieLabels(const std::vector &pieLabels, const std::string &label) { auto element = GetDataElementByLabel(label); if (element) { if (element->GetChartType() == QVariant("pie")) { auto dataY = element->GetYData(); element->SetPieLabels(ConvertVectorToQList(pieLabels)); if (static_cast(dataY.size()) != pieLabels.size()) { MITK_INFO << "data has " << dataY.size() << " entries whereas pie labels have " << pieLabels.size() << " entries. Unnamed pie labels automatically get a numerical label."; } } else { MITK_INFO << "label" << label << "has chart type " << element->GetChartType().toString().toStdString() << ", but pie is required"; } } } void QmitkChartWidget::Impl::SetTitle(const std::string &title) { m_C3Data.SetTitle(QString::fromStdString(title)); } void QmitkChartWidget::Impl::SetThemeName(QmitkChartWidget::ColorTheme style) { const std::string themeName(m_ColorThemeToName.at(style)); m_C3Data.SetThemeName(QString::fromStdString(themeName)); } void QmitkChartWidget::Impl::SetLegendPosition(QmitkChartWidget::LegendPosition legendPosition) { const std::string legendPositionName(m_LegendPositionToName.at(legendPosition)); m_C3Data.SetLegendPosition(QString::fromStdString(legendPositionName)); } void QmitkChartWidget::Impl::Show(bool showSubChart) { if (m_C3xyData.empty()) { MITK_WARN << "no data available for display in chart"; } else { m_C3Data.SetAppearance(showSubChart, m_C3xyData.front()->GetChartType() == QVariant("pie")); } InitializeJavaScriptChart(); } void QmitkChartWidget::Impl::SetShowLegend(bool show) { m_C3Data.SetShowLegend(show); } void QmitkChartWidget::Impl::SetStackedData(bool stacked) { m_C3Data.SetStackedData(stacked); } void QmitkChartWidget::Impl::SetShowErrorBars(bool show) { m_C3Data.SetShowErrorBars(show); } void QmitkChartWidget::Impl::SetShowDataPoints(bool showDataPoints) { if (showDataPoints == true) { m_C3Data.SetDataPointSize(6.5); } else { m_C3Data.SetDataPointSize(0); } } void QmitkChartWidget::Impl::SetShowSubchart(bool showSubChart) { m_C3Data.SetShowSubchart(showSubChart); } void QmitkChartWidget::Impl::SetChartType(const std::string &label, QmitkChartWidget::ChartType chartType) { auto element = GetDataElementByLabel(label); if (element) { if (chartType == ChartType::scatter) { SetShowDataPoints(true); MITK_INFO << "Enabling data points for all because of scatter plot"; } const std::string chartTypeName(m_ChartTypeToName.at(chartType)); element->SetChartType(QVariant(QString::fromStdString(chartTypeName))); } } void QmitkChartWidget::Impl::SetMinMaxValueXView(double minValueX, double maxValueX) { m_C3Data.SetMinValueXView(minValueX); m_C3Data.SetMaxValueXView(maxValueX); } void QmitkChartWidget::Impl::SetMinMaxValueYView(double minValueY, double maxValueY) { m_C3Data.SetMinValueYView(minValueY); m_C3Data.SetMaxValueYView(maxValueY); } QList QmitkChartWidget::Impl::ConvertErrorVectorToQList(const std::vector &error) { QList errorConverted; for (const auto &aValue : error) { errorConverted.append(aValue); } return errorConverted; } QList QmitkChartWidget::Impl::ConvertVectorToQList(const std::vector &vec) { QList vecConverted; for (const auto &aValue : vec) { vecConverted.append(QString::fromStdString(aValue)); } return vecConverted; } void QmitkChartWidget::Impl::SetXErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus) { auto element = GetDataElementByLabel(label); if (element) { auto errorConvertedPlus = ConvertErrorVectorToQList(errorPlus); auto errorConvertedMinus = ConvertErrorVectorToQList(errorMinus); element->SetXErrorDataPlus(errorConvertedPlus); element->SetXErrorDataMinus(errorConvertedMinus); } } void QmitkChartWidget::Impl::SetYErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus) { auto element = GetDataElementByLabel(label); if (element) { auto errorConvertedPlus = ConvertErrorVectorToQList(errorPlus); auto errorConvertedMinus = ConvertErrorVectorToQList(errorMinus); element->SetYErrorDataPlus(errorConvertedPlus); element->SetYErrorDataMinus(errorConvertedMinus); } } std::string QmitkChartWidget::Impl::ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const { return m_ChartTypeToName.at(chartType); } QSize QmitkChartWidget::Impl::sizeHint() const { return QSize(400, 300); } void QmitkChartWidget::Impl::CallJavaScriptFuntion(const QString &command) { m_WebEngineView->page()->runJavaScript(command); } void QmitkChartWidget::Impl::ClearJavaScriptChart() { m_WebEngineView->load(QUrl(QStringLiteral("qrc:///Chart/empty.html"))); } void QmitkChartWidget::Impl::InitializeJavaScriptChart() { auto alreadyRegisteredObjects = m_WebChannel->registeredObjects(); auto alreadyRegisteredObjectsValues = alreadyRegisteredObjects.values(); // only register objects that have not been registered yet if (alreadyRegisteredObjectsValues.indexOf(&m_C3Data) == -1) { m_WebChannel->registerObject(QStringLiteral("chartData"), &m_C3Data); } unsigned count = 0; for (auto &xyData : m_C3xyData) { // only register objects that have not been registered yet if (alreadyRegisteredObjectsValues.indexOf(xyData.get()) == -1) { QString variableName = "xyData" + QString::number(count); m_WebChannel->registerObject(variableName, xyData.get()); } count++; } m_WebEngineView->load(QUrl(QStringLiteral("qrc:///Chart/QmitkChartWidget.html"))); } std::string QmitkChartWidget::Impl::GetUniqueLabelName(const QList &labelList, const std::string &label) const { QString currentLabel = QString::fromStdString(label); int counter = 0; while (labelList.contains(currentLabel)) { currentLabel = QString::fromStdString(label + std::to_string(counter)); counter++; } return currentLabel.toStdString(); } QmitkChartWidget::QmitkChartWidget(QWidget *parent) : QWidget(parent), m_Impl(new Impl(this)) { connect(this, &QmitkChartWidget::PageSuccessfullyLoaded, this, &QmitkChartWidget::OnPageSuccessfullyLoaded); } QmitkChartWidget::~QmitkChartWidget() {} void QmitkChartWidget::SetColor(const std::string &label, const std::string &colorName) { m_Impl->SetColor(label, colorName); } void QmitkChartWidget::SetLineStyle(const std::string &label, LineStyle style) { m_Impl->SetLineStyle(label, style); } void QmitkChartWidget::SetMarkerSymbol(const std::string &label, MarkerSymbol symbol) { m_Impl->SetMarkerSymbol(label, symbol); } void QmitkChartWidget::SetYAxisScale(AxisScale scale) { m_Impl->SetYAxisScale(scale); } void QmitkChartWidget::AddData1D(const std::vector &data1D, const std::string &label, ChartType type) { m_Impl->AddData1D(data1D, label, type); } -void QmitkChartWidget::AddData2D(const std::map& data2D, const std::string& label, ChartType type) +void QmitkChartWidget::AddData2D(const std::vector< std::pair >& data2D, const std::string& label, ChartType type) { - m_Impl->AddData2D(data2D, label, type); + m_Impl->AddData2D(data2D, label, type); } -void QmitkChartWidget::AddChartExampleData(const std::map& data2D, +void QmitkChartWidget::AddChartExampleData(const std::vector< std::pair >& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData) { - m_Impl->AddChartExampleData(data2D, label, type, color, lineStyle, pieLabelsData); + m_Impl->AddChartExampleData(data2D, label, type, color, lineStyle, pieLabelsData); } void QmitkChartWidget::UpdateData1D(const std::vector &data1D, const std::string &label) { m_Impl->UpdateData1D(data1D, label); } -void QmitkChartWidget::UpdateData2D(const std::map &data2D, const std::string &label) +void QmitkChartWidget::UpdateData2D(const std::vector< std::pair > &data2D, const std::string &label) { m_Impl->UpdateData2D(data2D, label); } -void QmitkChartWidget::UpdateChartExampleData(const std::map& data2D, +void QmitkChartWidget::UpdateChartExampleData(const std::vector< std::pair >& data2D, const std::string& label, const std::string& type, const std::string& color, const std::string& lineStyle, const std::string& pieLabelsData) { - m_Impl->UpdateChartExampleData(data2D, label, type, color, lineStyle, pieLabelsData); + m_Impl->UpdateChartExampleData(data2D, label, type, color, lineStyle, pieLabelsData); } void QmitkChartWidget::RemoveData(const std::string &label) { m_Impl->RemoveData(label); } void QmitkChartWidget::UpdateLabel(const std::string &existingLabel, const std::string &newLabel) { m_Impl->UpdateLabel(existingLabel, newLabel); } QmitkChartxyData* QmitkChartWidget::GetDataElementByLabel(const std::string& label) const { return m_Impl->GetDataElementByLabel(label); } void QmitkChartWidget::SetXAxisLabel(const std::string &label) { m_Impl->SetXAxisLabel(label); } void QmitkChartWidget::SetYAxisLabel(const std::string &label) { m_Impl->SetYAxisLabel(label); } void QmitkChartWidget::SetPieLabels(const std::vector &pieLabels, const std::string &label) { m_Impl->SetPieLabels(pieLabels, label); } void QmitkChartWidget::SetTitle(const std::string &title) { m_Impl->SetTitle(title); } void QmitkChartWidget::SetShowDataPoints(bool showDataPoints) { m_Impl->SetShowDataPoints(showDataPoints); } void QmitkChartWidget::SetChartType(const std::string &label, ChartType type) { m_Impl->SetChartType(label, type); } void QmitkChartWidget::SetXErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus) { m_Impl->SetXErrorBars(label, errorPlus, errorMinus); } void QmitkChartWidget::SetYErrorBars(const std::string &label, const std::vector &errorPlus, const std::vector &errorMinus) { m_Impl->SetYErrorBars(label, errorPlus, errorMinus); } void QmitkChartWidget::SetLegendPosition(LegendPosition position) { m_Impl->SetLegendPosition(position); } void QmitkChartWidget::SetShowLegend(bool show) { m_Impl->SetShowLegend(show); } void QmitkChartWidget::SetStackedData(bool stacked) { m_Impl->SetStackedData(stacked); } void QmitkChartWidget::Show(bool showSubChart) { m_Impl->Show(showSubChart); } void QmitkChartWidget::Clear() { m_Impl->ClearData(); m_Impl->ClearJavaScriptChart(); } void QmitkChartWidget::OnLoadFinished(bool isLoadSuccessful) { if (isLoadSuccessful) { emit PageSuccessfullyLoaded(); } } void QmitkChartWidget::OnPageSuccessfullyLoaded() { auto themeName = m_Impl->GetThemeName(); QString command; if (themeName == "dark") { command = QString("changeTheme('dark')"); } else { command = QString("changeTheme('light')"); } m_Impl->CallJavaScriptFuntion(command); } void QmitkChartWidget::SetTheme(ColorTheme themeEnabled) { m_Impl->SetThemeName(themeEnabled); } void QmitkChartWidget::SetShowSubchart(bool showSubChart) { m_Impl->SetShowSubchart(showSubChart); } void QmitkChartWidget::SetShowErrorBars(bool showErrorBars) { m_Impl->SetShowErrorBars(showErrorBars); } void QmitkChartWidget::SetMinMaxValueXView(double minValueX, double maxValueX) { m_Impl->SetMinMaxValueXView(minValueX, maxValueX); } void QmitkChartWidget::SetMinMaxValueYView(double minValueY, double maxValueY) { m_Impl->SetMinMaxValueYView(minValueY, maxValueY); } void QmitkChartWidget::Reload() { const QString command = QString("Reload()"); m_Impl->CallJavaScriptFuntion(command); } QSize QmitkChartWidget::sizeHint() const { return m_Impl->sizeHint(); } void QmitkChartWidget::SavePlotAsImage() { m_Impl->GetImageUrl(); } diff --git a/Modules/Chart/src/QmitkChartxyData.cpp b/Modules/Chart/src/QmitkChartxyData.cpp index 3c2252d31f..7a57f2e983 100644 --- a/Modules/Chart/src/QmitkChartxyData.cpp +++ b/Modules/Chart/src/QmitkChartxyData.cpp @@ -1,43 +1,43 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include -QmitkChartxyData::QmitkChartxyData(const QMap &data, +QmitkChartxyData::QmitkChartxyData(const QList< QPair > &data, const QVariant &label, const QVariant &chartType, const QVariant &position) : m_LabelCount(position), m_Label(label), m_ChartType(chartType) { SetData(data); } -void QmitkChartxyData::SetData(const QMap &data) +void QmitkChartxyData::SetData(const QList< QPair > &data) { ClearData(); - for (const auto &entry : data.toStdMap()) + for (const auto &entry : data.toStdList()) { m_XData.push_back(entry.first); m_YData.push_back(entry.second); } emit SignalDataChanged(m_YData); } void QmitkChartxyData::ClearData() { this->m_YData.clear(); this->m_XData.clear(); this->m_XErrorDataPlus.clear(); this->m_XErrorDataMinus.clear(); this->m_YErrorDataPlus.clear(); this->m_YErrorDataMinus.clear(); } diff --git a/Modules/Chart/src/mitkChartExampleTestHelper.cpp b/Modules/Chart/src/mitkChartExampleTestHelper.cpp index 517766f712..ee749503f7 100644 --- a/Modules/Chart/src/mitkChartExampleTestHelper.cpp +++ b/Modules/Chart/src/mitkChartExampleTestHelper.cpp @@ -1,353 +1,353 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkChartExampleTestHelper.h" // std includes #include std::unique_ptr mitk::ChartExampleTestHelper::GetDataOne() { - auto myDataOne = std::make_unique(); + auto myDataOne = std::make_unique(); - QMap data; + QList< QPair > data; - for (int i = 0; i < 10; i++) - { - data.insert(i, i); - } + for (int i = 0; i < 10; i++) + { + data.append(QPair(i, i)); + } - myDataOne->SetData(data); - myDataOne->SetLabel("DataOne"); - myDataOne->SetChartType("bar"); - myDataOne->SetColor("red"); - myDataOne->SetLineStyle("solid"); + myDataOne->SetData(data); + myDataOne->SetLabel("DataOne"); + myDataOne->SetChartType("bar"); + myDataOne->SetColor("red"); + myDataOne->SetLineStyle("solid"); - return myDataOne; + return myDataOne; } std::unique_ptr mitk::ChartExampleTestHelper::GetDataTwo() { - auto myDataTwo = std::make_unique(); + auto myDataTwo = std::make_unique(); - QMap data; + QList< QPair > data; - for (int i = 10; i < 20; i++) - { - data.insert(i, i); - } + for (int i = 10; i < 20; i++) + { + data.append(QPair(i, i)); + } - myDataTwo->SetData(data); - myDataTwo->SetLabel("DataTwo"); - myDataTwo->SetChartType("bar"); - myDataTwo->SetColor("green"); - myDataTwo->SetLineStyle("solid"); + myDataTwo->SetData(data); + myDataTwo->SetLabel("DataTwo"); + myDataTwo->SetChartType("bar"); + myDataTwo->SetColor("green"); + myDataTwo->SetLineStyle("solid"); - return myDataTwo; + return myDataTwo; } std::unique_ptr mitk::ChartExampleTestHelper::GetDataThree() { - auto myDataThree = std::make_unique(); + auto myDataThree = std::make_unique(); - QMap data; + QList< QPair > data; - for (int i = 20; i < 30; i++) - { - data.insert(i, i); - } + for (int i = 20; i < 30; i++) + { + data.append(QPair(i, i)); + } - myDataThree->SetData(data); - myDataThree->SetLabel("DataThree"); - myDataThree->SetChartType("bar"); - myDataThree->SetColor("blue"); - myDataThree->SetLineStyle("solid"); + myDataThree->SetData(data); + myDataThree->SetLabel("DataThree"); + myDataThree->SetChartType("bar"); + myDataThree->SetColor("blue"); + myDataThree->SetLineStyle("solid"); - return myDataThree; + return myDataThree; } std::unique_ptr mitk::ChartExampleTestHelper::GetDataFour() { - auto myDataFour = std::make_unique(); + auto myDataFour = std::make_unique(); - QMap data; + QList< QPair > data; - for (int i = 30; i < 40; i++) - { - data.insert(i, i); - } + for (int i = 30; i < 40; i++) + { + data.append(QPair(i, i)); + } - myDataFour->SetData(data); - myDataFour->SetLabel("DataFour"); - myDataFour->SetChartType("bar"); - myDataFour->SetColor("yellow"); - myDataFour->SetLineStyle("solid"); + myDataFour->SetData(data); + myDataFour->SetLabel("DataFour"); + myDataFour->SetChartType("bar"); + myDataFour->SetColor("yellow"); + myDataFour->SetLineStyle("solid"); - return myDataFour; + return myDataFour; } std::unique_ptr mitk::ChartExampleTestHelper::GetDataFive() { - auto myDataFive = std::make_unique(); + auto myDataFive = std::make_unique(); - QMap data; + QList< QPair > data; - for (int i = 40; i < 50; i++) - { - data.insert(i, i); - } + for (int i = 40; i < 50; i++) + { + data.append(QPair(i, i)); + } - myDataFive->SetData(data); - myDataFive->SetLabel("DataFive"); - myDataFive->SetChartType("bar"); - myDataFive->SetColor("black"); - myDataFive->SetLineStyle("solid"); + myDataFive->SetData(data); + myDataFive->SetLabel("DataFive"); + myDataFive->SetChartType("bar"); + myDataFive->SetColor("black"); + myDataFive->SetLineStyle("solid"); - return myDataFive; + return myDataFive; } QmitkChartWidget::ChartType mitk::ChartExampleTestHelper::ReturnChartTypeByString(std::string chartTypeString) { - if (chartTypeString == "bar") - { - return QmitkChartWidget::ChartType::bar; - } - - if (chartTypeString == "line") - { - return QmitkChartWidget::ChartType::line; - } - - if (chartTypeString == "spline") - { - return QmitkChartWidget::ChartType::spline; - } - - if (chartTypeString == "pie") - { - return QmitkChartWidget::ChartType::pie; - } - - if (chartTypeString == "area") - { - return QmitkChartWidget::ChartType::area; - } - - if (chartTypeString == "area_spline") - { - return QmitkChartWidget::ChartType::area_spline; - } - - if (chartTypeString == "scatter") - { - return QmitkChartWidget::ChartType::scatter; - } - + if (chartTypeString == "bar") + { return QmitkChartWidget::ChartType::bar; + } + + if (chartTypeString == "line") + { + return QmitkChartWidget::ChartType::line; + } + + if (chartTypeString == "spline") + { + return QmitkChartWidget::ChartType::spline; + } + + if (chartTypeString == "pie") + { + return QmitkChartWidget::ChartType::pie; + } + + if (chartTypeString == "area") + { + return QmitkChartWidget::ChartType::area; + } + + if (chartTypeString == "area_spline") + { + return QmitkChartWidget::ChartType::area_spline; + } + + if (chartTypeString == "scatter") + { + return QmitkChartWidget::ChartType::scatter; + } + + return QmitkChartWidget::ChartType::bar; } QmitkChartWidget::ChartColor mitk::ChartExampleTestHelper::ReturnChartColorByString(std::string chartColorString) { - if (chartColorString == "red") - { - return QmitkChartWidget::ChartColor::red; - } - - if (chartColorString == "orange") - { - return QmitkChartWidget::ChartColor::orange; - } - - if (chartColorString == "yellow") - { - return QmitkChartWidget::ChartColor::yellow; - } - - if (chartColorString == "green") - { - return QmitkChartWidget::ChartColor::green; - } - - if (chartColorString == "blue") - { - return QmitkChartWidget::ChartColor::blue; - } - - if (chartColorString == "purple") - { - return QmitkChartWidget::ChartColor::purple; - } - - if (chartColorString == "brown") - { - return QmitkChartWidget::ChartColor::brown; - } - - if (chartColorString == "magenta") - { - return QmitkChartWidget::ChartColor::magenta; - } - - if (chartColorString == "tan") - { - return QmitkChartWidget::ChartColor::tan; - } - - if (chartColorString == "cyan") - { - return QmitkChartWidget::ChartColor::cyan; - } - - if (chartColorString == "olive") - { - return QmitkChartWidget::ChartColor::olive; - } - - if (chartColorString == "maroon") - { - return QmitkChartWidget::ChartColor::maroon; - } - - if (chartColorString == "navy") - { - return QmitkChartWidget::ChartColor::navy; - } - - if (chartColorString == "aquamarine") - { - return QmitkChartWidget::ChartColor::aquamarine; - } - - if (chartColorString == "turqouise") - { - return QmitkChartWidget::ChartColor::turqouise; - } - - if (chartColorString == "silver") - { - return QmitkChartWidget::ChartColor::silver; - } - - if (chartColorString == "lime") - { - return QmitkChartWidget::ChartColor::lime; - } - - if (chartColorString == "teal") - { - return QmitkChartWidget::ChartColor::teal; - } - - if (chartColorString == "indigo") - { - return QmitkChartWidget::ChartColor::indigo; - } - - if (chartColorString == "violet") - { - return QmitkChartWidget::ChartColor::violet; - } - - if (chartColorString == "pink") - { - return QmitkChartWidget::ChartColor::pink; - } - - if (chartColorString == "black") - { - return QmitkChartWidget::ChartColor::black; - } - - if (chartColorString == "white") - { - return QmitkChartWidget::ChartColor::white; - } - - if (chartColorString == "grey") - { - return QmitkChartWidget::ChartColor::grey; - } - + if (chartColorString == "red") + { return QmitkChartWidget::ChartColor::red; + } + + if (chartColorString == "orange") + { + return QmitkChartWidget::ChartColor::orange; + } + + if (chartColorString == "yellow") + { + return QmitkChartWidget::ChartColor::yellow; + } + + if (chartColorString == "green") + { + return QmitkChartWidget::ChartColor::green; + } + + if (chartColorString == "blue") + { + return QmitkChartWidget::ChartColor::blue; + } + + if (chartColorString == "purple") + { + return QmitkChartWidget::ChartColor::purple; + } + + if (chartColorString == "brown") + { + return QmitkChartWidget::ChartColor::brown; + } + + if (chartColorString == "magenta") + { + return QmitkChartWidget::ChartColor::magenta; + } + + if (chartColorString == "tan") + { + return QmitkChartWidget::ChartColor::tan; + } + + if (chartColorString == "cyan") + { + return QmitkChartWidget::ChartColor::cyan; + } + + if (chartColorString == "olive") + { + return QmitkChartWidget::ChartColor::olive; + } + + if (chartColorString == "maroon") + { + return QmitkChartWidget::ChartColor::maroon; + } + + if (chartColorString == "navy") + { + return QmitkChartWidget::ChartColor::navy; + } + + if (chartColorString == "aquamarine") + { + return QmitkChartWidget::ChartColor::aquamarine; + } + + if (chartColorString == "turqouise") + { + return QmitkChartWidget::ChartColor::turqouise; + } + + if (chartColorString == "silver") + { + return QmitkChartWidget::ChartColor::silver; + } + + if (chartColorString == "lime") + { + return QmitkChartWidget::ChartColor::lime; + } + + if (chartColorString == "teal") + { + return QmitkChartWidget::ChartColor::teal; + } + + if (chartColorString == "indigo") + { + return QmitkChartWidget::ChartColor::indigo; + } + + if (chartColorString == "violet") + { + return QmitkChartWidget::ChartColor::violet; + } + + if (chartColorString == "pink") + { + return QmitkChartWidget::ChartColor::pink; + } + + if (chartColorString == "black") + { + return QmitkChartWidget::ChartColor::black; + } + + if (chartColorString == "white") + { + return QmitkChartWidget::ChartColor::white; + } + + if (chartColorString == "grey") + { + return QmitkChartWidget::ChartColor::grey; + } + + return QmitkChartWidget::ChartColor::red; } QmitkChartWidget::LineStyle mitk::ChartExampleTestHelper::ReturnChartStyleByString(std::string chartStyleString) { - if (chartStyleString == "solid") - { - return QmitkChartWidget::LineStyle::solid; - } + if (chartStyleString == "solid") + { + return QmitkChartWidget::LineStyle::solid; + } - if (chartStyleString == "dashed") - { - return QmitkChartWidget::LineStyle::dashed; - } + if (chartStyleString == "dashed") + { + return QmitkChartWidget::LineStyle::dashed; + } - return QmitkChartWidget::LineStyle::solid; + return QmitkChartWidget::LineStyle::solid; } void mitk::ChartExampleTestHelper::Add(int dataSet) { - std::unique_ptr myData; - if (dataSet == 1) - { - myData = mitk::ChartExampleTestHelper::GetDataOne(); - } - - if (dataSet == 2) - { - myData = mitk::ChartExampleTestHelper::GetDataTwo(); - } - - if (dataSet == 3) - { - myData = mitk::ChartExampleTestHelper::GetDataThree(); - } - - if (dataSet == 4) - { - myData = mitk::ChartExampleTestHelper::GetDataFour(); - } - - if (dataSet == 5) - { - myData = mitk::ChartExampleTestHelper::GetDataFive(); - } - - std::map data = mitk::ChartExampleTestHelper::ToStdMap(myData->GetXData(), myData->GetYData()); - auto label = myData->GetLabel().toString().toStdString(); - auto type = myData->GetChartType().toString().toStdString(); - auto color = myData->GetColor().toString().toStdString(); - auto style = myData->GetLineStyle().toString().toStdString(); - - qmitkChartWidget.AddChartExampleData(data, label, type, color, style); + std::unique_ptr myData; + if (dataSet == 1) + { + myData = mitk::ChartExampleTestHelper::GetDataOne(); + } + + if (dataSet == 2) + { + myData = mitk::ChartExampleTestHelper::GetDataTwo(); + } + + if (dataSet == 3) + { + myData = mitk::ChartExampleTestHelper::GetDataThree(); + } + + if (dataSet == 4) + { + myData = mitk::ChartExampleTestHelper::GetDataFour(); + } + + if (dataSet == 5) + { + myData = mitk::ChartExampleTestHelper::GetDataFive(); + } + + std::vector< std::pair > data = mitk::ChartExampleTestHelper::ToStdPairList(myData->GetXData(), myData->GetYData()); + auto label = myData->GetLabel().toString().toStdString(); + auto type = myData->GetChartType().toString().toStdString(); + auto color = myData->GetColor().toString().toStdString(); + auto style = myData->GetLineStyle().toString().toStdString(); + + qmitkChartWidget.AddChartExampleData(data, label, type, color, style); } -std::map mitk::ChartExampleTestHelper::ToStdMap(QVariantList xData, QVariantList yData) +std::vector< std::pair > mitk::ChartExampleTestHelper::ToStdPairList(QVariantList xData, QVariantList yData) { - auto xDataConverted = xData.toVector().toStdVector(); - auto yDataConverted = yData.toVector().toStdVector(); + auto xDataConverted = xData.toVector().toStdVector(); + auto yDataConverted = yData.toVector().toStdVector(); - std::map data; - for (size_t i = 0; i < xDataConverted.size(); i++) - { - data.insert(std::make_pair(xDataConverted[i].toDouble(), yDataConverted[i].toDouble())); - } + std::vector< std::pair > data; + for (size_t i = 0; i < xDataConverted.size(); i++) + { + data.push_back(std::make_pair(xDataConverted[i].toDouble(), yDataConverted[i].toDouble())); + } - return data; + return data; } void mitk::ChartExampleTestHelper::ClearMemory() { - // Clear the vector - qmitkChartWidget.Clear(); + // Clear the vector + qmitkChartWidget.Clear(); } diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkHistogramVisualizationWidget.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkHistogramVisualizationWidget.cpp index 9afc4b49d0..76034019ba 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkHistogramVisualizationWidget.cpp +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkHistogramVisualizationWidget.cpp @@ -1,193 +1,197 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkHistogramVisualizationWidget.h" #include QmitkHistogramVisualizationWidget::QmitkHistogramVisualizationWidget(QWidget* parent) : QWidget(parent) { m_Controls.setupUi(this); m_Controls.checkBoxShowSubchart->setChecked(false); m_Controls.spinBoxNBins->setValue(m_DefaultNBins); m_Controls.spinBoxNBins->setMinimum(m_MinNBins); m_Controls.spinBoxNBins->setMaximum(m_MaxNBins); SetGUIElementsEnabled(false); CreateConnections(); } void QmitkHistogramVisualizationWidget::SetHistogram(itk::Statistics::Histogram::ConstPointer histogram, const std::string& dataLabel) { if (histogram == nullptr) return; m_Histogram = histogram; - m_Controls.chartWidget->AddData2D(ConvertHistogramToMap(m_Histogram), dataLabel); + m_Controls.chartWidget->AddData2D(ConvertHistogramToPairList(m_Histogram), dataLabel); m_Controls.chartWidget->SetChartType(dataLabel, QmitkChartWidget::ChartType::bar); m_Controls.chartWidget->SetXAxisLabel("Gray value"); m_Controls.chartWidget->SetYAxisLabel("Frequency"); m_Controls.chartWidget->Show(m_Controls.checkBoxShowSubchart->isChecked()); SetGUIElementsEnabled(true); } void QmitkHistogramVisualizationWidget::Reset() { m_Controls.chartWidget->Clear(); SetGUIElementsEnabled(false); } int QmitkHistogramVisualizationWidget::GetBins() { return m_Controls.spinBoxNBins->value(); } void QmitkHistogramVisualizationWidget::ResetDefault() { m_Controls.checkBoxUseDefaultNBins->setChecked(true); m_Controls.spinBoxNBins->setEnabled(false); m_Controls.spinBoxNBins->setValue(100); m_Controls.checkBoxShowSubchart->setChecked(false); } void QmitkHistogramVisualizationWidget::SetTheme(QmitkChartWidget::ColorTheme style) { m_Controls.chartWidget->SetTheme(style); } void QmitkHistogramVisualizationWidget::CreateConnections() { connect(m_Controls.buttonCopyHistogramToClipboard, &QPushButton::clicked, this, &QmitkHistogramVisualizationWidget::OnClipboardButtonClicked); connect(m_Controls.checkBoxUseDefaultNBins, &QCheckBox::clicked, this, &QmitkHistogramVisualizationWidget::OnDefaultNBinsCheckBoxChanged); connect(m_Controls.spinBoxNBins, &QSpinBox::editingFinished, this, &QmitkHistogramVisualizationWidget::OnNBinsSpinBoxValueChanged); connect(m_Controls.checkBoxShowSubchart, &QCheckBox::clicked, this, &QmitkHistogramVisualizationWidget::OnShowSubchartCheckBoxChanged); connect(m_Controls.checkBoxViewMinMax, &QCheckBox::clicked, this, &QmitkHistogramVisualizationWidget::OnViewMinMaxCheckBoxChanged); connect(m_Controls.doubleSpinBoxMaxValue, &QSpinBox::editingFinished, this, &QmitkHistogramVisualizationWidget::OnMaxValueSpinBoxValueChanged); connect(m_Controls.doubleSpinBoxMinValue, &QSpinBox::editingFinished, this, &QmitkHistogramVisualizationWidget::OnMinValueSpinBoxValueChanged); } void QmitkHistogramVisualizationWidget::SetGUIElementsEnabled(bool enabled) { this->setEnabled(enabled); m_Controls.tabWidgetPlot->setEnabled(enabled); m_Controls.checkBoxShowSubchart->setEnabled(enabled); m_Controls.checkBoxUseDefaultNBins->setEnabled(enabled); m_Controls.spinBoxNBins->setEnabled(!m_Controls.checkBoxUseDefaultNBins->isChecked()); m_Controls.buttonCopyHistogramToClipboard->setEnabled(enabled); m_Controls.checkBoxViewMinMax->setEnabled(enabled); m_Controls.doubleSpinBoxMaxValue->setEnabled(m_Controls.checkBoxViewMinMax->isChecked()); m_Controls.doubleSpinBoxMinValue->setEnabled(m_Controls.checkBoxViewMinMax->isChecked()); } -std::map QmitkHistogramVisualizationWidget::ConvertHistogramToMap(itk::Statistics::Histogram::ConstPointer histogram) const +std::vector< std::pair > QmitkHistogramVisualizationWidget::ConvertHistogramToPairList(itk::Statistics::Histogram::ConstPointer histogram) const { - std::map histogramMap; + std::map histogramMap; if (histogram) { auto endIt = histogram->End(); auto it = histogram->Begin(); // generating Lists of measurement and frequencies for (; it != endIt; ++it) { double frequency = it.GetFrequency(); double measurement = it.GetMeasurementVector()[0]; histogramMap.emplace(measurement, frequency); } } - return histogramMap; + std::vector< std::pair > histogram_list; + for(auto iter = histogramMap.begin(); iter != histogramMap.end(); ++iter) + histogram_list.push_back( std::pair(iter->first, iter->second) ); + + return histogram_list; } void QmitkHistogramVisualizationWidget::OnClipboardButtonClicked() { if (m_Histogram) { QApplication::clipboard()->clear(); QString clipboard("Measurement \t Frequency\n"); auto iter = m_Histogram->Begin(); auto iterEnd = m_Histogram->End(); for (; iter != iterEnd; ++iter) { clipboard = clipboard.append("%L1 \t %L2\n") .arg(iter.GetMeasurementVector()[0], 0, 'f', 2) .arg(iter.GetFrequency()); } QApplication::clipboard()->setText(clipboard, QClipboard::Clipboard); } } void QmitkHistogramVisualizationWidget::OnDefaultNBinsCheckBoxChanged() { if (m_Controls.checkBoxUseDefaultNBins->isChecked()) { m_Controls.spinBoxNBins->setEnabled(false); if (m_Controls.spinBoxNBins->value() != static_cast(m_DefaultNBins) ) { m_Controls.spinBoxNBins->setValue(m_DefaultNBins); OnNBinsSpinBoxValueChanged(); } } else { m_Controls.spinBoxNBins->setEnabled(true); } } void QmitkHistogramVisualizationWidget::OnNBinsSpinBoxValueChanged() { emit RequestHistogramUpdate(m_Controls.spinBoxNBins->value()); } void QmitkHistogramVisualizationWidget::OnShowSubchartCheckBoxChanged() { m_Controls.chartWidget->Show(m_Controls.checkBoxShowSubchart->isChecked()); } void QmitkHistogramVisualizationWidget::OnViewMinMaxCheckBoxChanged() { double min = m_Histogram->GetBinMin(0, 0); auto maxVector = m_Histogram->GetDimensionMaxs(0); double max; if (m_Controls.checkBoxUseDefaultNBins->isChecked()) max = maxVector[m_DefaultNBins - 1]; else max = maxVector[m_Controls.spinBoxNBins->value() - 1]; if (!m_Controls.checkBoxViewMinMax->isChecked()) { m_Controls.doubleSpinBoxMaxValue->setEnabled(false); m_Controls.doubleSpinBoxMinValue->setEnabled(false); m_Controls.chartWidget->Reload(); } else { m_Controls.doubleSpinBoxMinValue->setMinimum(min); m_Controls.doubleSpinBoxMinValue->setValue(min); m_Controls.doubleSpinBoxMaxValue->setMaximum(max); m_Controls.doubleSpinBoxMaxValue->setValue(max); m_Controls.doubleSpinBoxMaxValue->setEnabled(true); m_Controls.doubleSpinBoxMinValue->setEnabled(true); } } void QmitkHistogramVisualizationWidget::OnMinValueSpinBoxValueChanged() { m_Controls.doubleSpinBoxMaxValue->setMinimum(m_Controls.doubleSpinBoxMinValue->value()+1); m_Controls.chartWidget->SetMinMaxValueXView(m_Controls.doubleSpinBoxMinValue->value(),m_Controls.doubleSpinBoxMaxValue->value()); m_Controls.chartWidget->Show(); } void QmitkHistogramVisualizationWidget::OnMaxValueSpinBoxValueChanged() { m_Controls.doubleSpinBoxMinValue->setMaximum(m_Controls.doubleSpinBoxMaxValue->value()-1); m_Controls.chartWidget->SetMinMaxValueXView(m_Controls.doubleSpinBoxMinValue->value(),m_Controls.doubleSpinBoxMaxValue->value()); m_Controls.chartWidget->Show(); } diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkHistogramVisualizationWidget.h b/Modules/ImageStatisticsUI/Qmitk/QmitkHistogramVisualizationWidget.h index 71633b7524..67f5bbc990 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkHistogramVisualizationWidget.h +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkHistogramVisualizationWidget.h @@ -1,79 +1,79 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkHistogramVisualizationWidget_H__INCLUDED #define QmitkHistogramVisualizationWidget_H__INCLUDED #include #include // itk #include /** * \brief Widget for displaying Histograms. */ class MITKIMAGESTATISTICSUI_EXPORT QmitkHistogramVisualizationWidget : public QWidget { Q_OBJECT public: QmitkHistogramVisualizationWidget(QWidget *parent = nullptr); /** \brief Draws the histogram and enables the GUI elements. */ void SetHistogram(itk::Statistics::Histogram::ConstPointer histogram, const std::string &dataLabel); /** \brief Clears the histogram and disables all GUI elements. */ void Reset(); /** \brief Sets the theme (either dark or light) */ void SetTheme(QmitkChartWidget::ColorTheme style); /** \brief Resets the default settings */ void ResetDefault(); /** \brief Gets the number of bins to calculate */ int GetBins(); signals: /** \brief Signal to be emitted when the number of bins is changed by the user. The HistogramCalculator should connect to this signal and recalculate the data accordingly. */ void RequestHistogramUpdate(unsigned int nBins); private: void CreateConnections(); void SetGUIElementsEnabled(bool enabled); /** \brief Helper function to convert the histogram in order to forward it to the ChartWidget. */ - std::map ConvertHistogramToMap(itk::Statistics::Histogram::ConstPointer histogram) const; + std::vector > ConvertHistogramToPairList(itk::Statistics::Histogram::ConstPointer histogram) const; //slots /** \brief Saves the histogram to the clipboard. */ void OnClipboardButtonClicked(); /** \brief Enables / Disables SpinBox to change the number of bins. */ void OnDefaultNBinsCheckBoxChanged(); /** \brief Emits the signal RequestHistogramUpdate(unsigned int nBins) with the updated value. */ void OnNBinsSpinBoxValueChanged(); /** \brief Shows / Hides the subchart. */ void OnShowSubchartCheckBoxChanged(); /** \brief Enables / Disables SpinBoxes to set custom min and max values */ void OnViewMinMaxCheckBoxChanged(); /**\brief */ void OnMaxValueSpinBoxValueChanged(); /** \brief */ void OnMinValueSpinBoxValueChanged(); private: Ui::QmitkHistogramVisualizationControls m_Controls; const unsigned int m_DefaultNBins = 100; const unsigned int m_MinNBins = 10; const unsigned int m_MaxNBins = 10000; itk::Statistics::Histogram::ConstPointer m_Histogram; }; #endif // QmitkHistogramVisualizationWidget_H__INCLUDED