[Matplotlib-users] Error after upgrading Matplotlib and wxPython from a very old project

C M cmpython at gmail.com
Fri Jan 29 21:14:53 EST 2021


I had both Matplotlib and wxPython working well together from a 10+ yr old
project, but recently upgraded both. I had Matplotlib 1.1.3, I believe, and
wxPython 3.0 or so and I now have wxPython Phoenix (4.1.0), Matplotlib
2.2.5, and Python 2.7 (though I may upgrade to 3.9, just want to get this
all working first). What had been working fine stopped working now.

The issue is demonstrated in the pasted/attached small runnable sample.
It's an issue with the self._update_label_position function. The error I
get is:
TypeError: _update_label_position() takes exactly 2 arguments (3 given)

What has changed with Matplotlib that is causing this and how can I fix it?

----------------

from mpl_toolkits.axes_grid1 import make_axes_locatable
from mpl_toolkits.axes_grid1.axes_size import Padded
import mpl_toolkits.axes_grid1.axes_size as axes_size
from matplotlib.axes import Axes

import matplotlib.transforms as mtransforms

# axis_get_ticklabel_extents & axes_get_tightbbox are redefined due to
# a limitation of tge current axis_get_ticklabel_extents

def axis_get_ticklabel_extents(self, renderer, update_label_pos=False):
    """
    Get the extents of the tick labels on either side
    of the axes.
    """
    ticklabelBoxes = []
    ticklabelBoxes2 = []

    interval = self.get_view_interval()
    for tick, loc, label in self.iter_ticks():
        if tick is None: continue
        if not mtransforms.interval_contains(interval, loc): continue
        tick.update_position(loc)
        tick.set_label1(label)
        tick.set_label2(label)
        if tick.label1On and tick.label1.get_visible():
            extent = tick.label1.get_window_extent(renderer)
            ticklabelBoxes.append(extent)
        if tick.label2On and tick.label2.get_visible():
            extent = tick.label2.get_window_extent(renderer)
            ticklabelBoxes2.append(extent)

    # position of the label (and also the offsetText) need to be updated!
    if update_label_pos:
        self._update_label_position(ticklabelBoxes, ticklabelBoxes2)

    if len(ticklabelBoxes):
        bbox = mtransforms.Bbox.union(ticklabelBoxes)
    else:
        bbox = mtransforms.Bbox.from_extents(0, 0, 0, 0)
    if len(ticklabelBoxes2):
        bbox2 = mtransforms.Bbox.union(ticklabelBoxes2)
    else:
        bbox2 = mtransforms.Bbox.from_extents(0, 0, 0, 0)
    return bbox, bbox2


def axes_get_tightbbox(self, renderer):
    """
    return the tight bounding box of the axes.
    The dimension of the Bbox in canvas coordinate.
    """

    artists = []
    bb = []

    artists.append(self)

    if self.title.get_visible():
        artists.append(self.title)

    if self.xaxis.get_visible():
        artists.append(self.xaxis.label)
        bbx1, bbx2 = axis_get_ticklabel_extents(self.xaxis, renderer, True)
        bb.extend([bbx1, bbx2])
    if self.yaxis.get_visible():
        artists.append(self.yaxis.label)
        bby1, bby2 = axis_get_ticklabel_extents(self.yaxis, renderer, True)
        bb.extend([bby1, bby2])


    bb.extend([c.get_window_extent(renderer) for c in artists if
c.get_visible()])

    _bbox = mtransforms.Bbox.union([b for b in bb if b.width!=0 or
b.height!=0])

    return _bbox


class SizeFromFunc(axes_size._Base):
    def __init__(self, func):
        self._func = func

    def get_size(self, renderer):
        rel_size = 0.

        bb = self._func(renderer)
        dpi = renderer.points_to_pixels(72.)
        abs_size = bb/dpi

        return rel_size, abs_size

class GetExtentHelper(object):
    def _get_left(tight_bbox, axes_bbox):
        return axes_bbox.xmin - tight_bbox.xmin

    def _get_right(tight_bbox, axes_bbox):
        return tight_bbox.xmax - axes_bbox.xmax

    def _get_bottom(tight_bbox, axes_bbox):
        return axes_bbox.ymin - tight_bbox.ymin

    def _get_top(tight_bbox, axes_bbox):
        return tight_bbox.ymax - axes_bbox.ymax

    _get_func_map = dict(left=_get_left,
                         right=_get_right,
                         bottom=_get_bottom,
                         top=_get_top)

    del _get_left, _get_right, _get_bottom, _get_top

    def __init__(self, ax, direction):
        if isinstance(ax, Axes):
            self._ax_list = [ax]
        else:
            self._ax_list = ax

        try:
            self._get_func = self._get_func_map[direction]
        except KeyError:
            print "direction must be one of left, right, bottom, top"
            raise

    def __call__(self, renderer):
        vl = [self._get_func(axes_get_tightbbox(ax, renderer),
                             ax.bbox) for ax in self._ax_list]
        return max(vl)


