Skip to content

Building blocks ​

The picker window is assembled from building blocks that can be reused for other windows. They are not exported; call them as AdriaArrayGeometryPicker.picker_layout etc., or import them with using AdriaArrayGeometryPicker: picker_layout, ....

AdriaArrayGeometryPicker.AdriaArrayGeometryPicker Module
julia
AdriaArrayGeometryPicker

The AdriaArray geometry picker: a GLMakie window for visualizing GeophysicalModelGenerator.jl profiles (vertical cross-sections and horizontal slices) and picking points on them. Start it with geometry_picker.

The code is split into two parts:

Derived from MakiePickerGUI.jl (GeometryPicker repository); it contains only the code of its ready-made picker window.

source

Assembling a window ​

geometry_picker builds the window like this:

julia
using AdriaArrayGeometryPicker
using AdriaArrayGeometryPicker: picker_layout, on_profile_loaded, picking_state, menu_selection
using GLMakie

profile = Observable{Any}(nothing)
profile_file = Observable("")
profile_path = Observable("")
fig, panels, axis, widgets = picker_layout(; profile)
states = on_profile_loaded(profile, profile_file, axis, panels, widgets)
picking = picking_state(fig, profile, axis, widgets)
session = (; fig, profile, profile_file, profile_path, panels, axes = axis, widgets, picking, states...)
menu_selection(widgets.menu, session)
display(fig)
AdriaArrayGeometryPicker.picker_layout Function
julia
picker_layout(; size = (1200, 1000), profile = nothing, empty_height = 20,
              logo_file = <assets/AdA_Picker_logo_tr.png>) -> NamedTuple

Create the figure and window layout of the picker:

julia
┌─────────────┬───────────────┬─────────────┬──────────┐
│ menu        │ pick controls │ pick legend │ logo     │
├─────────────┼───────────────┴─────────────┴──────────┤
│ volume data │ topography (20 %)                      │
│ surface data│ profile                                │
│ point data  │                                        │
│ topography  │                                        │
│ compare     │                                        │
│ map overview│ colorbar / legends (160 px)            │
│ screenshot  │                                        │
└─────────────┴────────────────────────────────────────┘

This is the ready-made window for profile data and therefore specific to GeophysicalModelGenerator profiles (the widgets belong to the plot states). It is made of control_panel! panels, profile_plot_area! (plot panel), volume_panel! (volume data widgets) and map_panel! (map overview widgets); on_profile_loaded connects them. geometry_picker builds the whole window.

Keywords

  • size: size of the figure in pixels.

  • profile: the Observable that holds the profile. If given, every panel that has widgets switches to following its content as soon as profile holds a profile. This listener has the same priority (-10) as the one of connect_profile! and is registered first, so it runs before the loaders; this is harmless because every load_*! function fits its panel itself.

  • empty_height: the menu panels start with this small fixed content height.

  • logo_file: image shown in the top right corner (a warning is logged if it does not exist).

The first row and column of the window adapt to the panels; the plot panel takes the remaining space. The menu panel holds the dropdown menu (see menu_selection for its entries), the picking panel the picking toggle and a user name field, the picks panel the compare-picks toggle. The volume data panel holds the widgets of volume_panel! (a data dropdown, the colorbar limits, a colormap dropdown with a "reverse" checkbox and the same controls for the contour lines); volume_plot_state connects them. The plot panel is made by profile_plot_area!. The map overview panel holds the widgets of map_panel! (a "Load topography" button, a label and a map axis; connected by map_plot_state). The other collapsible panels are filled when a profile is loaded (see on_profile_loaded); only one of them is expanded at a time (see exclusive_panels!). The topography and profile axes are linked in x.

Returns

A NamedTuple (; fig, panels, axes, widgets):

  • fig: the figure,

  • panels: the content GridLayout of each menu panel (main_menu, pick_controls, pick_legend, volume_data_panel, surface_data_panel, point_data_panel, topography_data_panel, compare_picks_panel, map_data_panel, screenshot_data_panel), plus the layouts logo, plot and colorbar,

  • axes: topo_ax, profile, logo and map,

  • widgets: menu, pick_toggle, pick_name, pick_warning, compare_toggle, the volume data and contour controls volume_* (see volume_panel!), map_load_button, map_label (see map_panel!) and the expand / collapse toggles *_panel_toggle of the collapsible panels (volume, surface, point, topography, compare, map, screenshot).

Do not destructure the result into a variable named axes: that would shadow Base.axes in your module. The examples use axis.

Example

julia
profile = Observable{Any}(nothing)
fig, panels, axis, widgets = picker_layout(; profile)
display(fig)
source
AdriaArrayGeometryPicker.profile_plot_area! Function
julia
profile_plot_area!(gp; topography = true) -> NamedTuple

Create the plot panel of a profile GUI at the grid position gp (the plot panel of picker_layout):

julia
┌────────────────────────────────────────────┐
│ topography axis (20 % of the height)       │
├────────────────────────────────────────────┤
│ profile axis                               │
│                                            │
├──────────┬─────────┬─────────┬─────────────┤
│ colorbars│ surface │ point   │ compare     │  colorbar layout (160 px)
│          │ legend  │ legend  │ legend      │
└──────────┴─────────┴─────────┴─────────────┘

The topography axis has no decorations and is linked to the profile axis in x; the profile axis has no grid (it would show through the heatmap). The colorbar layout holds the colorbars of the volume data in its first column (see volume_plot_state) and right of them the legends of the surface data, point data and compared picks, in this order. The legends are packed from the left: a legend that does not exist (e.g. no surface data) leaves no gap. Requires nothing but a figure; the axes are meant for GeophysicalModelGenerator profiles.

Arguments

  • gp: grid position, e.g. fig[1, 2].

Keywords

  • topography: false creates no topography axis (topo_ax is then nothing), the profile axis takes the whole height.

Returns

A NamedTuple (; plot, topo_ax, profile, colorbar): the layout of the plot panel, the topography axis, the profile axis and the colorbar layout. It has the fields of the axes (profile, topo_ax) and panels (plot, colorbar) of picker_layout that the plot states and connect_profile! use, so it can be passed as either.

Example

julia
fig = Figure()
area = profile_plot_area!(fig[1, 2])
panel = control_panel!(fig[1, 1], "Volume data"; width = 340)
volume = volume_plot_state(area.profile, volume_panel!(panel), area.colorbar)
source
AdriaArrayGeometryPicker.set_profile_layout! Function
julia
set_profile_layout!(axes, profile; show_topography = true)

Adapt the plot panel to the type of profile: a vertical cross-section gets the topography axis above the profile axis. For a horizontal slice the topography axis is hidden and the profile axis takes its space; the profile axis then shows longitude / latitude and the depth of the slice as its title. Requires a GeophysicalModelGenerator ProfileData.

The topography axis is hidden by shrinking the layout row it sits in to zero height (its original size is restored when it is shown again), so it can be in any row of any layout.

Arguments

  • axes: a NamedTuple with the profile axis profile and, optionally, the topography axis topo_ax (nothing or missing: only the profile axis is adapted), e.g. the axes of picker_layout or the result of profile_plot_area!.

  • profile: the loaded profile (nothing is treated as vertical).

Keywords

  • show_topography: set to false to hide the topography axis of a vertical profile as well (e.g. if it has no topography data).

Returns nothing.

source
AdriaArrayGeometryPicker.on_profile_loaded Function
julia
on_profile_loaded(profile::Observable, profile_file::Observable, axes::NamedTuple,
                  panels::NamedTuple, widgets::NamedTuple)

