2013-12-09 4 views
7

मैं सकारात्मक और नकारात्मक दिशा में विस्तारित पैरामीटर की एक बड़ी श्रृंखला को कवर करने के लिए matplotlib के symlog पैमाने का उपयोग करता हूं। दुर्भाग्यवश, symlog-scale बहुत सहज नहीं है और शायद यह भी आमतौर पर उपयोग नहीं किया जाता है। इसलिए, मैं प्रमुख टिकों के बीच मामूली टिक डालकर प्रयुक्त स्केलिंग को और अधिक स्पष्ट बनाना चाहता हूं। पैमाने के लॉग भाग पर, मैं [2,3, ..., 9] * 10^ई पर टिक रखना चाहता हूं जहां e पास के प्रमुख टिक हैं। इसके अतिरिक्त, 0 और 0.1 के बीच की सीमा को समान रूप से रखा मामूली टिकों के साथ कवर किया जाना चाहिए, जो 0.01 अलग होगा।symlog पैमाने पर मामूली ticks कैसे रखें?

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.ticker import LogLocator, AutoLocator 

x = np.linspace(-5, 5, 100) 
y = x 

plt.plot(x, y) 
plt.yscale('symlog', linthreshy=1e-1) 

yaxis = plt.gca().yaxis 
yaxis.set_minor_locator(LogLocator(subs=np.arange(2, 10))) 

plt.show() 

दुर्भाग्य से, इस का उत्पादन नहीं करता जो मैं चाहता: कई छोटे टिक करने के लिए जिस तरह से देखते हैं

enter image description here

ध्यान दें कि मैं निम्नलिखित कोड का उपयोग कर इस तरह टिक पर पहुंचने के लिए matplotlib.ticker API उपयोग करने की कोशिश लगभग 0, जो शायद LogLocator के कारण हैं। इसके अलावा, नकारात्मक धुरी पर कोई मामूली टिक नहीं है।

यदि मैं उपयोग करता हूं और AutoLocator इसके बजाय कोई मामूली टिक दिखाई नहीं देता है। AutoMinorLocator केवल समान रूप से स्केल किए गए अक्ष का समर्थन करता है। मेरा सवाल यह है कि वांछित टिक प्लेसमेंट कैसे प्राप्त करें?

उत्तर

8

इस मुद्दे में थोड़ी गहरी खुदाई करते हुए, मैंने देखा कि सामान्य समाधान के साथ आना मुश्किल होगा। सौभाग्य से, मैं अपने डेटा पर कुछ कमी मान सकते हैं और एक कस्टम मेड वर्ग इसलिए समस्या का समाधान करने के लिए पर्याप्त था:

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.ticker import Locator 


class MinorSymLogLocator(Locator): 
    """ 
    Dynamically find minor tick positions based on the positions of 
    major ticks for a symlog scaling. 
    """ 
    def __init__(self, linthresh): 
     """ 
     Ticks will be placed between the major ticks. 
     The placement is linear for x between -linthresh and linthresh, 
     otherwise its logarithmically 
     """ 
     self.linthresh = linthresh 

    def __call__(self): 
     'Return the locations of the ticks' 
     majorlocs = self.axis.get_majorticklocs() 

     # iterate through minor locs 
     minorlocs = [] 

     # handle the lowest part 
     for i in xrange(1, len(majorlocs)): 
      majorstep = majorlocs[i] - majorlocs[i-1] 
      if abs(majorlocs[i-1] + majorstep/2) < self.linthresh: 
       ndivs = 10 
      else: 
       ndivs = 9 
      minorstep = majorstep/ndivs 
      locs = np.arange(majorlocs[i-1], majorlocs[i], minorstep)[1:] 
      minorlocs.extend(locs) 

     return self.raise_if_exceeds(np.array(minorlocs)) 

    def tick_values(self, vmin, vmax): 
     raise NotImplementedError('Cannot get tick locations for a ' 
            '%s type.' % type(self)) 


x = np.linspace(-5, 5, 100) 
y = x 

plt.plot(x, y) 
plt.yscale('symlog', linthreshy=1e-1) 

