Best Julia Computer Graphics in Jupyter?

I want to teach a mechanics class using Julia. What’s the best Julia Computer Graphics Package that works in Jupyter?

Do you mean plotting package? There are quite a few excellent packages available, and it’s hard to suggest one over the other without more context on what your requirements are (i.e. the types of plots and animations you need to create).

Also “best” is subjective and often depends on what a user is familiar with - there are packages that implement a grammar-of-graphics approach to plotting, others that are closer to the MATLAB/matplotlib syntax, there’s PGFPlots for TeX syntax, a GNUplot wrapper…

1 Like

Not just plotting! 3d Rendering to make it look like a video!

E.g., photorealistic graphics with Rendering!

Uh, I don’t think this is a sector where Julia libs excel.
Not that it can’t be done, just that majority of Julia community looked on other areas…

1 Like

So, there is no useful computer graphics package?

I don’t know any, that’s all I can say :-/

Edit:

I feel “native” Julia libs on computer graph are pretty unlikely to exist, but wrappers to C/C++ apps could well exist, or any how are relatively easy to make (have a look at Cxx)…

Julia ⇄ C++

As for C, C++ workflow is partially environment-dependent. We use in this section Cxx.jl under Linux, although Cxx.jl has also an experimental support for Windows.

It’s main advantage over other C++ wrap modules (notably CxxWrap.jl) is that it allows working on C++ code in multiple ways depending on the workflow that is required.

Interactive C++ prompt

If you type < in the Julia REPL (after you typed using Cxx ) you even obtain an interactive C++ prompt:

C++

Figure 6.1: C++ interactive prompt at the Julia REPL

From the figure, note how the compilation of the code you type is done just-in-time, as for Julia itself, and eventual compilation errors are hence reported straight-away.

Embed C++ code in a Julia program

Aside the REPL prompt, you can use C++ code in your Julia program without ever leaving the main Julia environment. Let’s start with a simple example:

using Cxx

# Define the C++ function and compile it
cxx"""
#include<iostream>
void myCppFunction() {
   int a = 10;
   std::cout << "Printing " << a << std::endl;
}
"""
# Execute it
icxx"myCppFunction();" # Return "Printing 10"
# OR
# Convert the C++ to Julia function
myJuliaFunction() = @cxx myCppFunction()
# Run the function
myJuliaFunction() # Return "Printing 10"