Create all plot states of the window of picker_layout (colorbar and volume data controls, surface, point and topography data, map overview, compared picks) and fill them with every profile loaded into profile (see connect_profile!). Requires a GeophysicalModelGenerator ProfileData and the layout of picker_layout; for a layout of your own, create the states you need and call connect_profile!.

Arguments

  • profile: Observable that holds the profile (see load_profile!).

  • profile_file: Observable with the name of the loaded file (set before profile changes), used as title of the topography axis.

  • axes, panels, widgets: as returned by picker_layout (the states are made with the picker_layout forms of the state functions, e.g. volume_plot_state(axes, panels, widgets)).

Every time a profile is loaded (listener with priority -10), the layout is adapted to the profile type (vertical cross-section or horizontal slice, see set_profile_layout!), the topography is plotted (with file name and start/end coordinates), the volume data dropdown is filled and its first field plotted as a heatmap, the axis limits of a horizontal slice are set (see fit_horizontal_axis!), and the surface data, point data, map overview and compared picks are replaced by those of the new profile. An error in one of these steps is logged and does not stop the others. See load_volume_data!, load_surface_data!, load_point_data!, load_topography_panel!, update_map_line! and clear_compare_picks! for the individual steps.

Returns the plot states (; volume, surface, points, topography, topomap, compare), which the GUI state (see gui_settings) is read from.

Example

julia
profile = Observable{Any}(nothing)
profile_file = Observable("")
fig, panels, axis, widgets = picker_layout(; profile)
states = on_profile_loaded(profile, profile_file, axis, panels, widgets)
profile_file[] = "Profile1.pgmg"
load_profile!(profile, joinpath(pkgdir(AdriaArrayGeometryPicker), "assets", "Profile1.pgmg"))
source
AdriaArrayGeometryPicker.connect_profile! Function
julia
connect_profile!(profile::Observable, states::NamedTuple; axes, profile_file = "",
                 priority = -10) -> ObserverFunction

Fill the plot states states with every profile that is loaded into profile: the listener that makes a GUI follow its profile. Only the states that are present are filled, so a GUI with e.g. only a volume and a point data panel passes (; volume, points). Requires a GeophysicalModelGenerator ProfileData.

Every time a profile is loaded, these steps are taken (in this order, each only if its state is present):

stepstate (field of states)function
layout of the plot panel– (always, if there are axes)set_profile_layout!
topography (axis title: profile_file)topography (topography_panel_state)load_topography_panel!
volume datavolume (volume_plot_state)load_volume_data!
axis limits of a horizontal slice– (always, if there are axes)fit_horizontal_axis!
surface datasurface (surface_plot_state)load_surface_data!
point datapoints (point_plot_state)load_point_data!
map overviewtopomap (map_plot_state)update_map_line!
compared picks are removedcompare (compare_plot_state)clear_compare_picks!

Other fields of states are ignored. An error in one of the steps is logged and does not stop the others. Without a topography state the topography axis (if any) stays hidden.

Arguments

Keywords

  • axes: NamedTuple with the profile axis profile and optionally the topography axis topo_ax, e.g. the result of profile_plot_area! or the axes of picker_layout (required; nothing: the layout and the axis limits are left alone).

  • profile_file: name of the profile file (String or Observable, read when a profile is loaded), the title of the topography axis.

  • priority: priority of the listener. The default -10 runs it after the listeners with default priority, and before the one of picking_state (-20).

Returns the listener, which can be removed with off.

Example

julia
fig = Figure(size = (1200, 900))
area = profile_plot_area!(fig[1, 2])
left = fig[1, 1] = GridLayout()
volume_panel = control_panel!(left[1, 1], "Volume data"; width = 340)
point_panel = control_panel!(left[2, 1], "Point data"; width = 340)
map_panel = control_panel!(left[3, 1], "Map"; width = 340)
map_widgets = map_panel!(map_panel)
states = (; volume = volume_plot_state(area.profile, volume_panel!(volume_panel), area.colorbar),
          points = point_plot_state(area.profile, point_panel, area.colorbar),
          topomap = map_plot_state(map_widgets.map_ax, map_widgets.map_load_button, map_widgets.map_label))
profile = Observable{Any}(nothing)
connect_profile!(profile, states; axes = area)
load_profile!(profile, joinpath(pkgdir(AdriaArrayGeometryPicker), "assets", "Profile1.pgmg"))
source
AdriaArrayGeometryPicker.menu_selection Function
julia
menu_selection(menu::Menu, session) -> ObserverFunction

Connect the entries of the dropdown menu (widgets.menu of picker_layout, or a Menu of your own with some of these entries) to their actions. Requires a GeophysicalModelGenerator profile GUI.

Each entry reads only the fields of session it needs. If a field is missing, choosing the entry logs a warning that names it and does nothing else; so a custom GUI can use the menu with the parts it has. Unknown entries are ignored.

entryactionsession fields
"Load Profile"choose a .pgmg file and load it (see open_profile!)profile; optional profile_file, profile_path
"Save State"save the path of the loaded profile and the settings of the GUI to a .aagps file (a JLD2 file, see save_gui_state)profile, profile_path; the parts listed in gui_settings
"Load State"restore them from a .aagps file (or a .jld2 state file of MakiePickerGUI.jl; see load_gui_state!)as "Save State"
"Save Picks"save the picks to a .aagpp (JLD2) or .csv file (see current_picks)profile, picking; optional profile_file, widgets.pick_name
"Load Picks"load picks (editable) from a file if they belong to the loaded profile (see set_picks!)as "Save Picks"
"Load Compare Picks"show the picks of a file (e.g. of another user) as a dashed line for comparison, not editable (see load_compare_picks!)profile, compare
"Save Screenshot"choose a file name and save an image of the whole window (see save_screenshot_dialog)fig
"Close"close the windowfig

The session of the ready-made picker has all of them (see the example below).

Dialogs run in a background task, so the window keeps rendering while they are open; errors are logged and the GUI keeps running.

Arguments

  • menu: the Menu; create it with default = nothing, so that no entry is preselected.

  • session: a NamedTuple (or any object with these properties) with the fields above.

Returns the listener, which can be removed with off.

Example

julia
profile = Observable{Any}(nothing)
profile_file = Observable("")
profile_path = Observable("")
fig, panels, axis, widgets = picker_layout(; profile)
states = on_profile_loaded(profile, profile_file, axis, panels, widgets)
picking = picking_state(fig, profile, axis, widgets)
session = (; fig, profile, profile_file, profile_path, panels, axes = axis, widgets, picking, states...)
menu_selection(widgets.menu, session)
source
AdriaArrayGeometryPicker.is_state_file Function
julia
is_state_file(path) -> Bool

Whether path is a GUI state file (see save_gui_state; usually .aagps): a JLD2 file with a "format" entry "AdriaArrayGeometryPicker state" (or "MakiePickerGUI state", written by MakiePickerGUI.jl). Decided by the content, not by the extension; anything that is not a JLD2 file, or a JLD2 file without such an entry (e.g. a .pgmg profile), gives false.

source

Profiles ​

AdriaArrayGeometryPicker.load_profile! Function
julia
load_profile!(profile::Observable, path) -> profile data

Load the GeophysicalModelGenerator profile stored in the .pgmg file path and assign it to profile, which notifies everything that listens to it (see on_profile_loaded). Returns the loaded ProfileData. The file may hold a vertical cross-section or a horizontal slice, see is_vertical.

Arguments

  • profile: Observable that holds the current profile (nothing before a profile is loaded).

  • path: path of the .pgmg file (a JLD2 file with a single ProfileData entry).

Example

