earthlab / matplotcheck

A python package for checking and testing matplotlib plots. We use this for autograding student assignments but there are many other potential use cases including package testing (for packages with plots)!
https://matplotcheck.readthedocs.io
BSD 3-Clause "New" or "Revised" License
18 stars 8 forks source link

Add functions to get simple aspects of plots #347

Open nkorinek opened 4 years ago

nkorinek commented 4 years ago

Currently, in matplotcheck, we have functions that check the plot color, style, and other simple attributes, to ensure that data types are properly grouped. This is seen in get_lines_by_attributes and get_points_by_attributes. While the idea is simple, the implementation is somewhat hard and sloppy. I would recommend making simple get functions in matplotcheck that can be called in the attributes functions to make it read cleaner, but could also be used externally to get the colors or style or what have you from the plot being graded. Just a thought!

lwasser commented 4 years ago

nice @nkorinek let's talk about this ... can you perhaps provide here some specifics maybe with links tot he code and examples of what is "sloppy" and your approach to clean it up!! this sounds like a great improvement and we know that this code needs some work!!

nkorinek commented 4 years ago

Ya, definitely, my bad!

I'll show an example of how this could work with point colors and style.

In matplotcheck right now, when we compare points by attributes, we check that their colors, styles, and sizes match with the following code:

for c in (
            coll
            for coll in self.ax.collections
            if type(coll) == matplotlib.collections.PathCollection
        ):
            colors, sizes = (
                [tuple(color) for color in c.get_facecolors()],
                c.get_sizes(),
            )
            styles, offsets = (
                [tuple(tuple(v) for v in p.vertices) for p in c.get_paths()],
                [tuple(o) for o in c.get_offsets()],
            )

This returns the requested information, but is hard to read, and the results can't be accessed outside the function.

I would recommend doing something like:

def get_point_color(self):
    for c in (
            coll
            for coll in self.ax.collections
            if type(coll) == matplotlib.collections.PathCollection
        ):
            return([tuple(color) for color in c.get_facecolors()])

That way in the attributes function we can just call get_point_color() instead of that big block of code. This would add more lines to the code overall, but would increase legibility and utility outside of the function to just get those attributes easily in a notebook you're grading.