From f0457c929c92b0652c4011b89d146569cf45f786 Mon Sep 17 00:00:00 2001 From: zhongjingjogy Date: Sat, 23 Jul 2022 10:25:18 +0800 Subject: [PATCH 1/7] Change fixed offset of ylabel to fit the length of yticks. --- src/frontend/Axis.hpp | 3 ++ src/frontend/Axis.tcc | 16 +++++++- tests/CMakeLists.txt | 5 +++ tests/TestYlabel.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 tests/TestYlabel.cpp diff --git a/src/frontend/Axis.hpp b/src/frontend/Axis.hpp index 917c04e..9272cd7 100644 --- a/src/frontend/Axis.hpp +++ b/src/frontend/Axis.hpp @@ -95,6 +95,9 @@ class Axis : public Drawable { /// the number of ticks displayed on the y axis int m_ny_ticks; + /// the length of maximum yticks length (in pixels) + int m_max_ytick_len; + /// the length (in pixels) of each tick float m_tick_len; diff --git a/src/frontend/Axis.tcc b/src/frontend/Axis.tcc index 78eddf1..409e566 100644 --- a/src/frontend/Axis.tcc +++ b/src/frontend/Axis.tcc @@ -37,6 +37,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "frontend/Axis.hpp" #include "frontend/Geometry.hpp" #include "frontend/Line.hpp" +#include +#include namespace trase { @@ -96,6 +98,8 @@ template void Axis::draw_common_ticks(Backend &backend) { backend.text_align(ALIGN_RIGHT | ALIGN_MIDDLE); + size_t max_char_len = 0; + // y ticks for (std::size_t i = 0; i < m_tick_info.y_pos.size(); ++i) { const float pos = m_tick_info.y_pos[i]; @@ -104,10 +108,19 @@ template void Axis::draw_common_ticks(Backend &backend) { backend.move_to(vfloat2_t(m_pixels.bmin[0] - m_tick_len / 2, pos)); backend.line_to(vfloat2_t(m_pixels.bmin[0], pos)); std::snprintf(buffer, sizeof(buffer), "%.*g", m_sig_digits + 1, val); + std::cout << "buffer: " << buffer << ", size of buffer = " << strlen(buffer) << std::endl; + + if (strlen(buffer) > max_char_len) { + max_char_len = strlen(buffer); + } + backend.text(vfloat2_t(m_pixels.bmin[0] - m_tick_len / 2, pos), buffer, NULL); } + /// TODO: Convertion from length * font_size to pixels + m_max_ytick_len = max_char_len * m_style.font_size() / 96.0 * 72.0; + backend.stroke_color(RGBA(0, 0, 0, 255)); backend.stroke_width(m_style.line_width() / 2); backend.stroke(); @@ -167,8 +180,7 @@ template void Axis::draw_common_ylabel(Backend &backend) { } backend.text_align(ALIGN_CENTER | ALIGN_BOTTOM); - const vfloat2_t point = vfloat2_t( - m_pixels.bmin[0] - 0.05f * (m_pixels.bmax[0] - m_pixels.bmin[0]), + const vfloat2_t point = vfloat2_t(m_pixels.bmin[0] - m_max_ytick_len, 0.5f * (m_pixels.bmax[1] + m_pixels.bmin[1])); backend.translate(point); backend.rotate(-pi / 2.0f); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 80e4b10..512bc82 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable ( TestVector.cpp TestLegend.cpp ) + if (CURL_FOUND) target_sources(trase_test PRIVATE TestCSVDownloader.cpp) endif (CURL_FOUND) @@ -33,4 +34,8 @@ target_include_directories (trase_test PRIVATE tests) target_link_libraries (trase_test PRIVATE trase) add_test (the_trase_test trase_test) +add_executable(test_trase_ylabel + TestYlabel.cpp +) +target_link_libraries(test_trase_ylabel PRIVATE trase) diff --git a/tests/TestYlabel.cpp b/tests/TestYlabel.cpp new file mode 100644 index 0000000..5f3ad0d --- /dev/null +++ b/tests/TestYlabel.cpp @@ -0,0 +1,89 @@ +#include "trase.hpp" +#include +#include + +using namespace trase; + +void test_1() { + std::string dest = "test_demo_1.svg"; + + std::vector predicted_data = { + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; + std::vector exp_data = { + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; + + auto fig = figure(); + auto ax = fig->axis(); + int predicted_size = predicted_data.size(); + int exp_size = exp_data.size(); + + std::vector x(predicted_size); + std::vector y(exp_size); + for (int i = 0; i < predicted_size; ++i) { + x[i] = predicted_data[i]; + } + for (int i = 0; i < exp_size; ++i) { + y[i] = exp_data[i]; + } + + auto data = create_data().x(x).y(y); + auto plt = ax->points(data); + + ax->xlabel("Pred. Target"); + ax->ylabel("Exp. Target"); + + // output to svg + std::ofstream out; + out.open(dest); + BackendSVG backend(out); + fig->draw(backend); + out.close(); +} + +void test_2() { + std::string dest = "test_demo_2.svg"; + + std::vector predicted_data = { + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; + std::vector exp_data = { + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; + + auto fig = figure(); + auto ax = fig->axis(); + int predicted_size = predicted_data.size(); + int exp_size = exp_data.size(); + + std::vector x(predicted_size); + std::vector y(exp_size); + for (int i = 0; i < predicted_size; ++i) { + x[i] = predicted_data[i] * 10.0; + } + for (int i = 0; i < exp_size; ++i) { + y[i] = exp_data[i] * 10.0; + } + + auto data = create_data().x(x).y(y); + auto plt = ax->points(data); + + ax->xlabel("Pred. Target"); + ax->ylabel("Exp. Target"); + + // output to svg + std::ofstream out; + out.open(dest); + BackendSVG backend(out); + fig->draw(backend); + out.close(); +} + +int main() { + + test_1(); + test_2(); + + return 0; +} \ No newline at end of file From 36a5ee9a74fc0d729eaa86db403b91bf03856eaf Mon Sep 17 00:00:00 2001 From: zhongjingjogy Date: Sat, 23 Jul 2022 10:28:57 +0800 Subject: [PATCH 2/7] remove debug cout. --- src/frontend/Axis.tcc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/Axis.tcc b/src/frontend/Axis.tcc index 409e566..6b0aad8 100644 --- a/src/frontend/Axis.tcc +++ b/src/frontend/Axis.tcc @@ -108,7 +108,6 @@ template void Axis::draw_common_ticks(Backend &backend) { backend.move_to(vfloat2_t(m_pixels.bmin[0] - m_tick_len / 2, pos)); backend.line_to(vfloat2_t(m_pixels.bmin[0], pos)); std::snprintf(buffer, sizeof(buffer), "%.*g", m_sig_digits + 1, val); - std::cout << "buffer: " << buffer << ", size of buffer = " << strlen(buffer) << std::endl; if (strlen(buffer) > max_char_len) { max_char_len = strlen(buffer); From 4218dabea11ab67598d2f3ad3796724205318299 Mon Sep 17 00:00:00 2001 From: zhongjingjogy Date: Sat, 23 Jul 2022 20:45:59 +0800 Subject: [PATCH 3/7] merge test for ylabel of axises to TestAxis.cpp. --- src/frontend/Axis.hpp | 3 ++ src/frontend/Axis.tcc | 9 +++-- tests/CMakeLists.txt | 8 +--- tests/TestAxis.cpp | 79 ++++++++++++++++++++++++++++++++++++++ tests/TestYlabel.cpp | 89 ------------------------------------------- 5 files changed, 88 insertions(+), 100 deletions(-) delete mode 100644 tests/TestYlabel.cpp diff --git a/src/frontend/Axis.hpp b/src/frontend/Axis.hpp index 9272cd7..206c317 100644 --- a/src/frontend/Axis.hpp +++ b/src/frontend/Axis.hpp @@ -222,6 +222,9 @@ class Axis : public Drawable { /// gets the number of ticks on this axis Vector get_ticks() const { return {m_nx_ticks, m_ny_ticks}; } + /// get the number of maximum yticks length (in pixels) + int max_ytick_len() const { return m_max_ytick_len; } + private: /// Create a new Geometry on this axis and return a shared pointer to it. /// diff --git a/src/frontend/Axis.tcc b/src/frontend/Axis.tcc index 6b0aad8..314fb0a 100644 --- a/src/frontend/Axis.tcc +++ b/src/frontend/Axis.tcc @@ -99,16 +99,16 @@ template void Axis::draw_common_ticks(Backend &backend) { backend.text_align(ALIGN_RIGHT | ALIGN_MIDDLE); size_t max_char_len = 0; - // y ticks for (std::size_t i = 0; i < m_tick_info.y_pos.size(); ++i) { + const float pos = m_tick_info.y_pos[i]; const float val = m_tick_info.y_val[i]; backend.move_to(vfloat2_t(m_pixels.bmin[0] - m_tick_len / 2, pos)); backend.line_to(vfloat2_t(m_pixels.bmin[0], pos)); std::snprintf(buffer, sizeof(buffer), "%.*g", m_sig_digits + 1, val); - + if (strlen(buffer) > max_char_len) { max_char_len = strlen(buffer); } @@ -117,8 +117,9 @@ template void Axis::draw_common_ticks(Backend &backend) { NULL); } - /// TODO: Convertion from length * font_size to pixels - m_max_ytick_len = max_char_len * m_style.font_size() / 96.0 * 72.0; + /// Convertion from length * font_size to pixels + /// The scale factor, i.e., 1.25, is for Roboto font (https://bugbox.clickteam.com/threads/82514-Useful-Roboto-Font-Size-Pixel-Heights!) + m_max_ytick_len = int(max_char_len * m_style.font_size() / 1.25); backend.stroke_color(RGBA(0, 0, 0, 255)); backend.stroke_width(m_style.line_width() / 2); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 512bc82..86ff642 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,10 +32,4 @@ endif (CURL_FOUND) target_include_directories (trase_test PRIVATE tests) target_link_libraries (trase_test PRIVATE trase) -add_test (the_trase_test trase_test) - -add_executable(test_trase_ylabel - TestYlabel.cpp -) - -target_link_libraries(test_trase_ylabel PRIVATE trase) +add_test (the_trase_test trase_test) \ No newline at end of file diff --git a/tests/TestAxis.cpp b/tests/TestAxis.cpp index 27e602b..0c724b0 100644 --- a/tests/TestAxis.cpp +++ b/tests/TestAxis.cpp @@ -137,3 +137,82 @@ TEST_CASE("set number of ticks", "[axis]") { CHECK(ax->get_ticks()[0] == 10); CHECK(ax->get_ticks()[1] == 10); } + + +TEST_CASE("ylabel position: case 1", "[axis]") { + std::vector predicted_data = { + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; + std::vector exp_data = { + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; + + auto fig = figure(); + auto ax = fig->axis(); + int predicted_size = predicted_data.size(); + int exp_size = exp_data.size(); + + std::vector x(predicted_size); + std::vector y(exp_size); + for (int i = 0; i < predicted_size; ++i) { + x[i] = predicted_data[i]; + } + for (int i = 0; i < exp_size; ++i) { + y[i] = exp_data[i]; + } + + auto data = create_data().x(x).y(y); + auto plt = ax->points(data); + + ax->xlabel("Pred. Target"); + ax->ylabel("Exp. Target"); + + // the default number of digits for the labels is set as 2 + CHECK(ax->max_ytick_len() == int(5 * 18.0 / 1.25)); + + // output to svg + std::ofstream out; + out.open("test_axis_ylabel_position_case1.svg"); + BackendSVG backend(out); + fig->draw(backend); + out.close(); +} + +TEST_CASE("ylabel position: case 2", "[axis]") { + std::vector predicted_data = { + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; + std::vector exp_data = { + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; + + auto fig = figure(); + auto ax = fig->axis(); + int predicted_size = predicted_data.size(); + int exp_size = exp_data.size(); + + std::vector x(predicted_size); + std::vector y(exp_size); + for (int i = 0; i < predicted_size; ++i) { + x[i] = predicted_data[i] * 10.0; + } + for (int i = 0; i < exp_size; ++i) { + y[i] = exp_data[i] * 10.0; + } + + auto data = create_data().x(x).y(y); + auto plt = ax->points(data); + + ax->xlabel("Pred. Target"); + ax->ylabel("Exp. Target"); + + // the default number of digits for the labels is set as 2 + CHECK(ax->max_ytick_len() == int(4 * 18.0 / 1.25)); + + // output to svg + std::ofstream out; + out.open("test_axis_ylabel_position_case2.svg"); + BackendSVG backend(out); + fig->draw(backend); + out.close(); +} diff --git a/tests/TestYlabel.cpp b/tests/TestYlabel.cpp deleted file mode 100644 index 5f3ad0d..0000000 --- a/tests/TestYlabel.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "trase.hpp" -#include -#include - -using namespace trase; - -void test_1() { - std::string dest = "test_demo_1.svg"; - - std::vector predicted_data = { - -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 - }; - std::vector exp_data = { - -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 - }; - - auto fig = figure(); - auto ax = fig->axis(); - int predicted_size = predicted_data.size(); - int exp_size = exp_data.size(); - - std::vector x(predicted_size); - std::vector y(exp_size); - for (int i = 0; i < predicted_size; ++i) { - x[i] = predicted_data[i]; - } - for (int i = 0; i < exp_size; ++i) { - y[i] = exp_data[i]; - } - - auto data = create_data().x(x).y(y); - auto plt = ax->points(data); - - ax->xlabel("Pred. Target"); - ax->ylabel("Exp. Target"); - - // output to svg - std::ofstream out; - out.open(dest); - BackendSVG backend(out); - fig->draw(backend); - out.close(); -} - -void test_2() { - std::string dest = "test_demo_2.svg"; - - std::vector predicted_data = { - -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 - }; - std::vector exp_data = { - -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 - }; - - auto fig = figure(); - auto ax = fig->axis(); - int predicted_size = predicted_data.size(); - int exp_size = exp_data.size(); - - std::vector x(predicted_size); - std::vector y(exp_size); - for (int i = 0; i < predicted_size; ++i) { - x[i] = predicted_data[i] * 10.0; - } - for (int i = 0; i < exp_size; ++i) { - y[i] = exp_data[i] * 10.0; - } - - auto data = create_data().x(x).y(y); - auto plt = ax->points(data); - - ax->xlabel("Pred. Target"); - ax->ylabel("Exp. Target"); - - // output to svg - std::ofstream out; - out.open(dest); - BackendSVG backend(out); - fig->draw(backend); - out.close(); -} - -int main() { - - test_1(); - test_2(); - - return 0; -} \ No newline at end of file From 29f3054226b24ef821f9899c0ab839fcb9ad4efa Mon Sep 17 00:00:00 2001 From: zhongjingjogy Date: Mon, 25 Jul 2022 08:27:05 +0800 Subject: [PATCH 4/7] test code for figuring out the bug with axis. --- src/frontend/Axis.hpp | 20 ++++++-- src/frontend/Axis.tcc | 19 ++++++-- tests/TestAxis.cpp | 107 ++++++++++++++---------------------------- 3 files changed, 65 insertions(+), 81 deletions(-) diff --git a/src/frontend/Axis.hpp b/src/frontend/Axis.hpp index 206c317..76cc569 100644 --- a/src/frontend/Axis.hpp +++ b/src/frontend/Axis.hpp @@ -95,8 +95,9 @@ class Axis : public Drawable { /// the number of ticks displayed on the y axis int m_ny_ticks; - /// the length of maximum yticks length (in pixels) - int m_max_ytick_len; + /// the length of maximum yticks char length + int m_max_ytick_char_len = 0; + std::string m_max_ytick_char = ""; /// the length (in pixels) of each tick float m_tick_len; @@ -223,7 +224,20 @@ class Axis : public Drawable { Vector get_ticks() const { return {m_nx_ticks, m_ny_ticks}; } /// get the number of maximum yticks length (in pixels) - int max_ytick_len() const { return m_max_ytick_len; } + int max_ytick_pixels() const { + /// Convertion from length * font_size to pixels + /// The scale factor, i.e., 1.25, is for Roboto font (https://bugbox.clickteam.com/threads/82514-Useful-Roboto-Font-Size-Pixel-Heights!) + return int(this->max_ytick_char_len() * m_style.font_size() / 1.25); + } + + // get the number of maximum char length of yticks + int max_ytick_char_len() const { return m_max_ytick_char_len; } + + // get default font size + float font_size() const { return m_style.font_size(); } + + // get maximum char + std::string max_ytick_char() const { return m_max_ytick_char; } private: /// Create a new Geometry on this axis and return a shared pointer to it. diff --git a/src/frontend/Axis.tcc b/src/frontend/Axis.tcc index 314fb0a..e8f12f6 100644 --- a/src/frontend/Axis.tcc +++ b/src/frontend/Axis.tcc @@ -98,7 +98,7 @@ template void Axis::draw_common_ticks(Backend &backend) { backend.text_align(ALIGN_RIGHT | ALIGN_MIDDLE); - size_t max_char_len = 0; + size_t max_char_len = this->max_ytick_char_len(); // y ticks for (std::size_t i = 0; i < m_tick_info.y_pos.size(); ++i) { @@ -111,15 +111,18 @@ template void Axis::draw_common_ticks(Backend &backend) { if (strlen(buffer) > max_char_len) { max_char_len = strlen(buffer); + m_max_ytick_char = std::string(buffer); } + // std::cout << "buffer: " << buffer << std::endl; backend.text(vfloat2_t(m_pixels.bmin[0] - m_tick_len / 2, pos), buffer, NULL); } - /// Convertion from length * font_size to pixels - /// The scale factor, i.e., 1.25, is for Roboto font (https://bugbox.clickteam.com/threads/82514-Useful-Roboto-Font-Size-Pixel-Heights!) - m_max_ytick_len = int(max_char_len * m_style.font_size() / 1.25); + m_max_ytick_char_len = max_char_len; + + // std::cout << "max_ytick_char_len: " << max_char_len << std::endl; + // std::cout << "max_ytick_char: " << m_max_ytick_char << std::endl; backend.stroke_color(RGBA(0, 0, 0, 255)); backend.stroke_width(m_style.line_width() / 2); @@ -179,8 +182,14 @@ template void Axis::draw_common_ylabel(Backend &backend) { return; } + + // std::cout << "ylabel: " << m_ylabel << std::endl; + // std::cout << "max_ytick_char: " << m_max_ytick_char << std::endl; + // std::cout << "max_ytick_pixels: " << this->max_ytick_pixels() << std::endl; + // std::cout << "max_ytick_char_len: " << this->max_ytick_char_len() << std::endl; + backend.text_align(ALIGN_CENTER | ALIGN_BOTTOM); - const vfloat2_t point = vfloat2_t(m_pixels.bmin[0] - m_max_ytick_len, + const vfloat2_t point = vfloat2_t(m_pixels.bmin[0] - this->max_ytick_pixels(), 0.5f * (m_pixels.bmax[1] + m_pixels.bmin[1])); backend.translate(point); backend.rotate(-pi / 2.0f); diff --git a/tests/TestAxis.cpp b/tests/TestAxis.cpp index 0c724b0..ff82576 100644 --- a/tests/TestAxis.cpp +++ b/tests/TestAxis.cpp @@ -141,78 +141,39 @@ TEST_CASE("set number of ticks", "[axis]") { TEST_CASE("ylabel position: case 1", "[axis]") { std::vector predicted_data = { - -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 - }; - std::vector exp_data = { - -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 - }; - - auto fig = figure(); - auto ax = fig->axis(); - int predicted_size = predicted_data.size(); - int exp_size = exp_data.size(); - - std::vector x(predicted_size); - std::vector y(exp_size); - for (int i = 0; i < predicted_size; ++i) { - x[i] = predicted_data[i]; - } - for (int i = 0; i < exp_size; ++i) { - y[i] = exp_data[i]; - } - - auto data = create_data().x(x).y(y); - auto plt = ax->points(data); - - ax->xlabel("Pred. Target"); - ax->ylabel("Exp. Target"); - - // the default number of digits for the labels is set as 2 - CHECK(ax->max_ytick_len() == int(5 * 18.0 / 1.25)); - - // output to svg - std::ofstream out; - out.open("test_axis_ylabel_position_case1.svg"); - BackendSVG backend(out); - fig->draw(backend); - out.close(); -} + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; + std::vector exp_data = { + -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 + }; -TEST_CASE("ylabel position: case 2", "[axis]") { - std::vector predicted_data = { - -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 - }; - std::vector exp_data = { - -13.8881, -13.8671, -13.8361, -13.7881, -13.7681, -13.7381, -12.6881, -12.661, -12.6481 - }; - - auto fig = figure(); - auto ax = fig->axis(); - int predicted_size = predicted_data.size(); - int exp_size = exp_data.size(); - - std::vector x(predicted_size); - std::vector y(exp_size); - for (int i = 0; i < predicted_size; ++i) { - x[i] = predicted_data[i] * 10.0; - } - for (int i = 0; i < exp_size; ++i) { - y[i] = exp_data[i] * 10.0; - } - - auto data = create_data().x(x).y(y); - auto plt = ax->points(data); - - ax->xlabel("Pred. Target"); - ax->ylabel("Exp. Target"); - - // the default number of digits for the labels is set as 2 - CHECK(ax->max_ytick_len() == int(4 * 18.0 / 1.25)); - - // output to svg - std::ofstream out; - out.open("test_axis_ylabel_position_case2.svg"); - BackendSVG backend(out); - fig->draw(backend); - out.close(); + auto fig = figure(); + auto ax = fig->axis(); + int predicted_size = predicted_data.size(); + int exp_size = exp_data.size(); + + std::vector x(predicted_size); + std::vector y(exp_size); + for (int i = 0; i < predicted_size; ++i) { + x[i] = predicted_data[i]; + } + for (int i = 0; i < exp_size; ++i) { + y[i] = exp_data[i]; + } + + auto data = create_data().x(x).y(y); + auto plt = ax->points(data); + + ax->xlabel("Pred. Target"); + ax->ylabel("Exp. Target"); + + // the default number of digits for the labels is set as 2 + std::cout << "ytick char: " << ax->max_ytick_char() << std::endl; + std::cout << "max_ytick_char_len: " << ax->max_ytick_char_len() << std::endl; + CHECK(ax->max_ytick_char_len() == 5); + CHECK(ax->font_size() == 18.0f); + CHECK(ax->max_ytick_pixels() == int(ax->max_ytick_char_len() * 18.0 / 1.25)); + + DummyDraw::draw("axis", fig); } + From 34167fd15c3ebbb06fef84497179ba13a26a85ee Mon Sep 17 00:00:00 2001 From: zhongjingjogy Date: Wed, 27 Jul 2022 15:03:20 +0800 Subject: [PATCH 5/7] remove explicit checking for the ylabel position. --- src/frontend/Axis.tcc | 10 ---------- tests/TestAxis.cpp | 7 ------- 2 files changed, 17 deletions(-) diff --git a/src/frontend/Axis.tcc b/src/frontend/Axis.tcc index e8f12f6..232655f 100644 --- a/src/frontend/Axis.tcc +++ b/src/frontend/Axis.tcc @@ -114,16 +114,12 @@ template void Axis::draw_common_ticks(Backend &backend) { m_max_ytick_char = std::string(buffer); } - // std::cout << "buffer: " << buffer << std::endl; backend.text(vfloat2_t(m_pixels.bmin[0] - m_tick_len / 2, pos), buffer, NULL); } m_max_ytick_char_len = max_char_len; - // std::cout << "max_ytick_char_len: " << max_char_len << std::endl; - // std::cout << "max_ytick_char: " << m_max_ytick_char << std::endl; - backend.stroke_color(RGBA(0, 0, 0, 255)); backend.stroke_width(m_style.line_width() / 2); backend.stroke(); @@ -182,12 +178,6 @@ template void Axis::draw_common_ylabel(Backend &backend) { return; } - - // std::cout << "ylabel: " << m_ylabel << std::endl; - // std::cout << "max_ytick_char: " << m_max_ytick_char << std::endl; - // std::cout << "max_ytick_pixels: " << this->max_ytick_pixels() << std::endl; - // std::cout << "max_ytick_char_len: " << this->max_ytick_char_len() << std::endl; - backend.text_align(ALIGN_CENTER | ALIGN_BOTTOM); const vfloat2_t point = vfloat2_t(m_pixels.bmin[0] - this->max_ytick_pixels(), 0.5f * (m_pixels.bmax[1] + m_pixels.bmin[1])); diff --git a/tests/TestAxis.cpp b/tests/TestAxis.cpp index ff82576..077fd33 100644 --- a/tests/TestAxis.cpp +++ b/tests/TestAxis.cpp @@ -167,13 +167,6 @@ TEST_CASE("ylabel position: case 1", "[axis]") { ax->xlabel("Pred. Target"); ax->ylabel("Exp. Target"); - // the default number of digits for the labels is set as 2 - std::cout << "ytick char: " << ax->max_ytick_char() << std::endl; - std::cout << "max_ytick_char_len: " << ax->max_ytick_char_len() << std::endl; - CHECK(ax->max_ytick_char_len() == 5); - CHECK(ax->font_size() == 18.0f); - CHECK(ax->max_ytick_pixels() == int(ax->max_ytick_char_len() * 18.0 / 1.25)); - DummyDraw::draw("axis", fig); } From 0b8b2ee27df4d5f4e15d4320482e8297eeaa31c1 Mon Sep 17 00:00:00 2001 From: zhongjingjogy Date: Thu, 28 Jul 2022 22:15:10 +0800 Subject: [PATCH 6/7] plotting with dash line. --- src/backend/BackendSVG.cpp | 6 ++- src/backend/BackendSVG.hpp | 4 ++ src/frontend/Line.tcc | 1 + src/util/Style.cpp | 7 +++ src/util/Style.hpp | 9 ++++ tests/CMakeLists.txt | 1 + tests/TestLines.cpp | 101 +++++++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 tests/TestLines.cpp diff --git a/src/backend/BackendSVG.cpp b/src/backend/BackendSVG.cpp index a7eeb2f..19aa6eb 100644 --- a/src/backend/BackendSVG.cpp +++ b/src/backend/BackendSVG.cpp @@ -258,6 +258,10 @@ void BackendSVG::clear_tooltip() { m_onmouseout_tooltip.clear(); } +void BackendSVG::stroke_style(const std::string &style) { + m_line_style = "stroke-dasharray=\"" + style + "\""; +} + void BackendSVG::stroke_width(const float lw) { m_linewidth = std::string("stroke-width=\"") + std::to_string(lw) + std::string("\""); @@ -269,7 +273,7 @@ void BackendSVG::fill_color(const RGBA &color) { void BackendSVG::stroke() { m_out << " void Line::draw_plot(Backend &backend) { backend.stroke_color(m_style.color()); backend.stroke_width(m_style.line_width()); + backend.stroke_style(std::to_string(m_style.line_style())); backend.stroke(); } diff --git a/src/util/Style.cpp b/src/util/Style.cpp index 067d461..cfd75f3 100644 --- a/src/util/Style.cpp +++ b/src/util/Style.cpp @@ -37,6 +37,8 @@ namespace trase { float Style::line_width() const noexcept { return m_line_width; } +float Style::line_style() const noexcept { return m_line_style; } + float Style::font_size() const noexcept { return m_font_size; } RGBA Style::color() const noexcept { return m_color; } @@ -48,6 +50,11 @@ Style &Style::line_width(const float lineWidth) noexcept { return *this; } +Style &Style::line_style(const float lineStyle) noexcept { + m_line_style = lineStyle; + return *this; +} + Style &Style::font_size(const float fontSize) noexcept { m_font_size = fontSize; return *this; diff --git a/src/util/Style.hpp b/src/util/Style.hpp index b7473bb..20b2820 100644 --- a/src/util/Style.hpp +++ b/src/util/Style.hpp @@ -45,6 +45,9 @@ class Style { /// the line width float m_line_width{3.f}; + /// the line style + float m_line_style{0.f}; + /// the font size float m_font_size{18.f}; @@ -61,6 +64,9 @@ class Style { /// get the current line width float line_width() const noexcept; + /// get the current line width + float line_style() const noexcept; + /// get the current font size float font_size() const noexcept; @@ -73,6 +79,9 @@ class Style { /// set the new line width Style &line_width(float lineWidth) noexcept; + /// set the new line style + Style &line_style(float lineStyle) noexcept; + /// set the new font size Style &font_size(float fontSize) noexcept; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 86ff642..5d2588e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable ( TestTransformMatrix.cpp TestVector.cpp TestLegend.cpp + TestLines.cpp ) if (CURL_FOUND) diff --git a/tests/TestLines.cpp b/tests/TestLines.cpp new file mode 100644 index 0000000..6082b21 --- /dev/null +++ b/tests/TestLines.cpp @@ -0,0 +1,101 @@ +/* +Copyright (c) 2018, University of Oxford. +All rights reserved. + +University of Oxford means the Chancellor, Masters and Scholars of the +University of Oxford, having an administrative office at Wellington +Square, Oxford OX1 2JD, UK. + +This file is part of the Oxford RSE C++ Template project. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "catch.hpp" + +#include "DummyDraw.hpp" + +#include "trase.hpp" +#include +#include + +using namespace trase; + +TEST_CASE("Lines creation", "[lines]") { + // create figure and axis + auto fig = figure(); + auto ax = fig->axis(); + + // create x and y vectors + const int n = 100; + std::vector x(n); + std::vector y(n); + const float k = 1.f; + auto logistic = [k](const float x) { return 1.f / (1.f + std::exp(-k * x)); }; + for (int i = 0; i < n; ++i) { + x[i] = -6.f + 12.f * static_cast(i) / n; + y[i] = logistic(x[i]); + } + + // create a trase dataset and then plot it using a line geometry + auto data = create_data().x(x).y(y); + auto plt = ax->line(data); + + // set line color = red and line width = 10 + plt->style().color(RGBA(255, 0, 0)).line_width(10).line_style(1.0); + + // label axis + ax->xlabel("x"); + ax->ylabel("y"); + + DummyDraw::draw("lines", fig); +} + +TEST_CASE("Hybrids lines creation", "[lines]") { + + auto fig = figure(); + auto ax = fig->axis(); + + { + auto data = create_data().x(std::vector{0, 1}).y(std::vector{0, 1}); + auto plt = ax->line(data); + plt->style().color(RGBA(255, 0, 0)).line_width(5).line_style(0.0); + } + + { + auto data = create_data().x(std::vector{0, 1}).y(std::vector{0.5, 1.5}); + auto plt = ax->line(data); + plt->style().color(RGBA(255, 0, 0)).line_width(5).line_style(2.0); + } + + { + auto data = create_data().x(std::vector{0, 1}).y(std::vector{-0.5, 0.5}); + auto plt = ax->line(data); + plt->style().color(RGBA(255, 0, 0)).line_width(5).line_style(2.0); + } + + ax->xlabel("Pred. Target"); + ax->ylabel("Exp. Target"); + + DummyDraw::draw("lines", fig); +} From dcaeb783a7f17bddf8498896b70f4db66de12f13 Mon Sep 17 00:00:00 2001 From: zhongjingjogy Date: Fri, 29 Jul 2022 08:20:28 +0800 Subject: [PATCH 7/7] assigned name to the line style. --- src/frontend/Line.tcc | 2 +- src/util/Style.cpp | 13 +++++++++++-- src/util/Style.hpp | 7 ++++--- tests/TestLines.cpp | 8 ++++---- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/frontend/Line.tcc b/src/frontend/Line.tcc index 00dcb2a..255d05c 100644 --- a/src/frontend/Line.tcc +++ b/src/frontend/Line.tcc @@ -174,7 +174,7 @@ template void Line::draw_plot(Backend &backend) { backend.stroke_color(m_style.color()); backend.stroke_width(m_style.line_width()); - backend.stroke_style(std::to_string(m_style.line_style())); + backend.stroke_style(m_style.line_style()); backend.stroke(); } diff --git a/src/util/Style.cpp b/src/util/Style.cpp index cfd75f3..21ae9db 100644 --- a/src/util/Style.cpp +++ b/src/util/Style.cpp @@ -37,7 +37,16 @@ namespace trase { float Style::line_width() const noexcept { return m_line_width; } -float Style::line_style() const noexcept { return m_line_style; } +std::string Style::line_style() const noexcept { + if (m_line_style == "solid") + return "0"; + else if (m_line_style == "dashed") + return "10,5"; + else if (m_line_style == "dotted") + return "10,3,2"; + else + return "0"; +} float Style::font_size() const noexcept { return m_font_size; } @@ -50,7 +59,7 @@ Style &Style::line_width(const float lineWidth) noexcept { return *this; } -Style &Style::line_style(const float lineStyle) noexcept { +Style &Style::line_style(const std::string lineStyle) noexcept { m_line_style = lineStyle; return *this; } diff --git a/src/util/Style.hpp b/src/util/Style.hpp index 20b2820..56b9021 100644 --- a/src/util/Style.hpp +++ b/src/util/Style.hpp @@ -37,6 +37,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define STYLE_H_ #include "util/Colors.hpp" +#include namespace trase { @@ -46,7 +47,7 @@ class Style { float m_line_width{3.f}; /// the line style - float m_line_style{0.f}; + std::string m_line_style{"solid"}; /// the font size float m_font_size{18.f}; @@ -65,7 +66,7 @@ class Style { float line_width() const noexcept; /// get the current line width - float line_style() const noexcept; + std::string line_style() const noexcept; /// get the current font size float font_size() const noexcept; @@ -80,7 +81,7 @@ class Style { Style &line_width(float lineWidth) noexcept; /// set the new line style - Style &line_style(float lineStyle) noexcept; + Style &line_style(std::string lineStyle) noexcept; /// set the new font size Style &font_size(float fontSize) noexcept; diff --git a/tests/TestLines.cpp b/tests/TestLines.cpp index 6082b21..e3cae76 100644 --- a/tests/TestLines.cpp +++ b/tests/TestLines.cpp @@ -62,7 +62,7 @@ TEST_CASE("Lines creation", "[lines]") { auto plt = ax->line(data); // set line color = red and line width = 10 - plt->style().color(RGBA(255, 0, 0)).line_width(10).line_style(1.0); + plt->style().color(RGBA(255, 0, 0)).line_width(10).line_style("dashed"); // label axis ax->xlabel("x"); @@ -79,19 +79,19 @@ TEST_CASE("Hybrids lines creation", "[lines]") { { auto data = create_data().x(std::vector{0, 1}).y(std::vector{0, 1}); auto plt = ax->line(data); - plt->style().color(RGBA(255, 0, 0)).line_width(5).line_style(0.0); + plt->style().color(RGBA(255, 0, 0)).line_width(5).line_style("solid"); } { auto data = create_data().x(std::vector{0, 1}).y(std::vector{0.5, 1.5}); auto plt = ax->line(data); - plt->style().color(RGBA(255, 0, 0)).line_width(5).line_style(2.0); + plt->style().color(RGBA(255, 0, 0)).line_width(5).line_style("dashed"); } { auto data = create_data().x(std::vector{0, 1}).y(std::vector{-0.5, 0.5}); auto plt = ax->line(data); - plt->style().color(RGBA(255, 0, 0)).line_width(5).line_style(2.0); + plt->style().color(RGBA(255, 0, 0)).line_width(5).line_style("dotted"); } ax->xlabel("Pred. Target");