11from __future__ import print_function , absolute_import
22
33import HTSeq
4+ import abc
45from argparse import ArgumentParser
56from collections import Counter
7+ import csv
8+ import logging
9+ from matplotlib .backends .backend_agg import FigureCanvasAgg
10+ from matplotlib .cm import ScalarMappable
11+ from matplotlib .figure import Figure
12+ from matplotlib .patches import Rectangle
13+ import os
14+ from pyreference import Reference
15+ from pyreference .utils import iv_iterators
16+ from pyreference .utils .file_utils import name_from_file_name , file_or_file_name
17+ from pyreference .utils .genomics_utils import opposite_strand , format_chrom
618import six
719import sys
820
921import numpy as np
10- from pyreference import Reference
11- from pyreference .utils import iv_iterators
12- from pyreference .utils .csv_utils import write_csv_dict
13- from pyreference .utils .file_utils import name_from_file_name
14- from pyreference .utils .genomics_utils import opposite_strand , format_chrom
15- from pyreference .utils .graphing import write_stacked_bar_graph , \
16- write_individual_bar_graphs
1722
1823
1924MAX_READ_LENGTH = 200
@@ -182,6 +187,222 @@ def main():
182187
183188
184189
190+ '''
191+ Created on 22Jan.,2018
192+
193+ @author: dlawrence
194+ '''
195+
196+
197+
198+
199+ def axis_stacked_bar_graph (ax , largs , arrays , labels , colors ):
200+ bottom = np .zeros (len (largs ), dtype = 'i' )
201+ for array , label , color in zip (arrays , labels , colors ):
202+ lines = ax .bar (largs , array , label = label , color = color , bottom = bottom , linewidth = 0 )
203+ bottom += array
204+
205+ return lines
206+
207+
208+ def write_stacked_bar_graph (graph_image , largs , arrays , labels , colors , ** kwargs ):
209+ '''largs = x-values
210+ arrays = list of lists y-values
211+ labels = list of labels, same length as arrays
212+ colors = list of colors, same length as arrays
213+
214+ kwargs:
215+ extra_func = method called with args=(ax, fig, lines)
216+ legend_side_ratio : eg 0.1 - Shrink figure by this
217+ legend_kwargs : Passed to ax.legend
218+ '''
219+ logging .info ("write_stacked_bar_graph: %s" , graph_image )
220+
221+ title = kwargs .get ("title" )
222+ extra_func = kwargs .get ("extra_func" )
223+ subtitle = kwargs .get ("subtitle" )
224+ x_label = kwargs .get ("x_label" )
225+ y_label = kwargs .get ("y_label" )
226+ legend_side_ratio = kwargs .get ("legend_side_ratio" )
227+
228+ # Old kwargs, which we passed to legend
229+ legend_kwargs = {"loc" : kwargs .get ("loc" ),
230+ "title" : kwargs .get ("legend_title" ),
231+ "prop" : kwargs .get ("legend_props" , {})}
232+ # Overwrite with legend_kwargs
233+ legend_kwargs .update (kwargs .get ("legend_kwargs" , {}))
234+
235+ fig = Figure (dpi = 300 )
236+ fig .patch .set_facecolor ('white' )
237+ ax = fig .add_subplot (111 )
238+ lines = axis_stacked_bar_graph (ax , largs , arrays , labels , colors )
239+
240+ if title :
241+ fig .suptitle (title , fontsize = 18 )
242+ if subtitle :
243+ ax .set_title (subtitle , fontsize = 12 )
244+ if extra_func :
245+ extra_func (ax , fig , lines )
246+ if x_label :
247+ ax .set_xlabel (x_label )
248+ if y_label :
249+ ax .set_ylabel (y_label )
250+
251+ ax .set_xlim (xmin = largs [0 ], xmax = largs [- 1 ]+ 1 )
252+
253+ if legend_side_ratio is not None :
254+ print ("legend_side_ratio: %f" % legend_side_ratio )
255+ assert 0 < legend_side_ratio < 1 , "legend_side_ratio: 0 < %f < 1" % legend_side_ratio
256+
257+ # Shrink current axis's height by legend_below_ratio on the bottom
258+ #ax = pyplot.axes()
259+ box = ax .get_position ()
260+ print ("Box w/h = (%f,%f)" % (box .width , box .height ))
261+
262+ new_width = box .height * (1.0 - legend_side_ratio )
263+ new_position = [box .x0 , box .y0 ,
264+ new_width , box .height ]
265+
266+ ax .set_position (new_position )
267+
268+ box = ax .get_position ()
269+ print ("NEW Box w/h = (%f,%f)" % (box .width , box .height ))
270+
271+
272+ print ("**legend_kwargs = %s" % legend_kwargs )
273+ ax .legend (** legend_kwargs )
274+
275+ canvas = FigureCanvasAgg (fig )
276+ canvas .print_png (graph_image )
277+
278+ def write_individual_bar_graphs (graph_image , largs , arrays , labels , colors , ** kwargs ):
279+ ''' same as write_stacked_bar_graph but writes out 1 plot per entry in array '''
280+
281+ (name_base , extension ) = os .path .splitext (graph_image )
282+
283+ title = kwargs .get ("title" , "" )
284+ y_label = kwargs .get ("y_label" , None )
285+ for array , label , color in zip (arrays , labels , colors ):
286+ kwargs ["title" ] = "%s (%s)" % (title , label )
287+ kwargs ["color" ] = color
288+
289+ bargraph = BarGraph (largs , array )
290+ bargraph .y_label = y_label
291+ individual_graph_image = "%s.%s%s" % (name_base , label , extension ) # extension still has dot
292+ bargraph .save (individual_graph_image )
293+
294+
295+ class GraphBase (object ):
296+ __metaclass__ = abc .ABCMeta
297+
298+ def __init__ (self , ** kwargs ):
299+ '''
300+ legend: [('label', 'color'), ('label2', 'color2')]
301+ '''
302+ self .title = kwargs .get ("title" )
303+ self .x_label = kwargs .get ("x_label" )
304+ self .y_label = kwargs .get ("y_label" )
305+ self .legend = kwargs .get ('legend' )
306+ self .plot_methods = [self .plot ]
307+
308+ def decorations (self , ax ):
309+ if self .title :
310+ ax .set_title (self .title )
311+ if self .x_label :
312+ ax .set_xlabel (self .x_label )
313+ if self .y_label :
314+ ax .set_ylabel (self .y_label )
315+
316+ @abc .abstractmethod
317+ def plot (self , ax ):
318+ return
319+
320+ def post_plot (self , ax ):
321+ if self .legend :
322+ patches = []
323+ labels = []
324+ for (name , color ) in self .legend :
325+ labels .append (name )
326+ patches .append (Rectangle ((0 , 0 ), 1 , 1 , fc = color ))
327+
328+ ax .legend (patches , labels , loc = 'upper left' )
329+
330+ def figure (self , figure ):
331+ ''' a hook method if you want to do something about the figure '''
332+ pass
333+
334+ def get_figure_and_axis (self , dpi ):
335+ figure = Figure (dpi = dpi )
336+ figure .patch .set_facecolor ('white' )
337+ ax = figure .add_subplot (1 , 1 , 1 )
338+ return figure , ax
339+
340+ def save (self , filename_or_obj , dpi = None , file_type = 'png' ):
341+ figure , ax = self .get_figure_and_axis (dpi )
342+
343+ self .decorations (ax )
344+ for plot in self .plot_methods :
345+ plot (ax ) # Implementation
346+ self .post_plot (ax )
347+ self .figure (figure )
348+
349+ canvas = FigureCanvasAgg (figure )
350+ if file_type == 'png' :
351+ canvas .print_png (filename_or_obj )
352+ elif file_type == 'pdf' :
353+ canvas .print_pdf (filename_or_obj )
354+
355+ def draw_origin (self , ax ):
356+ ax .axvline (c = 'black' , lw = 0.5 )
357+ ax .axhline (c = 'black' , lw = 0.5 )
358+
359+ def colorbar_from_cmap_array (self , figure , cmap , array ):
360+ mappable = ScalarMappable (cmap = cmap )
361+ mappable .set_array (array )
362+ figure .colorbar (mappable )
363+
364+
365+ def write_csv_dict (csv_file , headers , rows , extrasaction = None , dialect = None ):
366+ '''
367+ default dialect = 'excel', other dialect option: 'excel-tab'
368+ These are the same optional arguments as csv.DictWriter
369+ headers=keys for dicts
370+ rows=list of dicts
371+ '''
372+
373+
374+ if extrasaction is None :
375+ extrasaction = "raise"
376+ if dialect is None :
377+ dialect = 'excel'
378+
379+ f = file_or_file_name (csv_file , "wb" )
380+
381+ writer = csv .DictWriter (f , headers , extrasaction = extrasaction , dialect = dialect )
382+ writer .writerow (dict (zip (headers , headers )))
383+ writer .writerows (rows )
384+
385+
386+
387+ class BarGraph (GraphBase ):
388+ def __init__ (self , x , y , ** kwargs ):
389+ super (BarGraph , self ).__init__ (** kwargs )
390+ self .x = x
391+ self .y = y
392+ self .labels = kwargs .get ("labels" )
393+ self .color = kwargs .get ("color" )
394+
395+ def plot (self , ax ):
396+ width = 0.5
397+
398+ ax .set_xlim (xmin = self .x [0 ], xmax = self .x [- 1 ]+ 1 )
399+ ax .bar (self .x , self .y , width = width , color = self .color )
400+
401+ if self .labels :
402+ ax .set_xticks (self .x + width / 2 )
403+ ax .set_xticklabels (self .labels )
404+
405+
185406
186407if __name__ == '__main__' :
187408 main ()
0 commit comments