কোনও ম্যাটপ্ল্লিটিব প্লটে কীভাবে লাইনগুলি সরিয়ে ফেলা যায়


85

এটি কীভাবে কোনও ম্যাটপ্ল্লোলিব অক্ষের একটি লাইন (বা লাইন) মুছে ফেলতে পারে কারণ এটি আবর্জনা সংগ্রহ করে মেমরিটি ফিরে পায়? নীচের কোডটি লাইনটি মুছতে পারে বলে মনে হচ্ছে, তবে কখনই মেমরি প্রকাশ করে না (এমনকি স্পষ্ট কল দিয়েও gc.collect())

from matplotlib import pyplot
import numpy
a = numpy.arange(int(1e7))
# large so you can easily see the memory footprint on the system monitor.
fig = pyplot.Figure()
ax  = pyplot.add_subplot(1, 1, 1)
lines = ax.plot(a) # this uses up an additional 230 Mb of memory.
# can I get the memory back?
l = lines[0]
l.remove()
del l
del lines
# not releasing memory
ax.cla() # this does release the memory, but also wipes out all other lines.

সুতরাং একটি অক্ষ থেকে কেবল একটি লাইন মুছে ফেলা এবং স্মৃতি ফিরে পাওয়ার কোনও উপায় আছে? এই সম্ভাব্য সমাধানটিও কাজ করে না।

উত্তর:


71

আমি সেই কৌশলটি মিশ্রিত করছি lines.pop(0) l.remove()এবং del lদেখছি।

from matplotlib import pyplot
import numpy, weakref
a = numpy.arange(int(1e3))
fig = pyplot.Figure()
ax  = fig.add_subplot(1, 1, 1)
lines = ax.plot(a)

l = lines.pop(0)
wl = weakref.ref(l)  # create a weak reference to see if references still exist
#                      to this object
print wl  # not dead
l.remove()
print wl  # not dead
del l
print wl  # dead  (remove either of the steps above and this is still live)

আমি আপনার বড় ডেটাসেটটি পরীক্ষা করেছি এবং মেমরির প্রকাশের বিষয়টি সিস্টেম মনিটরেও নিশ্চিত হয়ে গেছে।

অবশ্যই সহজ উপায় (যখন ঝামেলা-শ্যুটিংয়ের সময় নয়) হ'ল এটি তালিকা থেকে পপ করা এবং removeকোনও কঠোর রেফারেন্স তৈরি না করেই লাইন অবজেক্টে কল করা:

lines.pop(0).remove()

আমি আপনার কোডটি চালিয়েছি এবং পেয়েছি: [8:37 অপরাহ্ন] @ ফ্ল্যাটপ: ~ / ডেস্কটপ / স্যান্ডবক্স> পাইথন ডিলিট_লাইন.পি <0x8dd348c এ দুর্বল; 0x8dd43ec এ 'লাইন 2 ডি' তে << 0x8dd348c এ দুর্বল; 0x8dd43ec এ 'লাইন 2 ডি' তে << 0x8dd348c এ দুর্বল; 0x8dd43ec এ 'লাইন 2 ডি' তে> আমি উবুন্টু 10.04-তে ম্যাটপ্ল্লোলিব সংস্করণ 0.99.1.1 ব্যবহার করছি
ডেভিড মর্টন

4
@ ডেভিড মর্টন আমি মাত্র 0.99.1 এ ডাউনগ্রেড করেছি এবং এখন আমি আপনার সমস্যার পুনরুত্পাদন করছি। আমার ধারণা আমি কেবলমাত্র ১.০.১ এ আপগ্রেড করার প্রস্তাব দিতে পারি। 0.99.x থেকে প্রচুর বাগফিক্স ছিল
পল

