def draw_points_and_poly_interval(key_name, X, y, reg_func_interval, degree, count): """Draws both the points and interval poly. regression on one picture""" import matplotlib.pyplot as plt X_quad = t_l.generate_polynomials(X, degree) interval_values = [ *map(lambda a: a[1], reg_func_interval.interval_values_quad_) ] plt.figure(figsize=(16, 9)) plt.title(key_name[:-1 - key_name[::-1].find('.')] + '\'s Interval Regression') plt.xlabel('time') plt.ylabel(key_name) plt.grid(True) plt.scatter(X, y, color='red', label='Sample Point', linewidths=1) y_func = reg_func_interval.predict(X_quad) picture_y_min = np.amin(y_func) picture_y_max = np.amax(y_func) plt.plot(X, y_func, color='orange', label='degree ' + str(degree), linewidth=3) for x_interval in interval_values: plt.plot([x_interval, x_interval], [picture_y_min, picture_y_max], color='k', linewidth=1.5, linestyle="--") plt.legend(loc='upper left') # plt.savefig('points_poly_' + str(count) + '.png', dpi=200) plt.show()
def draw_two_value_pairs_commX(key_name_1, key_name_2, X_1, X_2, y_1, y_2, reg_func_interval_1, reg_func_interval_2, degree, count): """Combines and draws value pairs Args: key_name_1: name of the first value key_name_2: name of the second value X_1: X of the first value X_2: X of the second value y_1: y of the first value y_2: y of the second value reg_func_interval_1: functions list of the first value reg_func_interval_2: functions list of the second value degree: degree of the function now count: the order of data pairs used for exportation Returns: No return """ comm_left = X_1[0] if X_1[0] > X_2[0] else X_2[0] comm_right = X_1[-1] if X_1[-1] < X_2[-1] else X_2[-1] comm_X = np.linspace(comm_left, comm_right, 1000) comm_X = comm_X.reshape(comm_X.shape[0], 1) comm_X_quad = t_l.generate_polynomials(comm_X, degree) y_1_func = reg_func_interval_1.predict(comm_X_quad) y_2_func = reg_func_interval_2.predict(comm_X_quad) # Displays pearson y_1_2_pearson_c_s = t_l.pearson_correlation_similarity(y_1_func, y_2_func) print(key_name_1, key_name_2) print('Pearson: ', y_1_2_pearson_c_s) print() import matplotlib.pyplot as plt plt.figure(figsize=(16, 9)) cm = plt.cm.get_cmap('rainbow') z_color = np.arange(len(y_1_func)) plt.title(key_name_1 + ' && ' + key_name_2) plt.xlabel(key_name_1) plt.ylabel(key_name_2) plt.grid(True) sc = plt.scatter(y_1_func, y_2_func, c=z_color, s=100, cmap=cm, label='Sample Points', alpha=.6) plt.legend() plt.colorbar(sc) # plt.savefig('Depth&Distance combinations_' + str(count) + '.png', dpi=200) plt.show()
def draw_points_and_poly(key_name, X, y, reg_func, degree, count): """Draws both the data points and polynomial regression""" import matplotlib.pyplot as plt X_quad = t_l.generate_polynomials(X, degree) plt.figure(figsize=(16, 9)) plt.xlabel('time') plt.ylabel(key_name) plt.grid(True) plt.scatter(X, y, color='red', label='Sample Point', linewidths=1) plt.plot(X, reg_func.predict(X_quad), color='orange', label='degree ' + str(degree), linewidth=3) plt.legend(loc='upper left') # plt.savefig('points_poly_data_1_ridge_' + str(count) + '.png', dpi=200) plt.show()
def make_polynomial_fitting_tv(tv_list, key_name, t_comps_ratio, degree=DEGREE_NOW, type='linear'): """Calculates the functions of polynomial regression Args: tv_list: lists of data values key_name: the name of data value for polynomial regression t_comps_ratio: the ratio of compression for timestamp degree: the degree of polynomial regression type: regression type ('linear' or 'ridge') Returns: A tuple of three elements: First element is a consequence of X Second element is polynomials generated according to the degree Third element is a consequence of y Fourth element is the function of regression """ pd.set_option('precision', VALUE_PRECISION) df_tv = pd.DataFrame(tv_list, columns=['time', key_name]) df_tv.sort_values(by='time') X_col_list = list(df_tv['time']) y_col_list = list(df_tv[key_name]) # Compress the value of timestamp X_delta_sp = X_col_list[0] / (10**t_comps_ratio) X_col_list_cms = [ *map(lambda a: a / (10**t_comps_ratio) - X_delta_sp, X_col_list) ] X = np.array(X_col_list_cms).reshape(len(X_col_list_cms), 1) y = np.array(y_col_list).reshape(len(y_col_list), 1) X_quad = t_l.generate_polynomials(X, degree) if type == 'linear': lin_reg = LinearRegression() lin_reg.fit(X_quad, y) return (X, X_quad, y, lin_reg) elif type == 'ridge': clf = linear_model.Ridge(alpha=0.0001) clf.fit(X_quad, y) return (X, X_quad, y, clf)
def make_plf_cols(tv_list, key_name, t_comps_ratio, degree, GaussFiltered=True, GF_s=GAUSS_FILTER_PRECISION): """Conducts timestamp compression and GaussFilter on values Args: tv_list: data values key_name: name of this data t_comps_ratio: the compression ratio on timestamp degree: degree of polynomial GaussFiltered: if it is GaussFiltered GF_s: the precision of GaussFilter Returns: A tuple of three elements: First element is a consequence of X Second element is polynomials generated according to the degree Third element is a consequence of y """ pd.set_option('precision', VALUE_PRECISION) df_tv = pd.DataFrame(tv_list, columns=['time', key_name]) df_tv.sort_values(by='time') X_col_list = list(df_tv['time']) y_col_list = list(df_tv[key_name]) X_delta_sp = X_col_list[0] // (10**t_comps_ratio) X_col_list_cms = [ *map(lambda a: a / (10**t_comps_ratio) - X_delta_sp, X_col_list) ] X = np.array(X_col_list_cms).reshape(len(X_col_list_cms), 1) y = np.array(y_col_list).reshape(len(y_col_list), 1) X_quad = t_l.generate_polynomials(X, degree) if GaussFiltered: y_list = [item[0] for item in y] y_GF = filters.gaussian_filter1d(y_list, GF_s) return (X, X_quad, np.array(y_GF)) else: return (X, X_quad, y)
def draw_two_p_and_d_interval(key_name_1, key_name_2, X_1, X_2, y_1, y_2, reg_func_interval_1, reg_func_interval_2, count, dp_num_1, dp_num_2, degree): """Displays data points, polynomials, derivatives and cross-zero points of derivatives of two data values Args: key_name_1: name of the first value key_name_2: name of the second value X_1: X of the first value X_2: X of the second value y_1: y of the first value y_2: y of the second value reg_func_interval_1: functions list of the first value reg_func_interval_2: functions list of the second value count: the order of data pairs used for exportation dp_num_1: number of displayed cross_zero_points of the first value dp_num_2: number of displayed cross_zero_points of the second value degree: degree of the function now Returns: No return """ def draw_cross_zero_lines(plt, cross_zero_points, y_max, y_min): """Displays cross-zero points by drawing vertical lines crossing cross-zero points""" has_draw_maximum = False has_draw_minimum = False for index, item in enumerate(cross_zero_points): if item[3] == 'maximum': color_now = 'blue' plt.scatter([ item[0], ], [ item[1], ], 30, color=color_now) plt.annotate('%.3f' % item[0], color=color_now, xy=(item[0], item[1]), xycoords='data', xytext=(+10, +10), textcoords='offset points', fontsize=10, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2", color=color_now)) if not has_draw_maximum: plt.plot([item[0], item[0]], [y_max, y_min], color=color_now, label='cz_maximum', linewidth=1.5, linestyle="--") else: plt.plot([item[0], item[0]], [y_max, y_min], color=color_now, linewidth=1.5, linestyle="--") has_draw_maximum = True elif item[3] == 'minimum': color_now = 'g' plt.scatter([ item[0], ], [ item[1], ], 30, color=color_now) plt.annotate('%.3f' % item[0], color=color_now, xy=(item[0], item[1]), xycoords='data', xytext=(+10, +10), textcoords='offset points', fontsize=10, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2", color=color_now)) if not has_draw_minimum: plt.plot([item[0], item[0]], [y_max, y_min], color=color_now, label='cz_minimum', linewidth=1.5, linestyle="--") else: plt.plot([item[0], item[0]], [y_max, y_min], color=color_now, linewidth=1.5, linestyle="--") has_draw_minimum = True plt.legend(loc='lower right') X_quad_1 = t_l.generate_polynomials(X_1, degree) X_1_left, X_1_right = (X_1[0], X_1[-1]) X_quad_1_d = t_l.generate_polynomials(X_1, degree - 1) X_quad_2 = t_l.generate_polynomials(X_2, degree) X_2_left, X_2_right = (X_2[0], X_2[-1]) X_quad_2_d = t_l.generate_polynomials(X_2, degree - 1) y_1_func = reg_func_interval_1.predict(X_quad_1) y_1_range = np.amax(y_1_func) - np.amin(y_1_func) y_1_max, y_1_min = (np.amax(y_1_func) + 0.08 * y_1_range, np.amin(y_1_func) - 0.08 * y_1_range) y_2_func = reg_func_interval_2.predict(X_quad_2) y_2_range = np.amax(y_2_func) - np.amin(y_2_func) y_2_max, y_2_min = (np.amax(y_2_func) + 0.08 * y_2_range, np.amin(y_2_func) - 0.08 * y_2_range) # Uses cross-zero points to find extremes of functions y_d_dp_1 = reg_func_interval_1.predict_d(X_quad_1_d) y_1_d_range = np.amax(y_d_dp_1) - np.amin(y_d_dp_1) y_1_d_max, y_1_d_min = (np.amax(y_d_dp_1) + 0.08 * y_1_d_range, np.amin(y_d_dp_1) - 0.08 * y_1_d_range) cross_zero_points_1 = t_l.calculate_cross_zero(X_1, y_d_dp_1) cross_zero_points_1_sorted = sorted(cross_zero_points_1, key=lambda a: a[4], reverse=True) y_d_dp_2 = reg_func_interval_2.predict_d(X_quad_2_d) y_2_d_range = np.amax(y_d_dp_2) - np.amin(y_d_dp_2) y_2_d_max, y_2_d_min = (np.amax(y_d_dp_2) + 0.08 * y_2_d_range, np.amin(y_d_dp_2) - 0.08 * y_2_d_range) cross_zero_points_2 = t_l.calculate_cross_zero(X_2, y_d_dp_2) cross_zero_points_2_sorted = sorted(cross_zero_points_2, key=lambda a: a[4], reverse=True) # Drawing part import matplotlib.pyplot as plt fig, axes = plt.subplots(4, 1, sharex=True, figsize=(18, 10)) fig.suptitle(key_name_1[:-1 - key_name_1[::-1].find('.')] + ' && ' + key_name_2[:-1 - key_name_2[::-1].find('.')]) axes[0].scatter(X_1, y_1, color='red', label='Sample Point', linewidths=1) axes[0].set_ylabel(key_name_1[:key_name_1.find('.')]) axes[0].grid(True) axes[0].axis([X_1_left, X_1_right, y_1_min, y_1_max]) axes[0].plot(X_1, y_1_func, color='orange', linewidth=3) axes[2].set_ylabel('Derivative 1st.') axes[2].grid(True) axes[2].axis([X_1_left, X_1_right, y_1_d_min, y_1_d_max]) axes[2].plot(X_1, y_d_dp_1, color='c', linewidth=3) axes[2].plot(X_1, [0] * len(X_1), color='black', linewidth=1) # Draws cross-zero data points dp_cross_zero_points_1 = cross_zero_points_1_sorted[:dp_num_1] if len( cross_zero_points_1_sorted) > dp_num_1 else cross_zero_points_1_sorted draw_cross_zero_lines(axes[2], dp_cross_zero_points_1, y_1_d_max, y_1_d_min) fig.subplots_adjust(hspace=0.1) plt.setp([a.get_xticklabels() for a in fig.axes], visible=True) plt.subplot(4, 1, 2) plt.scatter(X_2, y_2, color='red', label='Sample Point', linewidths=1) plt.ylabel(key_name_2[:key_name_2.find('.')]) plt.grid(True) plt.axis([X_2_left, X_2_right, y_2_min, y_2_max]) plt.plot(X_2, y_2_func, color='orange', linewidth=3) plt.subplot(4, 1, 4) plt.ylabel('Derivative 2nd.') plt.grid(True) plt.axis([X_2_left, X_2_right, y_2_d_min, y_2_d_max]) plt.plot(X_2, y_d_dp_2, color='c', linewidth=3) plt.plot(X_2, [0] * len(X_2), color='black', linewidth=1) dp_cross_zero_points_2 = cross_zero_points_2_sorted[:dp_num_2] if len( cross_zero_points_2_sorted) > dp_num_2 else cross_zero_points_2_sorted draw_cross_zero_lines(plt, dp_cross_zero_points_2, y_2_d_max, y_2_d_min) plt.show()
def draw_two_p_and_d_interval_commX(key_name_1, key_name_2, X_1, X_2, y_1, y_2, reg_func_interval_1, reg_func_interval_2, degree, count): """Uses a threshold of Pearson's r to filter correlated data pairs Displays both their polynomial functions and derivative functions Args: key_name_1: name of the first value key_name_2: name of the second value X_1: X of the first value X_2: X of the second value y_1: y of the first value y_2: y of the second value reg_func_interval_1: functions list of the first value reg_func_interval_2: functions list of the second value degree: degree of the function now count: the order of data pairs used for exportation Returns: No return """ # Finds comm_x for one comparison comm_left = X_1[0] if X_1[0] > X_2[0] else X_2[0] comm_right = X_1[-1] if X_1[-1] < X_2[-1] else X_2[-1] comm_X = np.linspace(comm_left, comm_right, 3000) comm_X = comm_X.reshape(comm_X.shape[0], 1) comm_X_quad = t_l.generate_polynomials(comm_X, degree) comm_X_quad_d = t_l.generate_polynomials(comm_X, degree - 1) y_1_func = reg_func_interval_1.predict(comm_X_quad) y_2_func = reg_func_interval_2.predict(comm_X_quad) y_d_dp_1 = reg_func_interval_1.predict_d(comm_X_quad_d) y_d_dp_2 = reg_func_interval_2.predict_d(comm_X_quad_d) # Displays pearson y_1_2_pearson_c_s = t_l.pearson_correlation_similarity(y_1_func, y_2_func) y_d_1_2_pearson_c_s = t_l.pearson_correlation_similarity( y_d_dp_1, y_d_dp_2) if abs(y_1_2_pearson_c_s) >= PEARSON_THRESHOLD: print(key_name_1, key_name_2) print('Pearson of y:', y_1_2_pearson_c_s) print('Pearson of y_d:', y_d_1_2_pearson_c_s) print() else: return 1 # Drawing part import matplotlib.pyplot as plt fig, axes = plt.subplots(4, 1, sharex=True, figsize=(16, 9)) fig.suptitle(key_name_1[:-1 - key_name_1[::-1].find('.')] + ' && ' + key_name_2[:-1 - key_name_2[::-1].find('.')]) plt.xlabel('time') axes[0].set_ylabel(key_name_1[key_name_1.find('.') + 1:key_name_1.rfind('.')]) axes[0].grid(True) axes[0].plot(comm_X, y_1_func, color='orange', label='interval regression', linewidth=3) axes[0].legend(loc='upper right') axes[1].set_ylabel(key_name_2[key_name_2.find('.') + 1:key_name_2.rfind('.')]) axes[1].grid(True) axes[1].plot(comm_X, y_2_func, color='orange', label='interval regression', linewidth=3) axes[1].legend(loc='upper right') axes[2].set_ylabel('Derivative 1st.') axes[2].grid(True) axes[2].plot(comm_X, y_d_dp_1, color='c', label='derivatives', linewidth=3) axes[2].plot(comm_X, [0] * len(comm_X), color='black', linewidth=1) axes[2].legend(loc='upper right') axes[3].set_ylabel('derivative 2nd.') axes[3].grid(True) axes[3].plot(comm_X, y_d_dp_2, color='c', label='derivatives', linewidth=3) axes[3].plot(comm_X, [0] * len(comm_X), color='black', linewidth=1) axes[3].legend(loc='upper right') # plt.savefig('candidate_pairs_' + str(count) + '.png', dpi=200) plt.show()
def draw_d_and_d_interval(key_name_1, key_name_2, X_1, X_2, reg_func_d_interval_1, reg_func_d_interval_2, degree): """Displays comparison of derivatives and their cross-zero points of two data values. Especially, paints the cross-zero points which are close to each other to visualize the possibility of correlation between derivatives Args: key_name_1: name of the first value key_name_2: name of the second value X_1: X of the first value X_2: X of the second value reg_func_interval_1: functions list of the first value reg_func_interval_2: functions list of the second value degree: degree of the function now Returns: No return """ # Finds comm_x for picture comm_left = X_1[0] if X_1[0]>X_2[0] else X_2[0] comm_right = X_1[-1] if X_1[-1]<X_2[-1] else X_2[-1] comm_X = np.linspace(comm_left,comm_right,5000) comm_X = comm_X.reshape(comm_X.shape[0], 1) comm_X_quad = t_l.generate_polynomials(comm_X, degree) comm_X_quad_d = t_l.generate_polynomials(comm_X, degree-1) # Uses cross-zero points to find extremes of functions dp_num_1 = DISPLAYED_CROSS_ZERO_NUM_1 y_d_dp_1 = reg_func_d_interval_1.predict_d(comm_X_quad_d) cross_zero_points_1 = t_l.calculate_cross_zero(comm_X, y_d_dp_1) cross_zero_points_1_sorted = sorted(cross_zero_points_1, key=lambda a:a[4], reverse=True) top_X_cross_zero_list_1 = [*map(lambda a:a[0], cross_zero_points_1_sorted[:dp_num_1] \ if len(cross_zero_points_1_sorted)>dp_num_1 \ else cross_zero_points_1_sorted)] dp_num_2 = DISPLAYED_CROSS_ZERO_NUM_2 y_d_dp_2 = reg_func_d_interval_2.predict_d(comm_X_quad_d) cross_zero_points_2 = t_l.calculate_cross_zero(comm_X, y_d_dp_2) cross_zero_points_2_sorted = sorted(cross_zero_points_2, key=lambda a:a[4], reverse=True) top_X_cross_zero_list_2 = [*map(lambda a:a[0], cross_zero_points_2_sorted[:dp_num_2] \ if len(cross_zero_points_2_sorted)>dp_num_2 \ else cross_zero_points_2_sorted)] total_near_count = 0 for index_2, item_2 in enumerate(top_X_cross_zero_list_2): for index_1, item_1 in enumerate(top_X_cross_zero_list_1): if abs(item_1-item_2) <= NEAR_DISTANCE: if cross_zero_points_2_sorted[index_2][-1] != 'catch': cross_zero_points_2_sorted[index_2] += ('catch',) total_near_count += 1 if cross_zero_points_1_sorted[index_1][-1] != 'catch': cross_zero_points_1_sorted[index_1] += ('catch',) total_near_count += 1 # For debug # total_czp_num = len(top_X_cross_zero_list_2) + len(top_X_cross_zero_list_1) # print(total_near_count, total_near_count/total_czp_num) # print(key_name_1,key_name_2) # print() import matplotlib.pyplot as plt fig, axarr = plt.subplots(2, sharex=True, figsize=(16,9)) # Plot 1 axarr[0].set_title('derivative 1') axarr[0].set_xlabel('time') axarr[0].set_ylabel(key_name_1) axarr[0].grid(True) y_d_1_range = np.amax(y_d_dp_1) - np.amin(y_d_dp_1) picture_y_d_1_max = np.amax(y_d_dp_1)+0.08*y_d_1_range picture_y_d_1_min = np.amin(y_d_dp_1)-0.08*y_d_1_range axarr[0].axis([comm_left,comm_right,picture_y_d_1_min,picture_y_d_1_max]) axarr[0].plot(comm_X, y_d_dp_1, color='c', linewidth=3) axarr[0].plot(comm_X, [0]*len(comm_X), color='black', linewidth=1) # Draws cross-zero data points has_draw_maximum_1 = False has_draw_minimum_1 = False for index, item in enumerate(cross_zero_points_1_sorted[:dp_num_1] \ if len(cross_zero_points_1_sorted)>dp_num_1 else cross_zero_points_1_sorted): if item[3]=='maximum': if item[-1] == 'catch': color_now = 'red' else: color_now = 'blue' axarr[0].scatter([item[0],],[item[1],], 30, color=color_now) axarr[0].annotate('%.3f' % item[0],color=color_now, xy=(item[0], item[1]), xycoords='data', xytext=(+10, +10), textcoords='offset points', fontsize=10, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2", color=color_now)) if not has_draw_maximum_1: axarr[0].plot([item[0],item[0]],[item[1],picture_y_d_1_min], color=color_now, label='cz_maximum', linewidth=1.5, linestyle="--") else: axarr[0].plot([item[0],item[0]],[item[1],picture_y_d_1_min], color=color_now, linewidth=1.5, linestyle="--") has_draw_maximum_1 = True elif item[3]=='minimum': if item[-1] == 'catch': color_now = 'red' else: color_now = 'g' axarr[0].scatter([item[0],],[item[1],], 30, color=color_now) axarr[0].annotate('%.3f' % item[0],color=color_now, xy=(item[0], item[1]), xycoords='data', xytext=(+10, +10), textcoords='offset points', fontsize=10, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2", color=color_now)) if not has_draw_minimum_1: axarr[0].plot([item[0],item[0]],[item[1],picture_y_d_1_min], color=color_now, label='cz_minimum', linewidth=1.5, linestyle="--") else: axarr[0].plot([item[0],item[0]],[item[1],picture_y_d_1_min], color=color_now, linewidth=1.5, linestyle="--") has_draw_minimum_1 = True axarr[0].legend(loc='lower right') # Plot 2 axarr[1].set_title('derivative 2') axarr[1].set_xlabel('time') axarr[1].set_ylabel(key_name_2) axarr[1].grid(True) y_d_2_range = np.amax(y_d_dp_2) - np.amin(y_d_dp_2) picture_y_d_2_max = np.amax(y_d_dp_2)+0.08*y_d_2_range picture_y_d_2_min = np.amin(y_d_dp_2)-0.08*y_d_2_range axarr[1].axis([comm_left,comm_right,picture_y_d_2_min,picture_y_d_2_max]) axarr[1].plot(comm_X, y_d_dp_2, color='c', linewidth=3) axarr[1].plot(comm_X, [0]*len(comm_X), color='black', linewidth=1) has_draw_maximum_2 = False has_draw_minimum_2 = False for index, item in enumerate(cross_zero_points_2_sorted[:dp_num_2] \ if len(cross_zero_points_2_sorted)>dp_num_2 else cross_zero_points_2_sorted): if item[3]=='maximum': if item[-1] == 'catch': color_now = 'red' else: color_now = 'blue' axarr[1].scatter([item[0],],[item[1],], 30, color=color_now) axarr[1].annotate('%.3f' % item[0],color=color_now, xy=(item[0], item[1]), xycoords='data', xytext=(+10, +10), textcoords='offset points', fontsize=10, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2", color=color_now)) if not has_draw_maximum_2: axarr[1].plot([item[0],item[0]],[item[1],picture_y_d_2_max], color=color_now, label='cz_maximum', linewidth=1.5, linestyle="--") else: axarr[1].plot([item[0],item[0]],[item[1],picture_y_d_2_max], color=color_now, linewidth=1.5, linestyle="--") has_draw_maximum_2 = True elif item[3]=='minimum': if item[-1] == 'catch': color_now = 'red' else: color_now = 'g' axarr[1].scatter([item[0],],[item[1],], 30, color=color_now) axarr[1].annotate('%.3f' % item[0],color=color_now, xy=(item[0], item[1]), xycoords='data', xytext=(+10, +10), textcoords='offset points', fontsize=10, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2", color=color_now)) if not has_draw_minimum_2: axarr[1].plot([item[0],item[0]],[item[1],picture_y_d_2_max], color=color_now, label='cz_minimum', linewidth=1.5, linestyle="--") else: axarr[1].plot([item[0],item[0]],[item[1],picture_y_d_2_max], color=color_now, linewidth=1.5, linestyle="--") has_draw_minimum_2 = True axarr[1].legend(loc='lower right') plt.show()