Giter Site home page Giter Site logo

Design of a plotting library about fig HOT 8 OPEN

certik avatar certik commented on August 16, 2024
Design of a plotting library

from fig.

Comments (8)

johandweber avatar johandweber commented on August 16, 2024 2

chart

from fig.

everythingfunctional avatar everythingfunctional commented on August 16, 2024

Here's my initial thoughts on the current design and where I think it ought to go.

The current "API" does not really assume bitmap as the underlying representation, which is good. The current implementation really does kind of assume bitmap as the underlying representation, which will mean some significant refactoring, which I think to a degree will motivate some adjustments to the API.

Also, the current API is very procedural. Create a canvas, draw a thing on it, draw another thing on it, have it output to somewhere. I'm not suggesting that's necessarily the wrong approach, but I wonder if there is a more declarative style that could be explored for the API.

I certainly agree that we should have some sort of intermediate representation that at least resembles vector graphics. Now here comes the question in terms of design. How do the API, intermediate representation, canvas, and backends interact with eachother. Some options.

A canvas is an abstract type, that supports the user API, and backends are implementations of that type. The intermediate representation is then a shared implementation detail of different backends. This has the benefit that different implementations can be optimized quite easily, but at the cost of maintainability, because adding to the API requires that all backends be immediately updated to account for the new feature.

A canvas has a backend, that it interacts with immediately when calls to the API are made. This somewhat decouples the backends from the API, but likely couples them more directly to the intermediate representation.

A canvas just translates API calls into intermediate representation, which is later processed by a backend. This has the benefit of fully decoupling the backends from the API, and potentially decoupling (to a degree) from the intermediate representation. The question then becomes does the canvas make calls to the backend, or vice versa. This has the effect that now the user has full control over when things are actually sent to some output.

I don't have strong preferences for which option to choose, but wanted to give some food for thought.

from fig.

perazz avatar perazz commented on August 16, 2024

It's a great start @AnonMiraj. I would like to add some practical comments to complement the design suggestions.

  • Your type(canvas) implements pixels and could be a good starting point for PNG or BMP, but it's better to keep the primitives separated from the implementation (pixel-by-pixel write). So for example:
type, abstract :: canvas
   character(:), allocatable :: title
   integer(coordinate) :: width, height
   type(background) :: bg
   type(line), allocatable :: lines(:)
   type(circle), allocatable :: circles(:)
   ...
end type canvas

type, extends(canvas) :: bmp_canvas
   type(point), allocatable :: pixels(:,:)
   contains
      procedure :: to_file  
end type bmp_canvas

This way you keep the primitives separate from the implementation.

  • you'll need a module for the library parameters. for example: what integer size do you plan to use for the pixels? I see it something like:
use iso_fortran_env, only: int16, 

integer, parameter :: pixel = int16
integer, parameter :: rgb_level = int8
integer, parameter :: coord = real32
  • you already started base classes (great!). However, vec2 and vec3 are typically reserved for geometric entities. I suggest you create new modules for each of them, but separate the pixel representation from the geometric representation:
module fig_vec2
use fig_constants

type, public :: vec2
   real(coord) :: x,y
end type vec2
...
end module fig_vec2

module fig_points
use fig_constants

type, public :: point
   integer(pixel) :: x,y
end type point
...
  • Great source of inspiration: 1 2

from fig.

AnonMiraj avatar AnonMiraj commented on August 16, 2024

It would be interesting to create a plotting library frontend. For that we should learn from Matplotlib, as well as the C++ version of it: https://github.com/alandefreitas/matplotplusplus. We need to figure out some good intermediate representation for vector objects that represent the plot.

For the backends some ideas are:

* the glfw library could be used (it seems it is in conda).

* SVG (pure Fortran, just emit the xml as a string)

* PNG (use a C library to actually save it, or stdlib)

* PPM (use stdlib, pure Fortran)

The last two backends can use the algorithms from this library.

CC @everythingfunctional, @perazz.