4
এখানে ইস্যুটি সম্ভবত রেফারেন্সগুলির একটি সমস্যা যখন এটি হওয়া উচিত নয় around আমি বাজি ধরব যে ওপ আইপিথন ব্যবহার করে জিনিসগুলি পরীক্ষা করে দেখছিল। আমার উত্তর দেখুন।
ভোরিটিসিটি

67

এটি একটি দীর্ঘ দীর্ঘ ব্যাখ্যা যা আমি আমার সহকর্মীর জন্য টাইপ করেছি। আমি মনে করি এটি এখানেও সহায়ক হবে। ধৈর্য ধরুন, যদিও। আপনি শেষের দিকে আসছেন এমন আসল সমস্যাটি আমি পেয়েছি। একটি টিজার হিসাবে, এটি আপনার Line2Dবস্তুর চারদিকে ঝুলন্ত অতিরিক্ত রেফারেন্স থাকার বিষয় ।

সতর্কতা: আমরা ডুব দেওয়ার আগে অন্য একটি নোট you আপনি যদি এটি পরীক্ষা করার জন্য আইপিথন ব্যবহার করে থাকেন তবে আইপিথন তার নিজস্ব রেফারেন্স রাখে এবং সেগুলি সমস্ত দুর্বল নয়। সুতরাং, আইপিথনে আবর্জনা সংগ্রহের পরীক্ষা করা কার্যকর হয় না। এটি কেবল বিষয়গুলিকে বিভ্রান্ত করে।

ঠিক আছে, আমরা এখানে যাই। প্রতিটি matplotlibবস্তু ( Figure, Axesইত্যাদি) বিভিন্ন গুণাবলীর মাধ্যমে তার শিশু শিল্পীদের অ্যাক্সেস সরবরাহ করে। নিম্নলিখিত উদাহরণটি বেশ দীর্ঘ হচ্ছে, তবে আলোকিত হওয়া উচিত।

আমরা একটি Figureঅবজেক্ট তৈরি করে শুরু করি , তারপরে Axesসেই চিত্রটিতে একটি বস্তু যুক্ত করি। নোট করুন axএবং fig.axes[0]একই জিনিস (একই id())।

>>> #Create a figure
>>> fig = plt.figure()
>>> fig.axes
[]

>>> #Add an axes object
>>> ax = fig.add_subplot(1,1,1)

>>> #The object in ax is the same as the object in fig.axes[0], which is 
>>> #   a list of axes objects attached to fig 
>>> print ax
Axes(0.125,0.1;0.775x0.8)
>>> print fig.axes[0]
Axes(0.125,0.1;0.775x0.8)  #Same as "print ax"
>>> id(ax), id(fig.axes[0])
(212603664, 212603664) #Same ids => same objects

এটি অক্ষ অক্ষের লাইনেও প্রসারিত:

>>> #Add a line to ax
>>> lines = ax.plot(np.arange(1000))

>>> #Lines and ax.lines contain the same line2D instances 
>>> print lines
[<matplotlib.lines.Line2D object at 0xce84bd0>]
>>> print ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>]

>>> print lines[0]
Line2D(_line0)
>>> print ax.lines[0]
Line2D(_line0)

>>> #Same ID => same object
>>> id(lines[0]), id(ax.lines[0])
(216550352, 216550352)

আপনি যদি plt.show()উপরের কাজটি করে কল করে থাকেন, আপনি অক্ষ এবং একটি একক লাইন সমেত একটি চিত্র দেখতে পাবেন:

অক্ষ এবং একটি একক লাইন সমেত একটি চিত্র

এখন, আমরা যখন দেখেছি যে বিষয়বস্তু linesএবং সামগ্রিক উপাদানগুলি ax.linesএকই, তবে linesভেরিয়েবল দ্বারা রেফারেন্স করা বস্তুটি ax.linesনীচের দ্বারা দেখা যায় এমন বস্তুর সাথে একইরকম নয় যা লক্ষ্য করা যায়:

>>> id(lines), id(ax.lines)
(212754584, 211335288)

