আমি ম্যাটপ্ললটিব সহ অনেক সাবপ্লটগুলির জন্য কীভাবে একটি একক কিংবদন্তি করব?


166

আমি একই ধরণের তথ্যের জন্য প্লট করছি, তবে বিভিন্ন দেশের জন্য ম্যাটপ্ল্লোব সহ একাধিক সাবপ্লট ots এটি হ'ল আমার কাছে একটি 3x3 গ্রিডে 9 টি প্লট রয়েছে, সমস্ত লাইনগুলির জন্য একই (অবশ্যই, প্রতি লাইনে বিভিন্ন মান)।

তবে, আমি একবারে চিত্রটিতে কীভাবে একটি একক কিংবদন্তি স্থাপন করতে পারি (যেহেতু সমস্ত 9 সাবপ্লটগুলির একই লাইন রয়েছে) to

আমি কেমন করে ঐটি করি?

উত্তর:


160

এখানে একটি দুর্দান্ত ফাংশন রয়েছে যা get_legend_handles_labels()আপনি শেষ অক্ষটিতে কল করতে পারেন (যদি আপনি তাদের উপরে পুনরাবৃত্তি করেন) যা আপনার label=আর্গুমেন্টগুলি থেকে প্রয়োজনীয় সবকিছু সংগ্রহ করবে :

handles, labels = ax.get_legend_handles_labels()
fig.legend(handles, labels, loc='upper center')

13
এটি শীর্ষ উত্তর হওয়া উচিত।
nnot101

1
এটি আসলে আরও অনেক দরকারী উত্তর! এটি আমার জন্য আরও জটিল ক্ষেত্রে ঠিক তেমন কাজ করেছিল।
gmaravel

1
নিখুঁত উত্তর!
দোরঘাম

4
সাব-প্লটগুলির জন্য আমি কীভাবে কিংবদন্তি সরিয়ে ফেলব?
বিএনডি

5
শুধু এই দুর্দান্ত উত্তর যুক্ত করতে। যদি আপনার প্লটগুলিতে গৌণ Y অক্ষ থাকে এবং তাদের উভয়কে মার্জ করতে হয় তবে এটি ব্যবহার করুন:handles, labels = [(a + b) for a, b in zip(ax1.get_legend_handles_labels(), ax2.get_legend_handles_labels())]
বিল

114

চিত্র আপনি যা খুঁজছেন তা হতে পারে: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.figlegnd

এখানে উদাহরণ: http://matplotlib.org/example/pylab_example/figlegnd_demo.html

আরেকটি উদাহরণ:

plt.figlegend( lines, labels, loc = 'lower center', ncol=5, labelspacing=0. )

বা:

fig.legend( lines, labels, loc = (0.5, 0), ncol=5 )

1
আমি কিংবদন্তিতে যে রেখাগুলি রাখতে চাই তা জানি, তবে আমি কীভাবে linesভেরিয়েবলটির পক্ষে যুক্তি রাখব legend?
patapouf_ai

1
@ পাতাপাউফ_ইই linesফলাফলগুলির তালিকা যা axes.plot()(যা প্রতিটি axes.plotবা অনুরূপ রুটিন একটি "লাইন" দেয়) থেকে ফিরে আসে। লিঙ্কযুক্ত উদাহরণ দেখুন।

17

figureঅনেকগুলি অক্ষ সহ একটি একক কিংবদন্তির স্বয়ংক্রিয় অবস্থানের জন্য , যেমনটি পেয়েছে subplots(), নীচের সমাধানটি সত্যিই ভালভাবে কাজ করে:

plt.legend( lines, labels, loc = 'lower center', bbox_to_anchor = (0,-0.1,1,1),
            bbox_transform = plt.gcf().transFigure )

সঙ্গে bbox_to_anchorএবং bbox_transform=plt.gcf().transFigureআপনি আপনার মাপ একটি নতুন সীমান্ত বক্স সংজ্ঞা হয় figureজন্য একটি রেফারেন্স হতে loc(0,-0.1,1,1)অন্যান্য শিল্পীদের উপর কিংবদন্তি স্থাপন করা রোধ করতে এই বাউডিং বাক্সটি কিছুটা নিচের দিকে সরানো ব্যবহার করে।

ওবিএস: আপনি ব্যবহারের fig.set_size_inches()আগে এবং ব্যবহারের আগে এই সমাধানটি ব্যবহার করুনfig.tight_layout()


