Skip to content

Commit

Permalink
Merge pull request #302 from ABRG-Models/dev/graph_with_right_axis
Browse files Browse the repository at this point in the history
Enable graphs of data with only a right axis
  • Loading branch information
sebjameswml authored Dec 6, 2024
2 parents 3d2109e + af1334f commit 2eb1f2f
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 22 deletions.
6 changes: 6 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,12 @@ if(USE_GLEW)
target_link_libraries(graph_twinax GLEW::GLEW)
endif()

add_executable(graph_rightaxis graph_rightaxis.cpp)
target_link_libraries(graph_rightaxis OpenGL::GL glfw Freetype::Freetype)
if(USE_GLEW)
target_link_libraries(graph_rightaxis GLEW::GLEW)
endif()

add_executable(graph_dynamic_sine graph_dynamic_sine.cpp)
target_link_libraries(graph_dynamic_sine OpenGL::GL glfw Freetype::Freetype)
if(USE_GLEW)
Expand Down
34 changes: 34 additions & 0 deletions examples/graph_rightaxis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// A graph with the axis on the right
#include <morph/Visual.h>
#include <morph/GraphVisual.h>
#include <morph/vvec.h>

using morph::unicode;

int main()
{
// Set up a morph::Visual 'scene environment'.
morph::Visual v(1024, 768, "Right-axis only GraphVisual example");
// Create a new GraphVisual with offset within the scene of 0,0,0
auto gv = std::make_unique<morph::GraphVisual<double>> (morph::vec<float>({0,0,0}));
v.bindmodel (gv);
gv->axisstyle = morph::axisstyle::box; // rather than twinax;
// Data for the x axis. A vvec is like std::vector, but with built-in maths methods
morph::vvec<double> x;
// This works like numpy's linspace() (the 3 args are "start", "end" and "num"):
x.linspace (-0.5, 0.8, 14);

// Set a graph up of x^3
std::string ds1legend = unicode::toUtf8 (unicode::alpha) + "(x) = x" + unicode::toUtf8 (unicode::ss3);
gv->setdata (x, x.pow(3), ds1legend, morph::axisside::right);
gv->ylabel = unicode::toUtf8 (unicode::alpha);

// finalize() makes the GraphVisual compute the vertices of the OpenGL model
gv->finalize();
// Add the GraphVisual OpenGL model to the Visual scene
v.addVisualModel (gv);
// Render the scene on the screen until user quits with 'Ctrl-q'
v.keepOpen();
// When v goes out of scope, gv will be deallocated
return 0;
}
30 changes: 20 additions & 10 deletions morph/GraphVisual.h
Original file line number Diff line number Diff line change
Expand Up @@ -1355,7 +1355,7 @@ namespace morph {
this->texts.push_back (std::move(lbl));
}
}
if (this->axisstyle == axisstyle::twinax && !this->omit_y_tick_labels) {
if ((this->axisstyle == axisstyle::twinax || !this->ytick_posns2.empty()) && !this->omit_y_tick_labels) {
x_for_yticks = this->width;
this->ytick_label_width2 = 0.0f;
for (unsigned int i = 0; i < this->ytick_posns2.size(); ++i) {
Expand Down Expand Up @@ -1473,7 +1473,7 @@ namespace morph {
{this->width + tl, (float)yt, -this->thickness}, this->uz,
this->axiscolour, this->axislinewidth*0.5f);
}
} else if (this->axisstyle == axisstyle::twinax) {
} else if (this->axisstyle == axisstyle::twinax || !this->ytick_posns2.empty()) {
// Draw ticks for y2
for (auto yt : this->ytick_posns2) {
this->computeFlatLine ({this->width, (float)yt, -this->thickness},
Expand Down Expand Up @@ -1699,14 +1699,22 @@ namespace morph {
if (this->manualticks == true) {
std::cout << "Writeme: Implement a manual tick-setting scheme\n";
} else {
if (!(this->abscissa_scale.ready() && this->ord1_scale.ready())) {
if (this->ord2_scale.ready()) {
if (!this->abscissa_scale.ready()) {
throw std::runtime_error ("abscissa scale is not set (though ord2 scale is set). Is there abscissa (x) data?");
}
} else if (!(this->abscissa_scale.ready() && this->ord1_scale.ready())) {
throw std::runtime_error ("abscissa and ordinate scales not set. Is there data?");
}
// Compute locations for ticks...
Flt _xmin = this->abscissa_scale.inverse_one (this->abscissa_scale.output_range.min);
Flt _xmax = this->abscissa_scale.inverse_one (this->abscissa_scale.output_range.max);
Flt _ymin = this->ord1_scale.inverse_one (this->ord1_scale.output_range.min);
Flt _ymax = this->ord1_scale.inverse_one (this->ord1_scale.output_range.max);
Flt _ymin = Flt{0};
Flt _ymax = Flt{1};
if (this->ord1_scale.ready()) {
_ymin = this->ord1_scale.inverse_one (this->ord1_scale.output_range.min);
_ymax = this->ord1_scale.inverse_one (this->ord1_scale.output_range.max);
}
Flt _ymin2 = Flt{0};
Flt _ymax2 = Flt{1};
if (this->ord2_scale.ready()) {
Expand All @@ -1724,11 +1732,13 @@ namespace morph {
this->xtick_posns.resize (this->xticks.size());
this->abscissa_scale.transform (xticks, xtick_posns);

realmin = this->ord1_scale.inverse_one (0);
realmax = this->ord1_scale.inverse_one (this->height);
this->yticks = this->maketicks (_ymin, _ymax, realmin, realmax, this->num_ticks_range);
this->ytick_posns.resize (this->yticks.size());
this->ord1_scale.transform (yticks, ytick_posns);
if (this->ord1_scale.ready()) {
realmin = this->ord1_scale.inverse_one (0);
realmax = this->ord1_scale.inverse_one (this->height);
this->yticks = this->maketicks (_ymin, _ymax, realmin, realmax, this->num_ticks_range);
this->ytick_posns.resize (this->yticks.size());
this->ord1_scale.transform (yticks, ytick_posns);
}

if (this->ord2_scale.ready()) {
realmin = this->ord2_scale.inverse_one (0);
Expand Down
24 changes: 12 additions & 12 deletions morph/scale.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,10 @@ namespace morph {
virtual S transform_one (const T& datum) const
{
if (this->type != scaling_function::Linear) {
throw std::runtime_error ("This transform function is for Linear scaling only");
throw std::runtime_error ("scale_impl<0=vector>::transform_one(): This transform function is for Linear scaling only");
}
if (params.size() != 2) {
throw std::runtime_error ("For linear scaling of ND vector lengths, need 2 params (set do_autoscale or call setParams())");
throw std::runtime_error ("scale_impl<0=vector>::transform_one(): For linear scaling of ND vector lengths, need 2 params (set do_autoscale or call setParams())");
}
S rtn(datum);
T_el vec_len = this->vec_length (datum);
Expand Down Expand Up @@ -364,7 +364,7 @@ namespace morph {
} else if (this->type == scaling_function::Linear) {
rtn = this->inverse_one_linear (datum);
} else {
throw std::runtime_error ("Unknown scaling");
throw std::runtime_error ("scale_impl<0=vector>::inverse_one(): Unknown scaling");
}
return rtn;
}
Expand All @@ -380,7 +380,7 @@ namespace morph {
virtual void compute_scaling (const T input_min, const T input_max)
{
if (this->type != scaling_function::Linear) {
throw std::runtime_error ("This scaling function is for Linear scaling only");
throw std::runtime_error ("scale_impl<0=vector>::compute_scaling)(): This scaling function is for Linear scaling only");
}
this->params.resize (2, T_el{0});
// Vector version: get lengths of input_min/max
Expand Down Expand Up @@ -445,7 +445,7 @@ namespace morph {
//! The inverse linear transform; x = (y-c)/m
T inverse_one_linear (const T& datum) const
{
if (this->params.size() < 2) { throw std::runtime_error ("Scaling params not set"); }
if (this->params.size() < 2) { throw std::runtime_error ("scale_impl<0=vector>::inverse_one_linear(): scaling params not set"); }
T rtn (datum);
std::size_t i = 0;
for (auto el : datum) {
Expand Down Expand Up @@ -499,7 +499,7 @@ namespace morph {
} else if (this->type == scaling_function::Linear) {
rtn = this->transform_one_linear (datum);
} else {
throw std::runtime_error ("Unknown scaling");
throw std::runtime_error ("scale_impl<1=scalar>::transform_one(): Unknown scaling");
}
return rtn;
}
Expand Down Expand Up @@ -533,7 +533,7 @@ namespace morph {
} else if (this->type == scaling_function::Linear) {
rtn = this->inverse_one_linear (datum);
} else {
throw std::runtime_error ("Unknown scaling");
throw std::runtime_error ("scale_impl<1=scalar>::inverse_one(): Unknown scaling");
}
return rtn;
}
Expand All @@ -553,7 +553,7 @@ namespace morph {
} else if (this->type == scaling_function::Linear) {
this->compute_scaling_linear (input_min, input_max);
} else {
throw std::runtime_error ("Unknown scaling");
throw std::runtime_error ("scale_impl<1=scalar>::compute_scaling(): Unknown scaling");
}
}

Expand Down Expand Up @@ -589,7 +589,7 @@ namespace morph {
//! Linear transform for scalar type; y = mx + c
S transform_one_linear (const T& datum) const
{
if (this->params.size() < 2) { throw std::runtime_error ("Scaling params not set"); }
if (this->params.size() < 2) { throw std::runtime_error ("scale_impl<1=scalar>::transform_one_linear(): (scalar) scaling params not set"); }
return (datum * this->params[0] + this->params[1]);
}

Expand All @@ -602,7 +602,7 @@ namespace morph {
//! The inverse linear transform; x = (y-c)/m
T inverse_one_linear (const S& datum) const
{
if (this->params.size() < 2) { throw std::runtime_error ("Scaling params not set"); }
if (this->params.size() < 2) { throw std::runtime_error ("scale_impl<1=scalar>::inverse_one_linear(): (scalar) scaling params not set"); }
return ((datum-this->params[1])/this->params[0]);
}

Expand Down Expand Up @@ -634,7 +634,7 @@ namespace morph {
// Have to check here as scale_impl<2, T, S> is built from scale_impl<1, T, S> but <= operator makes no sense
if constexpr (morph::number_type<T>::value == 1) {
if (input_min <= T{0} || input_max <= T{0}) {
throw std::runtime_error ("Can't logarithmically autoscale a range which includes zeros or negatives");
throw std::runtime_error ("scale_impl<1=scalar>::compute_scaling_log(): Can't logarithmically autoscale a range which includes zeros or negatives");
}
}
T ln_imin = std::log(input_min);
Expand Down Expand Up @@ -702,7 +702,7 @@ namespace morph {
{
// Log scaling complex range?
if (std::abs(input_min) == T{0} || std::abs(input_max) == T{0}) {
throw std::runtime_error ("Can't logarithmically autoscale a complex range which includes zeros");
throw std::runtime_error ("scale_impl<2, T, S>::compute_scaling_log(): Can't logarithmically autoscale a complex range which includes zeros");
}
T ln_imin = std::log(input_min);
T ln_imax = std::log(input_max);
Expand Down

0 comments on commit 2eb1f2f

Please sign in to comment.