2009-09-14 6 views
21

मैं दिनांक/समय मूल्य अक्ष पर लेबल निर्धारित करने के लिए "अच्छी संख्या" एल्गोरिदम खोज रहा हूं। मैं Paul Heckbert's Nice Numbers algorithm से परिचित हूं।समय/दिनांक अक्ष के लिए अच्छा ग्राफ लेबल के लिए एल्गोरिदम?

मेरे पास एक प्लॉट है जो एक्स अक्ष पर समय/दिनांक प्रदर्शित करता है और उपयोगकर्ता ज़ूम इन कर सकता है और एक छोटे से समय के फ्रेम को देख सकता है। मैं एक एल्गोरिदम की तलाश में हूं जो टिकों पर प्रदर्शित होने के लिए अच्छी तिथियां चुनता है।

उदाहरण के लिए:

  • एक दिन का समय को देखते हुए: 1/1 12:00, 1/1 04:00, 1/1 08:00 ...
  • एक सप्ताह को देखते हुए : 1/1, 1/2, 1/3 ...
  • एक महीने को देखते हुए: 09/01, 09/02, 09/03 ...

अच्छा लेबल टिक नहीं पहले दृश्य बिंदु से मेल खाने की आवश्यकता है, लेकिन इसके करीब है।

क्या कोई इस तरह के एल्गोरिदम से परिचित है?

उत्तर

6

'अच्छा संख्या' लेख आप से जुड़ा हुआ उल्लेख

दशमलव में सबसे अच्छी संख्या 1, 2, 5 और सभी बिजली के- 10 इन नंबरों

तो के गुणकों हैं कि मुझे लगता है कि उस समय/समय के साथ कुछ ऐसा करने के लिए आपको घटक टुकड़ों को तोड़कर शुरू करना होगा। तो अंतराल के प्रत्येक प्रकार के अच्छा कारकों पर विचार:

  • आप सेकंड दिखा रहे हैं या मिनट 1, 2, 3, 5, 10, 15, 30 (मैं छोड़ दिया 6, 12, 15, 20 का उपयोग करते हैं क्योंकि वे सही "महसूस" नहीं करते हैं)।
  • आप घंटे उपयोग 1, 2, 3, 4, 6, 8, 12
  • दिनों के लिए
  • दिखा रहे हैं तो का उपयोग 1, 2, 7
  • सप्ताह के लिए
  • का उपयोग 1, 2, 4 (13 और 26 फिट मॉडल लेकिन मेरे लिए बहुत अजीब लग रहे हैं)
  • महीने के लिए उपयोग करें 1, 2, 3, 4, 6
  • साल का उपयोग 1, 2, 5 और बिजली के- 10 गुणकों के लिए

अब स्पष्ट रूप से जब आप बड़ी मात्रा में आते हैं तो यह टूटने लगता है। निश्चित रूप से आप 30 मिनट या कुछ के "सुंदर" अंतराल में भी 5 सप्ताह के लायक मिनट नहीं दिखाना चाहते हैं। दूसरी तरफ, जब आपके पास केवल 48 घंटे का मूल्य होता है, तो आप 1 दिन अंतराल नहीं दिखाना चाहते हैं। जिस चाल के बारे में आपने पहले ही बताया है वह सभ्य संक्रमण बिंदु ढूंढ रहा है।

बस एक झुकाव पर, मैं कहूंगा कि एक उचित क्रॉसओवर बिंदु अगले अंतराल के जितना दोगुना होगा। यही कारण है कि आप निम्नलिखित (न्यूनतम और बाद में पता चला अंतराल की अधिकतम संख्या)

  • उपयोग सेकंड अगर आप कम से कम 2 मिनट के लायक है (1-120)
  • उपयोग मिनट यदि आपके पास कम से कम 2 घंटे के लायक देना होगा (2-120)
  • उपयोग घंटे यदि आपके पास कम से कम 2 दिनों के लायक (2-48)
  • उपयोग दिनों अगर आप कम से कम 2 सप्ताह तक (2-14)
  • उपयोग सप्ताह यदि आप कम है 2 महीने से अधिक (2-8/9)
  • यदि आपके पास 2 से कम है तो महीनों का उपयोग करें लायक साल (2-24)
  • अन्यथा (अपने पर्वतमाला कि लंबे समय से किया जा सकता है, तो यद्यपि आप दशकों, सदियों, आदि के साथ जारी रख सकता) साल का उपयोग