1
বা সরল loc='upper center', bbox_to_anchor=(0.5, 0), bbox_transform=plt.gcf().transFigureএবং এটি নিশ্চিতভাবে ওভারল্যাপ হবে না।
জোসিপোভিচ

2
আমি এখনও নিশ্চিত না কেন, তবে এভার্টের সমাধানটি আমার পক্ষে কার্যকর হয়নি - কিংবদন্তিটি বিচ্ছিন্ন হয়ে পড়েছে। এই সমাধানটি (ডিভারের মন্তব্যের পাশাপাশি) খুব পরিষ্কারভাবে কাজ করেছে - কিংবদন্তিটি প্রত্যাশিত এবং সম্পূর্ণ দৃশ্যমান হিসাবে স্থাপন করা হয়েছিল। ধন্যবাদ!
sudo

16

আপনার লুপের বাইরে আপনাকে একবার কিংবদন্তিটি জিজ্ঞাসা করতে হবে।

উদাহরণস্বরূপ, এক্ষেত্রে আমার কাছে একই লাইনগুলির সাথে 4 টি সাবপ্লট এবং একক কিংবদন্তি রয়েছে।

from matplotlib.pyplot import *

ficheiros = ['120318.nc', '120319.nc', '120320.nc', '120321.nc']

fig = figure()
fig.suptitle('concentration profile analysis')

for a in range(len(ficheiros)):
    # dados is here defined
    level = dados.variables['level'][:]

    ax = fig.add_subplot(2,2,a+1)
    xticks(range(8), ['0h','3h','6h','9h','12h','15h','18h','21h']) 
    ax.set_xlabel('time (hours)')
    ax.set_ylabel('CONC ($\mu g. m^{-3}$)')

    for index in range(len(level)):
        conc = dados.variables['CONC'][4:12,index] * 1e9
        ax.plot(conc,label=str(level[index])+'m')

    dados.close()

ax.legend(bbox_to_anchor=(1.05, 0), loc='lower left', borderaxespad=0.)
         # it will place the legend on the outer right-hand side of the last axes

show()

3
figlegend, যেমন এভার্ট দ্বারা উত্সাহিত, এটি আরও ভাল সমাধান বলে মনে হচ্ছে;)
কারলা

11
সমস্যাটি fig.legend()হ'ল এটির জন্য সমস্ত লাইন (প্লট) সনাক্তকরণ প্রয়োজন ... প্রতিটি সাবপ্লট হিসাবে আমি লাইনগুলি তৈরি করতে একটি লুপ ব্যবহার করছি, এটি কাটিয়ে ওঠার একমাত্র সমাধানটি হ'ল আগে একটি খালি তালিকা তৈরি করা is দ্বিতীয় লুপ, এবং তারপরে লাইনগুলি তৈরি করার সাথে যুক্ত করুন ... তারপরে আমি এই তালিকাটি fig.legend()ফাংশনের আর্গুমেন্ট হিসাবে ব্যবহার করব ।
কারলা


dadosসেখানে কি আছে?
শ্যামকখাদকা

1
@ শ্যামামখাদকা, আমার মূল স্ক্রিপ্টে নেটডিসিডিএফ dados4 ফাইলের একটি তালিকা (তালিকায় সংজ্ঞায়িত প্রতিটি ফাইলের জন্য ficheiros) ছিল ase প্রতিটি লুপে, পৃথক ফাইলটি পড়ে এবং চিত্রে একটি সাবপ্লট যুক্ত করা হয়।
কারলা

14

আমি লক্ষ করেছি যে কোনও উত্তর কোনও সাব-প্লটগুলিতে অনেকগুলি বক্ররেখার উল্লেখ করে একটি একক কিংবদন্তি সহ কোনও চিত্র প্রদর্শন করে না, তাই আপনাকে কৌতূহলী করতে আমি আপনাকে একটি দেখাতে হবে ...

এখানে চিত্র বর্ণনা লিখুন

এখন, আপনি কোডটি দেখতে চান , তাই না?

from numpy import linspace
import matplotlib.pyplot as plt

# Calling the axes.prop_cycle returns an itertoools.cycle

color_cycle = plt.rcParams['axes.prop_cycle']()

# I need some curves to plot

