Chaco plot padding and (outer_)position/bounds

20 views
Skip to first unread message

jpd...@sandia.gov

unread,
Feb 4, 2022, 3:12:12 AM2/4/22
to Enthought Tool Suite users
I am confused about what actually happens with the plot/outer position and bounds of a Chaco plot component when I try to modify the padding after the plot has been created.  (My use case is to do something like what is shown in https://stackoverflow.com/questions/34746604/automatic-paddings-in-chaco, where the size of tick labels can change a lot due to use of the zoom tool.)

When the plot is created, its outer_position is (0, 0), i.e., the lower left corner of the visual "component" in the traits view, and its position is (padding_left, padding_bottom), which by default is (50, 50), but I can change this by setting the plot's padding before any data are added.  If I subsequently change the plot's padding and redraw, its position remains the same and its outer_position changes to non-zero values to match the new padding; on the screen, neither the lower left corner of the plot axes nor that of the visual component move from where they were before, so it looks like the padding hasn't changed.

So how do I dynamically change the position and size of the plot to make the padding actually correspond to an outer_position at (0, 0)?  I was thinking this requires re-doing the layout, not just redrawing, but I haven't figured out how to do that.  (The invalidate_and_redraw method had no effect.)

Sorry I don't have time to make a toy example for this.  I'm hoping someone with deeper knowledge will be able to say "oh, just do this" (or "just forget it" if this is really too much to ask of Chaco).

Jean-Paul Davis

Corran Webster

unread,
Feb 4, 2022, 4:48:56 AM2/4/22
to Enthought Tool Suite users
Hi,

As a first thing to do in situations like this, calling do_layout() and/or invalidate_and_redraw() after a change sometimes resolves things.

Failing that, the outer_position is a property which is defined by the position and the padding, so when you change the padding the position stays fixed (ie. the location of the lower-left corner of the plot area) and the outer_position shifts.  Similarly, the outer_bounds (which is the total size of the plot) is a property - the size of the plotting area remains constant when the padding changes and the outer bounds change.

For plots inside something like an HPlotContainer or a VPlotContainer which is handling the layout, it will generally detect and adjust correctly.  You may need to call invalidate_and_redraw() and/or do_layout() to indicate that the layout has changed if it doesn't pick it up automatically, particularly if you are using backbuffering for speed.

For plots at the top-level (ie. not inside a Container), you are generally responsible for the positioning and layout relative to the window.  Probably the simplest is just to set the outer_position to (0, 0) immediately after changing the padding.  Because the outer_bounds also changed, your plot will be requesting more space from the containing window system (Qt or Wx) and so you may find that it changes size in the view (whether this happens is highly dependent on the containing TraitsUI layout).  If this happens and is undesirable, you can grab the value of outer_bounds before you set the padding, and then reset the outer_bounds to the old value afterwards, preserving the total size of the plot.  Again, after all of this you may need to call invalidate_and_redraw() to force a re-paint if it doesn't happen automatically.

Hope this helps
-- Corran

jpd...@sandia.gov

unread,
Feb 7, 2022, 6:09:44 PM2/7/22
to Enthought Tool Suite users
Thanks Corran, that information gave me enough to _almost_ figure it out.

In this case I am working with a top-level plot (traits view containing only a single plot Item, in its own window), sorry I didn't think to specify that earlier.  Somehow I had missed the do_layout() method in the documentation.  I found the "correct" way to set outer_position and outer_bounds properties in the Component class, using set_outer_position() and set_outer_bounds() methods.  While do_layout() does propagate the new padding and bounds to the axis objects, for some reason it does not update the actual axis-line drawing coordinates _origin_point and _end_axis_point.  To get the axes to draw correctly, I had to manually call (after do_layout) the private _calculate_geometry() and _compute_tick_positions() methods of each axis.  Could this be something of a "bug?"

Now the only thing left is that the bounds of the "background" (which make the plot area appear white and the padding area appear grey), and the x_axis line origin (but only for changes in one direction or the other depending on the order in which I call the two axes' _calculate_geometry() methods), don't update to match the axes lines until the next detection of user interaction -- when I click the mouse button, press CTRL, or even simply move the mouse pointer out of the plot window.  Even more strange: if I put a (VS Code) breakpoint anywhere inside my handler function and just hit F5 to continue from that point (without moving the mouse at all from where its button_up event initiated the zoom that led to the event I'm handling), the plot background (and x_axis origin when it's incorrect) gets updated correctly.  The commented-out lines in the code snippet below are all things I have tried, in different orders and combinations, plus I tried changing the order of lines before, and of the lines after, the do_layout call.  I'm hoping the problem is something you'll notice right away.

Jean-Paul

[inside my handler function triggered by changes to y_axis._tick_label_bounding_boxes]
y_ax = event.object
plt = y_ax.component
x_ax = plt.x_axis
outer_width = plt.outer_width
[compute new_padding_left]
plt.padding_left = new_padding_left # this increases plt.outer_width
plt.set_outer_position(0, 0) # automatically updates plt.position
plt.width = outer_width - plt.hpadding # automatically updates plt.outer_width
plt.do_layout()
x_ax._calculate_geometry() # in this order, _origin_point update delayed when padding_left decreases
y_ax._calculate_geometry() # reversed order, _origin_point update delayed when padding_left increases
x_ax._compute_tick_positions(plt)
y_ax._compute_tick_positions(plt)
# plt.do_layout()
# plt.invalidate_and_redraw()
# plt.request_redraw()
# event.handled = True  # also tried setting to False
Reply all
Reply to author
Forward
0 new messages