2012-11-29 20 views
5

पायथन। matplotlib: स्वतंत्र ग्रेडिएंट के रूप में बड़ी संख्या में लाइन सेगमेंट को रंगीन तरीके से रंगीन कैसे करें?
पहले से ही this और this और अन्य सामान पढ़ें; उनमें से कोई भी हमारा जवाब नहीं है!Matplotlib: स्वतंत्र ग्रेडियेंट्स के रूप में बड़ी संख्या में लाइन सेगमेंट को रंगीन करने के लिए, कुशलतापूर्वक

हमारे पास कई अलग-अलग लाइनें हैं जो ढाल रंग में प्रत्येक को साजिश करने की इच्छा रखते हैं।

ऊपर दिए गए पहले लिंक में उल्लिखित समाधान, यदि आपके पास लाइन की एक से अधिक स्ट्रिंग हैं तो काम नहीं करता है। दूसरे शब्दों में, रंग चक्र बदलने से साजिश में सबकुछ प्रभावित होता है न कि ब्याज की एकमात्र पंक्ति। यह हमारी रुचि का नहीं है।

matplotlib साइट पर दूसरा लिंक प्रत्येक पंक्ति के विभाजन को कई में उपयोग करता है। यह अच्छा दृष्टिकोण नहीं है क्योंकि बड़ी संख्या में लाइनों के लिए, 10000 या इससे भी अधिक; यहां तक ​​कि यदि आप प्रति पंक्ति केवल 10 सेगमेंट चुनते हैं तो परिणाम बहुत बड़ा है! फिर भी परिणामस्वरूप रेखाएं आसानी से रंगीन नहीं हैं! यदि आप सेगमेंटेशन की संख्या को बेहतर ढाल के लिए लाइन सेगमेंट का एक फ़ंक्शन बनाते हैं, तो परिणाम वास्तव में बहुत बड़ा होगा! प्रदर्शित करने में मुश्किल, फ़ाइल को ठीक से सहेजना मुश्किल है।

+2

मुझे लगता है कि आप 'matplotlib' की एक सीमा मारा है, लेकिन नहीं लगता कि यह आपकी मुख्य समस्या है। यदि आपके पास 10k लाइनें हैं, भले ही आपने उन्हें 1px चौड़े पर प्लॉट किया हो, फिर भी उन्हें अस्तर देने के लिए वास्तव में उन्हें सभी स्वतंत्र रूप से देखने में सक्षम होने के लिए एक विशाल प्रदर्शन/प्रिंट आउट की आवश्यकता होगी। यहां तक ​​कि यदि आप इस साजिश को बनाने का कोई तरीका ढूंढ सकते हैं, तो आप इसे उचित तरीके से देखने में सक्षम नहीं होंगे। क्या कोई तरीका है कि आप अपना डेटा अनाज कर सकते हैं? – tacaswell

+0

क्या आपने 10000 अलग-अलग लाइन संग्रहों के बजाय एकल लाइन संग्रह जोड़ने का प्रयास किया है? यह अभी भी धीमा है, लेकिन यह तेज़ है। पैनिंग और ज़ूमिंग करते समय यह और भी प्रतिक्रियाशील है। –

+0

@ जोकिंगटन: अच्छी चाल। – Developer

उत्तर

6

एक (मामूली) स्पीडअप 10000 अलग-अलग लाइन संग्रहों के बजाय एकल लाइन संग्रह जोड़ देगा।

जब तक सभी लाइनें समान रंगमंच साझा करती हैं, तब तक आप उन्हें एक पंक्ति संग्रह में समूहित कर सकते हैं, और प्रत्येक के पास अभी भी एक स्वतंत्र ढाल हो सकता है।

Matplotlib अभी भी इस तरह की चीज़ के लिए धीमा है। यह तेजी से ड्रा समय के बजाय गुणवत्ता उत्पादन के लिए अनुकूलित है। हालांकि, आप चीजों को थोड़ा (~ 3x) गति दे सकते हैं। (?)