def divider_append_size(self, position, size):

    if position == "left":
        self._horizontal.insert(0, size)
        self._xrefindex += 1
    elif position == "right":
        self._horizontal.append(size)
    elif position == "bottom":
        self._vertical.insert(0, size)
        self._yrefindex += 1
    elif position == "top":
        self._vertical.append(size)
    else:
        raise ValueError("the position must be one of left, right, bottom,
or top")


def divider_area_auto_adjustable(divider,
                                 use_axes, pad=0.0,
                                 adjust_dirs=["left", "right", "bottom",
"top"],
                                 ):
    for d in adjust_dirs:
        helper = GetExtentHelper(use_axes, d)
        size = SizeFromFunc(helper)
        padded_size = Padded(size, pad) # pad in inch
        divider_append_size(divider, d, padded_size)

def make_axes_area_auto_adjustable(ax,
                                   use_axes=None, pad=0.0,
                                   adjust_dirs=["left", "right", "bottom",
"top"]):

    divider = make_axes_locatable(ax)

    if use_axes is None:
        use_axes = ax

    divider_area_auto_adjustable(divider,
                                 use_axes=use_axes, pad=pad,
                                 adjust_dirs=adjust_dirs)

def onclick(event):
    canvas = event.canvas
    canvas.draw()

if __name__ == "__main__":

    import matplotlib.pyplot as plt
    def ex1():
        fig = plt.figure(1)
        #ax = plt.axes([0,0,1,1])
        ax = fig.add_subplot(111)
        ax.plot([0, 0.5, 1.3, 2,4],'o',ms=20)
        # ax = plt.subplot(111)
        ax.set_title('Title')
        ax.set_yticks([0.5])
        ax.set_yticklabels(["very long label"])

        fig.canvas.mpl_connect('button_press_event', onclick)


        make_axes_area_auto_adjustable(ax)


    def ex2():

        fig = plt.figure(2)
        ax1 = plt.axes([0,0,1,0.5])
        ax2 = plt.axes([0,0.5,1,0.5])

        ax1.set_yticks([0.5])
        ax1.set_yticklabels(["very long label"])
        ax1.set_ylabel("Y label")

        ax2.set_title("Title")

        make_axes_area_auto_adjustable(ax1, pad=0.1, use_axes=[ax1, ax2])
        make_axes_area_auto_adjustable(ax2, pad=0.1, use_axes=[ax1, ax2])

    def ex3():
        fig = plt.figure(3)
        ax1 = plt.axes([0,0,1,1])
        divider = make_axes_locatable(ax1)

        ax2 = divider.new_horizontal("100%", pad=0.3, sharey=ax1)
        ax2.tick_params(labelleft="off")
        fig.add_axes(ax2)

        divider_area_auto_adjustable(divider,
                                     use_axes=[ax1], pad=0.1,
                                     adjust_dirs=["left"])
        divider_area_auto_adjustable(divider,
                                     use_axes=[ax2], pad=0.1,
                                     adjust_dirs=["right"])
        divider_area_auto_adjustable(divider,
                                     use_axes=[ax1, ax2], pad=0.1,
                                     adjust_dirs=["top", "bottom"])

        ax1.set_yticks([0.5])
        ax1.set_yticklabels(["very long label"])

        ax2.set_title("Title")
        ax2.set_xlabel("X - Label")

    ex1()
    ex2()
    ex3()

    plt.show()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.python.org/pipermail/matplotlib-users/attachments/20210129/1203c0e8/attachment-0001.html>
-------------- next part --------------
from mpl_toolkits.axes_grid1 import make_axes_locatable
from mpl_toolkits.axes_grid1.axes_size import Padded
import mpl_toolkits.axes_grid1.axes_size as axes_size
from matplotlib.axes import Axes

import matplotlib.transforms as mtransforms

# axis_get_ticklabel_extents & axes_get_tightbbox are redefined due to
# a limitation of tge current axis_get_ticklabel_extents

def axis_get_ticklabel_extents(self, renderer, update_label_pos=False):
    """
    Get the extents of the tick labels on either side
    of the axes.
    """
    ticklabelBoxes = []
    ticklabelBoxes2 = []

    interval = self.get_view_interval()
    for tick, loc, label in self.iter_ticks():
        if tick is None: continue
        if not mtransforms.interval_contains(interval, loc): continue
        tick.update_position(loc)
        tick.set_label1(label)
        tick.set_label2(label)
        if tick.label1On and tick.label1.get_visible():
            extent = tick.label1.get_window_extent(renderer)
            ticklabelBoxes.append(extent)
        if tick.label2On and tick.label2.get_visible():
            extent = tick.label2.get_window_extent(renderer)
            ticklabelBoxes2.append(extent)

    # position of the label (and also the offsetText) need to be updated!
    if update_label_pos:
        self._update_label_position(ticklabelBoxes, ticklabelBoxes2)
 
    if len(ticklabelBoxes):
        bbox = mtransforms.Bbox.union(ticklabelBoxes)
    else:
        bbox = mtransforms.Bbox.from_extents(0, 0, 0, 0)
    if len(ticklabelBoxes2):
        bbox2 = mtransforms.Bbox.union(ticklabelBoxes2)
    else:
        bbox2 = mtransforms.Bbox.from_extents(0, 0, 0, 0)
    return bbox, bbox2


def axes_get_tightbbox(self, renderer):
    """
    return the tight bounding box of the axes.
    The dimension of the Bbox in canvas coordinate.
    """

    artists = []
    bb = []

    artists.append(self)

    if self.title.get_visible():
        artists.append(self.title)

    if self.xaxis.get_visible():
        artists.append(self.xaxis.label)
        bbx1, bbx2 = axis_get_ticklabel_extents(self.xaxis, renderer, True)
        bb.extend([bbx1, bbx2])
    if self.yaxis.get_visible():
        artists.append(self.yaxis.label)
        bby1, bby2 = axis_get_ticklabel_extents(self.yaxis, renderer, True)
        bb.extend([bby1, bby2])


    bb.extend([c.get_window_extent(renderer) for c in artists if c.get_visible()])

    _bbox = mtransforms.Bbox.union([b for b in bb if b.width!=0 or b.height!=0])

    return _bbox


class SizeFromFunc(axes_size._Base):
    def __init__(self, func):
        self._func = func

    def get_size(self, renderer):
        rel_size = 0.

        bb = self._func(renderer)
        dpi = renderer.points_to_pixels(72.)
        abs_size = bb/dpi

        return rel_size, abs_size

class GetExtentHelper(object):
    def _get_left(tight_bbox, axes_bbox):
        return axes_bbox.xmin - tight_bbox.xmin

    def _get_right(tight_bbox, axes_bbox):
        return tight_bbox.xmax - axes_bbox.xmax

    def _get_bottom(tight_bbox, axes_bbox):
        return axes_bbox.ymin - tight_bbox.ymin

    def _get_top(tight_bbox, axes_bbox):
        return tight_bbox.ymax - axes_bbox.ymax

    _get_func_map = dict(left=_get_left,
                         right=_get_right,
                         bottom=_get_bottom,
                         top=_get_top)

    del _get_left, _get_right, _get_bottom, _get_top
    
    def __init__(self, ax, direction):
        if isinstance(ax, Axes):
            self._ax_list = [ax]
        else:
            self._ax_list = ax
            
        try:
            self._get_func = self._get_func_map[direction]
        except KeyError:
            print "direction must be one of left, right, bottom, top"
            raise

    def __call__(self, renderer):
        vl = [self._get_func(axes_get_tightbbox(ax, renderer),
                             ax.bbox) for ax in self._ax_list]
        return max(vl)
    

def divider_append_size(self, position, size):

    if position == "left":
        self._horizontal.insert(0, size)
        self._xrefindex += 1
    elif position == "right":
        self._horizontal.append(size)
    elif position == "bottom":
        self._vertical.insert(0, size)
        self._yrefindex += 1
    elif position == "top":
        self._vertical.append(size)
    else:
        raise ValueError("the position must be one of left, right, bottom, or top")


def divider_area_auto_adjustable(divider, 
                                 use_axes, pad=0.0,
                                 adjust_dirs=["left", "right", "bottom", "top"],
                                 ):
    for d in adjust_dirs:
        helper = GetExtentHelper(use_axes, d)
        size = SizeFromFunc(helper)
        padded_size = Padded(size, pad) # pad in inch
        divider_append_size(divider, d, padded_size)

def make_axes_area_auto_adjustable(ax, 
                                   use_axes=None, pad=0.0,
                                   adjust_dirs=["left", "right", "bottom", "top"]):
    
    divider = make_axes_locatable(ax)

    if use_axes is None:
        use_axes = ax

    divider_area_auto_adjustable(divider, 
                                 use_axes=use_axes, pad=pad,
                                 adjust_dirs=adjust_dirs)

def onclick(event):
    canvas = event.canvas
    canvas.draw()

if __name__ == "__main__":
    
    import matplotlib.pyplot as plt
    def ex1():
        fig = plt.figure(1)
        #ax = plt.axes([0,0,1,1])
        ax = fig.add_subplot(111)
        ax.plot([0, 0.5, 1.3, 2,4],'o',ms=20)
        # ax = plt.subplot(111)
        ax.set_title('Title')
        ax.set_yticks([0.5])
        ax.set_yticklabels(["very long label"])

        fig.canvas.mpl_connect('button_press_event', onclick)

        make_axes_area_auto_adjustable(ax)
    
    ex1()

    plt.show()


More information about the Matplotlib-users mailing list