Fastest way to draw on Gtk.jl 'canvas' with plots produced from Plots.jl?

I am using Gtk to display on a canvas images which are plots/figures produced in Plots via GR. The workflow I use is to save the figure to a png, and then load it in the draw function for Gtk where the canvas surface is then updated. This incurs a large delay and the png filesize is not large.

How can I channel the figure production in plots directly to Gtk’s canvas t reduce the latency? (part of cairo.jl I assume)

using Gtk
function drawSys(widget)
    ctx = Gtk.getgc(widget)
    c = CairoRGBSurface(400,20);
    cr = CairoContext(c);

    set_source_rgb(cr,0.8,0.8,0.8);    # light gray
    rectangle(cr,0.0,0.0,800.0,650.0); # background
    fill(cr);
   
    image = read_from_png("dog.png")
    
    set_source_surface(ctx, image, 0, 0)
    paint(ctx)
   
end

There is a Gtk example (gtk_ex.jl) in the example section of GR.jl, which does exactly what you want.

2 Likes

Winston.jl is an alternative that works well

1 Like

Does winston integrate with Gtk any differently? is there a good MWE for it? is winston still being actively maintained?

Gadfly has also an nice integration with Gtk (with interactive figures and figure manager). It’s relatively easy to include in another widget.

c = Canvas()
p = Winston.plot(ones(50), "b-", linewidth=7)
display(c, p)

Thats it. The canvas needs be pushed into a layout (Grid) or directly to a window.

2 Likes

Regarding maintenance: I am using Winston in a Gtk /Winston System in production and was the one that brought Winston from 0.5 to 1.0. That does not mean that I develop features but its likely that this package will work as is, for the next Julia versions.

Winston is somewhat lightweight, although it has some inference issues, which make the time to first plot a little bit slow. I usually wait 3-5 seconds. Still my impression is that Gadfly is more heavy but has more functionality.

3 Likes

gtk_ex.jl produces a zero-size window…?

(v1.1) pkg> status Gtk GR
    Status `~/.julia/environments/v1.1/Project.toml`
  [9e28174c] BinDeps v0.8.10
  [159f3aea] Cairo v0.5.6
  [34da2185] Compat v2.1.0
  [28b8d3ca] GR v0.41.0
  [a2bd30eb] Graphics v0.4.0
  [4c0ca9eb] Gtk v0.16.5
  [d9be37ee] Homebrew v0.7.1
  [189a3867] Reexport v0.2.0
  [c17dfb99] WinRPM v0.4.2

julia> versioninfo()
Julia Version 1.1.0
Commit 80516ca202 (2019-01-21 21:24 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-2860QM CPU @ 2.50GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, sandybridge)

Here is a full example:

using Gtk.ShortNames
using Random
using Winston

c = Canvas()
w = Window(c, "Test Winston")
Gtk.showall(w)

p = Winston.plot(randn(50), "b-", linewidth=7);
display(c, p)
1 Like

I successfully tested it using Julia 1.2, Gtk 0.6.

(v1.2) pkg> st Gtk GR
    Status `~/.julia/environments/v1.2/Project.toml`
  [159f3aea] Cairo v0.6.0
  [28b8d3ca] GR v0.41.3 #master (https://github.com/jheinen/GR.jl.git)
  [4c0ca9eb] Gtk v0.17.0

julia> versioninfo()
Julia Version 1.2.0
Commit c6da87ff4b (2019-08-20 00:03 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-8569U CPU @ 2.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)

2 Likes
(v1.2) pkg> st Gtk GR
    Status `~/.julia/environments/v1.2/Project.toml`
  [159f3aea] Cairo v0.6.0
  [28b8d3ca] GR v0.41.3 #master (https://github.com/jheinen/GR.jl.git)
  [4c0ca9eb] Gtk v0.17.0

julia> versioninfo()
Julia Version 1.2.0
Commit c6da87ff4b (2019-08-20 00:03 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-2860QM CPU @ 2.50GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, sandybridge)

julia> include("/tmp/gtk_ex.jl")

Still I get only this icon in the Ubuntu taskbar:

Screenshot%20from%202019-10-02%2023-49-32

I tested examples from Gtk docs and they work fine.

What’s the reason why you are using Homebrew on a Linux box?

Who, me? :slight_smile:

I am not using Homebrew. Maybe you are referring to my typo taskbar → dash?

Edit: good catch, it is installed automatically as a dependency, strange…

As I mentioned in the other thread I removed .julia and reinstalled the relevant packages, still I get an empty window…

But in another almost identical box it works perfectly…strange. Anyway, it seems to be a local problem here.

Nice and fast demo!

I have been trying to adapt your example provided in https://github.com/jheinen/GR.jl/blob/master/examples/gtk_ex.jl, but encounter errors frequently when trying to modify the code. Eg. Trying to use the plot function within the example:

function plot(ctx, w, h)
    global sl

    ENV["GKS_WSTYPE"] = "142"
    ENV["GKSconid"] = @sprintf("%lu", UInt64(ctx.ptr))

    plt = gcf()
    plt[:size] = (w, h)
    nbins = Int64(Gtk.GAccessor.value(sl))

    plot(1:10,rand(10))#hexbin(x, y, nbins=nbins)
end

errors:

julia> FATAL ERROR: Gtk state corrupted by error thrown in a callback:
ERROR: MethodError: no method matching plot(::UnitRange{Int64}, ::Array{Float64,1})
Closest candidates are:
  plot(::Any, ::Any, !Matched::Any) at /home/xel/tmp/try.jl:10
Stacktrace:
 [1] plot(::Cairo.CairoContext, ::Int32, ::Int32) at /home/xel/tmp/try.jl:19
 [2] draw(::Gtk.GtkCanvas) at /home/xel/tmp/try.jl:31
 [3] draw(::Gtk.GtkCanvas, ::Bool) at /home/xel/.julia/packages/Gtk/aP55V/src/cairo.jl:90
 [4] notify_resize(::Ptr{GObject}, ::Ptr{Gtk.GdkRectangle}, ::Gtk.GtkCanvas) at /home/xel/.julia/packages/Gtk/aP55V/src/cairo.jl:67
 [5] (::getfield(Gtk, Symbol("##237#238")))() at /home/xel/.julia/packages/Gtk/aP55V/src/events.jl:2
 [6] g_sigatom(::Any) at /home/xel/.julia/packages/Gtk/aP55V/src/GLib/signals.jl:167
 [7] gtk_main() at /home/xel/.julia/packages/Gtk/aP55V/src/events.jl:1

Killed

this works with GR at the REPL where a GR window open up and shows the plot. Is there a problem with my system set up maybe?

Does this mean that the unmodified (using hexbin) code works?

1 Like

yes, the default example does work

I see the click example, do you know if it’s possible to click on some element in the plot and redraw other parts of the plot? For example, drag a point and re-fit the underlying curve

With Immerse ? I’m not sure how you would handle partial redraw, it’s probably much easier to redraw the whole thing.

@tobias.knopp and @jheinen, would it be possible to create the image file, but not write it to disk with save and then use pipes or streams to directly write it as an already created file on the canvas?