julia
profile = Observable{Any}(nothing)
load_profile!(profile, joinpath(pkgdir(AdriaArrayGeometryPicker), "assets", "Profile1.pgmg"))
source
AdriaArrayGeometryPicker.open_profile! Function
julia
open_profile!(session, path) -> profile data

Load the profile file path into the GUI (see load_profile!) and remember its file name (session.profile_file, the title of the topography axis and stored with the picks) and its full path (session.profile_path, for save_gui_state). Both are set before the profile, so the listeners of profile see the new names. Returns the loaded profile.

Arguments

  • session: a NamedTuple (or any object with these properties):

    • profile (required): the Observable that holds the profile,

    • profile_file (optional): Observable{String} that receives the file name,

    • profile_path (optional): Observable{String} that receives the absolute path.

    The session of the picker has them all (see menu_selection).

  • path: path of the .pgmg file.

Requires a GeophysicalModelGenerator ProfileData in the file.

source
AdriaArrayGeometryPicker.is_vertical Function
julia
is_vertical(profile) -> Bool

Whether profile is a vertical cross-section (true, also for nothing and for profiles without a vertical field) or a horizontal slice at a certain depth (false). Vertical and horizontal profiles are plotted and picked differently: along the profile (distance, depth) or in the lon / lat plane. Accepts a GeophysicalModelGenerator ProfileData or nothing.

source
AdriaArrayGeometryPicker.slice_depth Function
julia
slice_depth(profile) -> Float64

Depth of the horizontal slice profile (same sign convention as the depth of the data). Only meaningful for horizontal slices (is_vertical(profile) == false). Requires a GeophysicalModelGenerator ProfileData.

source

Volume data ​

AdriaArrayGeometryPicker.volume_panel! Function
julia
volume_panel!(panel::GridLayout; contours = true, colormaps = <all matplotlib and Crameri maps>,
              colormap = "viridis", contour_colormap = "coolwarm") -> NamedTuple

Create the widgets of the volume data panel in the layout panel (e.g. the content of a control_panel!) and let the panel follow their size (fit_panel!). These are the widgets of the volume data panel of picker_layout; they do nothing until volume_plot_state connects them. Requires nothing but a layout; the widgets are meant for the volume data of a GeophysicalModelGenerator ProfileData.

The rows of panel, from the top: a dropdown for the data field, the colorbar limits (min / max text fields around an interval slider), a label with the current limits, a colormap dropdown with a "reverse" checkbox; with contours = true also the same controls for contour lines of a second field (dropdown with a "show" toggle, colormap with "reverse" checkbox, colour range) and a text field for the contour levels.

Arguments

Keywords

  • contours: false leaves out the contour line widgets (the volume data are then only shown as a heatmap).

  • colormaps: the names of the colormaps in the colormap dropdowns.

  • colormap, contour_colormap: the initially selected colormaps.

Returns

A NamedTuple of the widgets, named as in the widgets of picker_layout: volume_menu, volume_cbar_min, volume_cbar_slider, volume_cbar_max, volume_cbar_label, volume_cmap_menu, volume_cmap_reverse and, with contours = true, volume_contour_menu, volume_contour_toggle, volume_contour_cmap_menu, volume_contour_cmap_reverse, volume_contour_cbar_min, volume_contour_cbar_slider, volume_contour_cbar_max and volume_contour_levels.

Example

julia
fig = Figure()
area = profile_plot_area!(fig[1, 2])
panel = control_panel!(fig[1, 1], "Volume data"; collapsible = true, width = 340)
widgets = volume_panel!(panel; colormaps = ["viridis", "roma", "coolwarm"])
volume = volume_plot_state(area.profile, widgets, area.colorbar)
source
AdriaArrayGeometryPicker.volume_plot_state Function
julia
volume_plot_state(ax::Axis, widgets, colorbar::GridLayout) -> NamedTuple
volume_plot_state(axes, panels, widgets) -> NamedTuple

Create the colorbars of the volume data and connect the volume data widgets (field dropdown, colorbar limits slider and text fields, colormap dropdown and reverse checkbox, and the same for the contour lines with their own colorbar and levels). Returns the state that load_volume_data! fills when a profile is loaded. Created once, before a profile is loaded; the plots follow the widgets from then on. Works for vertical and horizontal GeophysicalModelGenerator profiles alike.

Arguments

  • ax: the profile axis, in which the heatmap and the contour lines are plotted.

  • widgets: the widgets made by volume_panel! (any NamedTuple with these fields, e.g. the widgets of picker_layout). Without the volume_contour_* widgets (volume_panel!(panel; contours = false)) there are no contour lines and no contour colorbar.

  • colorbar: the layout for the colorbars (see profile_plot_area!). The colorbar of the heatmap and its title go into the rows 1 and 2 of its first column, those of the contour lines into the rows 3 and 4.

  • axes, panels: as returned by picker_layout; axes.profile and panels.colorbar are used.

Returns

A NamedTuple with the plots (heatmap, contour: Refs), the Observables they follow (colormap, colorrange, contour_colormap, contour_colorrange, levels), the profile axis ax, the widgets and a few internal fields. contours says whether there are contour lines.

Example

julia
fig = Figure()
area = profile_plot_area!(fig[1, 2])
panel = control_panel!(fig[1, 1], "Volume data"; width = 340)
volume = volume_plot_state(area.profile, volume_panel!(panel), area.colorbar)
profile = Observable{Any}(nothing)
connect_profile!(profile, (; volume); axes = area)    # or call `load_volume_data!` yourself
load_profile!(profile, joinpath(pkgdir(AdriaArrayGeometryPicker), "assets", "Profile1.pgmg"))
source
AdriaArrayGeometryPicker.load_volume_data! Function
julia
load_volume_data!(state, profile) -> nothing

Fill the field dropdowns with the data fields of profile.VolData and plot the first one as a heatmap and as contour lines (plot_volume!, plot_contours!), replacing the plots of the previous profile. On a horizontal slice the depth of the SurfData entries is offered as additional fields. Without volume data the dropdowns say so and the previous plots are removed. Called by connect_profile! for the state volume. Requires a GeophysicalModelGenerator ProfileData.

GeophysicalModelGenerator declares VolData as a single GeoData (or nothing); this package also accepts a NamedTuple of GeoData, whose fields are then all offered (a field name that occurs in several of them gets the key as prefix).

On a vertical profile the heatmap is over the distance along the profile and the depth; on a horizontal slice over longitude and latitude.

Arguments

  • state: the volume state of volume_plot_state (without contour widgets only the heatmap is plotted).

  • profile: the loaded profile.

Returns nothing.

source
AdriaArrayGeometryPicker.plot_volume! Function
julia
plot_volume!(state, geo::GeoData, field::Symbol)

Plot field of geo as a heatmap in the profile axis, replacing the previous one, and adapt the colorbar slider (range and initial limits: minus/plus the largest absolute value of the field, so they are symmetric around zero) and the colorbar title.

source
AdriaArrayGeometryPicker.plot_contours! Function
julia
plot_contours!(state, geo::GeoData, field::Symbol)

Plot field of geo as contour lines on top of the heatmap, replacing the previous ones. The levels follow state.levels, the lines are coloured with the contour colormap and colour range (own slider, range: plus/minus the largest absolute value of field) and are visible as long as the contour toggle is on. Their colorbar (created in volume_plot_state) sits below the one of the heatmap and is titled with the field name.

source
AdriaArrayGeometryPicker.clear_contours! Function
julia
clear_contours!(state)

Remove the contour lines and the title of their colorbar.

