我们有时会在单个图表上查看大量系统流程。 我用matplotlib创建了一个模型,如下所示。 由于数据点太多,因此图例与选择器互动,可以单独切换线条/艺术家的可见性以及整个组。
我遇到的问题是,在使用交互式导航缩放或平移之后,交互式图例在再次单击相同按钮之前不起作用。如果我使用缩放和平移,则图例将完全无响应并需要重新加载图表。
Python 3.6.0和Matplotlib 2.0.0
import numpy as np
import random
import operator
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
#Generate some fake data
datalength = 60
datavariance = 25
xline = np.array(range(datalength))
y1 = np.array(range(datalength))
groups = 5 #Number of groups
members = 4 #Number of members per group
grouping = {} #Nested dictionary to hold groups and member dictionaries
for g in range(groups):
groupmembers = {}
for m in range(members):
groupmembers[f'SP_{g+1}_{m+1}'] = []
grouping[f'SP_{g+1}'] = groupmembers
#Produces a nested dictionary like:
#grouping = {'PSP_1': {'PSP_1_1':[], 'PSP_1_2':[], 'PSP_1_3':[]},
# 'PSP_2': {'PSP_2_1':[], 'PSP_2_2':[], 'PSP_2_3':[]},
# 'PSP_3': {'PSP_3_1':[], 'PSP_3_2':[], 'PSP_3_3':[]}
# }
#Establish the figure and arrange the subplots
fig = plt.figure(figsize=(10,7))
ax1 = plt.subplot2grid((3,1), (0,0), rowspan=1, colspan=1, facecolor='white')
ax2 = plt.subplot2grid((3,1), (1,0), rowspan=1, colspan=1, facecolor='white')
ax3 = plt.subplot2grid((3,1), (2,0), rowspan=1, colspan=1, facecolor='white')
# Each member is plotted in each subplot and then the artist is added to the array in the nested dictionary.
for group in grouping:
for member in grouping[group]:
line1 = ax1.plot(xline, y1+np.random.randint(low=0, high=datavariance, size=datalength), lw=1, label=member, marker='.')
line2= ax2.scatter(np.random.randn(datalength)+4, y1+np.random.randint(low=0, high=datavariance, size=datalength), s=5, label=member)
line3 = ax3.hist(np.random.randn(datalength)+4, 20, histtype='step', lw=1, label=member)
#Dictionary entry of lines for member
grouping[group][member].extend((line1[0], line2, line3[2]))
#Chart labeling
ax1.set_title('Process Line', fontsize=10, bbox=dict(facecolor='white'))
ax2.set_title('Process Scatter', fontsize=10, bbox=dict(facecolor='white'))
ax3.set_title('Process Histogram', fontsize=10, bbox=dict(facecolor='white'))
fig.suptitle('System Processes', fontsize=16, bbox=dict(facecolor='white'))
leghandles, leglabels = ax1.get_legend_handles_labels() #Get handels and labels from subplot 1 for use in the legend.
grouplines = {} #Dictionary of lines by group
groupvisible = {} #Dictionary for visibility control
for group in grouping:
linearray = []
for member in grouping[group]:
for line in grouping[group][member]:
linearray.append(line)
grouplines[group] = linearray #Dictionary entry of Group:array of all lines in group
groupvisible[group] = True #Dictionary to control Group visibility
leghandles.append(Line2D([], [], label=group, marker='_', markersize=7, lw=4, color='black')) #Array entry of non-existent lines for Group legend
leglabels.append(group)
leghandles, leglabels = zip(*sorted(zip(leghandles, leglabels), key=operator.itemgetter(1))) #Sort legend by name
leghandlelist = list(leghandles) #Change tuple to list for inserting
leglabellist = list(leglabels) #Change tuple to list for inserting
for i in range(groups):
leghandlelist.insert((members+2)*i, Line2D([], [], lw=.0)) #Add fake like
leglabellist.insert((members+2)*i, ' ') #Add blank label
leghandles = tuple(leghandlelist) #Return handles to tuple
leglabels = tuple(leglabellist) #Return labels to tuple
mylegend = fig.legend(leghandles, leglabels, fancybox=True, shadow=True, loc='upper left', ncol=1, title='Process Groups')
#Associate the legend to plotted lines and set pickers on the legend item
legenditems = {}
for legendentry, plottedline in zip(mylegend.get_lines(), leghandles):
legendentry.set_picker(5)
legenditems[legendentry] = plottedline
plt.subplots_adjust(left=0.2, right=0.95, top=0.90, bottom=.05, wspace=.2, hspace=.3)
def onpick(event):
legendclick = event.artist #Legend object
legendlabel = legendclick.get_label() #Name of selected lines or group to toggle
#Check line visibility and toggle accordingly
vis = not legendclick.get_visible()
legendclick.set_visible(vis) #Toggle the clicked legend item
if legendlabel in grouplines.keys(): #If the selected legend item is a group name
for plottedline in grouplines[legendlabel]: #Toggle plotted lines for group members
try: #Toggle lines and scatter points
plottedline.set_visible(vis)
except: #Toggle histograms
for hi in range(len(plottedline)):
plottedline[hi].set_visible(vis)
for member in grouping[legendlabel]: #Toggle legend entries for group members
for entry in legenditems:
if entry.get_label() == member:
try: #Toggle lines and scatter points
entry.set_visible(vis)
except: #Toggle histograms
for hi in range(len(entry)):
print(hi)
else: #If a member item was selected
for group in grouping:
for member in grouping[group]:
if member == legendlabel: #Toggle member lines in each chart.
for i in range(len(grouping[group][member])):
try: #Toggle lines and scatter
selectedline = grouping[group][member][i]
selectedline.set_visible(vis)
except: #Toggle histogram
for hi in range(len(grouping[group][member][i])):
selectedline = grouping[group][member][i][hi]
selectedline.set_visible(vis)
fig.canvas.draw()
fig.canvas.mpl_connect('pick_event', onpick)
plt.show()