x = linspace(0, 1, 51)
f1 = x*(1-x)   ; lab1 = 'x - x x'
f2 = 0.25-f1   ; lab2 = '1/4 - x + x x' 
f3 = x*x*(1-x) ; lab3 = 'x x - x x x'
f4 = 0.25-f3   ; lab4 = '1/4 - x x + x x x'

# let's plot our curves (note the use of color cycle, otherwise the curves colors in
# the two subplots will be repeated and a single legend becomes difficult to read)
fig, (a13, a24) = plt.subplots(2)

a13.plot(x, f1, label=lab1, **next(color_cycle))
a13.plot(x, f3, label=lab3, **next(color_cycle))
a24.plot(x, f2, label=lab2, **next(color_cycle))
a24.plot(x, f4, label=lab4, **next(color_cycle))

# so far so good, now the trick

lines_labels = [ax.get_legend_handles_labels() for ax in fig.axes]
lines, labels = [sum(lol, []) for lol in zip(*lines_labels)]

# finally we invoke the legend (that you probably would like to customize...)

fig.legend(lines, labels)
plt.show()

দুটি লাইন

lines_labels = [ax.get_legend_handles_labels() for ax in fig.axes]
lines, labels = [sum(lol, []) for lol in zip(*lines_labels)]

একটি ব্যাখ্যা প্রাপ্য - এই লক্ষ্যে আমি একটি কার্যক্রমে জটিল অংশটি encapsulate করেছি, কোডের মাত্র 4 লাইন তবে ভারী মন্তব্য করেছি

def fig_legend(fig, **kwdargs):

    # generate a sequence of tuples, each contains
    #  - a list of handles (lohand) and
    #  - a list of labels (lolbl)
    tuples_lohand_lolbl = (ax.get_legend_handles_labels() for ax in fig.axes)
    # e.g. a figure with two axes, ax0 with two curves, ax1 with one curve
    # yields:   ([ax0h0, ax0h1], [ax0l0, ax0l1]) and ([ax1h0], [ax1l0])

    # legend needs a list of handles and a list of labels, 
    # so our first step is to transpose our data,
    # generating two tuples of lists of homogeneous stuff(tolohs), i.e
    # we yield ([ax0h0, ax0h1], [ax1h0]) and ([ax0l0, ax0l1], [ax1l0])
    tolohs = zip(*tuples_lohand_lolbl)

    # finally we need to concatenate the individual lists in the two
    # lists of lists: [ax0h0, ax0h1, ax1h0] and [ax0l0, ax0l1, ax1l0]
    # a possible solution is to sum the sublists - we use unpacking
    handles, labels = (sum(list_of_lists, []) for list_of_lists in tolohs)

    # call fig.legend with the keyword arguments, return the legend object

    return fig.legend(handles, labels, **kwdargs)

পিএস আমি সনাক্ত করেছিলাম যে sum(list_of_lists, [])তালিকার তালিকাকে সমতল করার জন্য এটি একটি অত্যন্ত অযোগ্য পদ্ধতি তবে ① আমি এর সংক্ষিপ্ততা পছন্দ করি ② সাধারণত কয়েকটি সাবপ্লট এবং ③ ম্যাটপ্ল্লোব এবং দক্ষতা কয়েক ধরণের বাঁক হয়? ;-)


3

গেমটি না খেয়ে দেরীতে থাকাকালীন আমি এখানে আরও একটি সমাধান দেব কারণ এটি গুগলে প্রদর্শিত প্রথম লিঙ্কগুলির মধ্যে একটি। ম্যাটপ্ল্লোব ২.২.২ ব্যবহার করে গ্রিডস্পেক বৈশিষ্ট্যটি ব্যবহার করে এটি অর্জন করা যায়। নীচের উদাহরণে লক্ষ্যটি হল নীচের অংশে দেখানো কিংবদন্তি সহ 2x2 ফ্যাশনে চারটি সাবপ্লট সাজানো। একটি নির্দিষ্ট স্থানে কিংবদন্তি স্থাপন করতে নীচে একটি 'ফ্যাক্স' অক্ষ তৈরি করা হয়। 'ভুল' অক্ষগুলি তখন কেবলমাত্র কিংবদন্তি শোগুলিতে বন্ধ থাকে। ফলাফল: https://i.stack.imgur.com/5LUWM.png

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

#Gridspec demo
fig = plt.figure()
fig.set_size_inches(8,9)
fig.set_dpi(100)