तो, मैं कैसे लगता है कि तुम शायद रहे हैं का एक उदाहरण के रूप में यह अब क्या कर रही:

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.collections import LineCollection 
# Make random number generation consistent between runs 
np.random.seed(5) 

def main(): 
    numlines, numpoints = 2, 3 
    lines = np.random.random((numlines, numpoints, 2)) 

    fig, ax = plt.subplots() 
    for line in lines: 
     # Add "num" additional segments to the line 
     segments, color_scalar = interp(line, num=20) 
     coll = LineCollection(segments) 
     coll.set_array(color_scalar) 
     ax.add_collection(coll) 
    plt.show() 

def interp(data, num=20): 
    """Add "num" additional points to "data" at evenly spaced intervals and 
    separate into individual segments.""" 
    x, y = data.T 
    dist = np.hypot(np.diff(x - x.min()), np.diff(y - y.min())).cumsum() 
    t = np.r_[0, dist]/dist.max() 

    ti = np.linspace(0, 1, num, endpoint=True) 
    xi = np.interp(ti, t, x) 
    yi = np.interp(ti, t, y) 

    # Insert the original vertices 
    indices = np.searchsorted(ti, t) 
    xi = np.insert(xi, indices, x) 
    yi = np.insert(yi, indices, y) 

    return reshuffle(xi, yi), ti 

def reshuffle(x, y): 
    """Reshape the line represented by "x" and "y" into an array of individual 
    segments.""" 
    points = np.vstack([x, y]).T.reshape(-1,1,2) 
    points = np.concatenate([points[:-1], points[1:]], axis=1) 
    return points 

if __name__ == '__main__': 
    main() 

इसके बजाय, मैं इन पंक्तियों के साथ कुछ कर रही सिफारिश करेंगे (केवल मतभेद main समारोह में हैं):

enter image description here

:

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.collections import LineCollection 
# Make random number generation consistent between runs 
np.random.seed(5) 

def main(): 
    numlines, numpoints = 2, 3 
    points = np.random.random((numlines, numpoints, 2)) 

    # Add "num" additional segments to each line 
    segments, color_scalar = zip(*[interp(item, num=20) for item in points]) 

    segments = np.vstack(segments) 
    color_scalar = np.hstack(color_scalar) 

    fig, ax = plt.subplots() 
    coll = LineCollection(segments) 
    coll.set_array(color_scalar) 
    ax.add_collection(coll) 

    plt.show() 

def interp(data, num=20): 
    """Add "num" additional points to "data" at evenly spaced intervals and 
    separate into individual segments.""" 
    x, y = data.T 
    dist = np.hypot(np.diff(x - x.min()), np.diff(y - y.min())).cumsum() 
    t = np.r_[0, dist]/dist.max() 

    ti = np.linspace(0, 1, num, endpoint=True) 
    xi = np.interp(ti, t, x) 
    yi = np.interp(ti, t, y) 

    # Insert the original vertices 
    indices = np.searchsorted(ti, t) 
    xi = np.insert(xi, indices, x) 
    yi = np.insert(yi, indices, y) 

    return reshuffle(xi, yi), ti 

def reshuffle(x, y): 
    """Reshape the line represented by "x" and "y" into an array of individual 
    segments.""" 
    points = np.vstack([x, y]).T.reshape(-1,1,2) 
    points = np.concatenate([points[:-1], points[1:]], axis=1) 
    return points 

if __name__ == '__main__': 
    main() 
दोनों संस्करणों

एक समान साजिश उत्पन्न


यदि हम 10000 तक लाइनों की संख्या क्रैंक करते हैं, हालांकि, हम प्रदर्शन में महत्वपूर्ण अंतर देखना शुरू कर देंगे।

3 अंक प्रत्येक के साथ 10000 लाइनों, और एक अतिरिक्त 20 अंक रंग ढाल के लिए भर अंतर्वेशित (प्रत्येक पंक्ति में 23 वर्ग) का उपयोग करते हुए और समय यह एक png करने के लिए एक आंकड़ा बचाने के लिए ले जाता है पर देख रहे हैं:

Took 10.866694212 sec with a single collection 
Took 28.594727993 sec with multiple collections 