yaxis = plt.gca().yaxis 
yaxis.set_minor_locator(MinorSymLogLocator(1e-1)) 

plt.show() 

यह पैदा करता है

enter image description here

ध्यान दें कि यह विधि केवल स्थानों प्रमुख के बीच टिक्स टिक्स। यदि आप छवि में ज़ूम और पैन करते हैं तो यह ध्यान देने योग्य हो जाएगा। इसके अलावा, रैखिक दहलीज को कक्षा में स्पष्ट रूप से आपूर्ति की जानी है, क्योंकि मुझे धुरी से आसानी से और मजबूती से इसे पढ़ने का कोई रास्ता नहीं मिला है।

+0

आप में जोड़ने के लिए नदी के ऊपर में एक जनसंपर्क खोला नहीं जा सका एमपीएल कोडबेस? – tacaswell

0

ओपीएस समाधान अच्छी तरह से काम करता है, लेकिन अक्षरों के किनारों पर टिक अंक उत्पन्न नहीं होते हैं यदि वे रैखिक दहलीज मूल्यों के गुणक नहीं हैं। मैं ऑप्स हैक कर लिया गया है निम्नलिखित (जो किनारों में जब नाबालिग टिक locatoin की स्थापना अस्थायी प्रमुख टिक स्थान जोड़कर भरता है) देने के लिए MinorSymLogLocator() वर्ग:

class MinorSymLogLocator(Locator): 
    """ 
    Dynamically find minor tick positions based on the positions of 
    major ticks for a symlog scaling. 
    """ 
    def __init__(self, linthresh, nints=10): 
     """ 
     Ticks will be placed between the major ticks. 
     The placement is linear for x between -linthresh and linthresh, 
     otherwise its logarithmically. nints gives the number of 
     intervals that will be bounded by the minor ticks. 
     """ 
     self.linthresh = linthresh 
     self.nintervals = nints 

    def __call__(self): 
     # Return the locations of the ticks 
     majorlocs = self.axis.get_majorticklocs() 

     if len(majorlocs) == 1: 
      return self.raise_if_exceeds(np.array([])) 

     # add temporary major tick locs at either end of the current range 
     # to fill in minor tick gaps 
     dmlower = majorlocs[1] - majorlocs[0] # major tick difference at lower end 
     dmupper = majorlocs[-1] - majorlocs[-2] # major tick difference at upper end 

     # add temporary major tick location at the upper end 
     if majorlocs[0] != 0. and ((majorlocs[0] != self.linthresh and dmlower > self.linthresh) or (dmlower == self.linthresh and majorlocs[0] < 0)): 
      majorlocs = np.insert(majorlocs, 0, majorlocs[0]*10.) 
     else: 
      majorlocs = np.insert(majorlocs, 0, majorlocs[0]-self.linthresh) 

     # add temporary major tick location at the upper end 
     if majorlocs[-1] != 0. and ((np.abs(majorlocs[-1]) != self.linthresh and dmupper > self.linthresh) or (dmupper == self.linthresh and majorlocs[-1] > 0)): 
      majorlocs = np.append(majorlocs, majorlocs[-1]*10.) 
     else: 
      majorlocs = np.append(majorlocs, majorlocs[-1]+self.linthresh) 

     # iterate through minor locs 
     minorlocs = [] 

     # handle the lowest part 
     for i in xrange(1, len(majorlocs)): 
      majorstep = majorlocs[i] - majorlocs[i-1] 
      if abs(majorlocs[i-1] + majorstep/2) < self.linthresh: 
       ndivs = self.nintervals 
      else: 
       ndivs = self.nintervals - 1. 

      minorstep = majorstep/ndivs 
      locs = np.arange(majorlocs[i-1], majorlocs[i], minorstep)[1:] 
      minorlocs.extend(locs) 

     return self.raise_if_exceeds(np.array(minorlocs)) 

    def tick_values(self, vmin, vmax): 
     raise NotImplementedError('Cannot get tick locations for a ' 
          '%s type.' % type(self)) 
संबंधित मुद्दे