source
AdriaArrayGeometryPicker.volume_entries Function
julia
volume_entries(voldata) -> Vector{Tuple{String,Tuple}}

Dropdown entries (label, (geodata, fieldname)) for all data fields in voldata, which is nothing, a single GeoData (as GeophysicalModelGenerator declares VolData) or a NamedTuple of them (also accepted by this package). The coordinate fields (*x_profile) and the *FlatCrossSection fields are left out. A field name that occurs in several GeoData objects gets the key of its object as prefix.

source
AdriaArrayGeometryPicker.surface_entries Function
julia
surface_entries(profile) -> Vector{Tuple{String,Tuple}}

Dropdown entries ("name: depth", (geodata, :depth)) for the surface data sets of a horizontal slice, which can be plotted like volume data (the depth of the surface is the value). Sets that only contain NaN are left out.

source

Surface and point data ​

AdriaArrayGeometryPicker.surface_plot_state Function
julia
surface_plot_state(ax::Axis, panel::GridLayout, colorbar::GridLayout) -> NamedTuple
surface_plot_state(axes, panels) -> NamedTuple

State for the surface data: what load_surface_data! created for the current profile (toggles and labels in the surface data panel, lines in the profile axis, the legend). Created once, before a profile is loaded; it creates nothing itself. Meant for a GeophysicalModelGenerator ProfileData.

Arguments

  • ax: the profile axis.

  • panel: the (empty) layout for the toggles, e.g. the content of a control_panel!.

  • colorbar: the colorbar layout (see profile_plot_area!); the legend goes right of the colorbars (the first legend).

  • axes, panels: as returned by picker_layout; axes.profile, panels.surface_data_panel and panels.colorbar are used.

Returns the state, a NamedTuple with the fields ax, panel, colorbar, the plots, the toggles with their labels and the legend (Ref).

source
AdriaArrayGeometryPicker.load_surface_data! Function
julia
load_surface_data!(state, profile) -> nothing

Replace the surface data of the previous profile by profile.SurfData: for each surface a label and a toggle in the surface data panel, a white line with a coloured line on top of it in the profile axis (visible as long as the toggle is on) and an entry in the "Surface data" legend, the first legend right of the colorbars (greyed out by Makie while the toggle is off). Surfaces that only contain NaN do not intersect the profile and are skipped, as is a Topography entry, which is plotted separately. On a horizontal slice, SurfData entries that cross the depth of the slice are shown as a contour line at that depth. The panel is empty and there is no legend if there is no surface data. Called by connect_profile! for the state surface. Requires a GeophysicalModelGenerator ProfileData.

Arguments

source
AdriaArrayGeometryPicker.point_plot_state Function
julia
point_plot_state(ax::Axis, panel::GridLayout, colorbar::GridLayout) -> NamedTuple
point_plot_state(axes, panels) -> NamedTuple

State for the point data: what load_point_data! created for the current profile (toggles and labels in the point data panel, scatter plots in the profile axis, the legend). Created once, before a profile is loaded; it creates nothing itself. Meant for a GeophysicalModelGenerator ProfileData.

Arguments

  • ax: the profile axis.

  • panel: the (empty) layout for the toggles, e.g. the content of a control_panel!.

  • colorbar: the colorbar layout (see profile_plot_area!); the legend goes right of the colorbars and the surface data legend (if there is one).

  • axes, panels: as returned by picker_layout; axes.profile, panels.point_data_panel and panels.colorbar are used.

Returns the state, a NamedTuple with the fields ax, panel, colorbar, the plots, the toggles with their labels and the legend (Ref).

source
AdriaArrayGeometryPicker.load_point_data! Function
julia
load_point_data!(state, profile) -> nothing

Replace the point data of the previous profile by profile.PointData: for each dataset a label and a toggle in the point data panel, a scatter plot in the profile axis (x_profile against depth_proj, visible as long as the toggle is on) and an entry in the "Point data" legend, right of the surface data legend if there is one (greyed out by Makie while the toggle is off). For a horizontal slice the points are plotted as longitude against latitude. Datasets without points are skipped. Called by connect_profile! for the state points. Requires a GeophysicalModelGenerator ProfileData.

Arguments

source

Topography ​

AdriaArrayGeometryPicker.topography_panel_state Function
julia
topography_panel_state(ax::Axis, panel::GridLayout; topo_ax = nothing) -> NamedTuple
topography_panel_state(axes, panels) -> NamedTuple

State of the topography panel: what load_topography_panel! created for the current profile (widgets in the panel, plots in the profile axis or the topography axis). Created once, before a profile is loaded; it creates nothing itself. Meant for a GeophysicalModelGenerator ProfileData.

Arguments

  • ax: the profile axis (the topography of a horizontal slice is plotted on top of it).

  • panel: the (empty) content layout for the widgets, made by control_panel!.

  • axes, panels: as returned by picker_layout; axes.profile, axes.topo_ax (optional) and panels.topography_data_panel are used.

Keywords

  • topo_ax: the axis above the profile axis in which the topography of a vertical profile is plotted (see profile_plot_area!); without it, the topography of vertical profiles is not shown (horizontal slices do not need it).

Returns

A NamedTuple with the fields axes ((; profile, topo_ax)), panel, the widgets (blocks) and plots (plots) of the current profile and controls, a Ref to the widgets of the panel that can be set programmatically (filled by load_topography_panel!):

  • vertical profile: (; menu, show, fill): data set dropdown (nothing if there is only one data set), the Toggle that shows the topography axis and the Checkbox for the fill,

  • horizontal slice: (; menu, mode, opacity, levels): data set dropdown (or nothing), the display mode Menu ("Heatmap", "Contours", "Off"), the opacity Slider of the heatmap and the Textbox of the contour levels,

  • nothing without topography data (or a vertical profile without topo_ax).

Example

julia
fig = Figure()
area = profile_plot_area!(fig[1, 2])
panel = control_panel!(fig[1, 1], "Topography"; width = 340)
topography = topography_panel_state(area.profile, panel; topo_ax = area.topo_ax)
profile = Observable{Any}(nothing)
connect_profile!(profile, (; topography); axes = area)
load_profile!(profile, joinpath(pkgdir(AdriaArrayGeometryPicker), "assets", "Profile1.pgmg"))
# vertical profile: (; menu, show, fill); switch the fill below the topography line off
topography.controls[].fill.checked[] = false
# on a horizontal slice it is (; menu, mode, opacity, levels), e.g.
# select_label!(topography.controls[].mode, "Contours")
source
AdriaArrayGeometryPicker.load_topography_panel! Function
julia
load_topography_panel!(state, profile, name)

Replace the content of the topography panel and the topography plot by those of profile (profile.TopoData; name, the file name, is the title of the topography axis). state is created by topography_panel_state. Requires a GeophysicalModelGenerator ProfileData; the result depends on the profile type:

  • vertical profile: the topography is plotted in the topography axis above the profile (see plot_topography!). The panel has a dropdown for the data set (if there are several), a toggle that shows or hides the axis (the profile axis then takes its space) and a checkbox for the grey / blue fill below the line.

  • horizontal slice: the topography is plotted on top of the volume data, as a heatmap (oleron colormap, centred around zero, with a slider for the opacity) or as contour lines (levels typed in a text field, default: one line at 0), or not at all. The panel has a dropdown for the data set (if there are several) and these controls.

Without topography data the panel only says so and the topography axis is hidden; the same for a vertical profile if the state has no topography axis. The widgets of the panel are available in state.controls[] (see topography_panel_state), so they can be set programmatically, e.g. with select_label! and set_text!. Called by connect_profile! for the state topography.