Yeah, I agree, a plotting library is certainly going to be really cool. My current plan is to leave the first 6 weeks of my GSoC period mostly for creating the API for the library and the back-end, and then spend the last 6 weeks just working on the plotting side.

  • For GLFW, I have already considered an approach that will render the graphics in a simple way, making GLFW an optional dependency for the library, while leaving most of the code base in pure Fortran. It will also use just a small subset of GLFW methods and functions, so I will not need to make bindings for the entire GLFW library just for the project. There are also alternatives to GLFW like SDL (someone already made bindings for SDL2) or something like RGFW (https://github.com/ColleagueRiley/RGFW), which is a relatively new project but is just one header file and provides almost all GLFW functionality.
  • Regarding SVG, I have decided to try supporting it. It will not be easy to maintain both raster and vector graphics, but it is possible and i will do my best.
  • For PNG, I have already discussed how to support raster file drivers on this issue #8. I have decided to make bindings for stb_image and stb_image_write and use them to write to PNG and BMP, but I am a bit confused by stdlib. Is there a way to write PNG or a deflating library made in Fortran?
  • As for PPM, it already exists in the current implementation.

from fig.

AnonMiraj avatar AnonMiraj commented on August 16, 2024

Here's my initial thoughts on the current design and where I think it ought to go.

The current "API" does not really assume bitmap as the underlying representation, which is good. The current implementation really does kind of assume bitmap as the underlying representation, which will mean some significant refactoring, which I think to a degree will motivate some adjustments to the API.

Initially, I wasn't planning to support vector graphics. That's why, for the current new design, there will need to be a lot of refactoring to support it.

Also, the current API is very procedural. Create a canvas, draw a thing on it, draw another thing on it, have it output to somewhere. I'm not suggesting that's necessarily the wrong approach, but I wonder if there is a more declarative style that could be explored for the API.

While I agree that a declarative approach is the right choice if the library were just for SVG or a plotting library, I'm not very keen on making this the case for FIG. It would be quite limiting for a general-use graphics library to be declarative. A procedural approach is going to give users more control and will be more fitting for my current vision of the library. It is possible in the future to use FIG to create a declarative API for graphics, but I don't think a declarative approach is the best option for the library right nowβ€”at least, that's my opinion. We may discuss this further in the next meeting.

However, I do plan to make the plotting library declarative. It is going to be more usable, flexible, and intuitive overall like this.

I certainly agree that we should have some sort of intermediate representation that at least resembles vector graphics. Now here comes the question in terms of design. How do the API, intermediate representation, canvas, and backends interact with eachother. Some options.

A canvas is an abstract type, that supports the user API, and backends are implementations of that type. The intermediate representation is then a shared implementation detail of different backends. This has the benefit that different implementations can be optimized quite easily, but at the cost of maintainability, because adding to the API requires that all backends be immediately updated to account for the new feature.

A canvas has a backend, that it interacts with immediately when calls to the API are made. This somewhat decouples the backends from the API, but likely couples them more directly to the intermediate representation.

A canvas just translates API calls into intermediate representation, which is later processed by a backend. This has the benefit of fully decoupling the backends from the API, and potentially decoupling (to a degree) from the intermediate representation. The question then becomes does the canvas make calls to the backend, or vice versa. This has the effect that now the user has full control over when things are actually sent to some output.

I don't have strong preferences for which option to choose, but wanted to give some food for thought.

I am more lenient towards an abstract canvas with different backends, but other options have a lot of merit too.

from fig.

AnonMiraj avatar AnonMiraj commented on August 16, 2024

@perazz
thanks for all the suggestions i will keep them in mind when i start to refactor the backend.

from fig.

johandweber avatar johandweber commented on August 16, 2024

Also, the current API is very procedural. Create a canvas, draw a thing on it, draw another thing on it, have it output to somewhere. I'm not suggesting that's necessarily the wrong approach, but I wonder if there is a more declarative style that could be explored for the API.

In my (not yet very well thought) opinion, having the same canvas as an argument may indicate which operations belong to the same "object" (which may or may not translate to an derived type in Fortran).

from fig.

johandweber avatar johandweber commented on August 16, 2024

As a (hopefully useful) basis for discussion, I have drawn a
schematic for a possible architecture.

I do not claim that this is necessarily the best option.

The color blue means that I am really unsure about it.

Of course not everything can be done at once and it might be important to
prioritize parts of the scheme.

from fig.

Related Issues (14)

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.