Author Archives: Julia Developers

Building GUIs with Julia, Tk, and Cairo, Part I

By: Julia Developers

Re-posted from: http://feedproxy.google.com/~r/JuliaLang/~3/SHZGDk581qM/graphical-user-interfaces-part1

This is the first of two blog posts designed to walk users through the process of creating GUIs in Julia.
Those following Julia development will know that plotting in Julia is still evolving, and one could therefore expect that it might be premature to build GUIs with Julia.
My own recent experience has taught me that this expectation is wrong: compared with building GUIs in Matlab (my only previous GUI-writing experience), Julia already offers a number of quite compelling advantages.
We’ll see some of these advantages on display below.

We’ll go through the highlights needed to create an image viewer GUI.
Before getting into how to write this GUI, first let’s play with it to get a sense for how it works.
It’s best if you just try these commands yourself, because it’s difficult to capture things like interactivity with static text and pictures.

You’ll need the ImageView package:

Pkg.add("ImageView")

It’s worth pointing out that this package is expected to evolve over time; however, if things have changed from what’s described in this blog, try checking out the “blog” branch directly from the repository.
I should also point out that this package was developed on the author’s Linux system, and it’s possible that things may not work as well on other platforms.

First let’s try it with a photograph. Load one this way:

using Images
using ImageView
img = imread("my_photo.jpg")

Any typical image format should be fine, it doesn’t have to be a jpg.
Now display the image this way:

display(img, pixelspacing = [1,1])

The basic command to view the image is display.
The optional pixelspacing input tells display that this image has a fixed aspect ratio, and that this needs to be honored when displaying the image. (Alternatively, you could set img["pixelspacing"] = [1,1] and then you wouldn’t have to tell this to the display function.)

You should get a window with your image:

photo

OK, nice.
But we can start to have some fun if we resize the window, which causes the image to get bigger or smaller:

photo

Note the black perimeter; that’s because we’ve specified the aspect ratio through the pixelspacing input, and when the window doesn’t have the same aspect ratio as the image you’ll have a perimeter either horizontally or vertically.
Try it without specifying pixelspacing, and you’ll see that the image stretches to fill the window, but it looks distorted:

display(img)

photo

(This won’t work if you’ve already defined "pixelspacing" for img; if necessary, use delete!(img, "pixelspacing") to remove that setting.)

Next, click and drag somewhere inside the image.
You’ll see the typical rubberband selection, and once you let go the image display will zoom in on the selected region.

photo
photo

Again, the aspect ratio of the display is preserved.
Double-clicking on the image restores the display to full size.

If you have a wheel mouse, zoom in again and scroll the wheel, which should cause the image to pan vertically.
If you scroll while holding down Shift, it pans horizontally; hold down Ctrl and you affect the zoom setting.
Note as you zoom via the mouse, the zoom stays focused around the mouse pointer location, making it easy to zoom in on some small feature simply by pointing your mouse at it and then Ctrl-scrolling.

Long-time users of Matlab may note a number of nice features about this behavior:

  • The resizing and panning is much smoother than Matlab’s
  • Matlab doesn’t expose modifier keys in conjunction with the wheel mouse, making it difficult to implement this degree of interactivity
  • In Matlab, zooming with the wheel mouse is always centered on the middle of the display, requiring you to alternate between zooming and panning to magnify a particular small region of your image or plot.

These already give a taste of some of the features we can achieve quite easily in Julia.

However, there’s more to this GUI than meets the eye.
You can display the image upside-down with

display(img, pixelspacing = [1,1], flipy=true)

or switch the x and y axes with

display(img, pixelspacing = [1,1], xy=["y","x"])

photo
photo

To experience the full functionality, you’ll need a “4D image,” a movie (time sequence) of 3D images.
If you don’t happen to have one lying around, you can create one via include("test/test4d.jl"), where test means the test directory in ImageView.
(Assuming you installed ImageView via the package manager, you can say include(joinpath(Pkg.dir(), "ImageView", "test", "test4d.jl")).)
This creates a solid cone that changes color over time, again in the variable img.
Then, type display(img).
You should see something like this:

GUI snapshot

The green circle is a “slice” from the cone.
At the bottom of the window you’ll see a number of buttons and our current location, z=1 and t=1, which correspond to the base of the cone and the beginning of the movie, respectively.
Click the upward-pointing green arrow, and you’ll “pan” through the cone in the z dimension, making the circle smaller.
You can go back with the downward-pointing green arrow, or step frame-by-frame with the black arrows.
Next, clicking the “play forward” button moves forward in time, and you’ll see the color change through gray to magenta.
The black square is a stop button. You can, of course, type a particular z, t location into the entry boxes, or grab the sliders and move them.

If you have a wheel mouse, Alt-scroll changes the time, and Ctrl-Alt-scroll changes the z-slice.

You can change the playback speed by right-clicking in an empty space within the navigation bar, which brings up a popup (context) menu:

GUI snapshot

By default, display will show you slices in the xy-plane.
You might want to see a different set of slices from the 4d image:

display(img, xy=["x","z"])

Initially you’ll see nothing, but that’s because this edge of the image is black.
Type 151 into the y: entry box (note its name has changed) and hit enter, or move the “y” slider into the middle of its range; now you’ll see the cone from the side.

GUI snapshot

This GUI is also useful for “plain movies” (2d images with time), in which case the z controls will be omitted and it will behave largely as a typical movie-player.
Likewise, the t controls will be omitted for 3d images lacking a temporal component, making this a nice viewer for MRI scans.

Again, we note a number of improvements over Matlab:

  • When you resize the window, note that the controls keep their initial size, while the image fills the window. With some effort this behavior is possible to achieve in Matlab, but (as you’ll see later in these posts) it’s essentially trivial with Julia and Tk.
  • When we move the sliders, the display updates while we drag it, not just when we let go of the mouse button.
  • If you try this with a much larger 3d or 4d image, you may also notice that the display feels snappy and responsive in a way that’s sometimes hard to achieve with Matlab.

Altogether advantages such as these combine to give a substantially more polished feel to GUI applications written in Julia.

This completes our tour of the features of this GUI.
Now let’s go through a few of the highlights needed to create it.
We’ll tackle this in pieces; not only will this make it easier to learn, but it also illustrates how to build re-useable components.
Let’s start with the navigation frame.

First steps: the navigation frame

First, let me acknowledge that this GUI is built on the work of many people who have contributed to Julia’s Cairo and Tk packages.
For this step, we’ll make particular use of John Verzani’s contribution of a huge set of convenience wrappers for most of Tk’s widget functionality.
John wrote up a nice set of examples that demonstrate many of the things you can do with it; this first installment is essentially just a “longer” example, and won’t surprise anyone who has read his documentation.

