diff --git a/Modules/Chart/CMakeLists.txt b/Modules/Chart/CMakeLists.txt index 102806e36d..3c3a31d467 100644 --- a/Modules/Chart/CMakeLists.txt +++ b/Modules/Chart/CMakeLists.txt @@ -1,4 +1,8 @@ MITK_CREATE_MODULE( DEPENDS MitkCore - PACKAGE_DEPENDS PRIVATE Qt5|WebEngineWidgets + PACKAGE_DEPENDS PUBLIC Qt5|WebEngineWidgets ) + +if(BUILD_TESTING) + ADD_SUBDIRECTORY(Test) +endif(BUILD_TESTING) \ No newline at end of file diff --git a/Modules/Chart/Test/CMakeLists.txt b/Modules/Chart/Test/CMakeLists.txt new file mode 100644 index 0000000000..1bb8b54172 --- /dev/null +++ b/Modules/Chart/Test/CMakeLists.txt @@ -0,0 +1,4 @@ +MITK_CREATE_MODULE_TESTS( + DEPENDS MitkCore MitkChart + PACKAGE_DEPENDS PUBLIC Qt5|WebEngineWidgets +) \ No newline at end of file diff --git a/Modules/Chart/Test/files.cmake b/Modules/Chart/Test/files.cmake new file mode 100644 index 0000000000..1724bbd59b --- /dev/null +++ b/Modules/Chart/Test/files.cmake @@ -0,0 +1,3 @@ +set(MODULE_TESTS + mitkChartExampleTest.cpp +) diff --git a/Modules/Chart/Test/mitkChartExampleTest.cpp b/Modules/Chart/Test/mitkChartExampleTest.cpp new file mode 100644 index 0000000000..f1a5e99972 --- /dev/null +++ b/Modules/Chart/Test/mitkChartExampleTest.cpp @@ -0,0 +1,195 @@ +/*=================================================================== +The Medical Imaging Interaction Toolkit (MITK) +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. +See LICENSE.txt or http://www.mitk.org for details. +===================================================================*/ + +// qt +#include + +// mitk chart +#include + +// mitk core +#include +#include +#include +#include + +// std includes +#include + +class mitkChartExampleTestSuite : public mitk::TestFixture +{ + QApplication a(); + CPPUNIT_TEST_SUITE(mitkChartExampleTestSuite); + MITK_TEST(AddingDataTest); + MITK_TEST(CheckingDataTest); + MITK_TEST(ClearingDataTest); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::ChartExampleTestHelper* helper; + +public: + + void setUp() override + { + helper = new mitk::ChartExampleTestHelper; + } + + void tearDown() override + { + delete helper; + } + + void AddingDataTest() + { + MITK_INFO << "=== AddingDataTest start ==="; + AddNewData(); + CheckData(); + ClearData(); + MITK_INFO << "=== AddingDataTest end ==="; + } + + void CheckingDataTest() + { + MITK_INFO << "=== CheckingDataTest start ==="; + CheckData(); + MITK_INFO << "=== CheckingDataTest end ==="; + } + + void ClearingDataTest() + { + MITK_INFO << "=== ClearingDataTest start ==="; + ClearData(); + MITK_INFO << "=== ClearingDataTest end ==="; + } + + + void AddNewData() + { + MITK_INFO << "=== AddNewData"; + + // Adding data + //size_t size; + for (size_t i = 1; i < 6; i++) + { + //helper.Add(i); + //size = helper.qmitkChartWidget.ReturnSizeOfMemory(); + //CPPUNIT_ASSERT_MESSAGE("Data storage does not contain the right amount of items!", size == i); + } + } + + void CheckData() + { + auto myDataOne = helper->GetDataOne(); + + auto xDataOne = myDataOne->GetXData(); + auto yDataOne = myDataOne->GetYData(); + auto labelOne = myDataOne->GetLabel(); + auto typeOne = myDataOne->GetChartType(); + auto colorOne = myDataOne->GetColor(); + auto styleOne = myDataOne->GetLineStyle(); + + auto dataToCheckOne = helper->qmitkChartWidget.GetDataElementByLabel(labelOne.toString().toStdString()); + + CPPUNIT_ASSERT_MESSAGE("Dataset one was not saved correctly", dataToCheckOne->GetXData() == xDataOne && + dataToCheckOne->GetYData() == yDataOne && + dataToCheckOne->GetLabel() == labelOne && + dataToCheckOne->GetChartType() == typeOne && + dataToCheckOne->GetColor() == colorOne && + dataToCheckOne->GetLineStyle() == styleOne); + + auto myDataTwo = helper->GetDataTwo(); + + auto xDataTwo = myDataTwo->GetXData(); + auto yDataTwo = myDataTwo->GetYData(); + auto labelTwo = myDataTwo->GetLabel(); + auto typeTwo = myDataTwo->GetChartType(); + auto colorTwo = myDataTwo->GetColor(); + auto styleTwo = myDataTwo->GetLineStyle(); + + auto dataToCheckTwo = helper->qmitkChartWidget.GetDataElementByLabel(labelTwo.toString().toStdString()); + + CPPUNIT_ASSERT_MESSAGE("Dataset two was not saved correctly", dataToCheckTwo->GetXData() == xDataTwo && + dataToCheckTwo->GetYData() == yDataTwo && + dataToCheckTwo->GetLabel() == labelTwo && + dataToCheckTwo->GetChartType() == typeTwo && + dataToCheckTwo->GetColor() == colorTwo && + dataToCheckTwo->GetLineStyle() == styleTwo); + + auto myDataThree = helper->GetDataThree(); + + auto xDataThree = myDataThree->GetXData(); + auto yDataThree = myDataThree->GetYData(); + auto labelThree = myDataThree->GetLabel(); + auto typeThree = myDataThree->GetChartType(); + auto colorThree = myDataThree->GetColor(); + auto styleThree = myDataThree->GetLineStyle(); + + auto dataToCheckThree = helper->qmitkChartWidget.GetDataElementByLabel(labelThree.toString().toStdString()); + + CPPUNIT_ASSERT_MESSAGE("Dataset three was not saved correctly", dataToCheckThree->GetXData() == xDataThree && + dataToCheckThree->GetYData() == yDataThree && + dataToCheckThree->GetLabel() == labelThree && + dataToCheckThree->GetChartType() == typeThree && + dataToCheckThree->GetColor() == colorThree && + dataToCheckThree->GetLineStyle() == styleThree); + + auto myDataFour = helper->GetDataFour(); + + auto xDataFour = myDataFour->GetXData(); + auto yDataFour = myDataFour->GetYData(); + auto labelFour = myDataFour->GetLabel(); + auto typeFour = myDataFour->GetChartType(); + auto colorFour = myDataFour->GetColor(); + auto styleFour = myDataFour->GetLineStyle(); + + auto dataToCheckFour = helper->qmitkChartWidget.GetDataElementByLabel(labelFour.toString().toStdString()); + + CPPUNIT_ASSERT_MESSAGE("Dataset one was not saved correctly", dataToCheckFour->GetXData() == xDataFour && + dataToCheckFour->GetYData() == yDataFour && + dataToCheckFour->GetLabel() == labelFour && + dataToCheckFour->GetChartType() == typeFour && + dataToCheckFour->GetColor() == colorFour && + dataToCheckFour->GetLineStyle() == styleFour); + + auto myDataFive = helper->GetDataFive(); + + auto xDataFive = myDataFive->GetXData(); + auto yDataFive = myDataFive->GetYData(); + auto labelFive = myDataFive->GetLabel(); + auto typeFive = myDataFive->GetChartType(); + auto colorFive = myDataFive->GetColor(); + auto styleFive = myDataFive->GetLineStyle(); + + auto dataToCheckFive = helper->qmitkChartWidget.GetDataElementByLabel(labelFive.toString().toStdString()); + + CPPUNIT_ASSERT_MESSAGE("Dataset one was not saved correctly", dataToCheckFive->GetXData() == xDataFive && + dataToCheckFive->GetYData() == yDataFive && + dataToCheckFive->GetLabel() == labelFive && + dataToCheckFive->GetChartType() == typeFive && + dataToCheckFive->GetColor() == colorFive && + dataToCheckFive->GetLineStyle() == styleFive); + } + + void ClearData() + { + MITK_INFO << "=== ClearData"; + + // Claering data + mitk::ChartExampleTestHelper helper; + helper.qmitkChartWidget.Clear(true); + //int size = helper.qmitkChartWidget.ReturnSizeOfMemory(); + //CPPUNIT_ASSERT_MESSAGE("Data storage was not cleared completly!", size == 0); + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkChartExample) diff --git a/Modules/Chart/files.cmake b/Modules/Chart/files.cmake index 939382e5b0..1257ac3022 100644 --- a/Modules/Chart/files.cmake +++ b/Modules/Chart/files.cmake @@ -1,21 +1,23 @@ set(CPP_FILES QmitkChartWidget.cpp QmitkChartData.cpp QmitkChartxyData.cpp + mitkChartExampleTestHelper.cpp ) set(H_FILES include/QmitkChartWidget.h include/QmitkChartData.h include/QmitkChartxyData.h + include/mitkChartExampleTestHelper.h ) set(MOC_H_FILES include/QmitkChartWidget.h include/QmitkChartData.h include/QmitkChartxyData.h ) set(QRC_FILES resource/Chart.qrc ) diff --git a/Modules/Chart/include/QmitkChartWidget.h b/Modules/Chart/include/QmitkChartWidget.h index 4da0fc9c19..ed95e789e5 100644 --- a/Modules/Chart/include/QmitkChartWidget.h +++ b/Modules/Chart/include/QmitkChartWidget.h @@ -1,291 +1,337 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #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 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); /*! * \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, + 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, const std::string &label, ChartType chartType = ChartType::bar); + //Add Function for the ChartExample + void AddChartExampleData(const std::map& 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 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; 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 21c0322e78..ee19a2810b 100644 --- a/Modules/Chart/include/QmitkChartxyData.h +++ b/Modules/Chart/include/QmitkChartxyData.h @@ -1,163 +1,165 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #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); public: explicit QmitkChartxyData(const QMap &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); 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 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); 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 = "solid"; + QVariant m_Color; + QVariant m_LineStyleName; }; #endif // QmitkC3xyData_h diff --git a/Modules/Chart/include/mitkChartExampleTestHelper.h b/Modules/Chart/include/mitkChartExampleTestHelper.h new file mode 100644 index 0000000000..faee3b5057 --- /dev/null +++ b/Modules/Chart/include/mitkChartExampleTestHelper.h @@ -0,0 +1,69 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#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); + void ClearMemory(); + + }; // end ChartExampleTestHelper +} // end mitk + +#endif diff --git a/Modules/Chart/src/QmitkChartWidget.cpp b/Modules/Chart/src/QmitkChartWidget.cpp index d5accfaacc..ef0c6ec19d 100644 --- a/Modules/Chart/src/QmitkChartWidget.cpp +++ b/Modules/Chart/src/QmitkChartWidget.cpp @@ -1,753 +1,919 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include "mitkExceptionMacro.h" #include #include class CustomPage : public QWebEnginePage { public: CustomPage(QObject *parent = nullptr) : QWebEnginePage(parent) {} - void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel /*level*/, + 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, const std::string &label, QmitkChartWidget::ChartType chartType); + + void AddChartExampleData(const std::map& 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, + 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 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; private: using ChartxyDataVector = std::vector>; std::string GetUniqueLabelName(const QList &labelList, const std::string &label) const; - QmitkChartxyData *GetDataElementByLabel(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_AxisScaleToName; }; -std::string QmitkChartWidget::Impl::GetThemeName() const -{ - return m_C3Data.GetThemeName().toString().toStdString(); -} - 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_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(); +} + 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::AddData1D(const std::vector &data1D, const std::string &label, QmitkChartWidget::ChartType type) { std::map transformedData2D; unsigned int count = 0; // transform the 1D data to 2D data for (const auto &ele : data1D) { transformedData2D[count] = ele; count++; } AddData2D(transformedData2D, label, type); } void QmitkChartWidget::Impl::AddData2D(const std::map &data2D, const std::string &label, QmitkChartWidget::ChartType type) { QMap data2DConverted; for (const auto &aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } const std::string chartTypeName(m_ChartTypeToName.at(type)); auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, label); if (type == ChartType::scatter) { SetShowDataPoints(true); MITK_INFO << "Enabling data points for all because of scatter plot"; } 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, + 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); + } + + 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)); + + chartData->SetColor(QVariant(QString::fromStdString(color))); + chartData->SetLineStyle(QVariant(QString::fromStdString(lineStyle))); + + 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()); + } + } + + 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; unsigned int count = 0; // transform the 1D data to 2D data for (const auto &ele : data1D) { transformedData2D[count] = ele; count++; } UpdateData2D(transformedData2D, label); } void QmitkChartWidget::Impl::UpdateData2D(const std::map &data2D, const std::string &label) { auto element = GetDataElementByLabel(label); if (element) { QMap data2DConverted; for (const auto &aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } element->SetData(data2DConverted); } } +void QmitkChartWidget::Impl::UpdateChartExampleData(const std::map& data2D, + const std::string& label, + const std::string& type, + const std::string& color, + const std::string& lineStyle, + const std::string& pieLabelsData) +{ + UpdateData2D(data2D, label); + + auto element = GetDataElementByLabel(label); + if (element) + { + element->SetChartType(QString::fromStdString(type)); + element->SetColor(QString::fromStdString(color)); + element->SetLineStyle(QString::fromStdString(lineStyle)); + + 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()); + } + } + + 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::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(); } } MITK_WARN << "label " << label << " not found in QmitkChartWidget"; 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::AddData2D(const std::map &data2D, const std::string &label, ChartType type) -{ - m_Impl->AddData2D(data2D, label, type); -} - 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::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) +{ + m_Impl->AddData2D(data2D, label, type); +} + +void QmitkChartWidget::AddChartExampleData(const std::map& 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); +} + 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) { m_Impl->UpdateData2D(data2D, label); } +void QmitkChartWidget::UpdateChartExampleData(const std::map& 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); +} + 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(); } diff --git a/Modules/Chart/src/mitkChartExampleTestHelper.cpp b/Modules/Chart/src/mitkChartExampleTestHelper.cpp new file mode 100644 index 0000000000..281188c0b1 --- /dev/null +++ b/Modules/Chart/src/mitkChartExampleTestHelper.cpp @@ -0,0 +1,357 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkChartExampleTestHelper.h" + +// std includes +#include + +std::unique_ptr mitk::ChartExampleTestHelper::GetDataOne() +{ + auto myDataOne = std::make_unique(); + + QMap data; + + for (int i = 0; i < 10; i++) + { + data.insert(i, i); + } + + myDataOne->SetData(data); + myDataOne->SetLabel("DataOne"); + myDataOne->SetChartType("bar"); + myDataOne->SetColor("red"); + myDataOne->SetLineStyle("solid"); + + return std::move(myDataOne); +} + +std::unique_ptr mitk::ChartExampleTestHelper::GetDataTwo() +{ + auto myDataTwo = std::make_unique(); + + QMap data; + + for (int i = 10; i < 20; i++) + { + data.insert(i, i); + } + + myDataTwo->SetData(data); + myDataTwo->SetLabel("DataTwo"); + myDataTwo->SetChartType("bar"); + myDataTwo->SetColor("green"); + myDataTwo->SetLineStyle("solid"); + + return std::move(myDataTwo); +} + +std::unique_ptr mitk::ChartExampleTestHelper::GetDataThree() +{ + auto myDataThree = std::make_unique(); + + QMap data; + + for (int i = 20; i < 30; i++) + { + data.insert(i, i); + } + + myDataThree->SetData(data); + myDataThree->SetLabel("DataThree"); + myDataThree->SetChartType("bar"); + myDataThree->SetColor("blue"); + myDataThree->SetLineStyle("solid"); + + return std::move(myDataThree); +} + +std::unique_ptr mitk::ChartExampleTestHelper::GetDataFour() +{ + auto myDataFour = std::make_unique(); + + QMap data; + + for (int i = 30; i < 40; i++) + { + data.insert(i, i); + } + + myDataFour->SetData(data); + myDataFour->SetLabel("DataFour"); + myDataFour->SetChartType("bar"); + myDataFour->SetColor("yellow"); + myDataFour->SetLineStyle("solid"); + + return std::move(myDataFour); +} + +std::unique_ptr mitk::ChartExampleTestHelper::GetDataFive() +{ + auto myDataFive = std::make_unique(); + + QMap data; + + for (int i = 40; i < 50; i++) + { + data.insert(i, i); + } + + myDataFive->SetData(data); + myDataFive->SetLabel("DataFive"); + myDataFive->SetChartType("bar"); + myDataFive->SetColor("black"); + myDataFive->SetLineStyle("solid"); + + return std::move(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; + } + + 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; + } + + return QmitkChartWidget::ChartColor::red; +} + +QmitkChartWidget::LineStyle mitk::ChartExampleTestHelper::ReturnChartStyleByString(std::string chartStyleString) +{ + if (chartStyleString == "solid") + { + return QmitkChartWidget::LineStyle::solid; + } + + if (chartStyleString == "dashed") + { + return QmitkChartWidget::LineStyle::dashed; + } + + 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::map mitk::ChartExampleTestHelper::ToStdMap(QVariantList xData, QVariantList yData) +{ + auto xDataConverted = xData.toVector().toStdVector(); + auto yDataConverted = yData.toVector().toStdVector(); + + std::map data; + for (int i = 0; i < xDataConverted.size(); i++) + { + data.insert_or_assign(xDataConverted[i].toDouble(), yDataConverted[i].toDouble()); + } + + return data; +} + +void mitk::ChartExampleTestHelper::ClearMemory() +{ + // Clear the vector + qmitkChartWidget.Clear(); +} diff --git a/Plugins/org.mitk.gui.qt.chartExample/CMakeLists.txt b/Plugins/org.mitk.gui.qt.chartExample/CMakeLists.txt index 0dca18627d..99ed16a323 100644 --- a/Plugins/org.mitk.gui.qt.chartExample/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.chartExample/CMakeLists.txt @@ -1,7 +1,7 @@ project(org_mitk_gui_qt_chartExample) mitk_create_plugin( EXPORT_DIRECTIVE CHARTEXAMPLE_EXPORT EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDS MitkQtWidgetsExt MitkChart + MODULE_DEPENDS MitkChart ) diff --git a/Plugins/org.mitk.gui.qt.chartExample/files.cmake b/Plugins/org.mitk.gui.qt.chartExample/files.cmake index b097c50982..7024c3059d 100644 --- a/Plugins/org.mitk.gui.qt.chartExample/files.cmake +++ b/Plugins/org.mitk.gui.qt.chartExample/files.cmake @@ -1,42 +1,30 @@ -set(SRC_CPP_FILES - -) - set(INTERNAL_CPP_FILES org_mitk_gui_qt_chartExample_Activator.cpp - ChartExample.cpp + QmitkChartExampleView.cpp ) set(UI_FILES - src/internal/ChartExampleControls.ui + src/internal/QmitkChartExampleViewControls.ui ) set(MOC_H_FILES src/internal/org_mitk_gui_qt_chartExample_Activator.h - src/internal/ChartExample.h + src/internal/QmitkChartExampleView.h ) # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench set(CACHED_RESOURCE_FILES resources/chart.svg plugin.xml ) -# list of Qt .qrc files which contain additional resources -# specific to this plugin -set(QRC_FILES - -) - -set(CPP_FILES ) - foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.chartExample/plugin.xml b/Plugins/org.mitk.gui.qt.chartExample/plugin.xml index ccea1d50e4..53427ffe1b 100644 --- a/Plugins/org.mitk.gui.qt.chartExample/plugin.xml +++ b/Plugins/org.mitk.gui.qt.chartExample/plugin.xml @@ -1,12 +1,12 @@ diff --git a/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExample.cpp b/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExample.cpp deleted file mode 100644 index f93e2e0d44..0000000000 --- a/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExample.cpp +++ /dev/null @@ -1,455 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -// Blueberry -#include -#include - -// Qmitk -#include "ChartExample.h" - -// Qt -#include - -const std::string ChartExample::VIEW_ID = "org.mitk.views.chartexample"; - -void ChartExample::SetFocus() -{ - m_Controls.m_buttonCreateChart->setFocus(); -} - -void ChartExample::CreateQtPartControl(QWidget *parent) -{ - // create GUI widgets from the Qt Designer's .ui file - m_Controls.setupUi(parent); - CreateConnectionsForGUIElements(); - connect(m_Controls.m_comboBoxChartType, &QComboBox::currentTextChanged, this, &ChartExample::AdaptDataGUI); - - m_Controls.m_groupBoxErrors->setVisible(false); - m_Controls.m_groupBoxXErrors->setVisible(false); - m_Controls.m_groupBoxYErrors->setVisible(false); - m_Controls.m_lineEditDataXVector->setVisible(false); - m_Controls.m_lineEditDataXVector->setText("0;1;2;3;4;5;6;7;8;9"); - ResetDataGUI(); - - m_Controls.m_doubleSpinBox_maxZoomX->setValue(10); - m_Controls.m_doubleSpinBox_maxZoomY->setValue(10); - - FillRandomDataValues(); - auto chartStyle = GetColorTheme(); - m_Controls.m_Chart->SetTheme(chartStyle); - - m_Controls.m_lineEditXAxisLabel->setText("xLabel"); - m_Controls.m_lineEditYAxisLabel->setText("yLabel"); - - m_ChartNameToChartType.emplace("bar", QmitkChartWidget::ChartType::bar); - m_ChartNameToChartType.emplace("line", QmitkChartWidget::ChartType::line); - m_ChartNameToChartType.emplace("spline", QmitkChartWidget::ChartType::spline); - m_ChartNameToChartType.emplace("pie", QmitkChartWidget::ChartType::pie); - m_ChartNameToChartType.emplace("area", QmitkChartWidget::ChartType::area); - m_ChartNameToChartType.emplace("area-spline", QmitkChartWidget::ChartType::area_spline); - m_ChartNameToChartType.emplace("scatter", QmitkChartWidget::ChartType::scatter); - - m_LineNameToLineType.emplace("solid", QmitkChartWidget::LineStyle::solid); - m_LineNameToLineType.emplace("dashed", QmitkChartWidget::LineStyle::dashed); - - m_AxisScaleNameToAxisScaleType.emplace("linear", QmitkChartWidget::AxisScale::linear); - m_AxisScaleNameToAxisScaleType.emplace("logarithmic", QmitkChartWidget::AxisScale::log); - - m_LegendPositionNameToLegendPositionType.emplace("bottom middle", QmitkChartWidget::LegendPosition::bottomMiddle); - m_LegendPositionNameToLegendPositionType.emplace("bottom right", QmitkChartWidget::LegendPosition::bottomRight); - m_LegendPositionNameToLegendPositionType.emplace("top right", QmitkChartWidget::LegendPosition::topRight); - m_LegendPositionNameToLegendPositionType.emplace("top left", QmitkChartWidget::LegendPosition::topLeft); - m_LegendPositionNameToLegendPositionType.emplace("middle right", QmitkChartWidget::LegendPosition::middleRight); -} - -void ChartExample::CreateConnectionsForGUIElements() -{ - connect(m_Controls.m_buttonCreateChart, &QPushButton::clicked, this, &ChartExample::CreateChart); - connect(m_Controls.m_buttonUpdateChart, &QPushButton::clicked, this, &ChartExample::UpdateChart); - connect(m_Controls.m_buttonClearChart, &QPushButton::clicked, this, &ChartExample::ClearChart); - connect(m_Controls.m_buttonAddData, &QPushButton::clicked, this, &ChartExample::AddData); - connect(m_Controls.m_checkBoxEnableDataX, &QCheckBox::toggled, this, &ChartExample::ShowXData); - connect(m_Controls.m_checkBoxEnableErrors, &QCheckBox::toggled, this, &ChartExample::ShowErrorOptions); - connect(m_Controls.m_checkBoxEnableXErrors, &QCheckBox::toggled, this, &ChartExample::ShowXErrorOptions); - connect(m_Controls.m_checkBoxEnableYErrors, &QCheckBox::toggled, this, &ChartExample::ShowYErrorOptions); - connect(m_Controls.m_doubleSpinBox_minZoomX, &QSpinBox::editingFinished, this, &ChartExample::AdaptZoomX); - connect(m_Controls.m_doubleSpinBox_maxZoomX, &QSpinBox::editingFinished, this, &ChartExample::AdaptZoomX); - connect(m_Controls.m_doubleSpinBox_minZoomY, &QSpinBox::editingFinished, this, &ChartExample::AdaptZoomY); - connect(m_Controls.m_doubleSpinBox_maxZoomY, &QSpinBox::editingFinished, this, &ChartExample::AdaptZoomY); - connect(m_Controls.m_comboBoxLegendPosition, &QComboBox::currentTextChanged, this, &ChartExample::OnLegendPositionChanged); - connect(m_Controls.m_lineEditTitle, &QLineEdit::editingFinished, this, &ChartExample::OnTitleChanged); - connect(m_Controls.m_lineEditXAxisLabel, &QLineEdit::editingFinished, this, &ChartExample::OnXAxisLabelChanged); - connect(m_Controls.m_lineEditYAxisLabel, &QLineEdit::editingFinished, this, &ChartExample::OnYAxisLabelChanged); - connect( - m_Controls.m_comboBoxYAxisScale, &QComboBox::currentTextChanged, this, &ChartExample::OnYAxisScaleChanged); - connect(m_Controls.m_checkBoxShowLegend, &QCheckBox::stateChanged, this, &ChartExample::OnShowLegendChanged); - connect(m_Controls.m_checkBoxStackedData, &QCheckBox::stateChanged, this, &ChartExample::OnStackedDataChanged); - connect(m_Controls.m_checkBoxShowDataPoints, &QCheckBox::stateChanged, this, &ChartExample::OnShowDataPointsChanged); - connect(m_Controls.m_checkBoxShowSubchart, &QCheckBox::stateChanged, this, &ChartExample::OnShowSubchartChanged); -} - -void ChartExample::FillRandomDataValues() -{ - std::vector numbers = GenerateRandomNumbers(10, 10.0); - std::string text = ConvertToText(numbers); - m_Controls.m_lineEditDataYVector->setText(QString::fromStdString(text)); - - m_Controls.m_lineEditDataLabel->setText("test" + QString::number(countForUID)); - - numbers = GenerateRandomNumbers(10, 10.0); - text = ConvertToText(numbers); - m_Controls.m_lineEditXErrorPlus->setText(QString::fromStdString(text)); - numbers = GenerateRandomNumbers(10, 10.0); - text = ConvertToText(numbers); - m_Controls.m_lineEditXErrorMinus->setText(QString::fromStdString(text)); - numbers = GenerateRandomNumbers(10, 10.0); - text = ConvertToText(numbers); - m_Controls.m_lineEditYErrorPlus->setText(QString::fromStdString(text)); - numbers = GenerateRandomNumbers(10, 10.0); - text = ConvertToText(numbers); - m_Controls.m_lineEditYErrorMinus->setText(QString::fromStdString(text)); - - countForUID++; -} - -void ChartExample::CreateChart() -{ - auto dataYAxisScaleType = - m_AxisScaleNameToAxisScaleType.at(m_Controls.m_comboBoxYAxisScale->currentText().toStdString()); - auto xAxisLabel = m_Controls.m_lineEditXAxisLabel->text().toStdString(); - auto yAxisLabel = m_Controls.m_lineEditYAxisLabel->text().toStdString(); - auto showLegend = m_Controls.m_checkBoxShowLegend->isChecked(); - auto legendPosition = - m_LegendPositionNameToLegendPositionType.at(m_Controls.m_comboBoxLegendPosition->currentText().toStdString()); - auto showDataPoints = m_Controls.m_checkBoxShowDataPoints->isChecked(); - auto stackedData = m_Controls.m_checkBoxStackedData->isChecked(); - auto showSubchart = m_Controls.m_checkBoxShowSubchart->isChecked(); - auto title = m_Controls.m_lineEditTitle->text().toStdString(); - - m_Controls.m_Chart->SetTitle(title); - m_Controls.m_Chart->SetYAxisScale(dataYAxisScaleType); - m_Controls.m_Chart->SetXAxisLabel(xAxisLabel); - m_Controls.m_Chart->SetYAxisLabel(yAxisLabel); - m_Controls.m_Chart->SetShowLegend(showLegend); - m_Controls.m_Chart->SetLegendPosition(legendPosition); - m_Controls.m_Chart->SetShowErrorBars(true); - m_Controls.m_Chart->SetShowDataPoints(showDataPoints); - m_Controls.m_Chart->SetStackedData(stackedData); - m_Controls.m_Chart->Show(showSubchart); -} - -void ChartExample::UpdateChart() { - // Test update mechanism - m_Controls.m_Chart->SetLineStyle("test0", QmitkChartWidget::LineStyle::dashed); - m_Controls.m_Chart->SetChartType("test0", QmitkChartWidget::ChartType::spline); - m_Controls.m_Chart->SetColor("test0", "violet"); - m_Controls.m_Chart->UpdateData2D({{0, 1}, {0.1, 2}, {0.2, 3}, {8, -2} }, "test0"); - m_Controls.m_Chart->UpdateLabel("test0", "newLabel"); -} - -void ChartExample::ClearChart() -{ - m_Controls.m_Chart->Clear(); - m_Controls.m_plainTextEditDataView->clear(); -} - -std::vector ChartExample::ConvertToDoubleVector(const QString &data, QChar delimiter) const -{ - std::vector output; - if (data.isEmpty()) - { - return output; - } - - for (const QString entry : data.split(delimiter)) - { - output.push_back(entry.toDouble()); - } - return output; -} - -std::vector ChartExample::ConvertToStringVector(const QString &data, QChar delimiter) const -{ - std::vector output; - if (data.isEmpty()) - { - return output; - } - - for (const QString entry : data.split(delimiter)) - { - output.push_back(entry.toStdString()); - } - return output; -} - -void ChartExample::AddData() -{ - QString data = m_Controls.m_lineEditDataYVector->text(); - auto dataY = ConvertToDoubleVector(data); - - auto chartType = m_ChartNameToChartType.at(m_Controls.m_comboBoxChartType->currentText().toStdString()); - std::string dataLabel = m_Controls.m_lineEditDataLabel->text().toStdString(); - std::string dataColor = m_Controls.m_lineEditColor->text().toStdString(); - auto dataLineStyleType = m_LineNameToLineType.at(m_Controls.m_comboBoxLineStyle->currentText().toStdString()); - - if (m_Controls.m_checkBoxEnableDataX->isChecked()) - { - QString lineEditDataX = m_Controls.m_lineEditDataXVector->text(); - auto dataX = ConvertToDoubleVector(lineEditDataX); - if (dataX.size() != dataY.size()) - { - mitkThrow() << "data x and y size have to be equal"; - } - auto dataXandY = CreateMap(dataX, dataY); - data = QString::fromStdString(ConvertToText(dataXandY)); - - m_Controls.m_Chart->AddData2D(dataXandY, dataLabel, chartType); - } - else - { - m_Controls.m_Chart->AddData1D(dataY, dataLabel, chartType); - } - if (!dataColor.empty()) - { - m_Controls.m_Chart->SetColor(dataLabel, dataColor); - } - - if (chartType == QmitkChartWidget::ChartType::pie) - { - QString pieLabelsData = m_Controls.m_lineEditPieDataLabel->text(); - if (!pieLabelsData.isEmpty()) - { - auto pieLabels = ConvertToStringVector(pieLabelsData); - m_Controls.m_Chart->SetPieLabels(pieLabels, dataLabel); - } - } - - if (m_Controls.m_checkBoxEnableErrors->isChecked()) - { - if (m_Controls.m_checkBoxEnableXErrors->isChecked()) - { - auto errorsPlus = ConvertToDoubleVector(m_Controls.m_lineEditXErrorPlus->text()); - auto errorsMinus = ConvertToDoubleVector(m_Controls.m_lineEditXErrorMinus->text()); - m_Controls.m_Chart->SetXErrorBars(m_Controls.m_lineEditDataLabel->text().toStdString(), errorsPlus, errorsMinus); - } - if (m_Controls.m_checkBoxEnableYErrors->isChecked()) - { - auto errorsPlus = ConvertToDoubleVector(m_Controls.m_lineEditYErrorPlus->text()); - auto errorsMinus = ConvertToDoubleVector(m_Controls.m_lineEditYErrorMinus->text()); - m_Controls.m_Chart->SetYErrorBars(m_Controls.m_lineEditDataLabel->text().toStdString(), errorsPlus, errorsMinus); - } - } - - m_Controls.m_Chart->SetLineStyle(dataLabel, dataLineStyleType); - - QString dataOverview; - dataOverview.append(m_Controls.m_lineEditDataLabel->text()); - dataOverview.append("(").append(m_Controls.m_comboBoxChartType->currentText()); - if (!dataColor.empty()) - { - dataOverview.append(", ").append(dataColor.c_str()); - } - dataOverview.append(", ").append(m_Controls.m_comboBoxLineStyle->currentText()); - dataOverview.append(")"); - dataOverview.append(":").append(data); - - m_Controls.m_plainTextEditDataView->appendPlainText(dataOverview); - - FillRandomDataValues(); -} - -void ChartExample::ShowXData(bool show) -{ - m_Controls.m_lineEditDataXVector->setVisible(show); -} - -void ChartExample::ShowErrorOptions(bool show) -{ - m_Controls.m_groupBoxErrors->setVisible(show); -} - -void ChartExample::ShowXErrorOptions(bool show) -{ - m_Controls.m_groupBoxXErrors->setVisible(show); -} - -void ChartExample::ShowYErrorOptions(bool show) -{ - m_Controls.m_groupBoxYErrors->setVisible(show); -} - -void ChartExample::AdaptZoomX() -{ - m_Controls.m_Chart->SetMinMaxValueXView(m_Controls.m_doubleSpinBox_minZoomX->value(), - m_Controls.m_doubleSpinBox_maxZoomX->value()); - m_Controls.m_Chart->Show(); -} - -void ChartExample::AdaptZoomY() -{ - m_Controls.m_Chart->SetMinMaxValueYView(m_Controls.m_doubleSpinBox_minZoomY->value(), - m_Controls.m_doubleSpinBox_maxZoomY->value()); - m_Controls.m_Chart->Show(); -} - -void ChartExample::AdaptDataGUI(const QString &chartType) -{ - ResetDataGUI(); - auto chartTypeEnum = m_ChartNameToChartType.at(chartType.toStdString()); - if (chartTypeEnum == QmitkChartWidget::ChartType::pie) - { - m_Controls.m_labelPieData->setVisible(true); - m_Controls.m_lineEditPieDataLabel->setVisible(true); - m_Controls.m_labelColor->setVisible(false); - m_Controls.m_lineEditColor->setVisible(false); - } - else if (chartTypeEnum == QmitkChartWidget::ChartType::line || chartTypeEnum == QmitkChartWidget::ChartType::area || - chartTypeEnum == QmitkChartWidget::ChartType::area_spline || - chartTypeEnum == QmitkChartWidget::ChartType::spline) - { - m_Controls.m_labelLineStyle->setVisible(true); - m_Controls.m_comboBoxLineStyle->setVisible(true); - } -} - -void ChartExample::ResetDataGUI() { - m_Controls.m_labelPieData->setVisible(false); - m_Controls.m_lineEditPieDataLabel->setVisible(false); - m_Controls.m_labelColor->setVisible(true); - m_Controls.m_lineEditColor->setVisible(true); - m_Controls.m_labelLineStyle->setVisible(false); - m_Controls.m_comboBoxLineStyle->setVisible(false); -} - -std::vector ChartExample::GenerateRandomNumbers(unsigned int amount, double max) const -{ - QRandomGenerator gen; - gen.seed(time(nullptr)); - - std::vector data; - for (unsigned int i = 0; i < amount; i++) - { - data.push_back(gen.bounded(max)); - } - - return data; -} - -std::map ChartExample::CreateMap(std::vector keys, std::vector values) const -{ - std::map aMap; - std::transform(keys.begin(), keys.end(), values.begin(), std::inserter(aMap, aMap.end()), [](double a, double b) { - return std::make_pair(a, b); - }); - return aMap; -} - -std::string ChartExample::ConvertToText(std::vector numbers, std::string delimiter) const -{ - std::ostringstream oss; - oss.precision(3); - - if (!numbers.empty()) - { - for (auto number : numbers) - { - oss << number << delimiter; - } - } - auto aString = oss.str(); - aString.pop_back(); - return aString; -} - -std::string ChartExample::ConvertToText(std::map numbers, std::string delimiter) const -{ - std::ostringstream oss; - oss.precision(3); - - if (!numbers.empty()) - { - for (const auto keyValue : numbers) - { - oss << keyValue.first << ":" << keyValue.second << delimiter; - } - } - auto aString = oss.str(); - aString.pop_back(); - return aString; -} - -QmitkChartWidget::ColorTheme ChartExample::GetColorTheme() const -{ - ctkPluginContext *context = berry::WorkbenchPlugin::GetDefault()->GetPluginContext(); - ctkServiceReference styleManagerRef = context->getServiceReference(); - if (styleManagerRef) - { - auto styleManager = context->getService(styleManagerRef); - if (styleManager->GetStyle().name == "Dark") - { - return QmitkChartWidget::ColorTheme::darkstyle; - } - else - { - return QmitkChartWidget::ColorTheme::lightstyle; - } - } - return QmitkChartWidget::ColorTheme::darkstyle; -} - -void ChartExample::OnLegendPositionChanged(const QString &newText) -{ - auto legendPosition = m_LegendPositionNameToLegendPositionType.at(newText.toStdString()); - m_Controls.m_Chart->SetLegendPosition(legendPosition); -} - -void ChartExample::OnTitleChanged() { - auto newTitle = m_Controls.m_lineEditTitle->text(); - m_Controls.m_Chart->SetTitle(newTitle.toStdString()); -} - -void ChartExample::OnXAxisLabelChanged() { - auto newXAxisLabel = m_Controls.m_lineEditXAxisLabel->text(); - m_Controls.m_Chart->SetXAxisLabel(newXAxisLabel.toStdString()); -} - -void ChartExample::OnYAxisLabelChanged() { - auto newYAxisLabel = m_Controls.m_lineEditYAxisLabel->text(); - m_Controls.m_Chart->SetYAxisLabel(newYAxisLabel.toStdString()); -} - -void ChartExample::OnYAxisScaleChanged(const QString &newYAxisScale) { - auto yAxisScale = m_AxisScaleNameToAxisScaleType.at(newYAxisScale.toStdString()); - m_Controls.m_Chart->SetYAxisScale(yAxisScale); -} - -void ChartExample::OnShowLegendChanged(int newState) { - m_Controls.m_Chart->SetShowLegend(newState == Qt::Checked); -} - -void ChartExample::OnStackedDataChanged(int newState) { - m_Controls.m_Chart->SetStackedData(newState == Qt::Checked); -} - -void ChartExample::OnShowDataPointsChanged(int newState) { - m_Controls.m_Chart->SetShowDataPoints(newState == Qt::Checked); -} - -void ChartExample::OnShowSubchartChanged(int newState) { - m_Controls.m_Chart->SetShowSubchart(newState == Qt::Checked); -} diff --git a/Plugins/org.mitk.gui.qt.chartExample/src/internal/QmitkChartExampleView.cpp b/Plugins/org.mitk.gui.qt.chartExample/src/internal/QmitkChartExampleView.cpp new file mode 100644 index 0000000000..7b8d8d66cb --- /dev/null +++ b/Plugins/org.mitk.gui.qt.chartExample/src/internal/QmitkChartExampleView.cpp @@ -0,0 +1,456 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// Blueberry +#include +#include + +// Qmitk +#include "QmitkChartExampleView.h" +#include + +const std::string QmitkChartExampleView::VIEW_ID = "org.mitk.views.qmitkchartexample"; + +void QmitkChartExampleView::SetFocus() +{ + m_Controls.m_buttonCreateChart->setFocus(); +} + +void QmitkChartExampleView::CreateQtPartControl(QWidget *parent) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi(parent); + CreateConnectionsForGUIElements(); + connect(m_Controls.m_comboBoxChartType, &QComboBox::currentTextChanged, this, &QmitkChartExampleView::AdaptDataGUI); + + m_Controls.m_lineEditDataXVector->setText("0;1;2;3;4;5;6;7;8;9"); + m_Controls.m_lineEditDataYVector->setText("0;1;2;3;4;5;6;7;8;9"); + m_Controls.m_lineEditDataLabel->setText("Test"); + m_Controls.m_lineEditXAxisLabel->setText("X-Axis"); + m_Controls.m_lineEditYAxisLabel->setText("Y-Axis"); + m_Controls.m_lineEditTitle->setText("Title"); + + m_Controls.m_labelPieData->setVisible(false); + m_Controls.m_lineEditPieDataLabel->setVisible(false); + + m_Controls.m_groupBoxErrors->setVisible(false); + m_Controls.m_groupBoxXErrors->setVisible(false); + m_Controls.m_groupBoxYErrors->setVisible(false); + + m_Controls.m_doubleSpinBox_maxZoomX->setValue(10); + m_Controls.m_doubleSpinBox_maxZoomY->setValue(10); + + m_AxisScaleNameToAxisScaleType.emplace("linear", QmitkChartWidget::AxisScale::linear); + m_AxisScaleNameToAxisScaleType.emplace("logarithmic", QmitkChartWidget::AxisScale::log); + + m_LegendPositionNameToLegendPositionType.emplace("bottom middle", QmitkChartWidget::LegendPosition::bottomMiddle); + m_LegendPositionNameToLegendPositionType.emplace("bottom right", QmitkChartWidget::LegendPosition::bottomRight); + m_LegendPositionNameToLegendPositionType.emplace("top right", QmitkChartWidget::LegendPosition::topRight); + m_LegendPositionNameToLegendPositionType.emplace("top left", QmitkChartWidget::LegendPosition::topLeft); + m_LegendPositionNameToLegendPositionType.emplace("middle right", QmitkChartWidget::LegendPosition::middleRight); +} + +void QmitkChartExampleView::CreateConnectionsForGUIElements() +{ + connect(m_Controls.m_buttonCreateChart, &QPushButton::clicked, this, &QmitkChartExampleView::CreateChart); + connect(m_Controls.m_buttonUpdateData, &QPushButton::clicked, this, &QmitkChartExampleView::UpdateData); + connect(m_Controls.m_buttonClearChart, &QPushButton::clicked, this, &QmitkChartExampleView::ClearChart); + connect(m_Controls.m_buttonAddData, &QPushButton::clicked, this, &QmitkChartExampleView::AddData); + connect(m_Controls.m_comboBoxExistingData, &QComboBox::currentTextChanged, this, &QmitkChartExampleView::UpdateSelectedData); + connect(m_Controls.m_checkBoxEnableErrors, &QCheckBox::toggled, this, &QmitkChartExampleView::ShowErrorOptions); + connect(m_Controls.m_checkBoxEnableXErrors, &QCheckBox::toggled, this, &QmitkChartExampleView::ShowXErrorOptions); + connect(m_Controls.m_checkBoxEnableYErrors, &QCheckBox::toggled, this, &QmitkChartExampleView::ShowYErrorOptions); + connect(m_Controls.m_doubleSpinBox_minZoomX, &QSpinBox::editingFinished, this, &QmitkChartExampleView::AdaptZoomX); + connect(m_Controls.m_doubleSpinBox_maxZoomX, &QSpinBox::editingFinished, this, &QmitkChartExampleView::AdaptZoomX); + connect(m_Controls.m_doubleSpinBox_minZoomY, &QSpinBox::editingFinished, this, &QmitkChartExampleView::AdaptZoomY); + connect(m_Controls.m_doubleSpinBox_maxZoomY, &QSpinBox::editingFinished, this, &QmitkChartExampleView::AdaptZoomY); + connect(m_Controls.m_comboBoxLegendPosition, &QComboBox::currentTextChanged, this, &QmitkChartExampleView::OnLegendPositionChanged); + connect(m_Controls.m_lineEditTitle, &QLineEdit::editingFinished, this, &QmitkChartExampleView::OnTitleChanged); + connect(m_Controls.m_lineEditXAxisLabel, &QLineEdit::editingFinished, this, &QmitkChartExampleView::OnXAxisLabelChanged); + connect(m_Controls.m_lineEditYAxisLabel, &QLineEdit::editingFinished, this, &QmitkChartExampleView::OnYAxisLabelChanged); + connect(m_Controls.m_comboBoxYAxisScale, &QComboBox::currentTextChanged, this, &QmitkChartExampleView::OnYAxisScaleChanged); + connect(m_Controls.m_checkBoxShowLegend, &QCheckBox::stateChanged, this, &QmitkChartExampleView::OnShowLegendChanged); + connect(m_Controls.m_checkBoxStackedData, &QCheckBox::stateChanged, this, &QmitkChartExampleView::OnStackedDataChanged); + connect(m_Controls.m_checkBoxShowDataPoints, &QCheckBox::stateChanged, this, &QmitkChartExampleView::OnShowDataPointsChanged); + connect(m_Controls.m_checkBoxShowSubchart, &QCheckBox::stateChanged, this, &QmitkChartExampleView::OnShowSubchartChanged); +} + +void QmitkChartExampleView::AddData() +{ + QString lineEditDataX = m_Controls.m_lineEditDataXVector->text(); + QString lineEditDataY = m_Controls.m_lineEditDataYVector->text(); + auto dataX = ConvertToDoubleVector(lineEditDataX); + auto dataY = ConvertToDoubleVector(lineEditDataY); + auto dataXandY = CreateMap(dataX, dataY); + QString data = QString::fromStdString(ConvertToText(dataXandY)); + + std::string dataLabel = m_Controls.m_lineEditDataLabel->text().toStdString(); + std::string chartTypeAsString = m_Controls.m_comboBoxChartType->currentText().toStdString(); + std::string chartColorAsString = m_Controls.m_comboBoxColor->currentText().toStdString(); + std::string chartLineStyleAsString = m_Controls.m_comboBoxLineStyle->currentText().toStdString(); + std::string pieLabelsAsString = m_Controls.m_lineEditPieDataLabel->text().toStdString(); + + if (std::find(labelStorage.begin(), labelStorage.end(), dataLabel) != labelStorage.end()) + { + m_Controls.m_labelInfo->setText("This data already exists"); + m_Controls.m_labelInfo->setStyleSheet("color: red;"); + return; + } + + if (dataX.size() != dataY.size()) + { + m_Controls.m_labelInfo->setText("Data x and y size have to be equal"); + m_Controls.m_labelInfo->setStyleSheet("color: red;"); + return; + } + + labelStorage.push_back(dataLabel); + m_Controls.m_Chart->AddChartExampleData(dataXandY, dataLabel, chartTypeAsString, chartColorAsString, chartLineStyleAsString, pieLabelsAsString); + m_Controls.m_comboBoxExistingData->addItem(m_Controls.m_lineEditDataLabel->text()); + + if (m_Controls.m_checkBoxEnableErrors->isChecked()) + { + if (m_Controls.m_checkBoxEnableXErrors->isChecked()) + { + auto errorsPlus = ConvertToDoubleVector(m_Controls.m_lineEditXErrorPlus->text()); + auto errorsMinus = ConvertToDoubleVector(m_Controls.m_lineEditXErrorMinus->text()); + m_Controls.m_Chart->SetXErrorBars(m_Controls.m_lineEditDataLabel->text().toStdString(), errorsPlus, errorsMinus); + } + if (m_Controls.m_checkBoxEnableYErrors->isChecked()) + { + auto errorsPlus = ConvertToDoubleVector(m_Controls.m_lineEditYErrorPlus->text()); + auto errorsMinus = ConvertToDoubleVector(m_Controls.m_lineEditYErrorMinus->text()); + m_Controls.m_Chart->SetYErrorBars(m_Controls.m_lineEditDataLabel->text().toStdString(), errorsPlus, errorsMinus); + } + } + + QString dataOverview; + dataOverview.append(m_Controls.m_lineEditDataLabel->text()); + dataOverview.append("(").append(m_Controls.m_comboBoxChartType->currentText()); + + dataOverview.append(", ").append(m_Controls.m_comboBoxLineStyle->currentText()); + dataOverview.append(")"); + dataOverview.append(":").append(data); + + m_Controls.m_plainTextEditDataView->appendPlainText(dataOverview); +} + +void QmitkChartExampleView::CreateChart() +{ + auto dataYAxisScaleType = + m_AxisScaleNameToAxisScaleType.at(m_Controls.m_comboBoxYAxisScale->currentText().toStdString()); + auto xAxisLabel = m_Controls.m_lineEditXAxisLabel->text().toStdString(); + auto yAxisLabel = m_Controls.m_lineEditYAxisLabel->text().toStdString(); + auto showLegend = m_Controls.m_checkBoxShowLegend->isChecked(); + auto legendPosition = + m_LegendPositionNameToLegendPositionType.at(m_Controls.m_comboBoxLegendPosition->currentText().toStdString()); + auto showDataPoints = m_Controls.m_checkBoxShowDataPoints->isChecked(); + auto stackedData = m_Controls.m_checkBoxStackedData->isChecked(); + auto showSubchart = m_Controls.m_checkBoxShowSubchart->isChecked(); + auto title = m_Controls.m_lineEditTitle->text().toStdString(); + + m_Controls.m_Chart->SetTitle(title); + m_Controls.m_Chart->SetYAxisScale(dataYAxisScaleType); + m_Controls.m_Chart->SetXAxisLabel(xAxisLabel); + m_Controls.m_Chart->SetYAxisLabel(yAxisLabel); + m_Controls.m_Chart->SetShowLegend(showLegend); + m_Controls.m_Chart->SetLegendPosition(legendPosition); + m_Controls.m_Chart->SetShowErrorBars(true); + m_Controls.m_Chart->SetShowDataPoints(showDataPoints); + m_Controls.m_Chart->SetStackedData(stackedData); + m_Controls.m_Chart->Show(showSubchart); +} + +void QmitkChartExampleView::UpdateData() +{ + if (m_Controls.m_comboBoxExistingData->currentText().isEmpty()) + { + m_Controls.m_labelInfo->setText("Please enter a valid Datalabel"); + m_Controls.m_labelInfo->setStyleSheet("color: red;"); + return; + } + + if (m_Controls.m_lineEditDataLabel->text() != m_Controls.m_comboBoxExistingData->currentText()) + { + return; + } + + QString lineEditDataX = m_Controls.m_lineEditDataXVector->text(); + QString lineEditDataY = m_Controls.m_lineEditDataYVector->text(); + auto dataX = ConvertToDoubleVector(lineEditDataX); + auto dataY = ConvertToDoubleVector(lineEditDataY); + auto dataXandY = CreateMap(dataX, dataY); + QString data = QString::fromStdString(ConvertToText(dataXandY)); + + std::string dataLabel = m_Controls.m_lineEditDataLabel->text().toStdString(); + std::string chartTypeAsString = m_Controls.m_comboBoxChartType->currentText().toStdString(); + std::string chartColorAsString = m_Controls.m_comboBoxColor->currentText().toStdString(); + std::string chartLineStyleAsString = m_Controls.m_comboBoxLineStyle->currentText().toStdString(); + std::string pieLabelsAsString = m_Controls.m_lineEditPieDataLabel->text().toStdString(); + + if (dataX.size() != dataY.size()) + { + m_Controls.m_labelInfo->setText("Data x and y size have to be equal"); + m_Controls.m_labelInfo->setStyleSheet("color: red;"); + return; + } + + m_Controls.m_Chart->UpdateChartExampleData(dataXandY, dataLabel, chartTypeAsString, chartColorAsString, chartLineStyleAsString, pieLabelsAsString); +} + +void QmitkChartExampleView::UpdateSelectedData() +{ + std::string label = m_Controls.m_comboBoxExistingData->currentText().toStdString(); + auto data = m_Controls.m_Chart->GetDataElementByLabel(label); + + if (data == nullptr) + { + return; + } + + auto x = data->GetXData(); + auto y = data->GetYData(); + + auto xVector = x.toVector().toStdVector(); + auto yVector = y.toVector().toStdVector(); + + QString xString = QString::fromStdString(ConvertToText(xVector)); + QString yString = QString::fromStdString(ConvertToText(yVector)); + + auto color = data->GetColor(); + auto type = data->GetChartType(); + auto style = data->GetLineStyle(); + + if (type.toString() == "pie") + { + m_Controls.m_comboBoxLineStyle->setVisible(false); + m_Controls.m_labelLineStyle->setVisible(false); + m_Controls.m_lineEditPieDataLabel->setVisible(true); + m_Controls.m_labelPieData->setVisible(true); + + auto pieLabelsString = ConvertToText(data->GetPieLabels()); + + m_Controls.m_lineEditPieDataLabel->setText(QString::fromStdString(pieLabelsString)); + } + + else + { + m_Controls.m_lineEditPieDataLabel->setVisible(false); + m_Controls.m_labelPieData->setVisible(false); + m_Controls.m_comboBoxLineStyle->setVisible(true); + m_Controls.m_labelLineStyle->setVisible(true); + m_Controls.m_comboBoxLineStyle->setCurrentText(style.toString()); + } + + m_Controls.m_lineEditDataXVector->setText(xString); + m_Controls.m_lineEditDataYVector->setText(yString); + m_Controls.m_lineEditDataLabel->setText(QString::fromStdString(label)); + m_Controls.m_comboBoxColor->setCurrentText(color.toString()); + m_Controls.m_comboBoxChartType->setCurrentText(type.toString()); +} + +void QmitkChartExampleView::ClearChart() +{ + m_Controls.m_Chart->Clear(); + + m_Controls.m_plainTextEditDataView->clear(); + + m_Controls.m_comboBoxExistingData->clear(); + + labelStorage.clear(); +} + +void QmitkChartExampleView::ShowErrorOptions(bool show) +{ + m_Controls.m_groupBoxErrors->setVisible(show); +} + +void QmitkChartExampleView::ShowXErrorOptions(bool show) +{ + m_Controls.m_groupBoxXErrors->setVisible(show); +} + +void QmitkChartExampleView::ShowYErrorOptions(bool show) +{ + m_Controls.m_groupBoxYErrors->setVisible(show); +} + +void QmitkChartExampleView::AdaptZoomX() +{ + m_Controls.m_Chart->SetMinMaxValueXView(m_Controls.m_doubleSpinBox_minZoomX->value(), + m_Controls.m_doubleSpinBox_maxZoomX->value()); + m_Controls.m_Chart->Show(); +} + +void QmitkChartExampleView::AdaptZoomY() +{ + m_Controls.m_Chart->SetMinMaxValueYView(m_Controls.m_doubleSpinBox_minZoomY->value(), + m_Controls.m_doubleSpinBox_maxZoomY->value()); + m_Controls.m_Chart->Show(); +} + +void QmitkChartExampleView::AdaptDataGUI(QString chartType) +{ + if (chartType == "pie") + { + m_Controls.m_labelPieData->setVisible(true); + m_Controls.m_lineEditPieDataLabel->setVisible(true); + m_Controls.m_labelLineStyle->setVisible(false); + m_Controls.m_comboBoxLineStyle->setVisible(false); + } + + else + { + m_Controls.m_labelLineStyle->setVisible(true); + m_Controls.m_comboBoxLineStyle->setVisible(true); + m_Controls.m_labelPieData->setVisible(false); + m_Controls.m_lineEditPieDataLabel->setVisible(false); + } +} + +void QmitkChartExampleView::OnLegendPositionChanged(const QString &newText) +{ + auto legendPosition = m_LegendPositionNameToLegendPositionType.at(newText.toStdString()); + m_Controls.m_Chart->SetLegendPosition(legendPosition); +} + +void QmitkChartExampleView::OnTitleChanged() { + auto newTitle = m_Controls.m_lineEditTitle->text(); + m_Controls.m_Chart->SetTitle(newTitle.toStdString()); +} + +void QmitkChartExampleView::OnXAxisLabelChanged() { + auto newXAxisLabel = m_Controls.m_lineEditXAxisLabel->text(); + m_Controls.m_Chart->SetXAxisLabel(newXAxisLabel.toStdString()); +} + +void QmitkChartExampleView::OnYAxisLabelChanged() { + auto newYAxisLabel = m_Controls.m_lineEditYAxisLabel->text(); + m_Controls.m_Chart->SetYAxisLabel(newYAxisLabel.toStdString()); +} + +void QmitkChartExampleView::OnYAxisScaleChanged(const QString &newYAxisScale) { + auto yAxisScale = m_AxisScaleNameToAxisScaleType.at(newYAxisScale.toStdString()); + m_Controls.m_Chart->SetYAxisScale(yAxisScale); +} + +void QmitkChartExampleView::OnShowLegendChanged(int newState) { + m_Controls.m_Chart->SetShowLegend(newState == Qt::Checked); +} + +void QmitkChartExampleView::OnStackedDataChanged(int newState) { + m_Controls.m_Chart->SetStackedData(newState == Qt::Checked); +} + +void QmitkChartExampleView::OnShowDataPointsChanged(int newState) { + m_Controls.m_Chart->SetShowDataPoints(newState == Qt::Checked); +} + +void QmitkChartExampleView::OnShowSubchartChanged(int newState) { + m_Controls.m_Chart->SetShowSubchart(newState == Qt::Checked); +} + +std::map QmitkChartExampleView::CreateMap(std::vector keys, std::vector values) const +{ + std::map aMap; + std::transform(keys.begin(), keys.end(), values.begin(), std::inserter(aMap, aMap.end()), [](double a, double b) { + return std::make_pair(a, b); + }); + return aMap; +} + +std::string QmitkChartExampleView::ConvertToText(std::map numbers, std::string delimiter) const +{ + std::ostringstream oss; + oss.precision(3); + + if (!numbers.empty()) + { + for (const auto keyValue : numbers) + { + oss << keyValue.first << ":" << keyValue.second << delimiter; + } + } + auto aString = oss.str(); + aString.pop_back(); + return aString; +} + +std::string QmitkChartExampleView::ConvertToText(std::vector numbers, std::string delimiter) const +{ + std::ostringstream oss; + oss.precision(3); + + if (!numbers.empty()) + { + for (auto number : numbers) + { + oss << number.toDouble() << delimiter; + } + } + auto aString = oss.str(); + aString.pop_back(); + return aString; +} + +std::string QmitkChartExampleView::ConvertToText(QVariantList list, std::string delimiter) const +{ + std::ostringstream oss; + + if (!list.isEmpty()) + { + for (auto element : list) + { + oss << element.toString().toStdString() << delimiter; + } + + auto aString = oss.str(); + aString.pop_back(); + return aString; + } + + return ""; +} + +std::vector QmitkChartExampleView::ConvertToDoubleVector(const QString& data, QChar delimiter) const +{ + std::vector output; + if (data.isEmpty()) + { + return output; + } + + for (const QString entry : data.split(delimiter)) + { + output.push_back(entry.toDouble()); + } + return output; +} + +std::vector QmitkChartExampleView::ConvertToStringVector(const QString& data, QChar delimiter) const +{ + std::vector output; + if (data.isEmpty()) + { + return output; + } + + for (const QString entry : data.split(delimiter)) + { + output.push_back(entry.toStdString()); + } + return output; +} diff --git a/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExample.h b/Plugins/org.mitk.gui.qt.chartExample/src/internal/QmitkChartExampleView.h similarity index 68% rename from Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExample.h rename to Plugins/org.mitk.gui.qt.chartExample/src/internal/QmitkChartExampleView.h index 5f8484ccc4..d070a16f8d 100644 --- a/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExample.h +++ b/Plugins/org.mitk.gui.qt.chartExample/src/internal/QmitkChartExampleView.h @@ -1,91 +1,88 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef ChartExample_h -#define ChartExample_h +#ifndef QmitkChartExample_h +#define QmitkChartExample_h #include -#include "ui_ChartExampleControls.h" +#include "ui_QmitkChartExampleViewControls.h" /** \brief Basic example for use of module mitkChart \sa QmitkAbstractView \ingroup ${plugin_target}_internal */ -class ChartExample : public QmitkAbstractView +class QmitkChartExampleView : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; protected: - void CreateQtPartControl(QWidget *parent) override; + virtual void CreateQtPartControl(QWidget *parent) override; void CreateConnectionsForGUIElements(); - void SetFocus() override; + virtual void SetFocus() override; + void AddData(); void CreateChart(); - void UpdateChart(); + void UpdateData(); + void UpdateSelectedData(); void ClearChart(); - void AddData(); +private: + std::map m_AxisScaleNameToAxisScaleType; + std::map m_LegendPositionNameToLegendPositionType; + + std::vector labelStorage; - void ShowXData(bool show); void ShowErrorOptions(bool show); void ShowXErrorOptions(bool show); void ShowYErrorOptions(bool show); void AdaptZoomX(); void AdaptZoomY(); - void AdaptDataGUI(const QString &chartType); - void ResetDataGUI(); + void AdaptDataGUI(QString chartType); -private: - void FillRandomDataValues(); - std::vector GenerateRandomNumbers(unsigned int amount, double max) const; - std::vector ConvertToDoubleVector(const QString &data, QChar delimiter = ';') const; - std::vector ConvertToStringVector(const QString &data, QChar delimiter = ';') const; - std::map CreateMap(std::vector keys, std::vector values) const; - std::string ConvertToText(std::vector numbers, std::string delimiter = ";") const; - std::string ConvertToText(std::map numbers, std::string delimiter = ";") const; - QmitkChartWidget::ColorTheme GetColorTheme() const; void OnLegendPositionChanged(const QString &newPosition); void OnTitleChanged(); void OnXAxisLabelChanged(); void OnYAxisLabelChanged(); void OnYAxisScaleChanged(const QString &newYAxisScale); void OnShowLegendChanged(int newState); void OnStackedDataChanged(int newState); void OnShowDataPointsChanged(int newState); void OnShowSubchartChanged(int newState); - std::map m_ChartNameToChartType; - std::map m_LineNameToLineType; - std::map m_AxisScaleNameToAxisScaleType; - std::map m_LegendPositionNameToLegendPositionType; + std::map CreateMap(std::vector keys, std::vector values) const; + std::string ConvertToText(std::vector numbers, std::string delimiter = ";") const; + std::string ConvertToText(std::map numbers, std::string delimiter = ";") const; + std::string ConvertToText(QVariantList list, std::string delimiter = ";") const; + std::vector ConvertToDoubleVector(const QString& data, QChar delimiter = ';') const; + std::vector ConvertToStringVector(const QString& data, QChar delimiter = ';') const; unsigned int countForUID = 0; - Ui::ChartExampleControls m_Controls; + Ui::QmitkChartExampleViewControls m_Controls; }; -#endif // ChartExample_h +#endif // QmitkChartExample_h diff --git a/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExampleControls.ui b/Plugins/org.mitk.gui.qt.chartExample/src/internal/QmitkChartExampleViewControls.ui similarity index 53% rename from Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExampleControls.ui rename to Plugins/org.mitk.gui.qt.chartExample/src/internal/QmitkChartExampleViewControls.ui index e42d3e837d..bc42605cee 100644 --- a/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExampleControls.ui +++ b/Plugins/org.mitk.gui.qt.chartExample/src/internal/QmitkChartExampleViewControls.ui @@ -1,688 +1,861 @@ - ChartExampleControls - + QmitkChartExampleViewControls + 0 0 455 1054 0 0 QmitkTemplate + + + + + + + 0 0 - 0 + 1 - + + + + 0 + 0 + 437 + 154 + + + + + 0 + 0 + + + + Chart settings + + + + + 10 + 10 + 421 + 101 + + + + + Qt::AlignCenter + + + + + Title: + + + + + + + + 0 + 0 + + + + + + + + X-Axis label: + + + + + + + + 0 + 0 + + + + + + + + Y-Axis label: + + + + + + + + 0 + 0 + + + + + + + + 0 0 420 - 436 + 535 0 0 Data - - - - data entry - - - - - - - - - - - - - 0 - 0 - - - - - - - - - - - x - - - - - - - y: - - - - - - - - - error - - - - + 0 0 Error values y error - - - - x error - - - - - - - - 0 - 0 - - - - GroupBox - - - - - - - - plus error - - - - - - - minus error - - - - - - - - - - - - - - 0 0 GroupBox - - - - plus error - - - 0 0 0 0 - - - - minus error - - + + + + + + + + + x error + + + + + + + + 0 + 0 + + + + GroupBox + + + + + + + + + - - - - data label - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - Chart type - - - - - - - - 0 - 0 - + + + + Qt::AlignCenter - - - bar - + + + + x: + + - - - line - + + + + + 0 + 0 + + + + + + - - - area - + + + + y: + + - - - pie - + + + + Data label: + + - - - spline - + + + + + 0 + 0 + + + - - - area-spline - + + + + Pie data labels: + + - - - scatter - + + + + + 0 + 0 + + + - - - - - - Color - - - - - - - - 0 - 0 - - - + + + + Existing data: + + + + + + + + + + Creates a test chart + + + Update data + + + + + + + Add data + + + + + + + + + + Color: + + + + + + + + red + + + + + orange + + + + + yellow + + + + + green + + + + + blue + + + + + purple + + + + + brown + + + + + magenta + + + + + tan + + + + + cyan + + + + + olive + + + + + maroon + + + + + navy + + + + + aquamarine + + + + + turquoise + + + + + silver + + + + + lime + + + + + teal + + + + + indigo + + + + + violet + + + + + pink + + + + + black + + + + + white + + + + + grey + + + + + + + + + 0 + 0 + + + + + solid + + + + + dashed + + + + + + + + Line style: + + + + + + + + 0 + 0 + + + + + bar + + + + + line + + + + + area + + + + + pie + + + + + spline + + + + + area-spline + + + + + scatter + + + + + + + + Chart: + + + + - - + + - Line style + Error - - - - - 0 - 0 - + + + + Zentrieren, Vertikal zentrieren - - - solid - - - - - dashed - - - - - - - pie data label + Data entry - - - - Add data - - - - + 0 0 437 - 236 + 158 0 0 Global options QLayout::SetDefaultConstraint QFormLayout::AllNonFixedFieldsGrow - - - Title - - - - - - - - - - XAxis label - - - - - - - - - - YAxis label - - - - - - - - + Y Axis scale - + linear logarithmic - - - - Show legend - - - true - - - - - - - Stacked data - - - - - - - Show data points - - - true - - - - - - - Show Subchart - - - - - + + Legend position - + 2 bottom middle bottom right top right top left middle right + + + + Show legend + + + true + + + + + + + Stacked data + + + + + + + Show data points + + + true + + + + + + + Show Subchart + + + - + 0 0 437 - 187 + 154 Zoom 0 0 431 121 - + x: - + y: Do image processing Create chart - - - - Do image processing - - - Update chart - - - - Clear chart + Clear chart and data - + Qt::Vertical 0 0 0 250 0 0 0 0 0 16777215 150 + + ArrowCursor + + + true + + + true + - + Qt::Vertical QSizePolicy::Expanding 20 0 QmitkChartWidget QWidget
QmitkChartWidget.h
diff --git a/Plugins/org.mitk.gui.qt.chartExample/src/internal/org_mitk_gui_qt_chartExample_Activator.cpp b/Plugins/org.mitk.gui.qt.chartExample/src/internal/org_mitk_gui_qt_chartExample_Activator.cpp index e6ef11119c..73ec95bf09 100644 --- a/Plugins/org.mitk.gui.qt.chartExample/src/internal/org_mitk_gui_qt_chartExample_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.chartExample/src/internal/org_mitk_gui_qt_chartExample_Activator.cpp @@ -1,29 +1,29 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "org_mitk_gui_qt_chartExample_Activator.h" -#include "ChartExample.h" +#include "QmitkChartExampleView.h" namespace mitk { void org_mitk_gui_qt_chartExample_Activator::start(ctkPluginContext *context) { - BERRY_REGISTER_EXTENSION_CLASS(ChartExample, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkChartExampleView, context) } void org_mitk_gui_qt_chartExample_Activator::stop(ctkPluginContext *context) { Q_UNUSED(context) } }