Jika saya memiliki rutinitas plot berikut yang memplot plot pencar dan regresi linier yang sesuai dan menggabungkan pegangan legenda:

import pandas as pd
from scipy.stats import linregress
import numpy as np
import matplotlib.pyplot as plt

#data and Regression
x = np.arange(0,5,1)
y = np.arange(0,10,2)
df = pd.DataFrame(data = {'x':x,'y':y})
s, intcpt, r, p, serr = linregress(df.x, df.y)
xHat = np.linspace(0,5,100)


# do the plotting
fig,ax = plt.subplots()
df.plot(x='x',y='y',ax=ax,label='series1',ls=' ',marker='x',c='blue')
ls_handle, = ax.plot(xHat, s*xHat + intcpt, linestyle='-', marker=None, c='blue')
handle2merge = [ls_handle]
handles, labels = ax.get_legend_handles_labels()
handle_combined = zip(handles, handle2merge)
ax.legend(handle_combined, labels)

Yang mengembalikan tempat penanda dan pegangan garis digabungkan terlihat seperti:

enter image description here

Sekarang saya ingin memplot dataset lain dengan cara yang sama:

#get current axis handles and labels
handle_start, label_start = ax.get_legend_handles_labels()

#second dataset and regression
x1 = np.arange(0,5,1)
y1 = np.arange(0,2.5,0.5)
df1 = pd.DataFrame(data = {'x':x1,'y':y1})
s1, intcpt1, r1, p1, serr1 = linregress(df1.x, df1.y)
xHat1 = np.linspace(0,5,100)

#plot second data set on same figure
marker_handle2, = ax.plot(df1.x, df1.y, marker = 'x', zorder=10,c='k', linestyle=' ')
line_handle2, = ax.plot(xHat, s1*xHat1 + intcpt1, linestyle='--', marker=None, c='k') 
new_line_handles = [line_handle2]
new_marker_handles= [marker_handle2]

ax.legend(handle_start + zip(new_marker_handles,new_line_handles), label_start + ['series2'])

Ini mengembalikan plot di mana pegangan untuk pegangan legenda series1 hanya berisi penanda.

enter image description here

Mengapa len(handle_start)=1 ketika saya membuat pegangan dengan handle_combined = zip(handles, handle2merge)?

2
dubbbdan 28 Mei 2019, 01:38

2 jawaban

Jawaban Terbaik

Saya telah melihat-lihat kodenya sedikit. Apa yang Anda lakukan adalah meneruskan list dari tuples ke ax.legend, yang tampaknya menarik setiap Artis di setiap tuple sebagai satu entri dalam legenda. Saya sebenarnya belum pernah menemukan perilaku ini sebelumnya; itu bisa berupa bug, atau penggunaan ax.legend yang tidak disengaja.

Namun demikian, saya pikir dalam kasus ini, karena Anda tahu seperti apa garis Anda sebelumnya, alih-alih berputar-putar dengan zip dan sebagainya, Anda bisa meneruskan Line2D khusus ke legend secara langsung:

import numpy as np

from scipy.stats import linregress

from matplotlib import pyplot as plt
from matplotlib import lines

x1 = np.arange(0, 5, 1)
y1 = np.arange(0, 10, 2)
x2 = np.arange(0, 5, 1)
y2 = np.arange(0, 2.5, 0.5)

m1, c1, r1, p1, serr1 = linregress(x1, y1)
m2, c2, r2, p2, serr2 = linregress(x2, y2)

x_pred = np.linspace(0,5,100)

fig, ax = plt.subplots()

first_line, = ax.plot(x_pred, x_pred * m1 + c1, ls='-', c='blue')
first_scatter = ax.scatter(x1, y1, marker='x', c='blue')

second_line, = ax.plot(x_pred, x_pred * m2 + c2, ls='--', c='black')
second_scatter = ax.scatter(x2, y2, marker='x', c='black')

ax.legend([lines.Line2D([0], [0], marker='x', ls='-', c='blue'),
           lines.Line2D([0], [0], marker='x', ls='--', c='black')],
          ['series_1', 'series_2'])

enter image description here

Saya membersihkan kode Anda sedikit, tetapi jangan ragu untuk mengambil hanya baris terakhir dan impor yang diperlukan.

3
gmds 27 Mei 2019, 22:59

Di baris terakhir, cukup gunakan pegangan gabungan yang sudah dibuat handle_combined alih-alih handle_start.

ax.legend(handle_combined + list(zip(new_marker_handles,new_line_handles)), 
          label_start + ['series2'])

Panjangnya adalah 1 tetapi jika Anda melihat isi daftar, itu adalah tupel yang terdiri dari dua objek. Jika Anda mencetak handle_combined, Anda mendapatkan daftar dua objek Line2D, salah satunya adalah penanda dan yang lainnya adalah garis.

print (handle_combined)
# [(<matplotlib.lines.Line2D object at xxxxxxxxx>, <matplotlib.lines.Line2D object at xxxxxxxxx>)]

Namun, jika Anda mencetak handle_start, ia hanya mengembalikan satu objek Line2D

print (handle_start)
# [<matplotlib.lines.Line2D object at xxxxxxxxx>]

enter image description here

0
Sheldore 27 Mei 2019, 22:52