तो, एकल लाइन संग्रह का उपयोग करके इस विशेष मामले में 3x स्पीडअप से थोड़ा कम होगा। यह तारकीय नहीं है, लेकिन यह कुछ भी नहीं है।

यह भी समय कोड और आउटपुट आकृति है, जो भी इसके लायक है (आउटपुट आंकड़े ड्राइंग के विभिन्न क्रमों के कारण काफी समान नहीं हैं।आप z के स्तर पर नियंत्रण की जरूरत है, तो आप अलग लाइन संग्रह से चिपक) होगा:

enter image description here

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.collections import LineCollection 
import time 
# Make random number generation consistent between runs 
np.random.seed(5) 

def main(): 
    numlines, numpoints = 10000, 3 
    lines = np.random.random((numlines, numpoints, 2)) 

    # Overly simplistic timing, but timeit is overkill for this exmaple 
    tic = time.time() 
    single_collection(lines).savefig('/tmp/test_single.png') 
    toc = time.time() 
    print 'Took {} sec with a single collection'.format(toc-tic) 

    tic = time.time() 
    multiple_collections(lines).savefig('/tmp/test_multiple.png') 
    toc = time.time() 
    print 'Took {} sec with multiple collections'.format(toc-tic) 

def single_collection(lines): 
    # Add "num" additional segments to each line 
    segments, color_scalar = zip(*[interp(item, num=20) for item in lines]) 
    segments = np.vstack(segments) 
    color_scalar = np.hstack(color_scalar) 

    fig, ax = plt.subplots() 
    coll = LineCollection(segments) 
    coll.set_array(color_scalar) 
    ax.add_collection(coll) 
    return fig 

def multiple_collections(lines): 
    fig, ax = plt.subplots() 
    for line in lines: 
     # Add "num" additional segments to the line 
     segments, color_scalar = interp(line, num=20) 
     coll = LineCollection(segments) 
     coll.set_array(color_scalar) 
     ax.add_collection(coll) 
    return fig 

def interp(data, num=20): 
    """Add "num" additional points to "data" at evenly spaced intervals and 
    separate into individual segments.""" 
    x, y = data.T 
    dist = np.hypot(np.diff(x - x.min()), np.diff(y - y.min())).cumsum() 
    t = np.r_[0, dist]/dist.max() 

    ti = np.linspace(0, 1, num, endpoint=True) 
    xi = np.interp(ti, t, x) 
    yi = np.interp(ti, t, y) 

    # Insert the original vertices 
    indices = np.searchsorted(ti, t) 
    xi = np.insert(xi, indices, x) 
    yi = np.insert(yi, indices, y) 

    return reshuffle(xi, yi), ti 

def reshuffle(x, y): 
    """Reshape the line represented by "x" and "y" into an array of individual 
    segments.""" 
    points = np.vstack([x, y]).T.reshape(-1,1,2) 
    points = np.concatenate([points[:-1], points[1:]], axis=1) 
    return points 

if __name__ == '__main__': 
    main() 
+0

बहुत बहुत धन्यवाद। यह वास्तव में अच्छी चाल है। हम आपका पूरा जवाब स्वीकार करते हैं। हम अब के लिए लगभग निश्चित हैं कि विभाजन के अवधारणा के आधार पर हम सबसे अधिक कर सकते हैं। हम यहां उल्लेख करना चाहते हैं कि हमारे आवेदन में एक बड़े त्रिकोणीय जाल कनेक्टेड शिखर के मूल्यों के अनुसार रंगीन होने के हमारे हित में है। हम आपके प्रयास की सराहना करते हैं। – Developer

+0

http://stackoverflow.com/a/10253183/2851664 इस समाधान को इंटरपोलेशन की आवश्यकता नहीं है, बहुत तेज है और अच्छे प्लॉट उत्पन्न करता है। – sebix

+0

@sebix - वह समाधान इस के समान है। इंटरपोलेशन यह एक वैकल्पिक है। यदि आप मूल शीर्षकों के बीच रंगों को आसानी से संक्रमण करना चाहते हैं तो आपको इसकी आवश्यकता होगी। –