Let’s create a couple of types to hold the data we’ll need.
We need a type that stores “GUI state,” which here consists of the currently-viewed location in the image and information needed to implement the “play” functionality:

type NavigationState
    # Dimensions:
    zmax::Int          # number of frames in z, set to 1 if only 2 spatial dims
    tmax::Int          # number of frames in t, set to 1 if only a single image
    z::Int             # current position in z-stack
    t::Int             # current moment in time
    # Other state data:
    timer              # nothing if not playing, TimeoutAsyncWork if we are
    fps::Float64       # playback speed in frames per second
end

Next, let’s create a type to hold “handles” to all the widgets:

type NavigationControls
    stepup                            # z buttons...
    stepdown
    playup
    playdown
    stepback                          # t buttons...
    stepfwd
    playback
    playfwd
    stop
    editz                             # edit boxes
    editt
    textz                             # static text (information)
    textt
    scalez                            # scale (slider) widgets
    scalet
end

It might not be strictly necessary to hold handles to all the widgets (you could do everything with callbacks), but having them available is convenient.
For example, if you don’t like the icons I created, you can easily initialize the GUI and replace, using the handles, the icons with something better.

We’ll talk about initialization later; for now, assume that we have a variable state of type NavigationState that holds the current position in the (possibly) 4D image, and ctrls which contains a fully-initialized set of widget handles.

Each button needs a callback function to be executed when it is clicked.
Let’s go through the functions for controlling t.
First there is a general utility not tied to any button, but it affects many of the controls:

function updatet(ctrls, state)
    set_value(ctrls.editt, string(state.t))
    set_value(ctrls.scalet, state.t)
    enableback = state.t > 1
    set_enabled(ctrls.stepback, enableback)
    set_enabled(ctrls.playback, enableback)
    enablefwd = state.t < state.tmax
    set_enabled(ctrls.stepfwd, enablefwd)
    set_enabled(ctrls.playfwd, enablefwd)
end

The first two lines synchronize the entry box and slider to the current value of state.t;
the currently-selected time can change by many different mechanisms (one of the buttons, typing into the entry box, or moving the slider), so we make state.t be the “authoritative” value and synchronize everything to it.
The remaining lines of this function control which of the t navigation buttons are enabled (if t==1, we can’t go any earlier in the movie, so we gray out the backwards buttons).

A second utility function modifies state.t:

function incrementt(inc, ctrls, state, showframe)
    state.t += inc
    updatet(ctrls, state)
    showframe(state)
end

Note the call to updatet described above.
The new part of this is the showframe function, whose job it is to display the image frame (or any other visual information) to the user.
Typically, the actual showframe function will need additional information such as where to render the image, but you can provide this information using anonymous functions.
We’ll see how that works in the next installment; below we’ll just create a simple “stub” function.

Now we get to callbacks which we’ll “bind” to the step and play buttons:

function stept(inc, ctrls, state, showframe)
    if 1 <= state.t+inc <= state.tmax
        incrementt(inc, ctrls, state, showframe)
    else
        stop_playing!(state)
    end
end

function playt(inc, ctrls, state, showframe)
    if !(state.fps > 0)
        error("Frame rate is not positive")
    end
    stop_playing!(state)
    dt = 1/state.fps
    state.timer = TimeoutAsyncWork(i -> stept(inc, ctrls, state, showframe))
    start_timer(state.timer, iround(1000*dt), iround(1000*dt))
end

stept() increments the t frame by the specified amount (typically 1 or -1), while playt() starts a timer that will call stept at regular intervals.
The timer is stopped if play reaches the beginning or end of the movie.
The stop_playing! function checks to see whether we have an active timer, and if so stops it:

function stop_playing!(state::NavigationState)
    if !is(state.timer, nothing)
        stop_timer(state.timer)
        state.timer = nothing
    end
end

An alternative way to handle playback without a timer would be in a loop, like this:

function stept(inc, ctrls, state, showframe)
    if 1 <= state.t+inc <= state.tmax
        incrementt(inc, ctrls, state, showframe)
    end
end

function playt(inc, ctrls, state, showframe)
    state.isplaying = true
    while 1 <= state.t+inc <= state.tmax && state.isplaying
        tcl_doevent()    # allow the stop button to take effect
        incrementt(inc, ctrls, state, showframe)
    end
    state.isplaying = false
end

With this version we would use a single Boolean value to signal whether there is active playback.
A key point here is the call to tcl_doevent(), which allows Tk to interrupt the execution of the loop to handle user interaction (in this case, clicking the stop button).
But with the timer that’s not necessary, and moreover the timer gives us control over the speed of playback.

Finally, there are callbacks for the entry and slider widgets:

function sett(ctrls,state, showframe)
    tstr = get_value(ctrls.editt)
    try
        val = int(tstr)
        state.t = val
        updatet(ctrls, state)
        showframe(state)
    catch
        updatet(ctrls, state)
    end
end

function scalet(ctrls, state, showframe)
    state.t = get_value(ctrls.scalet)
    updatet(ctrls, state)
    showframe(state)
end

sett runs when the user types an entry into the edit box; if the user types in nonsense like “foo”, it will gracefully reset it to the current position.

There’s a complementary set of these functions for the z controls.

These callbacks implement the functionality of this “navigation” GUI.
The other main task is initialization.
We won’t cover this in gory detail (you are invited to browse the code), but let’s hit a few highlights.

Creating the buttons

You can use image files (e.g., .png files) for your icons, but the ones here are created programmatically.
To do this, specify two colors, the “foreground” and “background”, as strings.
One also needs the data array (of type Bool) for the pixels that should be colored by the foreground color, and false for the ones to be set to the background.
There’s also the mask array, which can prevent the data array from taking effect in any pixels marked as false in the mask.

Given suitable data and mask arrays (here we just set the mask to trues), and color strings, we create the icon and assign it to a button like this:

icon = Tk.image(data, mask, "gray70", "black")  # background=gray70, foreground=black
ctrls.stop = Button(f, icon)

Here f is the “parent frame” that the navigation controller will be rendered in.
A frame is a container that organizes a collection of related GUI elements.
Later we’ll find out how to create one.

Assigning callbacks to widgets

The “stop” and “play backwards” buttons look like this:

