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

I am not sure what you are trying to do. If you have the image that you want to draw in an array you can directly draw it into a Gtk surface. Or
Use winston and its imagesc function. No need to store anything to a file.

2 Likes

Does the image need to be stored on disk? So if I produce a plot with pyplot, as an image plot handle, is it possible to bypass the disk write? The disk writes are producing a latency.

Yes, if you switch from using Pyplot to using Winston or Gadfly or GR. What matter is the canvas you are drawing on. Winston and Gadfly can draw on a Cairo canvas and that is directly compatible with Gtk

1 Like

So with the code I had:

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

if not using pyplot, can the use of winston in your code below simply be used with a replacement with GR/Gadfly ?

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

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

does it not need to use set_source_surface(ctx, image, 0, 0); paint(ctx) ?

in your example, the image is in a file. It thus of course needs to be loaded. But if your image is not stored on disk but in an array in memory, you can directly show it. You need to clarify what you have.

1 Like

I have heatmaps produced in pyplot (but can exchange with GR), which I save to file and then load after they are saved. Can I bypass the saving to disk by simply using the display(canvas,plotHandle)? @tknopp

PyPlot wont work. GR might work. @jheinen should know more. Winston definately works, but I am not sure what a heatmap is exactly. If it’s imagesc the Winston can do that.

https://winston.readthedocs.io/en/latest/fun/imagesc.html

1 Like

IMO it’s not a good idea to “mix” plot packages. I’d define either

  • define the MPLBACKEND environment to switch to a Gtk backend in Matplotlib (please refer to the Matplotlib documentation), or
  • use plain GR and generate the heatmap within the GR framework as in this example:
using Gtk.ShortNames, Gtk.GConstants

using Printf
using GR

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))

    heatmap(randn(nbins, nbins))
end

function draw(widget)
    ctx = Gtk.getgc(widget)
    w = Gtk.width(widget)
    h = Gtk.height(widget)

    Gtk.rectangle(ctx, 0, 0, w, h)
    Gtk.set_source_rgb(ctx, 1, 1, 1)
    Gtk.fill(ctx)

    plot(ctx, w, h)
end

function resize_event(widget)
    ctx = Gtk.getgc(widget)
    h = Gtk.height(widget)
    w = Gtk.width(widget)

    Gtk.paint(ctx)
end

function motion_notify_event(widget::Gtk.GtkCanvas, event::Gtk.GdkEventMotion)
    Gtk.GAccessor.text(lb, @sprintf("(%g, %g)", event.x, event.y))
end

function value_changed(widget::Gtk.GtkScale)
    global canvas
    draw(canvas)
end

win = Window("Gtk") |> (bx = Box(:v))
Gtk.set_gtk_property!(win, :double_buffered, false)
lb = Label("(-, -)")
sl = Scale(false, 10, 100, 1)
Gtk.GAccessor.value(sl, 30)
canvas = Canvas(600, 450)
push!(bx, lb, sl, canvas)

signal_connect(motion_notify_event, canvas, "motion-notify-event")
signal_connect(value_changed, sl, "value_changed")

canvas.resize = resize_event
canvas.draw = draw

Gtk.showall(win)

if !isinteractive()
    c = Condition()
    signal_connect(win, :destroy) do widget
        notify(c)
    end
    wait(c)
end
1 Like

Switching PyPlot to the Gtk backend will very likely not work since internally different Cairo / Gtk versions are used.

1 Like