Skip to content

Commit fc4dab5

Browse files
committed
core: add Tufte minimal style profile and example
1 parent c58ab8f commit fc4dab5

5 files changed

Lines changed: 122 additions & 1 deletion

File tree

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ if(BUILD_EXAMPLES)
8686

8787
add_executable(stats_plot_examples examples/stats_plot_examples.cpp)
8888
target_link_libraries(stats_plot_examples PRIVATE gnuplotpp::gnuplotpp)
89+
90+
add_executable(tufte_minimal_example examples/tufte_minimal_example.cpp)
91+
target_link_libraries(tufte_minimal_example PRIVATE gnuplotpp::gnuplotpp)
8992
endif()
9093

9194
if(BUILD_TESTING)

examples/tufte_minimal_example.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#include "gnuplotpp/gnuplot_backend.hpp"
2+
#include "gnuplotpp/logging.hpp"
3+
#include "gnuplotpp/plot.hpp"
4+
#include "gnuplotpp/presets.hpp"
5+
6+
#include <cmath>
7+
#include <filesystem>
8+
#include <string>
9+
#include <vector>
10+
11+
int main(int argc, char** argv) {
12+
using namespace gnuplotpp;
13+
14+
std::filesystem::path out_dir = "out/tufte_minimal_example";
15+
for (int i = 1; i < argc; ++i) {
16+
const std::string arg = argv[i];
17+
if (arg == "--out" && i + 1 < argc) {
18+
out_dir = argv[++i];
19+
}
20+
}
21+
22+
FigureSpec fs;
23+
fs.preset = Preset::Custom;
24+
apply_preset_defaults(fs);
25+
apply_style_profile(fs, StyleProfile::Tufte_Minimal);
26+
fs.size = FigureSizeInches{.w = 5.6, .h = 3.1};
27+
fs.formats = {OutputFormat::Pdf, OutputFormat::Png, OutputFormat::Svg};
28+
fs.title.clear();
29+
fs.auto_layout = true;
30+
fs.text_mode = TextMode::Enhanced;
31+
32+
Figure fig(fs);
33+
34+
AxesSpec ax;
35+
ax.xlabel = "Time [s]";
36+
ax.ylabel = "Normalized response";
37+
ax.legend = false;
38+
ax.grid = false;
39+
ax.has_xlim = true;
40+
ax.xmin = 0.0;
41+
ax.xmax = 20.0;
42+
ax.has_ylim = true;
43+
ax.ymin = 0.0;
44+
ax.ymax = 1.15;
45+
ax.has_xtick_step = true;
46+
ax.xtick_step = 5.0;
47+
ax.has_ytick_step = true;
48+
ax.ytick_step = 0.2;
49+
ax.gnuplot_commands = {
50+
"set border 3 linewidth 0.8 linecolor rgb '#1c1c1c'",
51+
"unset key",
52+
"set tics out nomirror",
53+
"set arrow 10 from graph 0, first 1.0 to graph 1, first 1.0 nohead lc rgb '#a8a8a8' dt 3 lw 0.9 back"};
54+
fig.axes(0).set(ax);
55+
56+
std::vector<double> t;
57+
std::vector<double> baseline;
58+
std::vector<double> treatment;
59+
t.reserve(320);
60+
baseline.reserve(320);
61+
treatment.reserve(320);
62+
63+
for (int i = 0; i < 320; ++i) {
64+
const double x = 20.0 * static_cast<double>(i) / 319.0;
65+
t.push_back(x);
66+
baseline.push_back(1.0 - 0.42 * std::exp(-0.20 * x));
67+
treatment.push_back(1.0 - 0.68 * std::exp(-0.34 * x));
68+
}
69+
70+
fig.axes(0).add_series(SeriesSpec{.label = "", .has_line_width = true, .line_width_pt = 2.2}, t, baseline);
71+
fig.axes(0).add_series(
72+
SeriesSpec{.label = "",
73+
.has_line_width = true,
74+
.line_width_pt = 2.2,
75+
.has_color = true,
76+
.color = "#4a4a4a"},
77+
t,
78+
treatment);
79+
80+
const double x_label = 18.6;
81+
ax.gnuplot_commands.push_back("set label 10 'Baseline' at " + std::to_string(x_label) + "," +
82+
std::to_string(baseline.back() + 0.035) +
83+
" font 'Helvetica,10' textcolor rgb '#111111'");
84+
ax.gnuplot_commands.push_back("set label 11 'Treatment' at " + std::to_string(x_label) + "," +
85+
std::to_string(treatment.back() - 0.05) +
86+
" font 'Helvetica,10' textcolor rgb '#4a4a4a'");
87+
fig.axes(0).set(ax);
88+
89+
fig.set_backend(make_gnuplot_backend());
90+
const auto result = fig.save(out_dir / "figures");
91+
if (!result.ok) {
92+
gnuplotpp::log::Error("plot render incomplete: ", result.message);
93+
return 1;
94+
}
95+
for (const auto& output : result.outputs) {
96+
gnuplotpp::log::Info("output: ", output.string());
97+
}
98+
return 0;
99+
}

include/gnuplotpp/presets.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
namespace gnuplotpp {
66

77
/** @brief High-level style bundles for common publication/presentation looks. */
8-
enum class StyleProfile { Science, IEEE_Strict, AIAA_Strict, Presentation, DarkPrintSafe };
8+
enum class StyleProfile {
9+
Science,
10+
IEEE_Strict,
11+
AIAA_Strict,
12+
Presentation,
13+
DarkPrintSafe,
14+
Tufte_Minimal
15+
};
916

1017
/** @brief Resolved size/style defaults for one preset. */
1118
struct PresetDefaults {

src/presets.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ void apply_style_profile(FigureSpec& spec, StyleProfile profile) {
126126
spec.style.grid = true;
127127
spec.palette = ColorPalette::Grayscale;
128128
break;
129+
case StyleProfile::Tufte_Minimal:
130+
spec.style.font = "Helvetica";
131+
spec.style.font_pt = 10.0;
132+
spec.style.line_width_pt = 1.8;
133+
spec.style.point_size = 0.6;
134+
spec.style.grid = false;
135+
spec.palette = ColorPalette::Grayscale;
136+
break;
129137
}
130138
}
131139

tests/api_test.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ int main() {
7171
apply_style_profile(spec, StyleProfile::Presentation);
7272
assert(spec.palette == ColorPalette::Viridis);
7373
assert(spec.style.font_pt >= 12.0);
74+
apply_style_profile(spec, StyleProfile::Tufte_Minimal);
75+
assert(spec.palette == ColorPalette::Grayscale);
76+
assert(!spec.style.grid);
77+
assert(spec.style.line_width_pt >= 1.5);
7478

7579
FigureSpec built_spec = FigureBuilder(spec).layout(1, 1).manifest(true).spec();
7680
assert(built_spec.write_manifest);

0 commit comments

Comments
 (0)