-
-
Notifications
You must be signed in to change notification settings - Fork 554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor all Visualizers to move fig/ax hooks to base class #62
Comments
So the primary idea here is that every single visualizer will need access to some matplotlib axes object to draw on (axes is where most of the plotting functions are). It also seems like they should have access to the figure object, though it is very unusual to modify that in any way -- so for now, let's focus on the When you look at Seaborn and Pandas plotting functions (not classes) most of them take as input an axes and return an axes. This allows you to chain multiple functions together: sns.heatmap().gridplot() Which is useful if you want to draw multiple lines or text or customize the graph. Although this api is not exactly what we'll use - what I'm trying to demonstrate is that the axis is a reusable thing until the figure is shown (or poofed). Every visualizer needs a hook to some axis to draw on, and if it can be passed in, then the same axis can be used in multiple visualizers (for example to draw a model curve on a prediction error plot or something like that). However, if it's not passed in, then it will create a new axis by using the Since we're doing a class based API and we know that every single visualizer needs an access, we can do this work once at the root of the API hierarchy - at class Visualizer(BaseEstimator):
def __init__(self, ax=None, **kwargs):
self.ax = ax Subclasses need to do something to the effect of: class SubVisualizer(Visualizer):
def __init__(self, ax=None, **kwargs):
super(SubVisualizer, self).__init__(ax=ax, **kwargs) Though you could just leave The next step is that you'll see the following code in my class SubVisualizer(Visualizer):
def draw(self, **kwargs):
if self.ax is None:
self.ax = plt.gca() This is so routine, it should also be a method on the class Visualizer(BaseEstimator):
def gca(self):
if self.ax is None:
self.ax = plt.gca()
return self.ax
def draw(self, **kwargs):
ax = self.gca() We could instead use the property decorator method: class Visualizer(BaseEstimator):
def __init__(self, ax=None, **kwargs):
self.ax = ax
@property
def ax(self):
if self._ax is None:
self._ax = plt.gca()
return self._ax
@ax.setter
def ax(self, value):
self._ax = value
def draw(self, **kwargs):
self.ax.plot(x, y, c='r') # If ax is None it will automatically be created. If something special needs to be done in These two different APIs set a tone for how users might extend and create new things with Yellowbrick - both are good, but different choices. There are other options as well, but these are the two most prominent. |
Let's save this refactor for the next version and not worry about it for this weekend! I'll try to clarify my comments from above. |
See commit 5f7ab81 |
Move fig/ax hooks to
__init__
in baseVisualizer
class.The text was updated successfully, but these errors were encountered: