2015-12-20 2 views
1

Я вижу, что set_xscale принимает параметр base, но я также хочу масштабировать с коэффициентом; т.е. если база 4 и фактор 10, то:Шкала шкалы с разным коэффициентом и основанием

40, 160, 640, ... 

Кроме того, документация говорит, что значения суб-сетки, представленные subsx должны быть целыми числами, но я хочу, значения с плавающей точкой.

Каков самый чистый способ сделать это?

ответ

1

Я не знаю какого-либо встроенного метода для применения коэффициента масштабирования после экспоненты, но вы можете создать собственный локатор галочки и форматировщик путем подкласса matplotlib.ticker.LogLocator и matplotlib.ticker.LogFormatter.

Вот довольно быстрый и грязный хак, который делает то, что вы ищете:

from matplotlib import pyplot as plt 
from matplotlib.ticker import LogLocator, LogFormatter, ScalarFormatter, \ 
           is_close_to_int, nearest_long 
import numpy as np 
import math 

class ScaledLogLocator(LogLocator): 
    def __init__(self, *args, scale=10.0, **kwargs): 
     self._scale = scale 
     LogLocator.__init__(self, *args, **kwargs) 

    def view_limits(self, vmin, vmax): 
     s = self._scale 
     vmin, vmax = LogLocator.view_limits(self, vmin/s, vmax/s) 
     return s * vmin, s * vmax 

    def tick_values(self, vmin, vmax): 
     s = self._scale 
     locs = LogLocator.tick_values(self, vmin/s, vmax/s) 
     return s * locs 

class ScaledLogFormatter(LogFormatter): 
    def __init__(self, *args, scale=10.0, **kwargs): 
     self._scale = scale 
     LogFormatter.__init__(self, *args, **kwargs) 

    def __call__(self, x, pos=None): 
     b = self._base 
     s = self._scale 

     # only label the decades 
     if x == 0: 
      return '$\mathdefault{0}$' 

     fx = math.log(abs(x/s))/math.log(b) 
     is_decade = is_close_to_int(fx) 
     sign_string = '-' if x < 0 else '' 

     # use string formatting of the base if it is not an integer 
     if b % 1 == 0.0: 
      base = '%d' % b 
     else: 
      base = '%s' % b 
     scale = '%d' % s 

     if not is_decade and self.labelOnlyBase: 
      return '' 
     elif not is_decade: 
      return ('$\mathdefault{%s%s\times%s^{%.2f}}$' 
        % (sign_string, scale, base, fx)) 
     else: 
      return (r'$%s%s\times%s^{%d}$' 
        % (sign_string, scale, base, nearest_long(fx))) 

Например:

fig, ax = plt.subplots(1, 1) 
x = np.arange(1000) 
y = np.random.randn(1000) 
ax.plot(x, y) 
ax.set_xscale('log') 
subs = np.linspace(0, 1, 10) 

majloc = ScaledLogLocator(scale=10, base=4) 
minloc = ScaledLogLocator(scale=10, base=4, subs=subs) 
fmt = ScaledLogFormatter(scale=10, base=4) 
ax.xaxis.set_major_locator(majloc) 
ax.xaxis.set_minor_locator(minloc) 
ax.xaxis.set_major_formatter(fmt) 
ax.grid(True) 

# show the same tick locations with non-exponential labels 
ax2 = ax.twiny() 
ax2.set_xscale('log') 
ax2.set_xlim(*ax.get_xlim()) 
fmt2 = ScalarFormatter() 
ax2.xaxis.set_major_locator(majloc) 
ax2.xaxis.set_minor_locator(minloc) 
ax2.xaxis.set_major_formatter(fmt2) 

enter image description here