bind(ctrls.stop, "command", path -> stop_playing!(state))
bind(ctrls.playback, "command", path -> playt(-1, ctrls, state, showframe)

The path input is generated by Tk/Tcl, but we don’t have to use it.
Instead, we use anonymous functions to pass the arguments relavant to this particular GUI instantiation.
Note that these two buttons share state; that means that any changes made by one callback will have impact on the other.

Placing the buttons in the frame (layout management)

Here our layout needs are quite simple, but I recommend that you read the excellent tutorial on Tk’s grid layout engine.
grid provides a great deal of functionality missing in Matlab, and in particular allows flexible and polished GUI behavior when resizing the window.

We position the stop button this way:

grid(ctrls.stop, 1, stopindex, padx=3*pad, pady=pad)

After the handle for the button itself, the next two inputs determine the row, column position of the widget.
Here the column position is set using a variable (an integer) whose value will depend on whether the z controls are present.
The pad settings just apply a bit of horizontal and vertical padding around the button.

To position the slider widgets, we could do something like this:

ctrls.scalez = Slider(f, 1:state.zmax)
grid(ctrls.scalez, 2, start:stop, sticky="we", padx=pad)

This positions them in row 2 of the frame’s grid, and has them occupy the range of columns (indicated by start:stop) used by the button controls for the same z or t axis.
The sticky setting means that it will stretch to fill from West to East (left to right).

In the main GUI we’ll use one more feature of grid, so let’s cover it now.
This feature controls how regions of the window expand or shrink when the window is resized:

grid_rowconfigure(win, 1, weight=1)
grid_columnconfigure(win, 1, weight=1)

This says that row 1, column 1 will expand at a rate of 1 when the figure is made larger.
You can set different weights for different GUI components.
The default value is 0, indicating that it shouldn’t expand at all.
That’s what we want for this navigation frame, so that the buttons keep their size when the window is resized.
Larger weight values indicate that the given component should expand (or shrink) at faster rates.

Putting it all together and testing it out

We’ll place the navigation controls inside a Tk frame.
Let’s create one from the command line:

using Tk
win = Toplevel()
f = Frame(win)
pack(f, expand=true, fill="both")

The first three lines create the window and the frame. pack is an alternative layout engine to grid, and slightly more convenient when all you want is to place a single item so that it fills its container.
(You can mix pack and grid as long as they are operating on separate containers.
Here we’ll have a frame packed in the window, and the widgets will be gridded inside the frame.)
After that fourth line, the window is rather tiny; the call to pack causes the frame to fill to expand the whole window, but at the moment the frame has no contents, so the window is as small as it can be.

GUI snapshot

We need a showframe callback; for now let’s create a very simple one that will help in testing:

showframe = x -> println("showframe z=", x.z, ", t=", x.t)

Next, load the GUI code (using ImageView.Navigation) and create the NavigationState and NavigationControls objects:

ctrls = NavigationControls()
state = NavigationState(40, 1000, 2, 5)

Here we’ve set up a fake movie with 40 image slices in z, and 1000 image stacks in t.

Finally, we initialize the widgets:

init_navigation!(f, ctrls, state, showframe)

GUI snapshot

Now when you click on buttons, or change the text in the entry boxes, you’ll see the GUI in action.
You can tell from the command line output, generated by showframe, what’s happening internally:

GUI snapshot

Hopefully this demonstrates another nice feature of developing GUIs in Julia: it’s straightforward to build re-usable components.
This navigation frame can be added as an element to any window, and the grid layout manager takes care of the rest.
All you need to do is to include ImageView/src/navigation.jl into your module, and you can make use of it with just a few lines of code.

Not too hard, right? The next step is to render the image, which brings us into the domain of Cairo.

Building GUIs with Julia, Tk, and Cairo, Part II

By: Julia Developers

Re-posted from: http://feedproxy.google.com/~r/JuliaLang/~3/CSFwY6PlofE/graphical-user-interfaces-part2

Drawing, painting, and plotting

In this installment, we’ll cover both low-level graphics (using Cairo) and plotting graphs inside GUIs (using Winston).
Here again we’re relying on infrastructure built by many people, including Jeff Bezanson, Mike Nolta, and Keno Fisher.

Cairo

The basics

The display of the image is handled by Cairo, a C library for two-dimensional drawing.
Julia’s Cairo wrapper isn’t currently documented, so let’s walk through a couple of basics first.

If you’re new to graphics libraries like Cairo, there are a few concepts that may not be immediately obvious but are introduced in the Cairo tutorial.
The key concept is that the Cairo API works like “stamping,” where a source gets applied to a destination in a region specified by a path.
Here, the destination will be the pixels corresponding to a region of a window on the screen.
We’ll control the source and the path to achieve the effects we want.

Let’s play with this.
First, inside a new window we create a Cairo-enabled Canvas for drawing:

using Base.Graphics
using Cairo
using Tk

win = Toplevel("Test", 400, 200)
c = Canvas(win)
pack(c, expand=true, fill="both")

We’ve created a window 400 pixels wide and 200 pixels high.
c is our Canvas, a type defined in the Tk package.
Later we’ll dig into the internals a bit, but for now suffice it to say that a Canvas is a multi-component object that you can often treat as a black box.
The initial call creating the canvas leaves a lot of its fields undefined, because you don’t yet know crucial details like the size of the canvas.
The call to pack specifies that this canvas fills the entire window, and simultaneously fills in the missing information in the Canvas object itself.

Note that the window is currently blank, because we haven’t drawn anything to it yet, so you can see whatever was lying underneath.
In my case it captured a small region of my desktop:

cairo snapshot

Now let’s do some drawing.
Cairo doesn’t know anything about Tk Canvases, so we have to pull out the part of it that works directly with Cairo:

ctx = getgc(c)

getgc means “get graphics context,” returning an object (here ctx) that holds all relevant information about the current state of drawing to this canvas.

One nice feature of Cairo is that the coordinates are abstracted; ultimately we care about screen pixels, but we can set up user coordinates that have whatever scaling is natural to the problem.
We just have to tell Cairo how to convert user coordinates to device (screen) coordinates.
We set up a coordinate system using set_coords, defined in base/graphics.jl:

function set_coords(ctx::GraphicsContext, x, y, w, h, l, r, t, b)

x (horizontal) and y (vertical) specify the upper-left corner of the drawing region in device coordinates, and w and h its width and height, respectively.
(Note Cairo uses (0,0) for the top-left corner of the window.) l, r, t, and b are the user coordinates corresponding to the left, right, top, and bottom, respectively, of this region.
Note that set_coords will also clip any drawing that occurs outside the region defined by x, y, w, and h; however, the coordinate system you’ve specified extends to infinity, and you can draw all the way to the edge of the canvas by calling reset_clip().

Let’s fill the drawing region with a color, so we can see it:

# Set coordinates to go from 0 to 10 within a 300x100 centered region
set_coords(ctx, 50, 50, 300, 100, 0, 10, 0, 10)
set_source_rgb(ctx, 0, 0, 1)   # set color to blue
paint(ctx)                     # paint the entire clip region

Perhaps surprisingly, nothing happened.
The reason is that the Tk Canvas implements a technique called double buffering, which means that you do all your drawing to a back (hidden) surface, and then blit the completed result to the front (visible) surface.
We can see this in action simply by bringing another window over the top of the window we’re using to draw, and then bringing our window back to the top; suddenly you’ll see a nice blue rectangle within the window, surrounded by whatever is in the background window(s):

cairo snapshot

Fortunately, to display your graphics you don’t have to rely on users changing the stacking order of windows: call reveal(c) to update the front surface with the contents of the back surface, followed by update() (or perhaps better, Tk.update() since update is a fairly generic name) to give Tk a chance to expose the front surface to the OS’s window manager.

Now let’s draw a red line:

move_to(ctx, -1, 5)
line_to(ctx, 7, 6)
set_source_rgb(ctx, 1, 0, 0)
set_line_width(ctx, 5)
stroke(ctx)
reveal(c)
Tk.update()

We started at a position outside the coordinate region (we’ll get to see the clipping in action this way).
The next command, line_to, creates a segment of a path, the way that regions are defined in Cairo.
The stroke command draws a line along the trajectory of the path, after which the path is cleared.
(You can use stroke_preserve if you want to re-use this path for another purpose later.)

Let’s illustrate this by adding a solid green rectangle with a magenta border, letting it spill over the edges of the previously-defined coordinate region:

reset_clip(ctx)
rectangle(ctx, 7, 5, 4, 4)
set_source_rgb(ctx, 0, 1, 0)
fill_preserve(ctx)
set_source_rgb(ctx, 1, 0, 1)
stroke(ctx)
reveal(c)
Tk.update()

fill differs from paint in that fill works inside the currently-defined path, whereas paint fills the entire clip region.

Here is our masterpiece, where the “background” may differ for you (mine was positioned over the bottom of a wikipedia page):

cairo snapshot

Rendering an image

Images are rendered in Cairo inside a rectangle (controlling placement of the image) followed by fill.
So far this is just like the simple drawing above.
The difference is the source, which now will be a surface instead of an RGB color.
If you’re drawing from Julia, chances are that you want to display an in-memory array.
The main trick is that Cairo requires this array to be a matrix of type Uint32 encoding the color.
The scheme is that the least significant byte is the blue value (ranging from 0x00 to 0xff), the next is green, and the next red.
(The most significant byte can encode the alpha value, or transparency, if you specify that transparency is to be used in your image surface.)

Both Winston and Images can generate a buffer of Uint32 for you.
Let’s try the one in Images:

using Images
img = imread("some_photo.jpg")
buf = uint32color(img)'
image(ctx, CairoRGBSurface(buf), 0, 0, 10, 10)
reveal(c)
Tk.update()

Rather than manually calling rectangle and fill, we use the convenience method image(ctx, surf, x, y, w, h) (defined in Cairo.jl).
Here x, y, w, h are user-coordinates of your canvas, not pixels on the screen or pixels in your image; being able to express location in user coordinates is the main advantage of using image().

The image should now be displayed within your window (squashed, because we haven’t worried about aspect ratio):

cairo snapshot

It fills only part of the window because of the coordinate system we’ve established, where the range 0:10 corresponds to an inset region in the center of the window.

While it’s a minor point, note that CairoRGBSurface takes a transpose for you, to convert from the column-major order of matrices in Julia to the row-major convention of Cairo.
Images avoids taking transposes unless necessary, and is capable of handling images with any storage order.
Here we do a transpose in preparation to have it be converted back to its original shape by CairoRGBSurface.
If performance is critical, you can avoid the default behavior of CairoRGBSurface by calling CairoImageSurface directly (see the Cairo.jl code).

Redrawing & resize support

A basic feature of windows is that they should behave properly under resizing operations.
This doesn’t come entirely for free, although the grid (and pack) managers of Tk take care of many details for us.
However, for Canvases we need to to do a little bit of extra work; to see what I mean, just try resizing the window we created above.

The key is to have a callback that gets activated whenever the canvas changes size, and to have this callback capable of redrawing the window at arbitrary size.
Canvases make this easy by having a field, resize, that you assign the callback to.
This function will receive a single argument, the canvas itself, but as always you can provide more information.
Taking our image example, we could set

c.resize = c->redraw(c, buf)

and then define

function redraw(c::Canvas, buf)
    ctx = getgc(c)
    set_source_rgb(ctx, 1, 0, 0)
    paint(ctx)
    set_coords(ctx, 50, 50, Tk.width(c)-100, Tk.height(c)-100, 0, 10, 0, 10)
    image(ctx, CairoRGBSurface(buf), 0, 0, 10, 10)
    reveal(c)
    Tk.update()
end

Here you can see that we’re aiming to be a bit more polished, and want to avoid seeing bits of the desktop around the borders of our drawing region.
So we fill the window with a solid color (but choose a garish red, to make sure we notice it) before displaying the image.
We also have to re-create our coordinate system, because that too was destroyed, and in this case we dynamically adjust the coordinates to the size of the canvas.
Finally, we redraw the image.
Note we didn’t have to go through the process of converting to Uint32-based color again.
Obviously, you can use this redraw function even for the initial rendering of the window, so there’s really no extra work in setting up your code this way.

If you grab the window handle and resize it, now you should see something like this:

cairo snapshot

Voila! We’re really getting somewhere now.

Unlike the complete GUI, this implementation doesn’t have the option to preserve the image’s aspect ratio.
However, there’s really no magic there; it all comes down to computing sizes and controlling the drawing region and coordinate system.

One important point: resizing the window causes the existing Cairo context(s) to be destroyed, and creates new ones suitable for the new canvas size.
One consequence is that your old ctx variable is now invalid, and trying to use it for drawing will cause a segfault.
For this reason, you shouldn’t ever store a ctx object on its own; always begin drawing by calling getgc(c) again.

Canvases and the mouse

A Canvas already comes with a set of fields prepared for mouse events.
For example, in the complete GUI we have the equivalent of the following:

selectiondonefunc = (c, bb) -> zoombb(imgc, img2, bb)
c.mouse.button1press = (c, x, y) -> rubberband_start(c, x, y, selectiondonefunc)

rubberband_start, a function defined in rubberband.jl, will now be called whenever the user presses the left mouse button.
selectiondonefunc is a callback that we supply; it will be executed when the user releases the mouse button, and it needs to implement whatever it is we want to achieve with the selected region (in this case, a zoom operation).
Part of what rubberband_start does is to bind selectiondonefunc to the release of the mouse button, via c.mouse.button1release.
bb is a BoundingBox (a type defined in base/graphics.jl) that will store the region selected by the user, and this gets passed to selectiondonefunc.
(The first two inputs to zoombb, imgc and img2, store settings that are relevant to this particular GUI but will not be described in detail here.)

The mouse inside a Canvas is an object of type MouseHandler, which has fields for press and release of all 3 mouse buttons and additional ones for motion.
However, a few cases (which happen to be relevant to this GUI) are not available in MouseHandler.
Here are some examples of how to configure these actions:

# Bind double-clicks
bind(c.c, "<Double-Button-1>", (path,x,y)->zoom_reset(imgc, img2))
# Bind Shift-scroll (using the wheel mouse)
bindwheel(c.c, "Shift", (path,delta)->panhorz(imgc,img2,int(delta)))

The delta argument for the wheel mouse will encode the direction of scrolling.

The rubber band (region selection)

Support for the rubber band is provided in the file rubberband.jl.
Like navigation.jl, this is a stand-alone set of functions that you should be able to incorporate into other projects.
It draws a dashed rectangle employing the same machinery we described at the top of this page, with slight modifications to create the dashes (through the set_dash function).
By now, this should all be fairly straightforward.

However, these functions use one additional trick worth mentioning.
Let’s finally look at the Tk Canvas object:

type Canvas
    c::TkWidget
    front::CairoSurface  # surface for window
    back::CairoSurface   # backing store
    frontcc::CairoContext
    backcc::CairoContext
    mouse::MouseHandler
    redraw

    function ...

Here we can explicitly see the two buffers, used in double-buffering, and their associated contexts.
getgc(c), where c is a Canvas, simply returns backcc.
This is why all drawing occurs on the back surface.
For the rubber band, we choose instead to draw on the front surface, and then (as the size of the rubber band changes) “repair the damage” by copying from the back surface.
Since we only have to modify the pixels along the band itself, this is fast.
You can see these details in rubberband.jl.

Winston

For many GUIs in Julia, an important component will be the ability to display data graphically.
While we could draw graphs directly with Cairo, it would be a lot of work to build from scratch; fortunately, there’s an excellent package, Winston, that already does this.

Since there’s a nice set of examples of some of the things you can do with Winston, here our focus is very narrow: how do you integrate Winston plots into GUIs built with Tk.
Fortunately, this is quite easy.
Let’s walk through an example:

using Tk
using Winston

win = Toplevel("Testing", 400, 200)
fwin = Frame(win)
pack(fwin, expand=true, fill="both")

We chose to fill the entire window with a frame fwin, so that everything inside this GUI will have a consistent background. All other objects will be placed inside fwin.

Next, let’s set up the elements, a Canvas on the left and a single button on the right:

c = Canvas(fwin, 300, 200)
grid(c, 1, 1, sticky="nsew")
fctrls = Frame(fwin)
grid(fctrls, 1, 2, sticky="sw", pady=5, padx=5)
grid_columnconfigure(fwin, 1, weight=1)
grid_rowconfigure(fwin, 1, weight=1)

ok = Button(fctrls, "OK")
grid(ok, 1, 1)

Finally, let’s plot something inside the Canvas:

x = linspace(0.0,10.0,1001)
y = sin(x)
p = FramedPlot()
add(p, Curve(x, y, "color", "red"))

Winston.display(c, p)
reveal(c)
Tk.update()

Winston snapshot

You’ll note that you can resize this window, and the plot grows or shrinks accordingly.

Easy, huh? The only part of this code that is specific to GUIs is the line Winston.display(c, p), where we specified that we wanted our plot to appear inside a particular Canvas.
Of course, there’s a lot of magic behind the scenes in Winston, but covering its internals is beyond our scope here.

Conclusions

There’s more one could cover, but most of the rest is fairly specific to this particular GUI.
A fair amount of code is needed to handle coordinates: selecting specific regions within the 4d image, and rendering to specific regions of the output canvas.
If you want to dive into these details, your best bet is to start reading through the ImageView code, but it’s not going to be covered in any more detail here.

Hopefully by this point you have a pretty good sense for how to produce on-screen output with Tk, Cairo, and Winston.
It takes a little practice to get comfortable with these tools, but the end result is quite powerful.
Happy hacking!

Passing Julia Callback Functions to C

By: Julia Developers

Re-posted from: http://feedproxy.google.com/~r/JuliaLang/~3/37Rn8aFhrvY/callback

One of the great strengths of Julia is that it is so easy to call C
code
natively, with no special “glue” routines or overhead to marshal
arguments and convert return values. For example, if you want to call
GNU GSL to compute a special function
like a Debye integral, it is as easy as:

debye_1(x) = ccall((:gsl_sf_debye_1,:libgsl), Cdouble, (Cdouble,), x)

at which point you can compute debye_1(2), debye_1(3.7), and so
on. (Even easier would be to use Jiahao Chen’s
GSL package for Julia, which has
already created such wrappers for you.) This makes a vast array of
existing C libraries accessible to you in Julia (along with Fortran
libraries and other languages with C-accessible calling conventions).

In fact, you can even go the other way around, passing Julia routines
to C, so that C code is calling Julia code in the form of callback
functions. For example, a C library for numerical integration might
expect you to pass the integrand as a function argument, which the
library will then call to evaluate the integrand as many times as
needed to estimate the integral. Callback functions are also natural
for optimization, root-finding, and many other numerical tasks, as well
as in many non-numerical problems. The purpose of this blog post is to
illustrate the techniques for passing Julia functions as callbacks to
C routines, which is straightforward and efficient but requires some
lower-level understanding of how functions and other values are passed as
arguments.

The code in this post requires Julia 0.2 (or a recent git facsimile
thereof); the key features needed for callback functions (especially
unsafe_pointer_to_objref) are not available in Julia 0.1.

Sorting with qsort

Perhaps the most well-known example of a callback parameter is
provided by the
qsort
function, part of the ANSI C standard library and declared in C as:

void qsort(void *base, size_t nmemb, size_t size,
           int(*compare)(const void *a, const void *b));

The base argument is a pointer to an array of length nmemb, with
elements of size bytes each. compare is a callback function which
takes pointers to two elements a and b and returns an integer
less/greater than zero if a should appear before/after b (or zero
if any order is permitted). Now, suppose that we have a 1d array A
of values in Julia that we want to sort using the qsort function
(rather than Julia’s built-in sort function). Before we worry about
calling qsort and passing arguments, we need to write a comparison
function that works for some arbitrary type T, e.g.

function mycompare{T}(a_::Ptr{T}, b_::Ptr{T})
    a = unsafe_load(a_)
    b = unsafe_load(b_)
    return a < b ? cint(-1) : a > b ? cint(+1) : cint(0)
end
cint(n) = convert(Cint, n)

Notice that we use the built-in function unsafe_load to fetch the
values pointed to by the arguments a_ and b_ (which is “unsafe”
because it will crash if these are not valid pointers, but qsort
will always pass valid pointers). Also, we have to be a little
careful about return values: qsort expects a function returning a C
int, so we must be sure to return Cint (the corresponding type in
Julia) via a call to convert.

Now, how do we pass this to C? A function pointer in C is essentially
just a pointer to the memory location of the machine code implementing
that function, whereas a function value mycompare (of type
Function) in Julia is quite different. Thanks to Julia’s JIT
compilation

approach,a Julia function may not even be compiled until the first
time it is called, and in general the same Julia function may be
compiled into multiple machine-code instantiations, which are
specialized for arguments of different types (e.g. different T in
this case). So, you can imagine that mycompare must internally
point to a rather complicated data structure (a jl_function_t in
julia.h, if you are interested), which holds information about the
argument types, the compiled versions (if any), and so on. In
general, it must store a
closure
with information about the environment in which the function was
defined; we will talk more about this below. In any case, it is a
very different object than a simple pointer to machine code for one
set of argument types. Fortunately, we can get the latter simply by
calling a built-in Julia function called cfunction:

const mycompare_c = cfunction(mycompare, Cint, (Ptr{Cdouble}, Ptr{Cdouble}))

Here, we pass cfunction three arguments: the function mycompare,
the return type Cint, and a tuple of the argument types, in this case to
sort an array of Cdouble (Float64) elements. Julia compiles a version of
mycompare specialized for these argument types (if it has not done
so already), and returns a Ptr{Void} holding the address of the
machine code, exactly what we need to pass to qsort. We are
now ready to call qsort on some sample data:

A = [1.3, -2.7, 4.4, 3.1]
ccall(:qsort, Void, (Ptr{Cdouble}, Csize_t, Csize_t, Ptr{Void}),
      A, length(A), sizeof(eltype(A)), mycompare_c)

After this executes, A is changed to the sorted array [ -2.7, 1.3,
3.1, 4.4]
. Note that Julia knows how to convert an array
A::Vector{Cdouble} into a Ptr{Cdouble}, how to compute the sizeof
a type in bytes (identical to C’s sizeof operator), and so on. For fun,
try inserting a println("mycompare($a,$b)") line into mycompare, which
will allow you to see the comparisons that qsort is performing (and to verify
that it is really calling the Julia function that you passed to it).

The problem with closures

We aren’t done yet, however. If you start passing callback functions to
C routines, it won’t be long before you discover that cfunction doesn’t
always work. For example, suppose we tried to declare our comparison
function inline, via:

mycomp = cfunction((a_,b_) -> unsafe_load(a_) < unsafe_load(b_) ? 
                              cint(-1) : cint(+1),
                   Cint, (Ptr{Cdouble}, Ptr{Cdouble}))

Julia barfs on this, printing ERROR: function is not yet c-callable. In
general, cfunction only works for “top-level” functions: named
functions defined in the top-level (global or module) scope, but not
anonymous (args -> value) functions and not functions defined within
other functions (“nested” functions). The reason for this stems from
one important concept in computer science: a
closure.

To understand the need for closures, and the difficulty they pose for
callback functions, suppose that we wanted to provide a nicer interface
for qsort, one which permitted the user to simply pass a lessthan function
returning true or false while hiding all of the low-level business with
pointers, Cint, and so on. We might like to do something of the form:

function qsort!{T}(A::Vector{T}, lessthan::Function)
    function mycompare(a_::Ptr{T}, b_::Ptr{T})
        a = unsafe_load(a_)
        b = unsafe_load(b_)
        return lessthan(a, b) ? cint(-1) : cint(+1)
    end
    mycompare_c = cfunction(mycompare, Cint, (Ptr{T}, Ptr{T}))
    ccall(:qsort, Void, (Ptr{T}, Csize_t, Csize_t, Ptr{Void}),
          A, length(A), sizeof(T), mycompare_c)
    A
end

Then we could simply call qsort!([1.3, -2.7, 4.4, 3.1], <) to sort
in ascending order using the built-in < comparison, or any other
comparison function we wanted. Unfortunately cfunction will again
barf when you try to call qsort!, and it is no longer so difficult
to understand why. Notice that the nested mycompare function is no
longer self-contained: it uses the variable lessthan from the
surrounding scope. This is a common pattern for nested functions and
anonymous functions: often, they are parameterized by local variables
in the environment where the function is defined. Technically, the
ability to have this kind of dependency is provided by lexical
scoping
in
a programming language like Julia, and is typical of any language in
which functions are
first-class
objects. In order to support lexical scoping, a Julia Function
object needs to internally carry around a pointer to the variables in
the enclosing environment, and this encapsulation is called a
closure.

In contrast, a C function pointer is not a closure. It doesn’t
enclose a pointer to the environment in which the function was
defined, or anything else for that matter; it is just the address of a
stream of instructions. This makes it hard, in C, to write functions
to transform other functions (higher-order
functions
) or to
parameterize functions by local variables. This apparently leaves us
with two options, neither of which is especially attractive:

  • We could store lessthan in a global variable, and reference that
    from a top-level mycompare function. (This is the traditional solution
    for C programmers calling qsort with parameterized comparison functions.)
    The problem with this strategy is that it is not re-entrant: it prevents us from calling qsort!
    recursively (e.g. if the comparison function itself needs to do a sort, for
    some complicated datastructure), or from calling qsort! from multiple
    threads (when a future Julia version supports shared-memory parallelism).
    Still, this is better than nothing.

  • Every time qsort! is called, Julia could JIT-compile a new version
    of mycompare, which hard-codes the reference to the lessthan
    argument passed on that call. This is technically possible and has
    been implemented in some languages (e.g. reportedly GNU
    Guile

    and Lua
    do something like this). However, this strategy
    comes at a price: it requires that callbacks be recompiled every time
    a parameter in them changes, which is not true of the global-variable
    strategy. Anyway, it is not implemented yet in Julia.

Fortunately, there is often a third option, because C programmers
long ago recognized these limitations of function pointers, and
devised a workaround: most modern C callback interfaces allow
arbitrary data to be passed through to the callback via a
“pass-through” (or “thunk”) pointer parameter. As explained in the
next section, we can exploit this technique in Julia to pass a “true”
closure as a callback.

Passing closures via pass-through pointers

The qsort interface is nowadays considered rather antiquated. Years
ago, it was supplemented on BSD-Unix systems, and eventually in GNU
libc, by a function called qsort_r that solves the problem of passing
parameters to the callback in a re-entrant way. This is how the BSD (e.g. MacOS)
qsort_r function is defined:

void qsort_r(void *base, size_t nmemb, size_t size, void *thunk,
             int (*compare)(void *thunk, const void *a, const void *b));

Compared to qsort, there is an extra thunk parameter, and this is
passed through to the compare function as its first argument. In this
way, you can pass a pointer to arbitrary data through to your callback,
and we can exploit this to pass a closure through for an arbitrary Julia
callback.

All we need is a way to convert a Julia Function into an opaque
Ptr{Void} so that we can pass it through to our callback, and then a
way to convert the opaque pointer back into a Function. The former
is automatic if we simply declare the ccall argument as type Any
(which passes the argument as an opaque Julia object pointer), and the
latter is accomplished by the built-in function
unsafe_pointer_to_objref. (Technically, we could use type
Function or an explicit call to pointer_from_objref instead of
Any.) Using these, we can now define a working high-level qsort!
function that takes an arbitrary lessthan comparison-function
argument:

function qsort!_compare{T}(lessthan_::Ptr{Void}, a_::Ptr{T}, b_::Ptr{T})
    a = unsafe_load(a_)
    b = unsafe_load(b_)
    lessthan = unsafe_pointer_to_objref(lessthan_)::Function
    return lessthan(a, b) ? cint(-1) : cint(+1)
end

function qsort!{T}(A::Vector{T}, lessthan::Function=<)
    compare_c = cfunction(qsort!_compare, Cint, (Ptr{Void}, Ptr{T}, Ptr{T}))
    ccall(:qsort_r, Void, (Ptr{T}, Csize_t, Csize_t, Any, Ptr{Void}),
          A, length(A), sizeof(T), lessthan, compare_c)
    return A
end

qsort!_compare is a top-level function, so cfunction has no
problem with it, and it will only be compiled once per type T to be
sorted (rather than once per call to qsort! or per lessthan
function). We use the explicit ::Function assertion to tell
the compiler that we will only pass Function pointers in
lessthan_. Note that we gave the lessthan argument a default value
of < (default arguments being a recent
feature
added to
Julia).

We can now do qsort!([1.3, -2.7, 4.4, 3.1]) and it will
return the array sorted in ascending order, or qsort!([1.3, -2.7,
4.4, 3.1], >)
to sort in descending order.

Warning: qsort_r is not portable

The example above has one major problem that has nothing to do with
Julia: the qsort_r function is not portable. The above example
won’t work on Windows, since the Windows C library doesn’t define
qsort_r (instead, it has a function called
qsort_s,
which of course uses an argument order incompatible with both the
BSD and GNU qsort_r functions). Worse, it will crash on GNU/Linux
systems, which do provide qsort_r but with an
incompatible
calling
convention
. And
as a result it is difficult to use qsort_r in a way that does not
crash either on GNU/Linux or BSD (e.g. MacOS) systems. This is how
glibc’s qsort_r is defined:

void qsort_r(void *base, size_t nmemb, size_t size,
             int (*compare)(const void *a, const void *b, void *thunk),
              void *thunk);

Note that the position of the thunk argument is moved, both in qsort_r itself and
in the comparison function. So, the corresponding qsort! Julia code on
GNU/Linux systems should be:

function qsort!_compare{T}(a_::Ptr{T}, b_::Ptr{T}, lessthan_::Ptr{Void})
    a = unsafe_load(a_)
    b = unsafe_load(b_)
    lessthan = unsafe_pointer_to_objref(lessthan_)::Function
    return lessthan(a, b) ? cint(-1) : cint(+1)
end

function qsort!{T}(A::Vector{T}, lessthan::Function=<)
    compare_c = cfunction(qsort!_compare, Cint, (Ptr{T}, Ptr{T}, Ptr{Void}))
    ccall(:qsort_r, Void, (Ptr{T}, Csize_t, Csize_t, Ptr{Void}, Any),
          A, length(A), sizeof(T), compare_c, lessthan)
    return A
end

If you really needed to call qsort_r from Julia, you could use the
above definitions if OS_NAME == :Linux and the BSD definitions
otherwise, with a third version using qsort_s on Windows, but
fortunately there is not much need as Julia comes with its own
perfectly adequate sort and sort! routines.

Passing closures in data structures

As another example that is oriented more towards numerical
computations, we’ll examine how we might call the numerical integration
routines in the GNU Scientific Library
(GSL)
. There is already a GSL
package
that handles the wrapper
work below for you, but it is instructive to look at how this is
implemented because GSL simulates closures in a slightly different
way, with data structures.

Like most modern C libraries accepting callbacks, GSL uses a void* pass-through
parameter to allow arbitrary data to be passed through to the callback routine,
and we can use that to support arbitrary closures in Julia. Unlike qsort_r,
however, GSL wraps both the C function pointer and the pass-through pointer in
a data structure called gsl_function:

struct {
    double (*function)(double x, void *params);
    void *params;
} gsl_function;

Using the techniques above, we can easily declare a GSL_Function type in Julia
that mirrors this C type, and with a constructor GSL_Function(f::Function) that
creates a wrapper around an arbitrary Julia function f:

function gsl_function_wrap(x::Cdouble, params::Ptr{Void})
    f = unsafe_pointer_to_objref(params)::Function
    convert(Cdouble, f(x))::Cdouble
end
const gsl_function_wrap_c = cfunction(gsl_function_wrap,
                                      Cdouble, (Cdouble, Ptr{Void}))

type GSL_Function
    func::Ptr{Void}
    params::Any
    GSL_Function(f::Function) = new(gsl_function_wrap_c, f)
end

One subtlety with the above code is that we need to explicitly
convert the return value of f to a Cdouble (in case the caller’s
code returns some other numeric type for some x, such as an Int).
Moreover, we need to explicitly assert (::Cdouble) that the result
of the convert was a Cdouble. As with the qsort example, this
is because cfunction only works if Julia can guarantee that
gsl_function_wrap returns the specified Cdouble type, and
Julia cannot infer the return type of convert since it does not
know the return type of f(x).

Given the above definitions, it is a simple matter to pass this to the
GSL
adaptive-integration

routines in a wrapper function gsl_integration_qag:

function gsl_integration_qag(f::Function, a::Real, b::Real, epsrel::Real=1e-12,
                             maxintervals::Integer=10^7)
    s = ccall((:gsl_integration_workspace_alloc,:libgsl), Ptr{Void}, (Csize_t,),
              maxintervals)
    result = Array(Cdouble,1)
    abserr = Array(Cdouble,1)
    ccall((:gsl_integration_qag,:libgsl), Cint,
          (Ptr{GSL_Function}, Cdouble,Cdouble, Cdouble, Csize_t, Cint, Ptr{Void}, 
           Ptr{Cdouble}, Ptr{Cdouble}),
          &GSL_Function(f), a, b, epsrel, maxintervals, 1, s, result, abserr)
    ccall((:gsl_integration_workspace_free,:libgsl), Void, (Ptr{Void},), s)
    return (result[1], abserr[1])
end

Note that &GSL_Function(f) passes a pointer to a GSL_Function
“struct” containing a pointer to gsl_function_wrap_c and f, corresponding
to the gsl_function* argument in C. The return value is a tuple of the estimated
integral and an estimated error.

For example, gsl_integration_qag(cos, 0, 1) returns
(0.8414709848078965,9.34220461887732e-15), which computes the
correct integral sin(1) to machine precision.

Taking out the trash (or not)

In the above examples, we pass an opaque pointer (object reference) to a
Julia Function into C. Whenever one passes pointers to Julia data into C
code, one has to ensure that the Julia data is not garbage-collected until
the C code is done with it, and functions are no exception to this rule.
An anonymous function that is no longer referred to by any Julia variable
may be garbage collected, at which point any C pointers to it become invalid.

This sounds scary, but in practice you don’t need to worry about it very often,
because Julia guarantees that ccall arguments won’t be garbage-collected until
the ccall exits. So, in all of the above examples, we are safe: the Function
only needs to live as long as the ccall.

The only danger arises when you pass a function pointer to C and the C code
saves the pointer in some data structure which it will use in a later ccall.
In that case, you are responsible for ensuring that the Function variable lives
(is referred to by some Julia variable) as long as the C code might need it.

For example, in the GSL one-dimensional minimization
interface
,
you don’t simply pass your objective function to a minimization
routine and wait until it is minimized. Instead, you call a GSL
routine to create a “minimizer object”, store your function pointer in this
object, call routines to iterate the minimization, and then deallocate the
minimizer when you are done. The Julia function must not be garbage-collected
until this process is complete. The easiest way to ensure this is to create
a Julia wrapper type around the minimizer object that stores an explicit
reference to the Julia function, like this:

type GSL_Minimizer
    m::Ptr{Void} # the gsl_min_fminimizer pointer
    f::Any  # explicit reference to objective, to prevent garbage-collection
    function GSL_Minimizer(t)
       m = ccall((:gsl_min_fminimizer_alloc,:libgsl), Ptr{Void}, (Ptr{Void},), t)
       p = new(m, nothing)
       finalizer(p, p -> ccall((:gsl_min_fminimizer_free,:libgsl),
                               Void, (Ptr{Void},), p.m))
       p
    end
end

This wraps around a gsl_min_fminimizer object of type t, with a
placeholder f to store a reference to the objective function (once
it is set below), including a finalizer to deallocate the GSL object
when the GSL_Minimizer is garbage-collected. The parameter t is
used to specify the minimization algorithm, which could default to
Brent’s algorithm via:

const gsl_brent = unsafe_load(cglobal((:gsl_min_fminimizer_brent,:libgsl), Ptr{Void}))
GSL_Minimizer() = GSL_Minimizer(gsl_brent)

(The call to cglobal yields a pointer to the
gsl_min_fminimizer_brent global variable in GSL, which we then
dereference to get the actual pointer via unsafe_load.)

Then, when we set the function to minimize (the “objective”), we store
an extra reference to it in the GSL_Minimizer to prevent
garbage-collection for the lifetime of the GSL_Minimizer, again
using the GSL_Function type defined above to wrap the callback:

function gsl_minimizer_set!(m::GSL_Minimizer, f, x0, xmin, xmax)
    ccall((:gsl_min_fminimizer_set,:libgsl), Cint,
          (Ptr{Void}, Ptr{GSL_Function}, Cdouble, Cdouble, Cdouble),
          m.m, &GSL_Function(f), x0, xmin, xmax)
    m.f = f
    m
end

There are then various GSL routines to iterate the minimizer and to check the
current x, objective value, or bounds on the minimum, which are convenient to wrap:

gsl_minimizer_iterate!(m::GSL_Minimizer) =
    ccall((:gsl_min_fminimizer_iterate,:libgsl), Cint, (Ptr{Void},), m.m)

gsl_minimizer_x(m::GSL_Minimizer) =
    ccall((:gsl_min_fminimizer_x_minimum,:libgsl), Cdouble, (Ptr{Void},), m.m)

gsl_minimizer_f(m::GSL_Minimizer) =
    ccall((:gsl_min_fminimizer_f_minimum,:libgsl), Cdouble, (Ptr{Void},), m.m)

gsl_minimizer_xmin(m::GSL_Minimizer) =
    ccall((:gsl_min_fminimizer_x_lower,:libgsl), Cdouble, (Ptr{Void},), m.m)
gsl_minimizer_xmax(m::GSL_Minimizer) =
    ccall((:gsl_min_fminimizer_x_upper,:libgsl), Cdouble, (Ptr{Void},), m.m)

Putting all of these together, we can minimize a simple function sin(x) in
the interval [-3,1], with a starting guess -1, via:

m = GSL_Minimizer()
gsl_minimizer_set!(m, sin, -1, -3, 1)
while gsl_minimizer_xmax(m) - gsl_minimizer_xmin(m) > 1e-6
    println("iterating at x = $(gsl_minimizer_x(m))")
    gsl_minimizer_iterate!(m)
end
println("found minimum $(gsl_minimizer_f(m)) at x = $(gsl_minimizer_x(m))")

After a few iterations, it prints found minimum -1.0 at x =
-1.5707963269964016
, which is the correct minimum (−π/2) to
about 10 digits.

At this point, I will shamelessly plug my own NLopt
package
for Julia, which wraps
around my free/open-source NLopt library
to provide many more optimization algorithms than GSL, with perhaps a nicer
interface. However, the techniques used to pass callback functions to
NLopt are actually quite similar to those used for GSL.

An even more complicated version of these techniques can be found in
the PyCall package to call
Python from Julia. In order to pass a Julia function to Python, we
again use cfunction on a wrapper function that handles the type
conversions and so on, and pass the actual Julia closure through via a
pass-through pointer. But in that case, the pass-through pointer
consists of a Python object that has been created with a new type that
allows it to wrap a Julia object, and garbage-collection is deferred
by storing the Julia object in a global dictionary of saved objects
(removing it via the Python destructor of the new type). That is all
somewhat tricky stuff and beyond the scope of this blog post; I only
mention it to illustrate the fact that it is possible to implement
quite complex inter-language calling behaviors purely in Julia by
building on the above techniques.