In mplot3d, how is format_zdata supposed to work? Why is sensible_format_data called?

Hi all,
I am using Matplotlib 1.0.1 and am seeing weird behaviour with mplot3d and
ticker formatters, and I think I need to submit a patch to axes3d, but am not
sure how much it will break, because format_zdata() and format_coord() look to
be defined inconsistently.

When trying to rotate a plot, which was created including the following
commands,
  ...
  ax.plot(x[0,alow:atop],x[1,alow:atop],x[2,alow:atop],c=rgb.tolist())
  ax.w_xaxis.set_major_locator(tic.LinearLocator(3))
  ax.w_xaxis.set_major_formatter(tic.FormatStrFormatter(''))
  ax.w_yaxis.set_major_locator(tic.LinearLocator(3))
  ax.w_yaxis.set_major_formatter(tic.FormatStrFormatter(''))
  ax.w_zaxis.set_major_locator(tic.LinearLocator(3))
  ax.w_zaxis.set_major_formatter(tic.FormatStrFormatter(''))
  plt.draw()
  ...

I received the following backtrace and error message:

/usr/lib64/python2.6/site-packages/matplotlib/backend_bases.pyc in
mouse_move(self, event)
   2393 if event.inaxes and event.inaxes.get_navigate():
   2394
-> 2395 try: s = event.inaxes.format_coord(event.xdata,
event.ydata)
   2396 except ValueError: pass
   2397 except OverflowError: pass

/usr/lib64/python2.6/site-packages/mpl_toolkits/mplot3d/axes3d.pyc in
format_coord(self, xd, yd)
    474
    475 xs = self.format_xdata(x)
--> 476 ys = self.format_ydata(y)
    477 zs = self.format_ydata(z)
    478 return 'x=%s, y=%s, z=%s' % (xs, ys, zs)

/usr/lib64/python2.6/site-packages/mpl_toolkits/mplot3d/axes3d.pyc in
format_ydata(self, y)
    424 except TypeError:
    425 fmt = self.w_yaxis.get_major_formatter()
--> 426 return sensible_format_data(fmt, y)
    427
    428 def format_zdata(self, z):

/usr/lib64/python2.6/site-packages/mpl_toolkits/mplot3d/axes3d.pyc in
sensible_format_data(self, value)
     26 if abs(value) > 1e4 or abs(value)<1e-3:
     27 s = '%1.4e' % value
---> 28 return self._formatSciNotation(s)
     29 else:
     30 return '%4.3f' % value

AttributeError: FormatStrFormatter instance has no attribute
'_formatSciNotation'

···

---
I am using FormatStrFormatter('') to try to obtain an empty tick.

[1] It looks like sensible_format_data() assumes that self is class
ScalarFormatter(Formatter), since this is the only ticker Formatter that has
attribute _formatSciNotation(s). As far as I can tell, this means that
sensible_format_data(fmt,y) should *only* be called if fmt has class
ScalarFormatter(Formatter).

[2] In axes3d.py, I see:

    def format_zdata(self, z):
        """
        Return z string formatted. This function will use the attribute
        self.fmt_zdata if it is callable, else will fall back on the yaxis
        major formatter
        """
        try:
            return self.fmt_zdata(z)
        except (AttributeError, TypeError):
            fmt = self.w_zaxis.get_major_formatter()
            return sensible_format_data(fmt, z)

To me, it looks like the call to sensible_format_data(fmt, z) is wrong. The
same error occurs in format_xdata() and format_ydata(). So I would like to
submit a patch for format_xdata(), format_ydata(), format_zdata(), e.g.:

    def format_zdata(self, z):
        """
        Return z string formatted. This function will use the attribute
        self.fmt_zdata if it is callable, else will fall back on the zaxis
        major formatter
        """
        try:
            return self.fmt_zdata(z)
        except (AttributeError, TypeError):
            fmt = self.w_zaxis.get_major_formatter()
            try:
                return sensible_format_data(fmt, z)
            except (AttributeError, TypeError):
                return format_data(fmt, z)

[3] But I am also worried about the comment "else will fall back on the yaxis
major formatter". Shouldn't this say "the zaxis major formatter", since that
is what the code does? Or should the code use the yaxis major formatter, since
that is what the documentation says? The documentation
http://matplotlib.github.com/mpl_toolkits/mplot3d/api.html agrees with the
comment and not with the code.

[4] In def format_coord(self, xd, yd), I see

        xs = self.format_xdata(x)
        ys = self.format_ydata(y)
        zs = self.format_ydata(z)

Why doesn't the last line say
        zs = self.format_zdata(z)
?

Best, Paul