Making a button grid with Makie?

I wanted to make a button grid that parallels the physical device I am plotting against, I am currently using code like this for the button section:

...
fig_volt = Figure()
...
elec_vis = fig_volt[2, 1:2] = GridLayout(halign=:left)
# For each of the lines of hardware (they are stacked)
for (i, line) in enumerate(volt.geo.order)
      electrodes = volt.geo.lines[line] # This just gives the line in order
      total_width = sum(e.right - e.left for e in electrodes) # if e.name != "_")
      # I make a new row for holding the line
      elec_row = elec_vis[i, 1] = GridLayout()
      for (j, electrode) in enumerate(electrodes)
            # There is special names that are set to _ to be ignored
            if electrode.name != "_"
                  # I calculated this previously as what I expected as a ratio
                  # But it didn't work, so I use the placeholder 20 currently
                  relative_width = (electrode.right - electrode.left) / total_width
                   e = Button(elec_row[1, j],
                                   label="$(electrode.name)",
                                   width=20, # Relative(relative_width),
                                   # I tried adjusting the font-size to the figure size but it was really laggy and didn't really work, goal was to keep font in the button, not getting cut off
                                   # fontsize=lift(x -> (relative_width / total_width) * x.widths[1], fig.scene.viewport),
                                   # I set these to false to get the buttons closer togeather
                                   height=Auto(false, 1),
                                   tellheight=false,
                                   tellwidth=false)
                        # While I was working on this I was debugging with this text
                        println("Working on $(electrode.name) with width: $(electrode.right - electrode.left), relative: $(relative_width)")
                        # This is why I wanted the buttons so they could interact with them like they expect them to be (as they worked with he physical layout)
                        on(e.clicks) do _
                            electrode_active[] = electrode.name
                        end
                    end
                end
            end
...

I was wondering if anyone could help me understand the display options better, I have been reading the docs but I can’t seem to make this one work in the way I want. Specifically, I want it to fit into the figure and adjust the rows of button size to be fit into the figure. Here is the current figure displaying:

If anyone is able to help I would very much appreciate it and have a good day :slight_smile:

Can you be more specific? Currently the buttons are all squished together but you would need a wider figure to accomodate them. But you don’t want a wider figure?

Yes, I was looking for a way to have the elements dynamically resize such that they would fit the figure best that they can. Currently, they go off of the figure (the middle two rows) and squash into each other. I didn’t know if there was a nice way to assign a grid of buttons that are edge to edge with each other and with widths that resize to fit depending on the figure size. This is why I tried the ‘fig.scene.viewport’ thing because that helps me get the current figure size and I thought I could calculate the fitting figure size for buttons, but the issue is that it halts the program when I resize (I think due to the volume of updates when updating something continuous?) Please let me know if this helps clarify and thank you for your engagement.

Ah no Button currently doesn’t have an official option to ignore the text width and just scale with the figure, I assumed that was never needed.

But you can set the internal field layoutobservables.autosize such that you overwrite the x value with nothing, which will make the button behave like it has no intrinsic width. The top row here has that workaround applied and the bottom row not. This will still not look good if you have too many buttons in a row.

The other way you could go is to make the figure big enough for all the buttons you have via resize_to_layout!.

f = Figure()

gl1 = GridLayout(f[1, 1], tellwidth = false)
gl2 = GridLayout(f[2, 1], tellwidth = false)

for i in 1:8
    b = Button(gl1[1, i], label = "$i")
    b.layoutobservables.autosize[] = (nothing, b.layoutobservables.autosize[][2])
    Button(gl2[2, i], label = "$i")
end

f

2 Likes

Thank you for your feedback and advice :slight_smile: