8
8
from bokeh .models import BoxAnnotation , HoverTool , WheelZoomTool , ColumnDataSource , Label , LabelSet , Segment , Toggle , Range1d , FreehandDrawTool , CustomJS
9
9
from bokeh .layouts import row
10
10
from bokeh .colors import RGB
11
+ from bokeh .io import export_svg , export_svgs
11
12
import pyslow5
12
13
import copy
13
14
import argparse
@@ -185,14 +186,14 @@ def plot_function(p, read_id, signal_tuple, sig_algn_data, fasta_sequence, base_
185
186
toggle_moves .js_link ('active' , move_annotation_labels , 'visible' )
186
187
187
188
source = ColumnDataSource (data = dict (x = x [:x_coordinate ], y = y [:x_coordinate ], x_real = x_real [:x_coordinate ]))
188
- p .quad (top = y_max , bottom = y_min , left = base_box_details ['left' ], right = base_box_details ['right' ], color = base_box_details ['fill_color' ], alpha = 0.75 )
189
+ p .quad (top = y_max , bottom = y_min , left = base_box_details ['left' ], right = base_box_details ['right' ], color = base_box_details ['fill_color' ], alpha = 0.75 , visible = draw_data [ 'no_colours' ] )
189
190
p .add_glyph (line_segment_source , glyph )
190
191
p .add_layout (base_annotation_labels )
191
192
p .add_layout (move_annotation_labels )
192
193
193
194
p .line ('x' , 'y' , name = "sig_plot_line" , line_width = 2 , source = source )
194
195
# add a circle renderer with a size, color, and alpha
195
- sample_labels = p .circle (x [:x_coordinate ], y [:x_coordinate ], radius = draw_data ["point_size" ], color = sample_label_colors , alpha = 0.5 )
196
+ sample_labels = p .circle (x [:x_coordinate ], y [:x_coordinate ], radius = draw_data ["point_size" ], color = sample_label_colors , alpha = 0.5 , visible = draw_data [ 'no_samples' ] )
196
197
toggle_samples = Toggle (label = "samples" , button_type = "danger" , active = True , height = 30 , width = 60 )
197
198
toggle_samples .js_link ('active' , sample_labels , 'visible' )
198
199
@@ -210,27 +211,26 @@ def plot_function(p, read_id, signal_tuple, sig_algn_data, fasta_sequence, base_
210
211
p .title = plot_title
211
212
212
213
if location_plot > (y_max - y_min ):
213
- if location_plot > PLOT_X_RANGE :
214
- p .x_range = Range1d (0 , PLOT_X_RANGE , bounds = (- 1 * PLOT_X_PADDING , location_plot + PLOT_X_PADDING ))
214
+ if location_plot > draw_data [ 'xrange' ] :
215
+ p .x_range = Range1d (0 , draw_data [ 'xrange' ] , bounds = (- 1 * PLOT_X_PADDING , location_plot + PLOT_X_PADDING ))
215
216
else :
216
217
p .x_range = Range1d (0 , location_plot , bounds = (- 1 * PLOT_X_PADDING , location_plot + PLOT_X_PADDING ))
217
218
218
219
renderer = p .multi_line ([[1 , 1 ]], [[1 , 1 ]], line_width = 4 , alpha = 0.4 , color = 'black' )
219
220
draw_tool = FreehandDrawTool (renderers = [renderer ], num_objects = 50 )
220
221
p .add_tools (draw_tool )
221
222
222
- x_callback_base_annotation = CustomJS (args = dict (base_annotation_labels = base_annotation_labels , init_font_size = base_annotation_labels .text_font_size [:- 2 ], init_xrange = PLOT_X_RANGE ), code = """
223
+ x_callback_base_annotation = CustomJS (args = dict (base_annotation_labels = base_annotation_labels , init_font_size = base_annotation_labels .text_font_size [:- 2 ], init_xrange = draw_data [ 'xrange' ] ), code = """
223
224
let xzoom = (init_font_size * init_xrange) / (cb_obj.end - cb_obj.start);
224
225
base_annotation_labels['text_font_size'] = String(xzoom) + 'pt';
225
226
""" )
226
227
p .x_range .js_on_change ('start' , x_callback_base_annotation )
227
228
228
- x_callback_move_annotation = CustomJS (args = dict (move_annotation_labels = move_annotation_labels , init_font_size = base_annotation_labels .text_font_size [:- 2 ], init_xrange = PLOT_X_RANGE ), code = """
229
+ x_callback_move_annotation = CustomJS (args = dict (move_annotation_labels = move_annotation_labels , init_font_size = base_annotation_labels .text_font_size [:- 2 ], init_xrange = draw_data [ 'xrange' ] ), code = """
229
230
let xzoom = (init_font_size * init_xrange) / (cb_obj.end - cb_obj.start);
230
231
move_annotation_labels['text_font_size'] = String(xzoom) + 'pt';
231
232
""" )
232
233
p .x_range .js_on_change ('start' , x_callback_move_annotation )
233
-
234
234
layout_ = p , row (toggle_bases , toggle_samples , toggle_moves )
235
235
return layout_
236
236
def plot_function_fixed_width (p , read_id , signal_tuple , sig_algn_data , fasta_sequence , base_limit , draw_data ):
@@ -389,14 +389,14 @@ def plot_function_fixed_width(p, read_id, signal_tuple, sig_algn_data, fasta_seq
389
389
fixed_width_x = fixed_width_x [1 :]
390
390
391
391
source = ColumnDataSource (data = dict (x = fixed_width_x [:x_coordinate ], y = y [:x_coordinate ], x_real = x_real [:x_coordinate ]))
392
- p .quad (top = y_max , bottom = y_min , left = base_box_details ['left' ], right = base_box_details ['right' ], color = base_box_details ['fill_color' ], alpha = 0.75 )
392
+ p .quad (top = y_max , bottom = y_min , left = base_box_details ['left' ], right = base_box_details ['right' ], color = base_box_details ['fill_color' ], alpha = 0.75 , visible = draw_data [ 'no_colours' ] )
393
393
p .add_glyph (line_segment_source , glyph )
394
394
p .add_layout (base_annotation_labels )
395
395
p .add_layout (move_annotation_labels )
396
396
397
397
p .line ('x' , 'y' , name = "sig_plot_line" , line_width = 2 , source = source )
398
398
# add a circle renderer with a size, color, and alpha
399
- sample_labels = p .circle (fixed_width_x [:x_coordinate ], y [:x_coordinate ], radius = draw_data ["point_size" ], color = sample_label_colors , alpha = 0.5 )
399
+ sample_labels = p .circle (fixed_width_x [:x_coordinate ], y [:x_coordinate ], radius = draw_data ["point_size" ], color = sample_label_colors , alpha = 0.5 , visible = draw_data [ 'no_samples' ] )
400
400
toggle_samples = Toggle (label = "samples" , button_type = "danger" , active = True , height = 30 , width = 60 )
401
401
toggle_samples .js_link ('active' , sample_labels , 'visible' )
402
402
@@ -414,8 +414,8 @@ def plot_function_fixed_width(p, read_id, signal_tuple, sig_algn_data, fasta_seq
414
414
p .title = plot_title
415
415
416
416
if location_plot > (y_max - y_min ):
417
- if location_plot > PLOT_X_RANGE :
418
- p .x_range = Range1d (0 , PLOT_X_RANGE , bounds = (- 1 * PLOT_X_PADDING , location_plot + PLOT_X_PADDING ))
417
+ if location_plot > draw_data [ 'xrange' ] :
418
+ p .x_range = Range1d (0 , draw_data [ 'xrange' ] , bounds = (- 1 * PLOT_X_PADDING , location_plot + PLOT_X_PADDING ))
419
419
else :
420
420
p .x_range = Range1d (0 , location_plot , bounds = (- 1 * PLOT_X_PADDING , location_plot + PLOT_X_PADDING ))
421
421
# else:
@@ -425,13 +425,13 @@ def plot_function_fixed_width(p, read_id, signal_tuple, sig_algn_data, fasta_seq
425
425
draw_tool = FreehandDrawTool (renderers = [renderer ], num_objects = 50 )
426
426
p .add_tools (draw_tool )
427
427
428
- x_callback_base_annotation = CustomJS (args = dict (base_annotation_labels = base_annotation_labels , init_font_size = base_annotation_labels .text_font_size [:- 2 ], init_xrange = PLOT_X_RANGE ), code = """
428
+ x_callback_base_annotation = CustomJS (args = dict (base_annotation_labels = base_annotation_labels , init_font_size = base_annotation_labels .text_font_size [:- 2 ], init_xrange = draw_data [ 'xrange' ] ), code = """
429
429
let xzoom = (init_font_size * init_xrange) / (cb_obj.end - cb_obj.start);
430
430
base_annotation_labels['text_font_size'] = String(xzoom) + 'pt';
431
431
""" )
432
432
p .x_range .js_on_change ('start' , x_callback_base_annotation )
433
433
434
- x_callback_move_annotation = CustomJS (args = dict (move_annotation_labels = move_annotation_labels , init_font_size = base_annotation_labels .text_font_size [:- 2 ], init_xrange = PLOT_X_RANGE ), code = """
434
+ x_callback_move_annotation = CustomJS (args = dict (move_annotation_labels = move_annotation_labels , init_font_size = base_annotation_labels .text_font_size [:- 2 ], init_xrange = draw_data [ 'xrange' ] ), code = """
435
435
let xzoom = (init_font_size * init_xrange) / (cb_obj.end - cb_obj.start);
436
436
move_annotation_labels['text_font_size'] = String(xzoom) + 'pt';
437
437
""" )
@@ -516,6 +516,9 @@ def run(args):
516
516
indt = "\t \t \t \t \t \t \t \t "
517
517
draw_data = {}
518
518
draw_data ["point_size" ] = args .point_size
519
+ draw_data ["no_colours" ] = args .no_colours
520
+ draw_data ["no_samples" ] = args .no_samples
521
+ draw_data ["xrange" ] = args .xrange
519
522
draw_data ["sig_plot_limit" ] = args .sig_plot_limit
520
523
draw_data ["fixed_base_width" ] = args .base_width
521
524
draw_data ["plot_dims" ] = {}
@@ -619,8 +622,6 @@ def run(args):
619
622
620
623
print ("plot region: {}-{}\t read_id: {}" .format (ref_start , ref_end , read_id ))
621
624
622
- output_file_name = args .output_dir + "/" + read_id + "_" + args .tag_name + ".html"
623
-
624
625
x = []
625
626
x_real = []
626
627
y = []
@@ -709,8 +710,15 @@ def run(args):
709
710
else :
710
711
layout_ = plot_function (p = p , read_id = read_id , signal_tuple = signal_tuple , sig_algn_data = sig_algn_dic , fasta_sequence = fasta_seq , base_limit = base_limit , draw_data = draw_data )
711
712
712
- output_file (output_file_name , title = read_id )
713
- save (layout_ )
713
+ output_file_name = args .output_dir + "/" + read_id + "_" + args .tag_name
714
+ if args .save_svg :
715
+ output_file_name += ".svg"
716
+ layout_ [0 ].output_backend = "svg"
717
+ export_svgs (layout_ , filename = output_file_name )
718
+ else :
719
+ output_file_name += ".html"
720
+ output_file (output_file_name , title = read_id )
721
+ save (layout_ )
714
722
print (f'output file: { os .path .abspath (output_file_name )} ' )
715
723
716
724
num_plots += 1
@@ -835,8 +843,6 @@ def run(args):
835
843
if not bool (re .match ('^[ACGTUMRWSYKVHDBN]+$' , fasta_seq )):
836
844
raise Exception ("Error: base characters other than A,C,G,T/U,M,R,W,S,Y,K,V,H,D,B,N were detected. Please check your sequence files" )
837
845
838
- output_file_name = args .output_dir + "/" + read_id + "_" + args .tag_name + ".html"
839
-
840
846
x = []
841
847
x_real = []
842
848
y = []
@@ -934,8 +940,15 @@ def run(args):
934
940
else :
935
941
layout_ = plot_function (p = p , read_id = read_id , signal_tuple = signal_tuple , sig_algn_data = sig_algn_dic , fasta_sequence = fasta_seq , base_limit = base_limit , draw_data = draw_data )
936
942
937
- output_file (output_file_name , title = read_id )
938
- save (layout_ )
943
+ output_file_name = args .output_dir + "/" + read_id + "_" + args .tag_name
944
+ if args .save_svg :
945
+ output_file_name += ".svg"
946
+ layout_ .output_backend = "svg"
947
+ export_svgs (layout_ , filename = output_file_name )
948
+ else :
949
+ output_file_name += ".html"
950
+ output_file (output_file_name , title = read_id )
951
+ save (layout_ )
939
952
print (f'output file: { os .path .abspath (output_file_name )} ' )
940
953
941
954
num_plots += 1
@@ -1055,8 +1068,6 @@ def run(args):
1055
1068
if not bool (re .match ('^[ACGTUMRWSYKVHDBN]+$' , fasta_seq )):
1056
1069
raise Exception ("Error: base characters other than A,C,G,T/U,M,R,W,S,Y,K,V,H,D,B,N were detected. Please check your sequence files" )
1057
1070
1058
- output_file_name = args .output_dir + "/" + read_id + "_" + args .tag_name + ".html"
1059
-
1060
1071
x = []
1061
1072
x_real = []
1062
1073
y = []
@@ -1151,9 +1162,17 @@ def run(args):
1151
1162
else :
1152
1163
layout_ = plot_function (p = p , read_id = read_id , signal_tuple = signal_tuple , sig_algn_data = sig_algn_dic , fasta_sequence = fasta_seq , base_limit = base_limit , draw_data = draw_data )
1153
1164
1154
- output_file (output_file_name , title = read_id )
1155
- save (layout_ )
1165
+ output_file_name = args .output_dir + "/" + read_id + "_" + args .tag_name
1166
+ if args .save_svg :
1167
+ output_file_name += ".svg"
1168
+ layout_ .output_backend = "svg"
1169
+ export_svgs (layout_ , filename = output_file_name )
1170
+ else :
1171
+ output_file_name += ".html"
1172
+ output_file (output_file_name , title = read_id )
1173
+ save (layout_ )
1156
1174
print (f'output file: { os .path .abspath (output_file_name )} ' )
1175
+
1157
1176
num_plots += 1
1158
1177
if num_plots == args .plot_limit :
1159
1178
break
@@ -1196,6 +1215,10 @@ def argparser():
1196
1215
parser .add_argument ('--sig_plot_limit' , required = False , type = int , default = SIG_PLOT_LENGTH , help = "maximum number of signal samples to plot" )
1197
1216
parser .add_argument ('--bed' , required = False , help = "bed file with annotations" )
1198
1217
parser .add_argument ('--print_bed_labels' , required = False , action = 'store_true' , help = "draw bed annotations with labels" )
1218
+ parser .add_argument ('--no_colours' , required = False , action = 'store_false' , help = "hide base colours" )
1219
+ parser .add_argument ('--no_samples' , required = False , action = 'store_false' , help = "hide sample points" )
1220
+ parser .add_argument ('--save_svg' , required = False , action = 'store_true' , help = "save as svg. tweak --region and --xrange to capture the necessary part of the plot" )
1221
+ parser .add_argument ('--xrange' , required = False , type = int , default = PLOT_X_RANGE , help = "initial x range" )
1199
1222
parser .add_argument ('-o' , '--output_dir' , required = True , type = str , default = "" , help = "output dir" )
1200
1223
return parser
1201
1224
0 commit comments