Arguments

  • state: the topography state of topography_panel_state.

  • profile: the loaded profile.

  • name: title of the topography axis (usually the file name).

Returns nothing.

source
AdriaArrayGeometryPicker.plot_topography! Function
julia
plot_topography!(ax::Axis, profile, name; key = nothing, fill = true) -> Bool

Plot the topography of a vertical profile in ax, replacing what was plotted before: an entry of profile.TopoData as a black line over the distance along the profile (x_profile), with a grey fill below the line and a blue fill where it lies below sea level. The profile ends are marked with "A" and "B". Requires a GeophysicalModelGenerator ProfileData of a vertical cross-section (the topography of a horizontal slice is plotted by load_topography_panel!).

Arguments

  • ax: the axis to plot in; its title is set to name and the start / end coordinates of the profile are written in its top left / top right corner.

  • profile: the loaded profile.

  • name: title of the axis, usually the file name.

Keywords

  • key: entry of TopoData to plot (default: the first).

  • fill: false plots only the line.

Returns false (and only clears ax) if the profile has no topography, true otherwise.

source
AdriaArrayGeometryPicker.fit_horizontal_axis! Function
julia
fit_horizontal_axis!(ax::Axis, profile)

Set the limits of the axis of a horizontal slice to the lon / lat extent of its topography (of the volume data if there is no topography) and its aspect ratio such that distances look approximately equal: a degree of longitude is cos(latitude) times as long as one of latitude. For a vertical profile the axis gets its default aspect ratio back and its limits are left alone. Called by connect_profile!. Requires a GeophysicalModelGenerator ProfileData.

Arguments

  • ax: the profile axis, e.g. area.profile of profile_plot_area!.

  • profile: the loaded profile.

Returns nothing.

source

Map overview ​

AdriaArrayGeometryPicker.map_panel! Function
julia
map_panel!(panel::GridLayout; width = 250, height = 200) -> NamedTuple

Create the widgets of the map overview in the layout panel (the content of a control_panel!) and let the panel follow their size (fit_panel!): a "Load topography" button, a label with the name of the loaded topography file and a map axis (longitude / latitude). These are the widgets of the map overview panel of picker_layout; they do nothing until map_plot_state connects them. Requires nothing but a layout; the map is meant for the profile line of a GeophysicalModelGenerator ProfileData.

Arguments

Keywords

  • width, height: initial size of the map axis in pixels (it gets the aspect ratio of the region once a profile or a topography is shown, at most 250 × 300).

Returns

A NamedTuple (; map_ax, map_load_button, map_label): the map Axis, the Button and the Label, named as in the axes (map) and widgets of picker_layout.

Example

julia
fig = Figure()
panel = control_panel!(fig[1, 1], "Map overview"; collapsible = true, width = 340)
map_widgets = map_panel!(panel)
topomap = map_plot_state(map_widgets.map_ax, map_widgets.map_load_button, map_widgets.map_label)
source
AdriaArrayGeometryPicker.map_plot_state Function
julia
map_plot_state(ax::Axis, load_button = nothing, label = nothing) -> NamedTuple
map_plot_state(axes, widgets) -> NamedTuple

Create the state of the map overview: the profile line in the map axis ax (a white line with a red one on top, from the start to the end point of the profile, empty until a profile is loaded) and, if given, connect the load_button, which asks for a file and calls load_topography!. Created once, before a profile is loaded; update_map_line! draws each loaded profile (called by connect_profile! for the state topomap). Meant for a GeophysicalModelGenerator ProfileData.

Arguments

  • ax: the map axis, e.g. map_ax of map_panel!.

  • load_button: a Button that loads a topography file (a JLD2 file with a GeoData), or nothing (load topography from code with load_topography!).

  • label: a Label that shows the name of the loaded topography file, or nothing.

  • axes, widgets: as returned by picker_layout; axes.map, widgets.map_load_button and widgets.map_label are used.

Returns

A NamedTuple with the map axis ax, the label, the Observables of the profile line (line_points) and of its labels (markers), and Refs to the topography heatmap, its extent and the path of the loaded topography file ("" if none).

Example

julia
fig = Figure()
panel = control_panel!(fig[1, 1], "Map overview"; collapsible = true, width = 340)
map_widgets = map_panel!(panel)
topomap = map_plot_state(map_widgets.map_ax, map_widgets.map_load_button, map_widgets.map_label)
load_topography!(topomap, "path/to/etopo1.jld2")
source
AdriaArrayGeometryPicker.load_topography! Function
julia
load_topography!(state, path)

Load the topography file path (a JLD2 file holding a GeoData object, e.g. etopo1.jld2) and plot it in the map overview as a heatmap with the oleron colormap, centred around zero, replacing the previous one. Only every n-th grid point is plotted, so that large grids stay responsive. The map is shown with the aspect ratio of the region, and the label of the state (if any) shows the file name. Needs no profile, but the topography file has to hold a GeophysicalModelGenerator GeoData.

Arguments

Returns the GeoData that was plotted; throws an error if the file holds no GeoData.

source
AdriaArrayGeometryPicker.update_map_line! Function
julia
update_map_line!(state, profile)

Draw the profile in the map overview, replacing the previous one: a vertical profile as a line from its start to its end point (marked "A" and "B"), a horizontal slice as a box of its lon / lat extent labelled with its depth. Without a loaded topography the map limits follow the profile. Called by connect_profile! for the state topomap. Requires a GeophysicalModelGenerator ProfileData.

Arguments

source
AdriaArrayGeometryPicker.fit_map! Function
julia
fit_map!(state)

Set limits and aspect ratio of the map to the loaded topography, or, as long as there is none, to the profile line. Internal helper of the map overview.

source

Compared picks ​

AdriaArrayGeometryPicker.compare_plot_state Function
julia
compare_plot_state(ax::Axis, panel::GridLayout, colorbar::GridLayout, compare_toggle = nothing) -> NamedTuple
compare_plot_state(axes, panels, widgets) -> NamedTuple

Create the state for picks shown for comparison (picks of other files, not editable): what add_compare_picks! and load_compare_picks! create (a label and a toggle per file in the panel, a dashed line per file in the profile axis, a legend in the colorbar layout). Created once, before a profile is loaded; it creates nothing itself. clear_compare_picks! removes the compared picks (called by connect_profile! for the state compare whenever a profile is loaded). Meant for a GeophysicalModelGenerator ProfileData.

Arguments

  • ax: the profile axis.

  • panel: the (empty) content layout for the labels and toggles, made by control_panel!.

  • colorbar: the colorbar layout (see profile_plot_area!); the legend goes right of the colorbars and the other legends.

  • compare_toggle: an optional Toggle that shows or hides all compared picks at once (a line is visible while its own toggle and compare_toggle are on); nothing: each line follows only its own toggle.

  • axes, panels, widgets: as returned by picker_layout; axes.profile, panels.compare_picks_panel, panels.colorbar and widgets.compare_toggle (the "Compare Picks" toggle of the pick legend panel) are used.

Returns

A NamedTuple with the fields ax, panel, colorbar, compare_toggle, the dashed lines with their toggles, labels, file paths, other_profile flags and picks (one entry per shown file), and the legend (Ref).

Example

julia
fig = Figure()
area = profile_plot_area!(fig[1, 2])
panel = control_panel!(fig[1, 1], "Compare picks"; collapsible = true, width = 340)
compare_toggle = Toggle(fig[2, 1]; active = true)
compare = compare_plot_state(area.profile, panel, area.colorbar, compare_toggle)
add_compare_picks!(compare, Picks([(100.0, -50.0), (300.0, -80.0)]), "example picks")
source
AdriaArrayGeometryPicker.add_compare_picks! Function
julia
add_compare_picks!(state, picks::Picks, label; other_profile = false, horizontal = false) -> line plot