दुर्भाग्य से, हमारी असंगत समय अंतराल का मतलब है कि आप के साथ खत्म कुछ मामलों में 1 सौ से अधिक अंतराल हो सकते हैं जबकि अन्य के पास 8 या 9 अधिकतर होते हैं। इसलिए आप अपने अंतराल का आकार चुनना चाहेंगे जैसे कि आपके पास 10-15 से अधिक अंतराल नहीं हैं (या 5 से कम उस बात के लिए)। इसके अलावा, अगर आपको लगता है कि ट्रैक रखने में आसान लगता है तो आप अगले सबसे बड़े अंतराल की सख्त परिभाषा से तोड़ सकते हैं। उदाहरण के लिए, आप 3 दिनों तक (72 घंटे) और सप्ताह तक 4 महीने तक का उपयोग कर सकते हैं। थोड़ा परीक्षण और त्रुटि आवश्यक हो सकती है।

तो वापस जाने के लिए, अपनी सीमा के आकार के आधार पर अंतराल प्रकार चुनें, फिर "अच्छे" संख्याओं में से एक को चुनकर अंतराल आकार चुनें जो आपको 5 और 15 टिक अंकों के बीच छोड़ देगा। या यदि आप टिक अंकों के बीच पिक्सेल की वास्तविक संख्या को जानते हैं और/या नियंत्रित कर सकते हैं तो आप ऊपरी और निचली सीमाओं को लगा सकते हैं कि टिक के बीच कितने पिक्सेल स्वीकार्य हैं (यदि वे बहुत दूर हैं तो ग्राफ को पढ़ने में मुश्किल हो सकती है, लेकिन अगर ग्राफ बहुत खराब हो जाएंगे और आपके लेबल ओवरलैप हो सकते हैं)।

1

अभी भी इस प्रश्न का कोई जवाब नहीं है ... मैं तब अपना पहला विचार फेंक दूंगा! मुझे लगता है कि आपके पास दृश्य धुरी की सीमा है।

शायद यह है कि मैं कैसे करूंगा।

असहज छद्म:

// quantify range 
rangeLength = endOfVisiblePart - startOfVisiblePart; 

// qualify range resolution 
if (range < "1.5 day") { 
    resolution = "day"; // it can be a number, e.g.: ..., 3 for day, 4 for week, ... 
} else if (range < "9 days") { 
    resolution = "week"; 
} else if (range < "35 days") { 
    resolution = "month"; 
} // you can expand this in both ways to get from nanoseconds to geological eras if you wish 

कि, यह (क्या आप पर आसान पहुंच के आधार पर) चाहिए प्रत्येक अच्छा लेबल टिक के लिए मूल्य निर्धारित करने के लिए काफी आसान हो जाने के बाद। 'रिज़ॉल्यूशन' के आधार पर, आप इसे अलग-अलग प्रारूपित करते हैं। उदा। एमएम/डीडी "सप्ताह" के लिए, एमएम: एसएस "मिनट", आदि के लिए, जैसा कि आपने कहा था।

+0

"1.5 दिन", "9 दिन" जैसी चीजें कार्यान्वयन की अवधि में अत्यधिक भाषा निर्भर हैं (मेरे लिए)। उदाहरण के लिए, सी या यहां तक ​​कि सी ++ में, मैं बस दोनों बार के बीच मिलीसेकंड में अंतर को पकड़ने के लिए एक हस्ताक्षरित लंबे समय तक उपयोग करता हूं, जबकि जावा में, मैं शायद समय या क्षण वर्ग बनाउंगा, और शायद पहले से ही उनमें से कुछ पहले से ही हैं। .. – Joanis

0

मेरा सुझाव है कि आप स्रोत कोड को gnuplot या RRDTool (या यहां तक ​​कि फ़्लोट) पर ले जाएं और जांचें कि वे इस समस्या से कैसे संपर्क करते हैं। सामान्य मामला आपकी साजिश की चौड़ाई के आधार पर लागू एन लेबल होने की संभावना है, जो निकटतम 'अच्छा' नंबर पर किसी प्रकार का 'स्नैपिंग' होता है।

