Browse Source

Improve plotting with swp2 control curve

tforest 2 months ago
parent
commit
4aedf5e280
1 changed files with 178 additions and 58 deletions
  1. 178 58
      swp2.py

+ 178 - 58
swp2.py View File

@@ -126,10 +126,11 @@ def plot_straight_x_y(x,y):
126 126
 
127 127
 def plot_all_epochs_thetafolder(full_dict, mu, tgen, title = "Title",
128 128
     theta_scale = True, ax = None, input = None, output = None):
129
-    my_dpi = 300
129
+    my_dpi = 500
130
+    L = full_dict["L"]
130 131
     if ax is None:
131 132
         # intialize figure
132
-        my_dpi = 300
133
+        #my_dpi = 300
133 134
         fnt_size = 18
134 135
         # plt.rcParams['font.size'] = fnt_size
135 136
         fig, ax1 = plt.subplots(figsize=(5000/my_dpi, 2800/my_dpi), dpi=my_dpi)
@@ -139,16 +140,16 @@ def plot_all_epochs_thetafolder(full_dict, mu, tgen, title = "Title",
139 140
         ax1 = ax[1][0,0]
140 141
     ax1.set_yscale('log')
141 142
     ax1.set_xscale('log')
142
-    ax1.grid(True,which="both", linestyle='--', alpha = 0.3)
143 143
     plot_handles = []
144 144
     best_plot = full_dict['all_epochs']['best']
145
-    p0, = ax1.plot(best_plot[0], best_plot[1], 'o', linestyle = "-",
145
+    p0, = ax1.plot(best_plot[0], best_plot[1], linestyle = "-",
146 146
     alpha=1, lw=2, label = str(best_plot[2])+' brks | Lik='+best_plot[3])
147 147
     plot_handles.append(p0)
148
+    #ax1.grid(True,which="both", linestyle='--', alpha = 0.3)
148 149
     for k, plot_Lk in enumerate(full_dict['all_epochs']['plots']):
149 150
         plot_Lk = str(full_dict['all_epochs']['plots'][k][3])
150 151
         # plt.rcParams['font.size'] = fnt_size
151
-        p, = ax1.plot(full_dict['all_epochs']['plots'][k][0], full_dict['all_epochs']['plots'][k][1], 'o', linestyle = "--",
152
+        p, = ax1.plot(full_dict['all_epochs']['plots'][k][0], full_dict['all_epochs']['plots'][k][1], linestyle = "-",
152 153
         alpha=1/(k+1), lw=1.5, label = str(full_dict['all_epochs']['plots'][k][2])+' brks | Lik='+plot_Lk)
153 154
         plot_handles.append(p)
154 155
     if theta_scale:
@@ -160,12 +161,20 @@ def plot_all_epochs_thetafolder(full_dict, mu, tgen, title = "Title",
160 161
         # ax1.axvline(x=recent_scale_upper_bound)
161 162
     else:
162 163
         # years
163
-        plt.set_xlabel("Time (years)", fontsize=fnt_size)
164
-        plt.set_ylabel("Individuals (N)", fontsize=fnt_size)
164
+        if ax is not None:
165
+            plt.set_xlabel("Time (years)", fontsize=fnt_size)
166
+            plt.set_ylabel("Effective pop. size (Ne)", fontsize=fnt_size)
167
+        else:
168
+            plt.xlabel("Time (years)", fontsize=fnt_size)
169
+            plt.ylabel("Effective pop. size (Ne)", fontsize=fnt_size)
170
+    # x_ticks = ax1.get_xticks()
171
+    # ax1.set_xticklabels([f'{k:.0e}\n{k/(mu):.0e}\n{k/(mu)*tgen:.0e}' for k in x_ticks], fontsize = fnt_size*0.5)
172
+    # ax1.set_xticklabels([f'{k}\n{k/(mu)}\n{k/(mu)*tgen}' for k in x_ticks], fontsize = fnt_size*0.8)
165 173
     # plt.rcParams['font.size'] = fnt_size
166 174
     # print(fnt_size, "rcParam font.size=", plt.rcParams['font.size'])
167 175
     ax1.legend(handles = plot_handles, loc='best', fontsize = fnt_size*0.5)
168 176
     ax1.set_title(title)
177
+    breaks = len(full_dict['all_epochs']['plots'])
169 178
     if ax is None:
170 179
         plt.savefig(title+'_b'+str(breaks)+'.pdf')
171 180
     # plot likelihood against nb of breakpoints
@@ -203,8 +212,9 @@ def plot_all_epochs_thetafolder(full_dict, mu, tgen, title = "Title",
203 212
     ax3.set_title(title+" AIC")
204 213
     if ax is None:
205 214
         plt.savefig(title+'_Breakpts_Likelihood_AIC.pdf')
206
-    # return plots
207
-    return ax[0], ax[1]
215
+    else:
216
+        # return plots
217
+        return ax[0], ax[1]
208 218
 
209 219
 def save_all_epochs_thetafolder(folder_path, mu, tgen, title = "Title", theta_scale = True, input = None, output = None):
210 220
     #scenari = {}
@@ -248,10 +258,11 @@ def save_all_epochs_thetafolder(folder_path, mu, tgen, title = "Title", theta_sc
248 258
             # do something with the theta without bp and skip the plotting
249 259
             N0 = y[0]
250 260
             #continue
251
-        for i in range(len(y)):
252
-            # divide by N0
253
-            y[i] = y[i]/N0
254
-            x[i] = x[i]/N0
261
+        if theta_scale:
262
+            for i in range(len(y)):
263
+                # divide by N0
264
+                y[i] = y[i]/N0
265
+                x[i] = x[i]/N0
255 266
         top_plots[greatest_likelihood] = x,y,epoch
256 267
     plots_likelihoods = list(top_plots.keys())
257 268
     for i in range(len(plots_likelihoods)):
@@ -294,9 +305,10 @@ def save_all_epochs_thetafolder(folder_path, mu, tgen, title = "Title", theta_sc
294 305
     # to return : plots ; Ln_Brks ; AIC_Brks ; best_Ln ; best_AIC
295 306
     # 'plots' dict keys: 'best', {epochs}('0', '1',...)
296 307
     if input == None:
297
-        saved_plots = {"S":S, "S0":S0, "L":L, "all_epochs":plots, "Ln_Brks":Ln_Brks,
298
-                        "AIC_Brks":AIC_Brks, "best_Ln":best_Ln,
299
-                        "best_AIC":best_AIC, "best_epoch_by_AIC":selected_brks_nb}
308
+        saved_plots = {"S":S, "S0":S0, "L":L, "mu":mu, "tgen":tgen,
309
+                       "all_epochs":plots, "Ln_Brks":Ln_Brks,
310
+                       "AIC_Brks":AIC_Brks, "best_Ln":best_Ln,
311
+                       "best_AIC":best_AIC, "best_epoch_by_AIC":selected_brks_nb}
300 312
     else:
301 313
         # if the dict has to be loaded from input
302 314
         with open(input, 'r') as json_file:
@@ -304,6 +316,8 @@ def save_all_epochs_thetafolder(folder_path, mu, tgen, title = "Title", theta_sc
304 316
             saved_plots["S"] = S
305 317
             saved_plots["S0"] = S0
306 318
             saved_plots["L"] = L
319
+            saved_plots["mu"] = mu
320
+            saved_plots["tgen"] = tgen
307 321
             saved_plots["all_epochs"] = plots
308 322
             saved_plots["Ln_Brks"] = Ln_Brks
309 323
             saved_plots["AIC_Brks"] = AIC_Brks
@@ -369,9 +383,10 @@ def save_k_theta(folder_path, mu, tgen, title = "Title", theta_scale = True,
369 383
                 for k in range(2, len(y)+2):
370 384
                     prop.append(y[k-2] / (k - 1) / sum_theta_i)
371 385
                 prop = prop[::-1]
372
-        # normalise to N0 (N0 of epoch1)
373
-        for i in range(len(y)):
374
-            y[i] = y[i]/N0
386
+        if theta_scale :
387
+            # normalise to N0 (N0 of epoch1)
388
+            for i in range(len(y)):
389
+                y[i] = y[i]/N0
375 390
         # x_plot, y_plot = plot_straight_x_y(x, y)
376 391
         p = x, y
377 392
         # add plot to the list of all plots to superimpose
@@ -394,8 +409,9 @@ def save_k_theta(folder_path, mu, tgen, title = "Title", theta_scale = True,
394 409
             y += list(np.repeat(thetas[i], len(group)))
395 410
             if epoch == 0:
396 411
                 N0 = y[0]
397
-        for i in range(len(y)):
398
-            y[i] = y[i]/N0
412
+        if theta_scale :
413
+            for i in range(len(y)):
414
+                y[i] = y[i]/N0
399 415
         x_2 = []
400 416
         T = 0
401 417
         for i in range(len(x)):
@@ -426,10 +442,10 @@ def save_k_theta(folder_path, mu, tgen, title = "Title", theta_scale = True,
426 442
         json.dump(saved_plots, json_file)
427 443
     return saved_plots
428 444
 
429
-def plot_scaled_theta(plot_lines, prop, title, ax = None, n_ticks = 10, subset = None):
445
+def plot_scaled_theta(plot_lines, prop, title, mu, tgen, swp2_lines = None, ax = None, n_ticks = 10, subset = None, theta_scale = False):
430 446
     # fig 2 & 3
431 447
     if ax is None:
432
-        my_dpi = 300
448
+        my_dpi = 500
433 449
         fnt_size = 18
434 450
         fig2, ax2 = plt.subplots(figsize=(5000/my_dpi, 2800/my_dpi), dpi=my_dpi)
435 451
         fig3, ax3 = plt.subplots(figsize=(5000/my_dpi, 2800/my_dpi), dpi=my_dpi)
@@ -442,37 +458,79 @@ def plot_scaled_theta(plot_lines, prop, title, ax = None, n_ticks = 10, subset =
442 458
     lines_fig2 = []
443 459
     lines_fig3 = []
444 460
     #plt.figure(figsize=(5000/my_dpi, 2800/my_dpi), dpi=my_dpi)
461
+    if swp2_lines:
462
+        for k in range(len(swp2_lines[0])):
463
+            swp2_lines[0][k] = swp2_lines[0][k]/tgen*mu
464
+        for k in range(len(swp2_lines[1])):
465
+            swp2_lines[1][k] = swp2_lines[1][k]*4*mu
466
+        # plot_lines = [[swp2_lines[0], swp2_lines[1]]]+plot_lines 
467
+
468
+        x2_plot, y2_plot = plot_straight_x_y(swp2_lines[0],swp2_lines[1])
469
+        p2, = ax2.plot(x2_plot, y2_plot, linestyle="-", alpha=0.75, lw=2, label = 'swp2')
470
+        lines_fig2.append(p2)
471
+        # Plotting (fig 3) which is the same but log scale for x
472
+        p3, = ax3.plot(x2_plot, y2_plot, linestyle="-", alpha=0.75, lw=2, label = 'swp2')
473
+        lines_fig3.append(p3)
445 474
     nb_breaks = len(plot_lines)
446 475
     for breaks, plot in enumerate(plot_lines):
447 476
         if subset is not None:
448 477
             if breaks not in subset :
449 478
                 # skip if not in subset
450
-                if max(subset) > nb_breaks and breaks == nb_breaks-1:
479
+                if max(subset) > nb_breaks and breaks == nb_breaks:
451 480
                     pass
452 481
                 else:
453 482
                     continue
454 483
         x,y=plot
484
+        # y = [k/(4*mu) for k in y]
485
+        # x = [k/(mu)*tgen for k in x]
455 486
         x2_plot, y2_plot = plot_straight_x_y(x,y)
456 487
         p2, = ax2.plot(x2_plot, y2_plot, 'o', linestyle="-", alpha=0.75, lw=2, label = str(breaks)+' brks')
457 488
         lines_fig2.append(p2)
458 489
         # Plotting (fig 3) which is the same but log scale for x
459 490
         p3, = ax3.plot(x2_plot, y2_plot, 'o', linestyle="-", alpha=0.75, lw=2, label = str(breaks)+' brks')
460 491
         lines_fig3.append(p3)
461
-    ax2.set_xlabel("Relative scale", fontsize=fnt_size)
462
-    ax2.set_ylabel("theta", fontsize=fnt_size)
463
-    ax2.set_title(title, fontsize=fnt_size)
464
-    ax2.legend(handles=lines_fig2, loc='best', fontsize = fnt_size*0.5)
492
+
493
+    ax3.axvline(x=500/tgen*mu, linestyle="--")
494
+    if theta_scale:
495
+        xlabel = "Theta scaled by N0"
496
+        ylabel = "Theta scaled by N0"
497
+    else:
498
+        xlabel = "Theta scale"
499
+        ylabel = "Theta"
465 500
     if ax is None:
501
+        # if not ax, then use the plt syntax, not ax...
502
+        plt.xlabel(xlabel, fontsize=fnt_size)
503
+        plt.ylabel(ylabel, fontsize=fnt_size)
504
+        plt.xlim(left=0)
505
+        x_ticks = list(plt.xticks())[0]
506
+        plt.gca().set_xticks(x_ticks)
507
+        plt.gca().set_xticklabels([f'{k:.0e}\n{k/(mu):.0e}\n{k/(mu)*tgen:.0e}' for k in x_ticks], fontsize = fnt_size*0.5)
508
+        plt.title(title, fontsize=fnt_size)
509
+        plt.legend(handles=lines_fig2, loc='best', fontsize = fnt_size*0.5)
510
+        plt.text(-0.13, -0.135, 'Coal. time\nGen. time\nYears', ha='left', va='bottom', transform=ax3.transAxes)
511
+        plt.subplots_adjust(bottom=0.2)  # Adjust the value as needed
466 512
         # nb of plot_lines represent the number of epochs stored (len(plot_lines) = #breaks+1)
467 513
         plt.savefig(title+'_plot2_'+str(len(plot_lines))+'.pdf')
468 514
         # close fig2 to save memory
469 515
         plt.close(fig2)
516
+    else:
517
+        # when ax subplotting is used
518
+        ax2.set_xlabel(xlabel, fontsize=fnt_size)
519
+        ax2.set_ylabel(ylabel, fontsize=fnt_size)
520
+        ax2.set_title(title, fontsize=fnt_size)
521
+        ax2.legend(handles=lines_fig2, loc='best', fontsize = fnt_size*0.5)
470 522
     ax3.set_xscale('log')
471 523
     ax3.set_yscale('log')
472
-    ax3.set_xlabel("log Relative scale", fontsize=fnt_size)
524
+    ax3.set_xlabel("time log scale", fontsize=fnt_size)
473 525
     ax3.set_ylabel("theta", fontsize=fnt_size)
474 526
     ax3.set_title(title, fontsize=fnt_size)
475 527
     ax3.legend(handles=lines_fig3, loc='best', fontsize = fnt_size*0.5)
528
+    x_ticks = list(ax3.get_xticks())
529
+    ax3.set_xlim(left=min(x_ticks))
530
+    ax3.set_xticks(x_ticks)
531
+    ax3.set_xticklabels([f'{k:.0e}\n{k/(mu):.0e}\n{k/(mu)*tgen:.0e}' for k in x_ticks], fontsize = fnt_size*0.5)
532
+    plt.text(-0.13, -0.135, 'Coal. time\nGen. time\nYears', ha='left', va='bottom', transform=ax3.transAxes)
533
+    plt.subplots_adjust(bottom=0.2)  # Adjust the value as needed
476 534
     if ax is None:
477 535
         # nb of plot_lines represent the number of epochs stored (len(plot_lines) = #breaks+1)
478 536
         plt.savefig(title+'_plot3_'+str(len(plot_lines))+'_log.pdf')
@@ -480,7 +538,7 @@ def plot_scaled_theta(plot_lines, prop, title, ax = None, n_ticks = 10, subset =
480 538
         plt.close(fig3)
481 539
     return ax
482 540
 
483
-def plot_raw_stairs(plot_lines, prop, title, ax = None, n_ticks = 10):
541
+def plot_raw_stairs(plot_lines, prop, title, ax = None, n_ticks = 10, rescale = False, subset = None):
484 542
     # multiple fig
485 543
     if ax is None:
486 544
         # intialize figure 1
@@ -494,7 +552,6 @@ def plot_raw_stairs(plot_lines, prop, title, ax = None, n_ticks = 10):
494 552
         ax1 = ax[0, 0]
495 553
         plt.subplots_adjust(wspace=0.3, hspace=0.3)
496 554
     plots = []
497
-
498 555
     for epoch, plot in enumerate(plot_lines):
499 556
         x,y = plot
500 557
         x_plot, y_plot = plot_straight_x_y(x,y)
@@ -527,40 +584,103 @@ def plot_raw_stairs(plot_lines, prop, title, ax = None, n_ticks = 10):
527 584
     # return plots
528 585
     return ax
529 586
 
530
-def combined_plot(folder_path, mu, tgen, breaks, title = "Title", theta_scale = True, selected_breaks = []):
587
+def combined_plot(folder_path, mu, tgen, breaks, title = "Title", theta_scale = False, selected_breaks = []):
531 588
     my_dpi = 300
532
-
533
-    save_k_theta(folder_path, mu, tgen, title, theta_scale, breaks_max = breaks, output = title+"_plotdata.json")
534
-    save_all_epochs_thetafolder(folder_path, mu, tgen, title, theta_scale, input = title+"_plotdata.json", output = title+"_plotdata.json")
589
+    saved_plots_dict = save_all_epochs_thetafolder(folder_path, mu, tgen, title, theta_scale, output = title+"_plotdata.json")
590
+    nb_of_epochs = len(saved_plots_dict["all_epochs"]["plots"])
591
+    print(nb_of_epochs)
592
+    best_epoch = saved_plots_dict["best_epoch_by_AIC"]
593
+    save_k_theta(folder_path, mu, tgen, title, theta_scale, breaks_max = nb_of_epochs, input = title+"_plotdata.json", output = title+"_plotdata.json")
535 594
 
536 595
     with open(title+"_plotdata.json", 'r') as json_file:
537 596
         loaded_data = json.load(json_file)
538
-    # plot page 1 of summary
539
-    fig1, ax1 = plt.subplots(2, 2, figsize=(5000/my_dpi, 2970/my_dpi), dpi=my_dpi)
540
-    # fig1.tight_layout()
541
-    # Adjust absolute space between the top and bottom rows
542
-    fig1.subplots_adjust(hspace=0.35)  # Adjust this value based on your requirement
543
-    # plot page 2 of summary
544
-    fig2, ax2 = plt.subplots(2, 2, figsize=(5000/my_dpi, 2970/my_dpi), dpi=my_dpi)
545
-    # fig2.tight_layout()
546
-    ax1 = plot_raw_stairs(plot_lines = loaded_data['raw_stairs'],
547
-                            prop = loaded_data['prop'], title = title, ax = ax1)
548
-    ax1 = plot_scaled_theta(plot_lines = loaded_data['scaled_stairs'],
549
-                                prop = loaded_data['prop'], title = title, ax = ax1, subset=[loaded_data['best_epoch_by_AIC']]+selected_breaks)
550
-    ax2 = plot_scaled_theta(plot_lines = loaded_data['scaled_stairs'],
551
-                            prop = loaded_data['prop'], title = title, ax = ax2)
552
-    ax1, ax2 = plot_all_epochs_thetafolder(loaded_data, mu, tgen, title, theta_scale, ax = [ax1, ax2])
553
-    fig1.savefig(title+'_combined_p1.pdf')
554
-    print("Wrote", title+'_combined_p1.pdf')
555
-    fig2.savefig(title+'_combined_p2.pdf')
556
-    print("Wrote", title+'_combined_p2.pdf')
597
+
598
+    # START OF COMBINED PLOT CODE
599
+        
600
+    # # plot page 1 of summary
601
+    # fig1, ax1 = plt.subplots(2, 2, figsize=(5000/my_dpi, 2970/my_dpi), dpi=my_dpi)
602
+    # # fig1.tight_layout()
603
+    # # Adjust absolute space between the top and bottom rows
604
+    # fig1.subplots_adjust(hspace=0.35)  # Adjust this value based on your requirement
605
+    # # plot page 2 of summary
606
+    # fig2, ax2 = plt.subplots(2, 2, figsize=(5000/my_dpi, 2970/my_dpi), dpi=my_dpi)
607
+    # # fig2.tight_layout()
608
+    # ax1 = plot_raw_stairs(plot_lines = loaded_data['raw_stairs'],
609
+    #                         prop = loaded_data['prop'], title = title, ax = ax1)
610
+    # ax1 = plot_scaled_theta(plot_lines = loaded_data['scaled_stairs'],
611
+    #                             prop = loaded_data['prop'], title = title, ax = ax1, subset=[loaded_data['best_epoch_by_AIC']]+selected_breaks)
612
+    # ax2 = plot_scaled_theta(plot_lines = loaded_data['scaled_stairs'],
613
+    #                         prop = loaded_data['prop'], title = title, ax = ax2)
614
+    # ax1, ax2 = plot_all_epochs_thetafolder(loaded_data, mu, tgen, title, theta_scale, ax = [ax1, ax2])
615
+    
616
+    # fig1.savefig(title+'_combined_p1.pdf')
617
+    # print("Wrote", title+'_combined_p1.pdf')
618
+    # fig2.savefig(title+'_combined_p2.pdf')
619
+    # print("Wrote", title+'_combined_p2.pdf')
620
+
621
+    # END OF COMBINED PLOT CODE
622
+
623
+
624
+    # Start of Parsing real swp2 output
625
+    folder_splitted = folder_path.split("/")
626
+    swp2_summary = "/".join(folder_splitted[:-2])+'/'+folder_splitted[-3]+".final.summary"
627
+    swp2_vals = parse_stairwayplot_output_summary(stwplt_out = swp2_summary)
628
+    swp2_x, swp2_y = swp2_vals[0], swp2_vals[1]
629
+    # End of Parsing real swp2 output
557 630
     plot_raw_stairs(plot_lines = loaded_data['raw_stairs'],
558 631
                             prop = loaded_data['prop'], title = title, ax = None)
559
-    plot_scaled_theta(plot_lines = loaded_data['scaled_stairs'],
560
-                            prop = loaded_data['prop'], title = title, ax = None)
632
+    plot_scaled_theta(plot_lines = loaded_data['scaled_stairs'], mu = mu, tgen = tgen, subset=[loaded_data['best_epoch_by_AIC']]+selected_breaks,
633
+    # plot_scaled_theta(plot_lines = loaded_data['scaled_stairs'], subset=list(range(0,3))+[loaded_data['best_epoch_by_AIC']]+selected_breaks,
634
+                            prop = loaded_data['prop'], title = title, swp2_lines = [swp2_x, swp2_y], ax = None)
635
+    plot_all_epochs_thetafolder(loaded_data, mu, tgen, title, theta_scale, ax = None)
636
+
637
+    # plt.close(fig1)
638
+    # plt.close(fig2)
639
+def parse_stairwayplot_output_summary(stwplt_out, xlim = None, ylim = None, title = "default title", plot = False):
640
+    #col 5
641
+    year = []
642
+    # col 6
643
+    ne_median = []
644
+    ne_2_5 = []
645
+    ne_97_5 = []
646
+    ne_12_5 = []
647
+    # col 10
648
+    ne_87_5 = []
649
+    with open(stwplt_out, "r") as stwplt_stream:
650
+        for line in stwplt_stream:
651
+            ## Line format
652
+            # mutation_per_site	n_estimation	theta_per_site_median	theta_per_site_2.5%	theta_per_site_97.5%	year	Ne_median	Ne_2.5%	Ne_97.5%	Ne_12.5%	Ne_87.5%
653
+            if not line.startswith("mutation_per_site"):
654
+                #not header
655
+                values = line.strip().split()
656
+                year.append(float(values[5]))
657
+                ne_median.append(float(values[6]))
658
+                ne_2_5.append(float(values[7]))
659
+                ne_97_5.append(float(values[8]))
660
+                ne_12_5.append(float(values[9]))
661
+                ne_87_5.append(float(values[10]))
561 662
 
562
-    plt.close(fig1)
563
-    plt.close(fig2)
663
+    vals = [year, ne_median, ne_2_5, ne_97_5, ne_12_5, ne_87_5]
664
+    if plot :
665
+        # plot parsed data
666
+        label = ["Ne median", "Ne 2.5%",	"Ne 97.5%",	"Ne 12.5%",	"Ne 87.5%"]
667
+        for i in range(1, 5):
668
+            fig, = plt.plot(year, vals[i], '--', alpha = 0.4)
669
+            fig.set_label(label[i])
670
+        #     # last plot is median
671
+        fig, = plt.plot(year, ne_median, 'r-', lw=2)
672
+        fig.set_label(label[0])
673
+        plt.legend()
674
+        plt.ylabel("Individuals (Ne)")
675
+        plt.xlabel("Time (years)")
676
+        if xlim:
677
+            plt.xlim(xlim)
678
+        if ylim:
679
+            plt.ylim(ylim)
680
+        plt.title(title)
681
+        plt.show()
682
+        plt.close()
683
+    return vals
564 684
 
565 685
 if __name__ == "__main__":
566 686