Skip to content

Change default padding based on axis titles#735

Merged
aaronayres35 merged 7 commits into
masterfrom
fix/ylabel-clipped
Jul 23, 2021
Merged

Change default padding based on axis titles#735
aaronayres35 merged 7 commits into
masterfrom
fix/ylabel-clipped

Conversation

@aaronayres35
Copy link
Copy Markdown
Contributor

@aaronayres35 aaronayres35 commented May 11, 2021

closes #564

Currently, with manual testing this seems to work how I want it to but I am not sure the current solution is worth the added complexity.
If we're going to add complexity to the code I think it might be better to try and get a more "perfect" approach that sets padding directly based off of the axis title extent. Hence the WIP title as I am still thinking about alternate solutions.

Comment thread chaco/data_view.py
padding_bottom = 50
padding_left = 50
padding_right = 50
padding_top = Property(
Copy link
Copy Markdown
Contributor Author

@aaronayres35 aaronayres35 May 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if explicitly set (or if padding trait is sett, which then explicitly sets these), that value will always be used. Setting sets the shadow traits (with leading underscore), and in the getters we explicitly check if the shadow trait is set and return it. Otherwise we then check for axis titles and adjust as needed either returning 80 or 50 as a default.

Note I am just now considering if a user explicitly sets one off these traits to 0 I dont think it will work as then we will not enter the if getattr(self, MAP[side]) block. This is a bug that needs fixing.
EDIT: fixed

Comment thread chaco/data_view.py
)
padding_right = Property(
observe='y_axis.[title,orientation], x_axis.[title,orientation]'
)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I handle all 4 cases because it is possible to set axis orientation to "top" or "bottom" as well

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as an example, this code:

rom numpy import linspace, sin
from traits.api import HasTraits, Instance
from traitsui.api import View, Item
from chaco.api import Plot, ArrayPlotData
from enable.api import ComponentEditor

class LinePlot(HasTraits):
    plot = Instance(Plot)

    traits_view = View(
        Item('plot',editor=ComponentEditor(), show_label=False),
        width=500, height=500, resizable=True, title="Chaco Plot")

    def _plot_default(self):
        x = linspace(-14, 14, 100)
        y = sin(x) * x**3
        plotdata = ArrayPlotData(x=x, y=y)

        plot = Plot(plotdata)
        plot.plot(("x", "y"), type="line", color="blue")
        plot.title = "sin(x) * x^3"

        plot.padding_left = 0
        
        plot.x_axis.title = "X AXIS"
        plot.y_axis.title = "Y AXIS"
        
        plot.y_axis.orientation = "top"
       
        return plot

if __name__ == "__main__":
    LinePlot().configure_traits()

yields this on master:
Screen Shot 2021-05-12 at 9 38 47 AM

and this on this branch:
Screen Shot 2021-05-12 at 9 39 02 AM

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extra padding on the bottom on this branch (80 rather than 50) I'm not a huge fan of. This is due to the simplistic nature of just adding space if we have an axis title. As you can see, at the top we need extra space so axis title doesn't overlap with plot title. Similarly left right we need it (hence the original issue), because axis ticks / values take up some of the spacing and sort of push the axis title further away from the plot. The x axis doesn't usually have this problem because of the orientation of the numbers on the ticks. In other words the text for 1000 for example is much wider than it is tall, and 100000 even wider, but the same height.

In reality an ideal solution would calculate explicitly the extent of the ticks, and the size of the axis title and allocate spacing to perfectly fit what we need. The awkward thing about this code feels like it would live in a draw method inside the axis itself, but the DataView is where the padding is held. Should the Axis take control over the DataViews padding? That feels wrong.
In any case that is a separate issue / approach entirely. I am just pointing out something I don't love about the current solution.

Perhaps we just make the assumption that padding_bottom can be 50 regardless of the presence or absence of an axis title? We were just assuming 50 always before anyway.

@aaronayres35 aaronayres35 requested a review from rahulporuri May 12, 2021 14:46
Comment thread chaco/data_view.py
Comment on lines +224 to +227
_padding_top = Union(None, Int())
_padding_bottom= Union(None, Int())
_padding_left = Union(None, Int())
_padding_right = Union(None, Int())
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rahulporuri
I looked into it and Int(allow_none=True) does not work / is not implemented.

>>> from traits.api import HasTraits, Instance, Int
>>> class Thing(HasTraits):
...     a = Int()
...     b = Int(allow_none=True)
...     c = Instance(HasTraits, allow_none=False)
...     d = Instance(HasTraits)  # default value of allow_none for Instance trait type is True
... 
>>> thing = Thing()
>>> thing.d = None
>>> thing.c = None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/aayres/Desktop/traits/traits/base_trait_handler.py", line 75, in error
    object, name, self.full_info(object, name, value), value
traits.trait_errors.TraitError: The 'c' trait of a Thing instance must be a HasTraits, but a value of None <class 'NoneType'> was specified.
>>> thing.b = None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/aayres/Desktop/traits/traits/base_trait_handler.py", line 75, in error
    object, name, self.full_info(object, name, value), value
traits.trait_errors.TraitError: The 'b' trait of a Thing instance must be an integer, but a value of None <class 'NoneType'> was specified.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this deserves an issue in traits - traits should explicitly complain during class definition instead of at runtime.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, for my own understanding we want to catch a user setting allow_none in a trait definition correct? I suspect, since allow_none is not a supported arg/kwarg for the Int trait type, it is now being used as metadata? Ie one could do something like @observe('+allow_none')?
We should probably special handle this case

@aaronayres35 aaronayres35 changed the title [WIP] Change default padding based on axis titles Change default padding based on axis titles May 17, 2021
@aaronayres35 aaronayres35 mentioned this pull request Jun 1, 2021
44 tasks
Copy link
Copy Markdown
Contributor

@rahulporuri rahulporuri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

I've been putting off reviewing this PR because proposed solution looks slightly overworked/unweidly and I was hoping i'd be able to conjure something better out of thin air.

Alas, some solution is better than no solution so let's go ahead with this.

A couple of comments though :

  • it would be good to add tests for the new code - to check that the padding values are what we expect
  • i'm not sure where but i would like a reference to the original issue in the new code so that people who come asking questions know where to look.

@aaronayres35
Copy link
Copy Markdown
Contributor Author

@rahulporuri this PR look good to push through?

@rahulporuri
Copy link
Copy Markdown
Contributor

still LGTM

@aaronayres35 aaronayres35 merged commit cbf53e7 into master Jul 23, 2021
@aaronayres35 aaronayres35 deleted the fix/ylabel-clipped branch July 23, 2021 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Y label gets clipped

2 participants