The workflow is straight-forward: you first embed the C++ code with the cxx""" string macro. You are then ready to “use” the functions defined in cxx""" either calling them directly with C++ code embedded in icxx""" or converting them in Julia function with the @cxx macro and then using Julia code to call the (Julia) function.

The above example however doesn’t imply any transfer of data between Julia and C++, while if you want to embed C++, most likely it is in order to pass some data to C++ and retrieve the output to use in your Julia program.

The following example shows how data transfer between Julia and C++ (both ways) is handled automatically for elementary types:

using Cxx
cxx"""
#include<iostream>
int myCppFunction2(int arg1) {
   return arg1+1;
}
"""
juliaValue = icxx"myCppFunction2(9);" # 10
# OR
myJuliaFunction2(arg1) = @cxx myCppFunction2(arg1)
juliaValue = myJuliaFunction2(99)     # 100

However when the transfer involves complex data structures (like arrays or, as in the following example, arrays of arrays) things become more complex, as the Julia types have to be converted in the C++ types, and vice versa:

using Cxx
cxx"""
#include <vector>
using namespace std;
vector<double> rowAverages (vector< vector<double> > rows) {
  // Compute average of each row..
  vector <double> averages;
  for (int r = 0; r < rows.size(); r++){
    double rsum = 0.0;
    double ncols= rows[r].size();
    for (int c = 0; c< rows[r].size(); c++){
      rsum += rows[r][c];
    }
    averages.push_back(rsum/ncols);
  }
  return averages;
}
"""
rows_julia = [[1.5,2.0,2.5],[4,5.5,6,6.5,8]]
rows_cpp   = convert(cxxt"vector< vector< double > > ", rows_julia)
rows_avgs  = collect(icxx"rowAverages($rows_cpp);")
# OR
rowAverages(rows) = @cxx rowAverages(rows)
rows_avgs  = collect(rowAverages(rows_cpp))

The conversion from Julia data to C++ data (to be used as argument(s) of the C++ function) is done using the familiar convert(T,source) function, but where T is here given by the expression returned by cxxt"[{cpp} type]" .
The converted data can then be used in the C++ function call, with the note that if the direct call form of icxx" is used, this has to be interpolated using the dollar $ operator.

Finally, collect is used to copy data from the C++ structures returned by the C++ function to a Julia structure (avoiding copying is also possible using pointers).

Load a C++ library

The third way to use C++ code is to load a C++ library and call directly the functions defined in that library. The advantage is that the library doesn’t need to be aware that will be used in Julia (i.e. no special Julia headers or libraries are required at compile time of the C++ library) as the wrap is done entirely in Julia. This has the advantage that pre-existing libraries can be reused.

Let’s reuse our last example, but this time we compile it in a shared library.

mycpplib.cpp:

#include <vector>
#include "mycpplib.h"
using namespace std;
vector<double> rowAverages (vector< vector<double> > rows) {
  // Compute average of each row..
  vector <double> averages;
  for (int r = 0; r < rows.size(); r++){
    double rsum = 0.0;
    double ncols= rows[r].size();
    for (int c = 0; c< rows[r].size(); c++){
      rsum += rows[r][c];
    }
    averages.push_back(rsum/ncols);
  }
  return averages;
}

mycpplib.h:

#include <vector>
std::vector<double> rowAverages (std::vector< std::vector<double> > rows);

We can then compile the shared library with g++ , a C++ compiler:

  • g++ -shared -fPIC -o libmycpplib.so mycpplib.cpp

We are now ready to use it in Julia:

using Cxx
using Libdl 

const path_to_lib = pwd()
addHeaderDir(path_to_lib, kind=C_System) 
cxxinclude("mycpplib.h") 
Libdl.dlopen(joinpath(path_to_lib, "libmycpplib"), Libdl.RTLD_GLOBAL) 

rows_julia = [[1.5,2.0,2.5],[4,5.5,6,6.5,8]]
rows_cpp   = convert(cxxt"std::vector< std::vector< double > >", rows_julia)
rows_avgs  = collect(icxx"rowAverages($rows_cpp);")

The only new things here is that we need to explicitly load the standard lib Libdl (1 ), add the C++ header(s) (2 and 3) and finally open the shared library (4).

We are now able to use the functions defined in the library as if we embedded the C++ code in the Julia script.

5 Likes

Not sure what do you want to achieve exactly or if this fits your needs… but maybe this is usefull https://github.com/JuliaRobotics/MeshCatMechanisms.jl

1 Like

How about Makie.jl or PlotlyJS.jl ?

See here what’s possible now: Using JSCall to interact with ThreeJS - Nextjournal

[And for non-browser (Julia had 99% of the speed of C++ for graphics years ago), otherwise you must use WebGL: GitHub - JuliaGL/ModernGL.jl: OpenGL 3+ bindings for Julia

With the notebook environments, built on web technology, I’m just not sure if packages you use do need to be too. I.e. possibly you could use the OpenGL package above (or similar see on more modern Vulcan below, OpenGL easier?), and the notebook just opens a window.]

And here before: JSoC 2015 project: Interactive 3D Graphics in the Browser with Compose3D

Seemingly what you want (code below are wrappers, making the use of three.js transparent, while in demo above, while you can use it that way, it’s seemingly non-ideal, not a transparent way, and I’m not sure if it works in your exact notebook environment):

Currently, only WebGL backends using Three.JS are supported which allows you to draw 3D in a Jupyter notebook.

It and GitHub - rohitvarkey/ThreeJS.jl: Julia interface to WebGL using Three-js custom elements and Patchwork.jl (see animation there) are however outdated, need to be updated for Julia 1.0 (shouldn’t be too hard, I understand there are even tools to help with such). [You can still run them with the appropriate pre-1.0 Julia version, at least to see if worth it.]

https://randomfantasies.com/2016/02/why-im-betting-on-vulkan-and-julia/

Julia has no support (while does for underlying SPIR-V), that I know of, for the “future webGPU standard” (except on Apple):

https://news.ycombinator.com/item?id=22020511

For different kind of GPU programming (he’s still I believe the expert on Julia also for graphics rendering):

1 Like

“Computer graphics” is an extremely broad field, so it is hard to suggest anything without a more specific question. What exactly are you trying to do? Animated plots?

For Jupyter, I would investigate GitHub - JuliaPlots/WGLMakie.jl: WebGL backend for Makie

1 Like