0

This is a generic problem but I'd like to ask the question based on a concrete example. But please keep in mind the generality (not necessarily static or class methods).

Suppose I'd like to draw regular plots or loglog plots depending on a conditional draw_log with the some data. We set up the figure and the axes

import matplotlib.pyplot as plt
x, y = [1,2,3], [10, 200, 1]
fig, ax_lst = plt.subplots(3, 2)
draw_log = False

for row in range(3):
    for col in range(2):
        # The loop to be removed
        if draw_log:
            ax_lst[row, col].plot(x, y)
        else:
            ax_lst[row, col].loglog(x, y)

What I would like to use is the first class citizenship of the methods such that

plotter = ?????.plot if draw_log else ?????.loglog

and then use the generic plotter method name ax_lst[row, col].plotter(x, y) but this requires to access the method on the particular instance not the parent class.

I've searched for passing the method name as a parameter type questions but they seem to be related either to the assignment within the class definition or external methods.

How can I point the assignment to the method belonging to any instance?

percusse
  • 3,006
  • 1
  • 14
  • 28
  • So, basically you want to replace the whole if-else statement in your example with one function call, right? – SergiyKolesnikov Mar 28 '18 at 17:03
  • @SergiyKolesnikov For this particular problem yes that would be the goal. But for a more general problem suppose you want to control the behavior of many method calls with an if-switch placed at the top. Ideally I would like to control the method name called from an instance. – percusse Mar 28 '18 at 17:04

1 Answers1

1

You can create a custom plotter method.

Your ax_lst[row, col] are instances of <class 'matplotlib.axes.AxesSubplot'>, but there's no such class in matplotlib.axes. As explained in this answer,

there is no AxesSubplot class.. until one is needed, when one is built from SubplotBase

So we can add it to SubplotBase:

import matplotlib.axes
import matplotlib.pyplot as plt

x, y = [1,2,3], [10, 200, 1]
fig, ax_lst = plt.subplots(3, 2)
draw_log = False

def plotter(self, *args, **kwargs):
    return getattr(self, 'plot' if draw_log else 'loglog')(*args, **kwargs)

matplotlib.axes.SubplotBase.plotter = plotter

for row in range(3):
    for col in range(2):
        ax_lst[row, col].plotter(x, y, 'r-')

plt.show()
Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50