Show picks (not editable) as a dashed coloured line on top of a solid white one in the profile axis, with a toggle and label in the panel of the state and an entry in the comparison legend (the last legend of the colorbar layout; greyed out by Makie while the line is hidden). The line is visible while its toggle and the compare_toggle of the state (if any) are on. With horizontal = true (horizontal slice) the picks are drawn at their longitude / latitude. With other_profile = true (picks of another profile) the label in the panel gets a red background. state is created by compare_plot_state.

Arguments

  • state: the compare state.

  • picks: the Picks to show (the first two coordinates are drawn).

  • label: text of the label and the legend entry.

Keywords

  • other_profile: mark the picks as belonging to another profile.

  • horizontal: the picks are made on a horizontal slice (drawn at lon / lat).

Returns the dashed line plot. Needs no profile data itself; the coordinates of picks must be those of the profile axis (see current_picks for the columns of picks made on a profile).

source
AdriaArrayGeometryPicker.load_compare_picks! Function
julia
load_compare_picks!(session, path) -> Bool

Load the pick file path (see load_picks) and show its picks for comparison (see add_compare_picks!), labelled with the file name (and the user, if stored). Picks of another profile (see picks_match_profile) are shown as well, as they may still be useful, but their label in the panel gets a red background. Switches the compare_toggle of the compare state (if it has one) on, so that the new line is visible.

Arguments

  • session: a NamedTuple (or any object with these properties) with the fields profile (the Observable that holds the profile) and compare (the state of compare_plot_state), e.g. (; profile, compare); the session of the picker (see menu_selection) has both.

  • path: a pick file (see load_picks).

Returns true if the picks were added; false (and warns) if no profile is loaded or the file is already shown. Requires a GeophysicalModelGenerator ProfileData.

source
AdriaArrayGeometryPicker.clear_compare_picks! Function
julia
clear_compare_picks!(state)

Remove all picks shown for comparison (their lines, toggles, labels and the legend). Called when another profile is loaded, since the picks belong to the previous one (see connect_profile!). Needs no profile.

Arguments

Returns state.

source

Picks on a profile ​

AdriaArrayGeometryPicker.picking_state Function
julia
picking_state(fig, profile::Observable, ax::Axis; active = Observable(true)) -> NamedTuple
picking_state(fig, profile::Observable, axes, widgets) -> NamedTuple

Make the profile axis pickable with pickable! and return its picking state (; picks, scatter, dragging, index). The data coordinates of the picks are x (distance along the profile) and depth; on a horizontal slice they are longitude and latitude instead. picks holds them as Point3d (double precision, z = PICK_Z); set them from code with set_pick_points! or set_picks!. Profile-specific wrapper of the generic pickable!; requires a GeophysicalModelGenerator ProfileData in profile.

Picking is active while active is true. A newly loaded profile clears the picks (listener of profile with priority -20). See current_picks and set_picks! for the connection to Picks.

Arguments

  • fig: the figure of the window (fig of picker_layout).

  • profile: Observable that holds the profile.

  • ax: the profile axis.

  • axes, widgets: as returned by picker_layout; picks are made in axes.profile while the "Picking" toggle widgets.pick_toggle is on.

Keywords

  • active: Observable{Bool} that switches picking on and off, e.g. the active of a Toggle (default: always on).

Returns

The picking state of pickable!, (; picks, scatter, dragging, index).

Example

julia
# window of `picker_layout`
profile = Observable{Any}(nothing)
fig, panels, axis, widgets = picker_layout(; profile)
picking = picking_state(fig, profile, axis, widgets)

# own layout
fig = Figure()
area = profile_plot_area!(fig[1, 1])
toggle = Toggle(fig[2, 1]; active = true)
picking = picking_state(fig, profile, area.profile; active = toggle.active)
source
AdriaArrayGeometryPicker.pick_lonlat Function
julia
pick_lonlat(profile, x) -> (lon, lat)

Longitude and latitude of the picks at the distances x along profile, interpolated linearly from the coordinates of the profile data (see profile_track). NaN for distances outside the profile, and for all picks if the profile has no coordinates. Vertical profiles only; requires a GeophysicalModelGenerator ProfileData.

Arguments

  • profile: the loaded profile (or nothing).

  • x: vector of distances along the profile.

Returns the vectors (lon, lat), one value per distance.

source
AdriaArrayGeometryPicker.profile_track Function
julia
profile_track(profile) -> Union{Nothing,NTuple{3,Vector{Float64}}}

Distance along the profile (x_profile) with the longitude and latitude at each distance, sorted by distance: from the topography of profile (TopoData, finest sampling) or, without topography, from the first column of the volume data. nothing if neither is available (and for horizontal slices, which have no x_profile). Requires a GeophysicalModelGenerator ProfileData of a vertical cross-section.

Returns (x, lon, lat), three vectors of the same length.

source
AdriaArrayGeometryPicker.picks_match_profile Function
julia
picks_match_profile(profile, picks::Picks; warn = true) -> Bool

Whether picks belong to profile: they were made on the same type of profile (vertical or horizontal; files that do not say are taken as vertical) and their start / end coordinates (vertical) or depth (horizontal), if the file has them, are those of the profile. Requires a GeophysicalModelGenerator ProfileData.

Arguments

  • profile: the loaded profile (or nothing).

  • picks: the Picks, e.g. from load_picks; its metadata profile_type, start_lonlat, end_lonlat and depth are compared.

Keywords

  • warn: log a warning that says why the picks do not match.

Returns true if the picks match, false if not or if no profile is loaded.

source

Settings of a window ​

AdriaArrayGeometryPicker.gui_settings Function
julia
gui_settings(session) -> Dict{String,Any}

The settings of the GUI that can be restored together with the profile (see apply_settings!, save_gui_state). Only the parts that the session has are read; a custom GUI without e.g. a map overview or compared picks simply has no such entries. Requires a GeophysicalModelGenerator ProfileData to be loaded.

Arguments

  • session: a NamedTuple (or any object with these properties). The session of the picker (see menu_selection) has all of them; a custom GUI passes those it has, with these names (all optional except profile):
session fieldentries of the settings
profile (required)– (the profile type decides how compared picks are stored)
volume (volume_plot_state)"volume_field", "volume_limits", "volume_cmap", "volume_cmap_reverse"; with contour widgets also "contour_field", "contour_visible", "contour_limits", "contour_cmap", "contour_cmap_reverse", "contour_levels"
surface (surface_plot_state)"surface_visible": label => toggle state of each surface
points (point_plot_state)"point_visible": label => toggle state of each point data set
topography (topography_panel_state)"topography_controls": "dataset" (if there are several), "show" and "fill" (vertical profile) or "mode", "opacity" and "levels" (horizontal slice); empty without topography data
topomap (map_plot_state)"topography_path": the topography file of the map overview ("" if none)
picking (picking_state)"picks": the editable picks as x and depth vectors (longitude and latitude on a horizontal slice)
compare (compare_plot_state)"compare_picks": one Dict per file shown for comparison with its label, path, the picks (x, depth), other_profile and visible (its toggle); "compare_visible": the compare_toggle of the state, if it has one
widgets.pick_name (a Textbox)"user_name"
widgets.<name>_panel_toggle (Toggles, <name> one of volume, surface, point, topography, compare, map, screenshot)"expanded_panels": name => toggle state

The picks themselves are stored (not only the paths of their files), so that a state can be restored even if the pick files have been moved or deleted.

Returns

The settings as a Dict{String,Any} of plain values (strings, numbers, vectors, dictionaries), so that it can be stored in a JLD2 file.

Example

julia
fig = Figure()
area = profile_plot_area!(fig[1, 2])
volume_panel = control_panel!(fig[1, 1], "Volume data"; width = 340)
volume = volume_plot_state(area.profile, volume_panel!(volume_panel; contours = false), area.colorbar)
profile = Observable{Any}(nothing)
connect_profile!(profile, (; volume); axes = area)
picking = picking_state(fig, profile, area.profile)
load_profile!(profile, joinpath(pkgdir(AdriaArrayGeometryPicker), "assets", "Profile1.pgmg"))
session = (; profile, volume, picking)
settings = gui_settings(session)      # "volume_field", "volume_limits", ..., "picks"
apply_settings!(session, settings)
source
AdriaArrayGeometryPicker.apply_settings! Function
julia
apply_settings!(session, settings) -> session

Restore settings (see gui_settings) in the GUI. A profile has to be loaded already (requires a GeophysicalModelGenerator ProfileData). Only the parts that the session has are restored: entries for parts it does not have (e.g. contour settings for a volume state without contour widgets, or a map overview) are skipped, as are settings that do not fit the profile (e.g. a field that it does not contain; a warning is logged).

Arguments

  • session: as for gui_settings; the same fields are read (and written).

  • settings: a Dict as returned by gui_settings, e.g. from a state file.

Returns session. The topography of the map overview is loaded again from its file (if the session has a topomap and the file still exists).

source

Generic: panels and widgets ​

These do not depend on the profile data and work in any Makie figure.

AdriaArrayGeometryPicker.control_panel! Function
julia
control_panel!(gp, title; color = :steelblue1, empty_height = 20, collapsible = false,
               expanded = true, width = nothing) -> GridLayout

Create a menu panel at the grid position gp: a colored header with title and below it an empty GridLayout for the panel's widgets, which is returned. Generic.

Arguments

  • gp: grid position, e.g. fig[1, 1].

  • title: text of the header.

Keywords

  • color: color of the header.

  • empty_height: height of the content while it has no widgets.

  • collapsible: add an expand / collapse toggle to the header.

  • expanded: initial state of the toggle (only with collapsible = true).

  • width: fixed width of the panel (default: determined by the content).

An empty layout has no size that Makie can determine, which would make the whole window layout undeterminable. The content row therefore starts with the fixed height empty_height; call fit_panel! once widgets have been added to make it follow its content.

With collapsible = true the header gets a toggle (on: expanded, initially expanded) that shows or hides the widgets of the panel; width fixes the panel width, so that the layout does not move when panels are collapsed. Collapsible panels start expanded unless expanded = false is given; exclusive_panels! keeps only one of several panels expanded.

Example

julia
fig = Figure()
content = control_panel!(fig[1, 1], "Options"; collapsible = true)
Button(content[1, 1]; label = "Go")
fit_panel!(content)
source
AdriaArrayGeometryPicker.fit_panel! Function
julia
fit_panel!(content::GridLayout) -> Bool

Let the menu panel whose content layout is content follow the size of its widgets; call it after adding widgets. Panels without widgets keep their fixed height, because an empty layout has no determinable size. A collapsible panel whose toggle is off is collapsed instead: its widgets are hidden and its content has no height. Widgets added later are hidden as well when fit_panel! is called again. Generic.

Arguments

  • content: the content layout of a panel, as returned by control_panel!. The panel is resized through the layout around content (the row below the header), so any other layout throws an ArgumentError. The plot states, volume_panel! and map_panel! call fit_panel! on their panel, so their panels have to be made by control_panel! as well.

Returns true if the panel now follows its content, false if it is empty or collapsed.

Example

julia
fig = Figure()
panel = control_panel!(fig[1, 1], "Options")
Button(panel[1, 1]; label = "Go")
fit_panel!(panel)      # true
source
AdriaArrayGeometryPicker.set_visible! Function
julia
set_visible!(layout::GridLayout, visible::Bool)

Show or hide all widgets in layout, including those in nested layouts. Hidden widgets still react to the mouse, and those of a collapsed panel sit on top of the panels below it, so hidden widgets with a mouse interaction are also shrunk to zero size (and get their size back when they are shown again). Generic. Returns nothing.

source
AdriaArrayGeometryPicker.panel_toggle Function
julia
panel_toggle(content::GridLayout) -> Union{Toggle,Nothing}

The expand / collapse toggle of the collapsible panel whose content layout is content (as returned by control_panel! with collapsible = true), nothing for a panel that is not collapsible. Generic.

source
AdriaArrayGeometryPicker.exclusive_panels! Function
julia
exclusive_panels!(contents) -> Vector{Toggle}

Let only one of the collapsible panels with the content layouts contents (a tuple or vector of layouts returned by control_panel! with collapsible = true) be expanded at a time: expanding one collapses the others. If several of them are expanded when this is called (control_panel! creates expanded panels by default), the first expanded one stays expanded and the others are collapsed. Returns the toggles of the panels (see panel_toggle), in the order of contents. Generic. Throws an ArgumentError if one of the panels is not collapsible.

source
AdriaArrayGeometryPicker.link_range_controls! Function
julia
link_range_controls!(slider, minbox, maxbox, range::Observable, label = nothing)

Connect an IntervalSlider with a min and a max Textbox: moving the slider sets range to its interval and shows the limits in the text fields (and in label, if given); entering a number in a text field moves the slider to the closest possible value. Generic.

Arguments

  • slider: an IntervalSlider.

  • minbox, maxbox: Textboxes for the lower and upper limit.

  • range: Observable that receives the interval (lo, hi).

  • label: optional Label showing the limits as "Colorbar limits: lo to hi".

source
AdriaArrayGeometryPicker.parse_levels Function
julia
parse_levels(text) -> Union{Nothing,Vector{Float64}}

Contour levels from a string of numbers separated by commas, semicolons or spaces, sorted and without duplicates. nothing if text is empty or not a list of numbers. Generic.

Example

julia
parse_levels("1, 2.5; 0.5 2.5")   # [0.5, 1.0, 2.5]
parse_levels("a b")               # nothing
source
AdriaArrayGeometryPicker.label_of Function
julia
label_of(option) -> String

The text a dropdown shows for one of its options (a string, or a (label, value) tuple).

source
AdriaArrayGeometryPicker.select_label! Function
julia
select_label!(menu::Menu, label) -> Bool

Select the entry of the dropdown menu whose text is label (options are strings or (label, value) tuples), as if the user had chosen it: menu.selection changes and its listeners run. Generic.

Arguments

  • menu: a Menu.

  • label: the text of the entry (nothing selects nothing).

Returns true if the entry was found and selected, false otherwise (the selection is then left alone).

Example

julia
fig = Figure()
menu = Menu(fig[1, 1]; options = ["Heatmap", "Contours", "Off"])
select_label!(menu, "Contours")   # true
source
AdriaArrayGeometryPicker.set_text! Function
julia
set_text!(box::Textbox, text::AbstractString)

Set the text of the text field box programmatically, as if the user had typed text and pressed enter: the shown text (displayed_string) and the stored text (stored_string, whose listeners run) change. An empty text clears the field (stored_string becomes nothing). Generic. Returns the new stored text.

Example

julia
fig = Figure()
levels = Textbox(fig[1, 1]; placeholder = "Contour levels")
set_text!(levels, "-1, 0, 1")
source

Generic: picking on an axis ​