rows   = 17 #the larger the number here, the smaller the spacing around the legend
start1 = 0
end1   = int((rows-1)/2)
start2 = end1
end2   = int(rows-1)

gspec = gridspec.GridSpec(ncols=4, nrows=rows)

axes = []
axes.append(fig.add_subplot(gspec[start1:end1,0:2]))
axes.append(fig.add_subplot(gspec[start2:end2,0:2]))
axes.append(fig.add_subplot(gspec[start1:end1,2:4]))
axes.append(fig.add_subplot(gspec[start2:end2,2:4]))
axes.append(fig.add_subplot(gspec[end2,0:4]))

line, = axes[0].plot([0,1],[0,1],'b')           #add some data
axes[-1].legend((line,),('Test',),loc='center') #create legend on bottommost axis
axes[-1].set_axis_off()                         #don't show bottommost axis

fig.tight_layout()
plt.show()

3

যদি আপনি বারের চার্ট সহ প্রতিটি বারের জন্য আলাদা রঙের সাবপ্লট ব্যবহার করছেন। নিজেকে ব্যবহার করে নিদর্শনগুলি তৈরি করা আরও দ্রুত হতে পারেmpatches

r m c kনীচের মতো কিংবদন্তিটি সেট করতে পারেন বলে বিভিন্ন রঙের সাথে আপনার চারটি বার রয়েছে Say

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
labels = ['Red Bar', 'Magenta Bar', 'Cyan Bar', 'Black Bar']


#####################################
# insert code for the subplots here #
#####################################


# now, create an artist for each color
red_patch = mpatches.Patch(facecolor='r', edgecolor='#000000') #this will create a red bar with black borders, you can leave out edgecolor if you do not want the borders
black_patch = mpatches.Patch(facecolor='k', edgecolor='#000000')
magenta_patch = mpatches.Patch(facecolor='m', edgecolor='#000000')
cyan_patch = mpatches.Patch(facecolor='c', edgecolor='#000000')
fig.legend(handles = [red_patch, magenta_patch, cyan_patch, black_patch],labels=labels,
       loc="center right", 
       borderaxespad=0.1)
plt.subplots_adjust(right=0.85) #adjust the subplot to the right for the legend

1
+1 সেরা! আমি এইভাবে এটি plt.legendআমার সমস্ত সাবপ্লটগুলির জন্য একটি কিংবদন্তি যুক্ত করতে সরাসরি যুক্ত করেছি
ব্যবহারকারী

স্বয়ংক্রিয় হ্যান্ডলগুলি এবং হস্তনির্মিত লেবেলগুলিকে একত্রিত করার জন্য এটি দ্রুততর: handles, _ = plt.gca().get_legend_handles_labels()তারপরেfig.legend(handles, labels)
এসএমসিএস

1

এই উত্তরটি কিংবদন্তির অবস্থানে @ ইভার্টের পরিপূরক।

কিংবদন্তি ও সাবপ্লট এর শিরোনামের ওভারল্যাপের কারণে @ এভার্টের সমাধানটিতে আমার প্রথম চেষ্টা ব্যর্থ হয়েছে।

প্রকৃতপক্ষে, ওভারল্যাপগুলির কারণে ঘটে fig.tight_layout()যা চিত্রের কিংবদন্তি বিবেচনা না করে সাবপ্লটসের বিন্যাসকে পরিবর্তন করে। তবে, fig.tight_layout()প্রয়োজনীয়।

ওভারল্যাপগুলি এড়ানোর জন্য, আমরা fig.tight_layout()চিত্রটির কিংবদন্তির জন্য ফাঁকা স্থান ছেড়ে যেতে বলতে পারি fig.tight_layout(rect=(0,0,1,0.9))

টাইট_লেআউট () পরামিতিগুলির বিবরণ


1

@ Gboffi's এবং বেন উসমানের উত্তরের উপরে তৈরি করতে:

একই রঙে এবং লেবেল সহ বিভিন্ন সাবপ্লটগুলিতে একের আলাদা আলাদা লাইন থাকে এমন পরিস্থিতিতে, কেউ এর লাইনের সাথে কিছু করতে পারে

labels_handles = {
  label: handle for ax in fig.axes for handle, label in zip(*ax.get_legend_handles_labels())
}

fig.legend(
  labels_handles.values(),
  labels_handles.keys(),
  loc="upper center",
  bbox_to_anchor=(0.5, 0),
  bbox_transform=plt.gcf().transFigure,
)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.