From 86cf4c970bd6ad0fa90d503b0c9875afa1f184dd Mon Sep 17 00:00:00 2001
From: adisidev <64905594+adisidev@users.noreply.github.com>
Date: Sun, 1 Jun 2025 08:44:37 +0800
Subject: [PATCH 1/4] Add req.txt, instruct activating the venv
---
README.md | 3 ++-
requirements.txt | 4 ++++
2 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 requirements.txt
diff --git a/README.md b/README.md
index 485ecd0e..ce420560 100644
--- a/README.md
+++ b/README.md
@@ -55,10 +55,11 @@ We manage dependencies with a Python virtual environment and Conan 2. The projec
Only `Debug` build commands are shown below, but the same commands can be run with `Release` build by replacing `Debug` with `Release`.
-1. Create a virtual environment with the required dependencies:
+1. Create a virtual environment with the required dependencies and activate it:
``` shell
virtualenv .venv && .venv/bin/pip install -r requirements.txt
+source .venv/bin/activate
```
2. Setup Conan
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..4c8687e3
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,4 @@
+conan==2.16.1
+cmake==3.30.0
+pip
+wheel
From 70c9f580957fc0dc4da310b9d93033b9b605cd97 Mon Sep 17 00:00:00 2001
From: amishn2008 <168089586+amishn2008@users.noreply.github.com>
Date: Sun, 1 Jun 2025 09:15:57 +0800
Subject: [PATCH 2/4] Add link under the cartogram image
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index ce420560..495f1399 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
+The website can be accessed using this link.
This program uses the fast flow-based method developed by Michael T. Gastner, Vivien Seguy, and Pratyush More. For more information, you may refer to the following [paper](https://www.pnas.org/content/115/10/E2156):
From de109959c6056f44f118c8ad33141cd20fc6362f Mon Sep 17 00:00:00 2001
From: amishn2008 <168089586+amishn2008@users.noreply.github.com>
Date: Sun, 8 Jun 2025 10:27:24 +0800
Subject: [PATCH 3/4] Add link and instructions for repo or website
---
README.md | 1 +
src/cartogram_info/cartogram_info.cpp | 6 ++++++
src/draw/draw.cpp | 21 +++++++++++++++++++++
src/main.cpp | 4 ++++
4 files changed, 32 insertions(+)
diff --git a/README.md b/README.md
index 495f1399..35d279ae 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,7 @@
The website can be accessed using this link.
+This repository contains the underlying C++ program that powers go-cart.io. If you'd only like to create a cartogram, you may find it easier to visit the website directly. Otherwise, if you'd like to make code contributions, feature suggestions and/or play with the inner workings of our cartogram generator, you're at the right place!
This program uses the fast flow-based method developed by Michael T. Gastner, Vivien Seguy, and Pratyush More. For more information, you may refer to the following [paper](https://www.pnas.org/content/115/10/E2156):
diff --git a/src/cartogram_info/cartogram_info.cpp b/src/cartogram_info/cartogram_info.cpp
index 08762d12..7d7d3e1c 100644
--- a/src/cartogram_info/cartogram_info.cpp
+++ b/src/cartogram_info/cartogram_info.cpp
@@ -435,6 +435,12 @@ void CartogramInfo::write_shifted_insets()
void CartogramInfo::write_svg(const std::string &suffix)
{
+ // Skip SVG creation if output is being redirected to stdout
+
+ if (args_.redirect_exports_to_stdout) {
+ return;
+ }
+
InsetState insets_combined = convert_to_inset_state();
insets_combined.rescale_map();
diff --git a/src/draw/draw.cpp b/src/draw/draw.cpp
index 041c11e7..fb9e8a17 100644
--- a/src/draw/draw.cpp
+++ b/src/draw/draw.cpp
@@ -72,6 +72,13 @@ void InsetState::write_delaunay_triangles(
const std::string &filename,
const bool draw_projected_points)
{
+
+
+
+ // Skip if redirecting to stdout
+ if (args_.redirect_exports_to_stdout) {
+ return;
+ }
std::cerr << "Writing " << filename << ".svg" << std::endl;
Canvas cvs(filename + ".svg", lx_, ly_);
@@ -118,6 +125,10 @@ void InsetState::write_delaunay_triangles(
void InsetState::write_quadtree(const std::string &filename)
{
+ // Skip if redirecting to stdout
+ if (args_.redirect_exports_to_stdout) {
+ return;
+ }
std::cerr << "Writing " << filename << ".svg" << std::endl;
Canvas cvs(filename + ".svg", lx_, ly_);
@@ -135,6 +146,10 @@ void InsetState::write_quadtree(const std::string &filename)
void InsetState::write_intersections_image()
{
+ // Skip if redirecting to stdout
+ if (args_.redirect_exports_to_stdout) {
+ return;
+ }
unsigned int res = intersections_resolution;
std::string svg_name = inset_name() + "_intersections_" +
std::to_string(n_finished_integrations()) + ".svg";
@@ -165,6 +180,12 @@ void InsetState::write_map(
const bool equal_area_map,
const std::unordered_map vectors) const
{
+ std::cerr << "Redirect value: " << args_.redirect_exports_to_stdout << std::endl;
+
+ // Skip if redirecting to stdout
+ if (args_.redirect_exports_to_stdout) {
+ return;
+ }
const auto svg_name = file_name + ".svg";
std::cerr << "Writing " << svg_name << std::endl;
diff --git a/src/main.cpp b/src/main.cpp
index cf62e2d7..3195bf55 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2,8 +2,12 @@
#include "parse_arguments.hpp"
#include "progress_tracker.hpp"
+
int main(const int argc, const char *argv[])
{
+
+ std::cerr << "Cartogram C++ version 0.1.0" << std::endl;
+
// Parse command-line arguments
Arguments args = parse_arguments(argc, argv);
From d079fac66699f6911666a86611d39eb489b5bc3b Mon Sep 17 00:00:00 2001
From: amishn2008 <168089586+amishn2008@users.noreply.github.com>
Date: Sun, 8 Jun 2025 10:38:04 +0800
Subject: [PATCH 4/4] Allow Scientific Notation for CSV Files
---
include/string_to_decimal_converter.hpp | 14 ++++
src/misc/string_to_decimal_converter.cpp | 90 ++++++++++++++++++++----
2 files changed, 90 insertions(+), 14 deletions(-)
diff --git a/include/string_to_decimal_converter.hpp b/include/string_to_decimal_converter.hpp
index 8d4a741f..fc6ff2b1 100644
--- a/include/string_to_decimal_converter.hpp
+++ b/include/string_to_decimal_converter.hpp
@@ -4,6 +4,20 @@
#include
#include
+/**
+ * @brief A utility class for converting string representations of numbers to decimal format.
+ *
+ * This class handles various number formats including:
+ * - Regular decimal numbers (e.g. "123.456", "123,456")
+ * - Scientific notation (e.g. "1.23e-4", "1.23E4")
+ * - Special value "NA"
+ *
+ * For scientific notation:
+ * - Both 'e' and 'E' are supported as exponent markers
+ * - The mantissa can use either '.' or ',' as decimal separator
+ * - The exponent must be an integer and can be negative
+ * - The mantissa must be a valid decimal number
+ */
class StringToDecimalConverter
{
private:
diff --git a/src/misc/string_to_decimal_converter.cpp b/src/misc/string_to_decimal_converter.cpp
index 29e6b322..2967af43 100644
--- a/src/misc/string_to_decimal_converter.cpp
+++ b/src/misc/string_to_decimal_converter.cpp
@@ -7,7 +7,7 @@ const std::string StringToDecimalConverter::NA_ = "NA";
bool StringToDecimalConverter::is_valid_char(char ch)
{
- return (std::isdigit(ch)) || ch == point_ || ch == comma_ || ch == minus_;
+ return (std::isdigit(ch)) || ch == point_ || ch == comma_ || ch == minus_ || ch == 'e' || ch == 'E';
}
std::string StringToDecimalConverter::remove_char(std::string str, char ch)
@@ -87,22 +87,66 @@ bool StringToDecimalConverter::is_str_valid_characters(const std::string &str)
return true;
}
- // Only 0 to 9, '.', '-', and ',' are allowed
+ // Only 0 to 9, '.', '-', ',', 'e', and 'E' are allowed
for (const auto &c : str) {
if (!is_valid_char(c)) {
return false;
}
}
- // '-' can only be used once
- if (count_char(str, minus_) > 1) {
- return false;
+ // '-' can only be used once in the mantissa and once in the exponent
+ size_t first_e = str.find_first_of("eE");
+ if (first_e != std::string::npos) {
+ // Check mantissa part
+ std::string mantissa = str.substr(0, first_e);
+ if (count_char(mantissa, minus_) > 1) {
+ return false;
+ }
+ if (count_char(mantissa, minus_) == 1 && mantissa[0] != minus_) {
+ return false;
+ }
+ // Check exponent part
+ std::string exponent = str.substr(first_e + 1);
+ if (count_char(exponent, minus_) > 1) {
+ return false;
+ }
+ if (count_char(exponent, minus_) == 1 && exponent[0] != minus_) {
+ return false;
+ }
+ } else {
+ // No scientific notation, check as before
+ if (count_char(str, minus_) > 1) {
+ return false;
+ }
+ if (count_char(str, minus_) == 1 && str[0] != minus_) {
+ return false;
+ }
}
- // '-' can only be used at the beginning
- if (count_char(str, minus_) == 1 and str[0] != minus_) {
+ // Check for valid scientific notation format
+ size_t e_count = count_char(str, 'e') + count_char(str, 'E');
+ if (e_count > 1) {
return false;
}
+ if (e_count == 1) {
+ size_t e_pos = str.find_first_of("eE");
+ // Must have digits before and after 'e'/'E'
+ if (e_pos == 0 || e_pos == str.length() - 1) {
+ return false;
+ }
+ // Must have at least one digit after 'e'/'E'
+ bool has_digit_after = false;
+ for (size_t i = e_pos + 1; i < str.length(); i++) {
+ if (std::isdigit(str[i])) {
+ has_digit_after = true;
+ break;
+ }
+ }
+ if (!has_digit_after) {
+ return false;
+ }
+ }
+
return true;
}
@@ -111,19 +155,37 @@ bool StringToDecimalConverter::is_str_correct_format(const std::string &str)
assert(is_str_valid_characters(str));
assert(is_str_NA(str) == false);
- // if the number of commas and points both are more than 1, then this format
- // does not belong to any known convention
+ // Handle scientific notation separately
+ size_t e_pos = str.find_first_of("eE");
+ if (e_pos != std::string::npos) {
+ // Check mantissa part
+ std::string mantissa = str.substr(0, e_pos);
+ if (has_multiple_commas_and_points(mantissa)) {
+ return false;
+ }
+ if (has_invalid_comma_point_sequence(mantissa)) {
+ return false;
+ }
+ if (has_separator_at_the_end(mantissa)) {
+ return false;
+ }
+ // Exponent part should only contain digits and optional minus sign
+ std::string exponent = str.substr(e_pos + 1);
+ for (char c : exponent) {
+ if (!std::isdigit(c) && c != minus_) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Original format validation for non-scientific notation
if (has_multiple_commas_and_points(str)) {
return false;
}
-
- // Check for commas before and after a point, or points before and after a
- // comma
if (has_invalid_comma_point_sequence(str)) {
return false;
}
-
- // Check for separators at the end of the string
if (has_separator_at_the_end(str)) {
return false;
}