Giter VIP home page Giter VIP logo

trase's Issues

Pointers

I'm still getting to grips with the structure, so might have this wrong.

It looks as though there's a Drawable with a vector of children, and a pointer to parent.

Ought this be a vector of unique_ptr to children, with a raw pointer to parent?

Also, in Figure, is there any need for m_axis to be a shared_ptr rather than unique_ptr?

support for rendering latex equations

I would really like to be able to add latex equations for axis labels, but this seems like it would be very difficult to achieve in pure C++. There seems to be no C++ parsers or renderers for latex. Any ideas for how to do this?

Here is a java library for latex: https://github.com/opencollab/jlatexmath
Here is a "C++" library for latex that laughably just generates javascript (!) and use KaTex to render the equations (perhaps their parser is in C++, I didn't check): https://github.com/goldsborough/latexpp

axis class

  • name: Axis
  • derived from Drawable (#5)
  • draws an axis using set x/y extents

member functions:

  • plot(x, y): create new Plot1D,
  • plot2d(matrix), create new Plot2D
  • sym_plot(lambda f) create new SymPlot1D (uses current axis limits and N=100 points by default)
  • sym_plot2d(lambda f) create new SymPlot2D (uses current axis limits and N=100 points by default)
  • xlim(std::array<float> xlimits) set x limits for axis
  • ylim(std::array<float> xlimits) set y limits for axis
  • xlabel(std::array<float> xlimits) set x label for axis
  • ylabel(std::array<float> xlimits) set y label for axis
  • legend() show Legend

other features:

  • finds closest plot point to cursor and highlights this, creates custom ticks on the axis for this point so user can see exactly what this point is
  • zooming in/out of current cursor position using mouse wheel
  • click and drag of axis to pan the plot

behaviour of circle and rect for different backends

The OpenGL backend uses paths to draw a circle or rect, this is nice cause you can combine the circle or rect with another path, and then set a common stroke/fill combo at the end. But this is costly for the svg backend, which would prefer to write a single circle or rect element. I propose to match the svg behaviour, where the circle and rect functions draw the shapes immediately (so you don't put a stroke or fill command after)

License

Currently this is still

Copyright (c) 2018, University of Oxford.

This file is part of the Oxford RSE C++ Template project.

Do you want this project to be completely separate from RSE @martinjrobins? (Might be nice to write a blog post about it anyway).

initial feature list

  • Figure class #2
  • Axis class #3
  • Drawable class #5
  • Plot1D plot class #4
  • Legend class #11
  • SymPlot1D plot class #6
  • Plot2D class #7
  • SymPlot2D plot class #8
  • BackendGL openGL drawing class #9
  • serialisation to SVG #16

API for aesthetic begin/end functions in DataWithAesthetics

The begin and end functions in DataWithAesthetics use the aesthetic tag classes as arguments to choose an aesthetic, ie.

template <typename Aesthetic>
ColumnIterator DataWithAesthetic::end(const Aesthetic &a);

So they are called like

auto it = data.begin(Aesthetic::x());

I think it is cleaner to use a template argument, like so:

auto it = data.begin<Aesthetic::x>();

resulting in two less round brackets to type. I propose switching to the latter

clang-tidy pointer arithmetic warning

do we want to turn off this warning @fcooper8472 , seems like pointer arithmetic is kinda essential for an iterator!

/home/travis/build/trase-cpp/trase/src/util/ColumnIterator.hpp:92:26: warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
  void increment() { m_p += m_stride; }

1D plot class

  • name: Plot1D
  • derived from Drawable
  • has a vector of N x and y points, draws these on the parent axis along with lines between

member functions:

  • set_values(std::vector<float>&& x, std::vector<float>&& y): takes r-values to the vectors holding x and y, sets the data points to plot, updates limits for self and parent axis
  • set_color(RGBA color): set line color (this might want to be moved to Drawable?)
  • set_linewidth(float pixels): set line width in pixels (this might want to be moved to Drawable? see #41 )
  • set_linestyle(????): set line style. Need to come up with a way of representing a line style (this might want to be moved to Drawable? see #41)

related functions:

  • Axis::plot(const std::vector<T1>& x, const std::vector<T2>& y): creates a Plot1D on the given Axis, adjust limits of axis to make the Plot1D fit. T1 and T2 are convertible to float
  • Axis::plot(std::vector<float>&& x, std::vector<float>&& y): creates a Plot1D on the given Axis using r-value vectors. The data is moved rather than copied.
  • Axis::plot(Container x, Container2 y): creates a Plot1D on the given Axis using any given container
  • Axis::plot(initialiser_list x, initialiser_list y): creates a Plot1D using initialiser lists

symbolic 1D plot class

  • name SymPlot1D
  • plots a function object on its parent Axis using the resolution (n points) provided
  • templated on the function object type, additional parameters to function object are alterable via sliders (see this SO post for tips to count parameters)

member functions:

  • set_n(const int N): set the number of points to plot

related functions:

  • Axis::plot(const F& f): plot a symbolic function on the given Axis. f is the function object, x limits are set by the current axis, N=100 is the default number of points to use when plotting

svg animation using values and keyTimes

Rather than multiple entries with "from"/"to" entries in the svg, it might be neater to use the "values" and "keyTimes" attributes:

values="50; 250; 120;250; 170; 250; 210; 250"
keyTimes="0; 0.15; 0.3; 0.45; 0.6; 0.75; 0.9; 1"

Add encoding information to svg serialization

Here's a useful tool that can determine SVG standards compliance:
https://validator.w3.org/

Currently the test svg is missing encoding information, which should simply look something like
encoding="utf-8" in the document header.

Matplotlib's first line in SVG docs is

<?xml version="1.0" encoding="utf-8" standalone="no"?>

trase currently has

<?xml version="1.0" standalone="no"?>

highlighted points near mouse cursor

One of the current features of the GL backend is to highlight points that are near to the mouse cursor and give their exact x,y values.

  • Currently a few points might be highlighted as they are just chosen from all points within a radius, this should be changed to the closest point within that radius
  • I think the same functionality can be given to the SVG backend, as the SVG spec allows you to specify mouseover events: https://www.w3.org/TR/SVG11/interact.html#SVGEvents

layout of multiple axis on figure

At the moment new axes are created on-top of each other, this should be changed to a sensible default, e.g 2x1 subplots for two plots, 2x2 for 3 or 4 plots, etc., with the user being able to change how the axes are tiled/placed.

histogram geometry

note that histogram geometry will be the first to have a default transform (x-> histogram to -> y)

clang-tidy static storage initialisation

Is the solution to this to add a noexcept to the Colormap constructor?

/home/travis/build/trase-cpp/trase/src/util/Colors.cpp:126:27: warning: initialization of 'viridis' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
const Colormap Colormaps::viridis(std::vector<Vector<float, 3>>{
                          ^
/home/travis/build/trase-cpp/trase/src/util/Colors.cpp:107:11: note: possibly throwing constructor declared here
Colormap::Colormap(std::vector<Vector<float, 3>> list)

styling for Drawables

We need a consistent way of styling axes, plots etc.

I was thinking of a class Style, that is contained in Drawable, and which uses chaining to set its parameters:

class Style {
float m_linewidth;
LineStyle m_linestyle;
RGBA m_color;
std::string m_font;
....
Style& line_width(const float lw);
Style& line_style(const std::string& ls);
Style& color(const RGBA& lw);
};

That way you would write something like:

auto plt = ax->plot(x,y)
plt->style().line_width(3.f).line_style(".-").color(RGBA(0,0,0,255));

Or you could set a consistent style for multiple plots:

auto my_style = create_style().line_width(3.f).line_style(".-").color(RGBA(0,0,0,255)).font("Roboto");
auto plt = ax->plot(x,y)
plt->style() =  my_style.color(blue);
auto plt = ax->plot(x,y)
plt->style() =  my_style.color(green);

thoughts @fcooper8472?

Drawable base class

  • base class for Axis, Plot1D etc

member variables:

  • std::vector<Drawable *> m_children
  • m_area: area as ratio of parent
  • m_pixels: current area as raw pixels
  • m_time_span: maximum time for animation
  • m_times: frame times for animation
  • m_time: current time for animation

member functions:

  • void resize(const std::array<float, 4> &parent_pixels): resize itself and its children
  • template <typename Backend> void draw(Backend &backend): draw itself and its children
  • add_frame(time): add a new animation frame
  • float get_frame_index(): get frame index associated with current time (as a float, could be in-between frames)
  • set_time(time): set current animation time
  • 'std::string to_svg()`: create a string to represent the object in the SVG format #16

figure class

name: Figure

  • set the window title as "Figure X", where X is the figure id
  • holds an axis (#3) object.

member functions:

  • save(const char *filename): save to filename (requires #10)
  • show(Backend& backend): This draws the figure using the given backend, control of main program is suspended until the figure is closed.
  • axis(): returns the figure axis as std::shared_ptr<Axis>

related functions:

  • figure(): creates new figure, returns std::shared_ptr<Figure>.

symbolic 2D plot class

  • name SymPlot2D
  • plots a 2d image or heatmap defined by a C++ function object to the parent Axis
  • similar to SymPlot, templated on function object, and other parameters of function are modifiable via sliders

related functions:

  • Axis::plot2d(const F& f, int N, std::array<float, 4> limits): creates a SymPlot2D on the current axis. N is the number of points to use along each axis (so N*N points in total), limits gives the x-y min and max limits that the data is plotted over
  • Axis::plot2d(const F& f, int N): creates a SymPlot2D on the current axis. N is the number of points to use along each axis (so N*N points in total), uses the current limits of the axis
  • Axis::plot2d(const F& f): creates a SymPlot2D on the current axis. N=50 is the number of points to use, uses the current limits of the axis

Web font support in svg backend

Would be good to optionally link-in web fonts (such as Google fonts) when using the SVG backend.

This will require:

  1. A method to add an attribute to the svg such as:
<style type="text/css">
    @import url('https://fonts.googleapis.com/css?family=Indie+Flower');
</style>
  1. The ability to change the font wherever fonts are passed in to the backend (currently just in Axis::draw_common. This might be best as a method on the axis class that fills in a new member variable on the axis class.

Make use of new vector member on

Due to #32 there is now a std::vector<std::shared_ptr<Axis>> m_axes; in Figure.

As a result there are several calls to m_axes.back() littered through the code. Some clearly ought to be replaced by a loop over all axes, but some are less clear:

m_axes.back()->serialise(backend);

Image geometry

  • name: Image
  • plot a 2D matrix of values to the screen as an image or a heatmap
  • derived from Drawable

related functions:

  • Axis::image(DataWithAesthetics data, Transform transform = Transform(Identity)): creates a Image on the current axis.

2d vector class

currently using std::array<float,2> for 2d vectors, should do a proper 2d vector class that can do common vector operations in order to make the code more readable

fonts for BackendGL need to match functionality in svg backend

At the moment, the BackendGL uses a single font that must be in the a hard-coded directory. Be nice if the functionality was the same as the SVG backend. I.e. can use any of the locally install fonts, or perhaps even download a web font if requested.

2d bounding box class for Axis

The Axis class uses std::array<float,4> for its xy limits [xmin,ymin,xmax,ymax]. This should be a separate bounding box class, which allows for:

  • adding bounding boxes together to get the minimum box enclosing both: ie. [0,0,1,1] + [0.5,0.5,2,2] = [0,0,2,2]
  • translating bounding box by an 2d vector
  • scaling bounding box by a scalar amount

plots not restricted to axis

if Plot1D lines are outside the current Axis limits, they are drawn outside the axis, only lines within the axis should be drawn

Adding attributes to tags in svg backend

I would like to implement some helper to make this kind of thing look less nasty (easier to read, reason about, and maintain):

m_out << "x=\"" << min[0] << "\" y=\"" << min[1] << "\" width=\"" << delta[0] << "\" height=\"" << delta[1] << "\" ";

There are several possible options.

1. Function template, something like:

template<typename T>
std::string att(const std::string& name, const T val)
{
  std::stringstream ss;
  ss << std::setprecision(5) << name << "=\"" << val << "\" ";
  return ss.str();
}

so that the above example becomes

m_out << att("x", min[0]) << att("y", min[1]) << att("width", delta[0]) << att("height", delta[1]); 

This looks quite nice, and is certainly much easier to read. But, the overhead of generating lots of stringstream objects and returning strings is high (~2x slower). Speed probably isn't a massive concern at this stage, but let's avoid massive slowdowns if there's a better option.

2. As above, but sending straight to m_out:

I don't like this option at all, because the example becomes:

att("x", min[0]); att("y", min[1]); att("width", delta[0]); att("height", delta[1]); 

It's super unclear at a glance what's happening and doesn't have any flexibility at all.

3. A small class for gathering attributes:

struct attribs {
  std::stringstream ss;
  attribs& add(const std::string& name, const float val) {
    ss << std::setprecision(5) << name << "=\"" << val << "\" ";
    return *this;
  }
  /* overload << */
};

The example becomes

attribs att;
att.add("x", min[0]).add("y", min[1]).add("width", delta[0]).add("height", delta[1]);
m_out << att;

This has a greatly reduced cost vs 1, is flexible, but perhaps not the most elegant.

@martinjrobins Any other ideas for how this might look?

makes naming of draw functions and backends more meaningful

Makes some function names more meaningful, and groups backends into Backend, and AnimatedBackend concepts.

  • serialise -> draw
  • change template args that require animated backends to AnimatedBackend
  • derive BackendSVG from a base class AnimatedBackend, which is derived from Backend
  • derive BackendGL from a base class Backend

Add svg backend tests

We ought to unit test the svg backend methods. Simple things will be very straightforward, like

  SECTION("finalise produces correct string") {
    backend.finalise();
    CHECK(out.str() == "</svg>\n");
  }

For functions taking arguments, such as circle, we can check that specific parameter values end up as expected in the resulting string.

Cairo backend

need to write a cairo backend similar to #9 to, for example, write plots to svg files

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.