हर बार जब मैंने ऐसा एल्गोरिदम लिखा है (वास्तव में कई बार), मैंने 'वरीयताओं' की एक तालिका का उपयोग किया है ... यानी: साजिश पर समय सीमा के आधार पर, तय करें कि मैं उपयोग कर रहा हूं या नहीं मुख्य धुरी बिंदु के रूप में सप्ताह, दिन, घंटे, मिनट आदि। मैं आमतौर पर कुछ पसंदीदा स्वरूपण शामिल करता हूं, क्योंकि मैं शायद ही कभी ग्राफ पर साजिश के प्रत्येक मिनट की तारीख देखना चाहता हूं।

मैं खुश हूं लेकिन किसी को फॉर्मूला (जैसे हेकबर्ट करता है) का उपयोग करके 'अच्छा' खोजने के लिए आश्चर्यचकित हूं, क्योंकि मिनटों, घंटों, दिनों और हफ्तों के बीच समय इकाइयों में बदलाव उस रैखिक नहीं है।

0

-

"अच्छा संख्या" का एक अनुभवहीन विस्तार [संपादित करें मैं http://www.acooke.org/cute/AutoScalin0.html में यह एक छोटे से अधिक विस्तार] एल्गोरिथ्म आधार 12 और 60 है, जो घंटे और मिनट के लिए अच्छा अंतराल देता है के लिए काम करने लगता है।उदाहरण के लिए

LIM10 = (10, [(1.5, 1), (3, 2), (7, 5)], [1, 2, 5]) 
LIM12 = (12, [(1.5, 1), (3, 2), (8, 6)], [1, 2, 6]) 
LIM60 = (60, [(1.5, 1), (20, 15), (40, 30)], [1, 15, 40]) 


def heckbert_d(lo, hi, ntick=5, limits=None): 
    ''' 
    Heckbert's "nice numbers" algorithm for graph ranges, from "Graphics Gems". 
    ''' 
    if limits is None: 
     limits = LIM10 
    (base, rfs, fs) = limits 
    def nicenum(x, round): 
     step = base ** floor(log(x)/log(base)) 
     f = float(x)/step 
     nf = base 
     if round: 
      for (a, b) in rfs: 
       if f < a: 
        nf = b 
        break 
     else: 
      for a in fs: 
       if f <= a: 
        nf = a 
        break 
     return nf * step 
    delta = nicenum(hi-lo, False) 
    return nicenum(delta/(ntick-1), True) 


def heckbert(lo, hi, ntick=5, limits=None): 
    ''' 
    Heckbert's "nice numbers" algorithm for graph ranges, from "Graphics Gems". 
    ''' 
    def _heckbert(): 
     d = heckbert_d(lo, hi, ntick=ntick, limits=limits) 
     graphlo = floor(lo/d) * d 
     graphhi = ceil(hi/d) * d 
     fmt = '%' + '.%df' % max(-floor(log10(d)), 0) 
     value = graphlo 
     while value < graphhi + 0.5*d: 
      yield fmt % value 
      value += d 
    return list(_heckbert()) 

इसलिए, यदि आप 0 से 60 सेकंड प्रदर्शित करना चाहते हैं 0 से 5 के लिए

>>> heckbert(0, 60, limits=LIM60) 
['0', '15', '30', '45', '60'] 

या घंटे,,:

>>> heckbert(0, 5, limits=LIM12) 
['0', '2', '4', '6'] 
इस कोड को मैं सिर्फ एक साथ काट दिया है
0

सिद्धांत में आप अपनी अवधारणा भी बदल सकते हैं। जहां यह विज़ुअलाइजेशन के केंद्र में आपका डेटा नहीं है, लेकिन केंद्र में आपके पास अपना स्केल है।

जब आप अपने डेटा की तिथियों की शुरुआत और अंत को जानते हैं, तो आप सभी तिथियों के साथ एक स्केल बना सकते हैं और इस पैमाने पर डेटा भेज सकते हैं। एक निश्चित पैमाने की तरह।

आपके पास साल, महीने, दिन, घंटे, ... के पैमाने का स्केलिंग हो सकता है और इन स्केलों को स्केलिंग सीमित कर सकता है, जिसका मतलब है कि आप मुफ्त स्केलिंग की अवधारणा को हटाते हैं।

लाभ आसानी से तिथियों के अंतराल दिखा सकता है। लेकिन अगर आपके पास बहुत सारे अंतराल हैं, तो यह भी बेकार हो सकता है।