ফলস্বরূপ, কোনও উপাদান থেকে সরানো linesবর্তমান প্লটের কিছুই করে না, তবে উপাদানটিকে ax.linesসরিয়ে দিয়ে বর্তমান প্লট থেকে সেই লাইনটি সরিয়ে ফেলা হয়। সুতরাং:

>>> #THIS DOES NOTHING:
>>> lines.pop(0)

>>> #THIS REMOVES THE FIRST LINE:
>>> ax.lines.pop(0)

সুতরাং, আপনি যদি কোডের দ্বিতীয় লাইনটি চালনা করেন তবে আপনি বর্তমান প্লট থেকে Line2Dঅন্তর্ভুক্ত থাকা অবজেক্টটি সরিয়ে ax.lines[0]ফেলবেন এবং এটি চলে যাবে। দ্রষ্টব্য যে এটি ax.lines.remove()অর্থের মাধ্যমেও করা যেতে পারে যে আপনি Line2Dকোনও ভেরিয়েবেলে একটি উদাহরণ সংরক্ষণ করতে পারেন , তারপরে ax.lines.remove()সেই লাইনটি মুছতে এটি পাস করুন :

>>> #Create a new line
>>> lines.append(ax.plot(np.arange(1000)/2.0))
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>,  <matplotlib.lines.Line2D object at 0xce84dx3>]

অক্ষ এবং দুটি লাইনের সমষ্টিযুক্ত একটি চিত্র figure

>>> #Remove that new line
>>> ax.lines.remove(lines[0])
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84dx3>]

অক্ষের একটি সেট এবং কেবল দ্বিতীয় লাইনের সমন্বিত একটি চিত্র

উপরের সমস্তটি fig.axesযেমন কাজ করে তেমনি এটির জন্যও কাজ করেax.lines

এখন, এখানে আসল সমস্যা। যদি আমরা ax.lines[0]কোনও weakref.refবস্তুর মধ্যে থাকা রেফারেন্সটি সংরক্ষণ করি , তবে এটি মুছে ফেলার চেষ্টা করুন, আমরা লক্ষ্য করব যে এটি আবর্জনা সংগ্রহ করে না:

>>> #Create weak reference to Line2D object
>>> from weakref import ref
>>> wr = ref(ax.lines[0])
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>

>>> #Delete the line from the axes
>>> ax.lines.remove(wr())
>>> ax.lines
[]

>>> #Test weakref again
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>

রেফারেন্স এখনও লাইভ! কেন? এটি কারণ কারণ Line2Dঅবজেক্টের আরও একটি রেফারেন্স রয়েছে যা রেফারেন্সটি wrনির্দেশ করে। মনে রাখবেন কীভাবে linesএকই আইডি ছিল না ax.linesতবে একই উপাদানগুলি রয়েছে? ঠিক আছে, সমস্যা।

>>> #Print out lines
>>> print lines
[<matplotlib.lines.Line2D object at 0xce84bd0>,  <matplotlib.lines.Line2D object at 0xce84dx3>]

To fix this problem, we simply need to delete `lines`, empty it, or let it go out of scope.

>>> #Reinitialize lines to empty list
>>> lines = []
>>> print lines
[]
>>> print wr
<weakref at 0xb758af8; dead>

সুতরাং, গল্পটির নৈতিকতা হল, নিজের পরে পরিষ্কার করুন। আপনি যদি কোনও জিনিস আবর্জনা সংগ্রহের প্রত্যাশা করেন তবে তা না হয় তবে আপনি সম্ভবত কোনও রেফারেন্স কোথাও রেখে যাচ্ছেন।