AdriaArrayGeometryPicker.PICK_Z Constant
julia
PICK_Z = 1000

z value of the pick markers of pickable!: the third coordinate of every pick, so that the markers are drawn above the heatmap, contours, surface lines and points. Generic. Use set_pick_points! to set picks from code without handling it yourself.

source
AdriaArrayGeometryPicker.pickable! Function
julia
pickable!(fig, ax::Axis; active = Observable(true)) -> NamedTuple

Make ax pickable and return the picking state (; picks, scatter, dragging, index). Generic: works on any Axis, independent of the profile data. picks is an Observable{Vector{Point3d}} with the picked points in data coordinates of ax, in double precision (Point3d = Point3{Float64}), so values set from code or loaded from a file are kept exactly. The third coordinate is always PICK_Z; it only keeps the markers on top of everything else. The picks are drawn by scatter.

Picking is active while active (e.g. the active Observable of a Toggle) is true. The mouse is handled with high priority, so clicks on picks do not zoom or pan the axis:

  • A + click adds a pick at the mouse position (inside ax),

  • D + click removes the pick under the mouse,

  • click and drag a pick moves it (release the button to drop it).

(Holding ctrl in addition is allowed.) Picks(state.picks[]) converts the picks to a Picks; set_pick_points! sets them from code.

Arguments

  • fig: the figure that contains ax (its mouse events are used).

  • ax: the axis to pick on.

Keywords

  • active: Observable{Bool} that switches picking on and off (default: always on).

Returns

The picking state (; picks, scatter, dragging, index). dragging and index are Refs used internally to track the pick being moved. For picking on a GMG profile see picking_state.

Example

julia
fig = Figure()
ax = Axis(fig[1, 1])
toggle = Toggle(fig[2, 1]; active = true)
state = pickable!(fig, ax; active = toggle.active)
on(state.picks) do pts
    println(length(pts), " picks")
end
source
AdriaArrayGeometryPicker.set_pick_points! Function
julia
set_pick_points!(picking, points) -> picking

Replace the picks of the picking state picking (of pickable! or picking_state) by points, given as 2D points in data coordinates of the axis: any indexable objects with at least two coordinates (tuples, Point2, Point3, vectors; a third coordinate is ignored). The picks are stored in double precision with the z value PICK_Z, which keeps the markers on top. Generic.

Arguments

  • picking: the picking state; only its field picks is used.

  • points: the new picks, e.g. [(1.0, 2.0), (3.0, 4.0)] or points(p) of a Picks (an empty vector removes all picks).

Returns picking.

Example

julia
fig = Figure()
ax = Axis(fig[1, 1])
picking = pickable!(fig, ax)
set_pick_points!(picking, [(1.0, 2.0), (3.0, 4.5)])
picking.picks[]     # [Point3d(1.0, 2.0, 1000.0), Point3d(3.0, 4.5, 1000.0)]
source

Generic: file dialogs and screenshots ​

The native file dialogs block the thread they run on. The with_* functions run them in a background task, so that the window keeps drawing while a dialog is open. The dialogs can be replaced, for example in tests:

julia
AdriaArrayGeometryPicker.OPEN_DIALOG[] = (; kwargs...) -> "picks.aagpp"
AdriaArrayGeometryPicker.open_dialog Function
julia
open_dialog(; filter = "", dir = "") -> Union{String,Nothing}

Show a native "open file" dialog and return the chosen path, or nothing if cancelled. Generic, independent of any profile data.

Keywords

  • filter: file filter in NativeFileDialog syntax, e.g. "aagpp,csv" or "png;jpg,jpeg".

  • dir: directory the dialog starts in (default: the dialog's own choice).

This call blocks; inside GUI callbacks use with_open_dialog. The dialog can be replaced (e.g. in tests) by setting AdriaArrayGeometryPicker.OPEN_DIALOG[].

source
AdriaArrayGeometryPicker.save_dialog Function
julia
save_dialog(; filter = "", dir = "") -> Union{String,Nothing}

Show a native "save file" dialog and return the chosen path, or nothing if cancelled. Keywords as for open_dialog. Generic, independent of any profile data. This call blocks; inside GUI callbacks use with_save_dialog.

source
AdriaArrayGeometryPicker.with_open_dialog Function
julia
with_open_dialog(f; filter = "", dir = "") -> Task

Show an "open file" dialog without blocking the GUI and call f(path) with the chosen path. Nothing happens if the dialog is cancelled. Errors thrown by f are logged, not rethrown. The task's result is the return value of f (or nothing). Keywords as for open_dialog. Generic.

Example

julia
with_open_dialog(path -> @info("chosen: $path"); filter = "csv")
source
AdriaArrayGeometryPicker.with_save_dialog Function
julia
with_save_dialog(f; filter = "", dir = "") -> Task

Show a "save file" dialog without blocking the GUI and call f(path) with the chosen path. Keywords as for open_dialog; see with_open_dialog. Generic.

source
AdriaArrayGeometryPicker.save_picks_dialog Function
julia
save_picks_dialog(picks; extra = nothing, filter = "aagpp,csv", dir = "") -> Task

Ask for a file name and save picks there (see save_picks). picks can be a Picks, a vector of points, or a zero-argument function returning either (evaluated when the dialog is closed, so the state at that moment is saved). Generic.

Arguments

  • picks: what to save, see above.

Keywords

  • extra: function points -> NamedTuple computing additional columns, see save_picks.

  • filter, dir: as for open_dialog.

Returns the Task of with_save_dialog; its result is the path written.

source
AdriaArrayGeometryPicker.load_picks_dialog Function
julia
load_picks_dialog(f = identity; filter = "aagpp,jld2,csv", dir = "") -> Task

Ask for a pick file, load it with load_picks and call f(picks) with the resulting Picks. Generic.

Arguments

  • f: function called with the loaded picks (default identity).

Keywords

Returns the Task of with_open_dialog; its result is the return value of f.

Example

julia
load_picks_dialog(p -> println(length(p), " picks loaded"))
source
AdriaArrayGeometryPicker.OPEN_DIALOG Constant

Function (; filter, dir) -> path used by open_dialog. Return "" or nothing on cancel.

source
AdriaArrayGeometryPicker.SAVE_DIALOG Constant

Function (; filter, dir) -> path used by save_dialog. Return "" or nothing on cancel.

source
AdriaArrayGeometryPicker.PICKS_FILTER Constant

File filter for pick files, in NativeFileDialog syntax.

source
AdriaArrayGeometryPicker.IMAGE_FILTER Constant

File filter for screenshots, in NativeFileDialog syntax.

source
AdriaArrayGeometryPicker.save_screenshot Function
julia
save_screenshot(path, fig; px_per_unit = 2, kwargs...) -> String

Save fig as an image and return the path written. A path without extension gets .png appended. Generic: works for any Makie Figure (or scene).

Arguments

  • path: output file; the format follows the extension (e.g. .png).

  • fig: the figure to save.

Keywords

  • px_per_unit: resolution scaling, 2 by default (twice the window resolution).

  • kwargs...: passed to Makie.save.

Example

julia
fig = Figure()
lines(fig[1, 1], 1:10)
save_screenshot(joinpath(tempdir(), "window.png"), fig)
source
AdriaArrayGeometryPicker.save_screenshot_dialog Function
julia
save_screenshot_dialog(fig; filter = "png", dir = "", kwargs...) -> Task

Ask for a file name and save a screenshot of fig there (see save_screenshot). Generic. Keywords filter and dir are as for open_dialog; the remaining kwargs... are passed to save_screenshot. Returns the Task of with_save_dialog.

source