Repository: matplotlib/matplotlib
File: lib/matplotlib/scale.py (Python)

Code before:
        axis.set_major_locator(AutoLocator())
        axis.set_major_formatter(ScalarFormatter())
        axis.set_minor_formatter(NullFormatter())
        # update the minor locator for x and y axis based on rcParams
        if (axis.axis_name == 'x' and mpl.rcParams['xtick.minor.visible'] or
                axis.axis_name == 'y' and mpl.rcParams['ytick.minor.visible']):
            axis.set_minor_locator(AutoMinorLocator())
        else:
            axis.set_minor_locator(NullLocator())


class LogTransform(Transform):
    input_dims = output_dims = 1

    def __init__(self, base, nonpositive='clip'):
        super().__init__()
        if base <= 0 or base == 1:
            raise ValueError('The log base cannot be <= 0 or == 1')
        self._base = base
        self._clip = _api.check_getitem(
            {"clip": True, "mask": False}, nonpositive=nonpositive)
        self._calc_log_params()

    def _calc_log_params(self):
        self._log_func = {np.e: np.log, 2: np.log2, 10: np.log10}.get(self._base)
        self._inv_log_base = 1.0 / np.log(self._base) if not self._log_func else 1

    @property
    def base(self):
        return self._base

    @base.setter
    def base(self, value):
        if value <= 0 or value == 1:
            raise ValueError('The log base cannot be <= 0 or == 1')
        self._base = value
        self._calc_log_params()

    def __str__(self):
        return "{}(base={}, nonpositive={!r})".format(
            type(self).__name__, self.base, "clip" if self._clip else "mask")

    def transform_non_affine(self, values):
        # Ignore invalid values due to nans being passed to the transform.
        with np.errstate(divide="ignore", invalid="ignore"):
            if self._log_func:  # If possible, do everything in a single call to NumPy.
                out = self._log_func(values)
            else:
                out = np.log(values) * self._inv_log_base
            if self._clip:
                # SVG spec says that conforming viewers must support values up

Review comment (suggestion):
Can't we instead do something like
```suggestion
        if self._log_func is None:
            inv_log_base = 1 / np.log(self._base)
            self._log_func = lambda x: np.log(x) * inv_log_base
```
this would result in always a valid _log_func and simply the logic down the road to just `out = self._log_func(value)` - no conditionals needed anymore.

There *might* be issues with pickling - I know we care for that in some places - not sure whether it is relevant here. But then anyway we should strip _inv_log_func in `__getstate__` and recalculate from `self._base` in `__setstate__`. 




Code after:
        axis.set_major_locator(AutoLocator())
        axis.set_major_formatter(ScalarFormatter())
        axis.set_minor_formatter(NullFormatter())
        # update the minor locator for x and y axis based on rcParams
        if (axis.axis_name == 'x' and mpl.rcParams['xtick.minor.visible'] or
                axis.axis_name == 'y' and mpl.rcParams['ytick.minor.visible']):
            axis.set_minor_locator(AutoMinorLocator())
        else:
            axis.set_minor_locator(NullLocator())


class LogTransform(Transform):
    input_dims = output_dims = 1

    def __init__(self, base, nonpositive='clip'):
        super().__init__()
        if base <= 0 or base == 1:
            raise ValueError('The log base cannot be <= 0 or == 1')
        self.base = base
        self._clip = _api.check_getitem(
            {"clip": True, "mask": False}, nonpositive=nonpositive)
        self._log_funcs = {np.e: np.log, 2: np.log2, 10: np.log10}

    def __str__(self):
        return "{}(base={}, nonpositive={!r})".format(
            type(self).__name__, self.base, "clip" if self._clip else "mask")

    def transform_non_affine(self, values):
        # Ignore invalid values due to nans being passed to the transform.
        with np.errstate(divide="ignore", invalid="ignore"):
            log_func = self._log_funcs.get(self.base)
            if log_func:
                out = log_func(values)
            else:
                out = np.log(values) / np.log(self.base)
            if self._clip:
                # SVG spec says that conforming viewers must support values up
                # to 3.4e38 (C float); however experiments suggest that
                # Inkscape (which uses cairo for rendering) runs into cairo's
                # 24-bit limit (which is apparently shared by Agg).
                # Ghostscript (used for pdf rendering appears to overflow even
                # earlier, with the max value around 2 ** 15 for the tests to
                # pass. On the other hand, in practice, we want to clip beyond
                #     np.log10(np.nextafter(0, 1)) ~ -323
                # so 1000 seems safe.
                out[values <= 0] = -1000
        return out

    def inverted(self):
        return InvertedLogTransform(self.base)