4
ঠিক আমার যা প্রয়োজন ছিল। আমি হাজার হাজার মানচিত্রের চক্রান্ত করছি, প্রতিটি একটি বিশ্ব মানচিত্রের অভিক্ষেপের শীর্ষে ছড়িয়ে ছিটিয়ে প্লট রয়েছে। তারা প্রতি 3 সেকেন্ড সময় নিচ্ছিল! ইতিমধ্যে অঙ্কিত মানচিত্রের সাথে চিত্রটি পুনরায় ব্যবহার করে এবং অক্ষর সংগ্রহগুলি থেকে ফলাফল সংগ্রহের পপিংয়ের মাধ্যমে আমি এটিকে এক সেকেন্ডের ১/৩ এ নামিয়েছি। ধন্যবাদ!
গ্যারিবিশপ

4
আমি মনে করি এমপিএলের বর্তমান সংস্করণগুলিতে এটি আর দরকার নেই। শিল্পীর একটি remove()ফাংশন থাকে যা তাদের এমপিএল দিক থেকে পরিষ্কার করে দেয় এবং তারপরে আপনাকে কেবল আপনার রেফারেন্সগুলিই ট্র্যাক রাখা প্রয়োজন।
টাকাসওয়েল

4
হু, কোন ধারণা ম্যাটপ্ল্লোব এর কোন সংস্করণে এই পরিবর্তনটি একই রকম হতে পারে?
Vorticity

ম্যাটপ্ল্লোলিব অ্যানিমেশনটিতে একগুচ্ছ প্লট ব্যবহার করার সময় এটি দরকারী বলে মনে হয়েছিল। অন্যথায়, আপনি ব্যবহারে প্রচুর পরিমাণে মেমরি নিয়ে এসেছেন। এখন এই জিনিসটি আরও দ্রুত করা।
ড্যানি স্ট্যাপল

14

আমি বিভিন্ন ফোরামে প্রচুর বিভিন্ন উত্তর চেষ্টা করেছি। আমার ধারণা এটি আপনার বিকাশকারী মেশিনের উপর নির্ভর করে। তবে আমি বিবৃতি ব্যবহার করেছি

ax.lines = []

এবং পুরোপুরি কাজ করে। আমি cla()প্লটের সাথে আমার তৈরি সমস্ত সংজ্ঞা মুছে ফেলার কারণটি ব্যবহার করি না

প্রাক্তন

pylab.setp(_self.ax.get_yticklabels(), fontsize=8)

তবে আমি অনেকবার লাইনগুলি মুছে ফেলার চেষ্টা করেছি। আমি মুছে ফেলার সময় সেই লাইনের রেফারেন্সটি পরীক্ষা করতে দুর্বল পাঠাগারটি ব্যবহার করেছিলাম তবে আমার পক্ষে কিছুই কার্যকর হয়নি।

আশা করি এটি অন্য কারও জন্য কাজ করে = D


এখানে ইস্যুটি সম্ভবত রেফারেন্সগুলির একটি সমস্যা যখন এটি হওয়া উচিত নয় around আমি বাজি ধরব যে ওপ আইপিথন ব্যবহার করে জিনিসগুলি পরীক্ষা করে দেখছিল। আমার উত্তর দেখুন।
ভোরিটিসিটি

5

(উপরের লোকটির মতো একই উদাহরণ ব্যবহার করে)

from matplotlib import pyplot
import numpy
a = numpy.arange(int(1e3))
fig = pyplot.Figure()
ax  = fig.add_subplot(1, 1, 1)
lines = ax.plot(a)

for i, line in enumerate(ax.lines):
    ax.lines.pop(i)
    line.remove()

1

আশা করি এটি অন্যকে সহায়তা করতে পারে: উপরের উদাহরণগুলি ব্যবহার করুন ax.lines। আরও সাম্প্রতিক এমপিএল (3.3.1) এর সাথে রয়েছে ax.get_lines()। এটি কল করার প্রয়োজনকে বাইপাস করেax.lines=[]

for line in ax.get_lines(): # ax.lines:
    line.remove()
# ax.lines=[] # needed to complete removal when using ax.lines
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.