diff --git a/HtmlPigeonListener.py b/HtmlPigeonListener.py index 4fc8e50..4c10c99 100644 --- a/HtmlPigeonListener.py +++ b/HtmlPigeonListener.py @@ -7,634 +7,850 @@ # HTML Pigeon Listener could take as input some type of design list # that can help specify layout class HtmlPigeonListener(PigeonListener): - # vars for drawing glpyhs - design = [] - cur_part = {'type': '', 'name': '', 'fwd': True, - 'opts': {'color': (0,0,0), 'label': '', 'label_y_offset': 0, 'label_size': 5}} - part_type = '' - name = '' - fwd = True - color = '' - label_y_offset = 0 - col_map = {} - - # vars for drawing arcs - arcs = [] - cur_arc = {'type' : '', 'from_part' : '', 'to_part' : '', - 'opts':{'color':(0,0,0), 'linewidth':1, - 'arc_height_start':10, 'arc_height_end':15, - 'label_y_offset': 0, 'rep_to_rep_name': ''}} - gettingFromPart = False - haveFromPart = False - arc_type = '' - from_part = {} - to_part = {} - ind_name = '' - rep2_name = '' - glyphToGlyphInd = False - - _has_vector = False - _vector_label = None - - @property - def has_vector(self): - return self._has_vector - - @property - def vector_label(self): - return self._vector_label - - def clear_cur_part(self): - self.part_type = '' - self.name = '' - self.fwd = True - self.color = '' - self.label_y_offset = 0 - self.cur_part = {'type': '', 'name': '', 'fwd': True, - 'opts': {'color': (0,0,0), 'label': '', 'label_y_offset': 0, 'label_size': 3.5, - 'scale': 1}} - - - - def clear_cur_arc(self): + # vars for drawing glpyhs + design = [] + cur_part = { + "type": "", + "name": "", + "fwd": True, + "opts": { + "color": (0, 0, 0), + "label": "", + "label_y_offset": 0, + "label_size": 5, + }, + } + part_type = "" + name = "" + fwd = True + color = "" + label_y_offset = 0 + col_map = {} + + # vars for drawing arcs + arcs = [] + cur_arc = { + "type": "", + "from_part": "", + "to_part": "", + "opts": { + "color": (0, 0, 0), + "linewidth": 1, + "arc_height_start": 10, + "arc_height_end": 15, + "label_y_offset": 0, + "rep_to_rep_name": "", + }, + } + gettingFromPart = False + haveFromPart = False + arc_type = "" + from_part = {} + to_part = {} + ind_name = "" + rep2_name = "" + glyphToGlyphInd = False + + _has_vector = False + _vector_label = None + + @property + def has_vector(self): + return self._has_vector + + @property + def vector_label(self): + return self._vector_label + + def clear_cur_part(self): + self.part_type = "" + self.name = "" + self.fwd = True + self.color = "" + self.label_y_offset = 0 + self.cur_part = { + "type": "", + "name": "", + "fwd": True, + "opts": { + "color": (0, 0, 0), + "label": "", + "label_y_offset": 0, + "label_size": 3.5, + "scale": 1, + }, + } + + def clear_cur_arc(self): + self.gettingFromPart = False + self.haveFromPart = False + self.glyphToGlyphInd = False + self.arc_type = "" + self.ind_name = "" + self.rep2_name = "" + self.from_part = {} + self.to_part = {} + self.cur_arc = { + "type": "", + "from_part": "", + "to_part": "", + "opts": { + "color": (0, 0, 0), + "linewidth": 1, + "arc_height_start": 10, + "arc_height_end": 15, + "label_y_offset": 0, + "label_size": 3.5, + }, + } + + def __init__(self): + self.col_map["1"] = (0.6, 0.6, 1.0) # light blue + self.col_map["2"] = (0.0, 0.0, 0.9) # blue + + self.col_map["3"] = (0.6, 1.0, 0.6) # light green + self.col_map["4"] = (0.0, 0.8, 0.0) # green + + self.col_map["5"] = (1.0, 0.6, 0.6) # light red + self.col_map["6"] = (0.9, 0.0, 0.0) # red + + self.col_map["7"] = (1.0, 0.7, 0.5) # light orange + self.col_map["8"] = (1.0, 0.5, 0.0) # orange + + self.col_map["9"] = (0.8, 0.4, 0.8) # light purple + self.col_map["10"] = (0.45, 0.0, 0.45) # purple + + self.col_map["11"] = (1.0, 1.0, 0.4) # light yellow + self.col_map["12"] = (0.9, 0.9, 0.0) # yellow + + self.col_map["13"] = (0.7, 0.7, 0.7) # grey + self.col_map["14"] = (0.0, 0.0, 0.0) # black + + self.fwd = True + self.y_offset = 0 + + pass + + def getDesignList(self): + return self.design + + def getArcList(self): + return self.arcs + + # Enter a parse tree produced by PigeonParser#script. + def enterScript(self, ctx: PigeonParser.ScriptContext): + # print('enterScript') + pass + + # Exit a parse tree produced by PigeonParser#script. + def exitScript(self, ctx: PigeonParser.ScriptContext): + # print('exitScript') + pass + + # Enter a parse tree produced by PigeonParser#pigeoncommands. + def enterPigeoncommands(self, ctx: PigeonParser.PigeoncommandsContext): + # print('enterPigeoncommands') + pass + + # Exit a parse tree produced by PigeonParser#pigeoncommands. + def exitPigeoncommands(self, ctx: PigeonParser.PigeoncommandsContext): + # print('exitPigeoncommands') + pass + + # Enter a parse tree produced by PigeonParser#promoter. + def enterPromoter(self, ctx: PigeonParser.PromoterContext): + self.part_type = "Promoter" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterPromoter') + pass + + # Exit a parse tree produced by PigeonParser#promoter. + def exitPromoter(self, ctx: PigeonParser.PromoterContext): + if not self.fwd: + self.label_y_offset *= -1 + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitPromoter') + pass + + # Enter a parse tree produced by PigeonParser#repressor. + def enterRepressor(self, ctx: PigeonParser.RepressorContext): + self.part_type = "RBS" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterRepressor') + pass + + # Exit a parse tree produced by PigeonParser#repressor. + def exitRepressor(self, ctx: PigeonParser.RepressorContext): + if not self.fwd: + self.label_y_offset *= -1 + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitRepressor') + pass + + # Enter a parse tree produced by PigeonParser#codingseq. + def enterCodingseq(self, ctx: PigeonParser.CodingseqContext): + self.part_type = "CDS" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = 0 + # print('enterCodingseq') + pass + + # Exit a parse tree produced by PigeonParser#codingseq. + def exitCodingseq(self, ctx: PigeonParser.CodingseqContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "scale": 5, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + "arrowhead_height": 0, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitCodingseq') + pass + + # Enter a parse tree produced by PigeonParser#transcription. + def enterTranscription(self, ctx: PigeonParser.TranscriptionContext): + self.part_type = "Terminator" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterTranscription') + pass + + # Exit a parse tree produced by PigeonParser#transcription. + def exitTranscription(self, ctx: PigeonParser.TranscriptionContext): + if not self.fwd: + self.label_y_offset *= -1 + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitTranscription') + pass + + # Enter a parse tree produced by PigeonParser#stop. + def enterStop(self, ctx: PigeonParser.StopContext): + self.part_type = "Spacer" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterStop') + pass + + # Exit a parse tree produced by PigeonParser#stop. + def exitStop(self, ctx: PigeonParser.StopContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitStop') + pass + + # Enter a parse tree produced by PigeonParser#operator. + def enterOperator(self, ctx: PigeonParser.OperatorContext): + self.part_type = "Operator" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = 0 + # print('enterOperator') + pass + + # Exit a parse tree produced by PigeonParser#operator. + def exitOperator(self, ctx: PigeonParser.OperatorContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitOperator') + pass + + # Enter a parse tree produced by PigeonParser#degredationtag. + def enterDegredationtag(self, ctx: PigeonParser.DegredationtagContext): + self.part_type = "Degredation" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterDegredationtag') + pass + + # Exit a parse tree produced by PigeonParser#degredationtag. + def exitDegredationtag(self, ctx: PigeonParser.DegredationtagContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitDegredationtag') + pass + + # Enter a parse tree produced by PigeonParser#righttriangle. + def enterRighttriangle(self, ctx: PigeonParser.RighttriangleContext): + self.part_type = "Triangle" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterRighttriangle') + pass + + # Exit a parse tree produced by PigeonParser#righttriangle. + def exitRighttriangle(self, ctx: PigeonParser.RighttriangleContext): + if not self.fwd: + self.label_y_offset *= -1 + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitRighttriangle') + pass + + # Enter a parse tree produced by PigeonParser#lefttriangle. + def enterLefttriangle(self, ctx: PigeonParser.LefttriangleContext): + self.part_type = "Triangle" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + self.fwd = False + # print('enterLefttriangle') + pass + + # Exit a parse tree produced by PigeonParser#lefttriangle. + def exitLefttriangle(self, ctx: PigeonParser.LefttriangleContext): + if not self.fwd: + self.label_y_offset *= -1 + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitLefttriangle') + pass + + # Enter a parse tree produced by PigeonParser#invert. + def enterInvert(self, ctx: PigeonParser.InvertContext): + self.fwd = False + # self.label_y_offset = 5 # don't necessarily want to always do this + pass + + # Exit a parse tree produced by PigeonParser#invert. + def exitInvert(self, ctx: PigeonParser.InvertContext): + pass + + # Enter a parse tree produced by PigeonParser#bar. + def enterBar(self, ctx: PigeonParser.BarContext): + self.part_type = "Bar" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterBar') + pass + + # Exit a parse tree produced by PigeonParser#bar. + def exitBar(self, ctx: PigeonParser.BarContext): + if not self.fwd: + self.label_y_offset *= -1 + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitBar') + pass + + def enterThree(self, ctx: PigeonParser.BarContext): + self.part_type = "3Overhang" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterThree') + pass + + # Exit a parse tree produced by PigeonParser#bar. + def exitThree(self, ctx: PigeonParser.BarContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4.0, + "end_pad": 4.0, + "y_extent": 1.5, + "x_extent": 10, + "linewidth": 1.5, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitThree') + pass + + def enterFive(self, ctx: PigeonParser.BarContext): + self.part_type = "5Overhang" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterFive') + pass + + # Exit a parse tree produced by PigeonParser#bar. + def exitFive(self, ctx: PigeonParser.BarContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4.0, + "end_pad": 4.0, + "y_extent": 1.5, + "x_extent": 10, + "linewidth": 1.5, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitFive') + pass + + def enterScar(self, ctx: PigeonParser.ScarContext): + self.part_type = "Scar" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + + def exitScar(self, ctx: PigeonParser.ScarContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4.0, + "end_pad": 4.0, + "y_extent": 1.5, + "x_extent": 10, + "linewidth": 1.5, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + + def enterGene(self, ctx: PigeonParser.CodingseqContext): + self.part_type = "CDS" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = 0 + # print('enterGene') + pass + + # Exit a parse tree produced by PigeonParser#codingseq. + def exitGene(self, ctx: PigeonParser.CodingseqContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + "y_extent": 4, + "x_extent": 20, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitGene') + pass + + def enterFseq(self, ctx: PigeonParser.CodingseqContext): + self.part_type = "FSequence" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = 0 + # print('enterFseq') + pass + + # Exit a parse tree produced by PigeonParser#codingseq. + def exitFseq(self, ctx: PigeonParser.CodingseqContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": 0, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + "y_extent": 5, + "x_extent": 40, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitFseq') + pass + + def enterZring(self, ctx: PigeonParser.DegredationtagContext): + self.part_type = "ZRing" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterZring') + pass + + # Exit a parse tree produced by PigeonParser#degredationtag. + def exitZring(self, ctx: PigeonParser.DegredationtagContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitZring') + pass + + def enterXbar(self, ctx: PigeonParser.BarContext): + self.part_type = "XBar" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + print("enterBar") + pass + + # Exit a parse tree produced by PigeonParser#bar. + def exitXbar(self, ctx: PigeonParser.BarContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitBar') + pass + + def enterBox(self, ctx: PigeonParser.CodingseqContext): + self.part_type = "CDS" + self.color = (0.0, 0.0, 0.0) + self.label_y_offset = -8 + # print('enterBox') + pass + + # Exit a parse tree produced by PigeonParser#codingseq. + def exitBox(self, ctx: PigeonParser.CodingseqContext): + self.cur_part = { + "type": self.part_type, + "name": self.name, + "fwd": self.fwd, + "opts": { + "color": self.color, + "label": self.name, + "label_y_offset": self.label_y_offset, + "label_style": "italic", + "label_size": 3.5, + "start_pad": 4, + "end_pad": 4, + "arrowhead_height": 0, + "arrowhead_length": 0, + "x_extent": 15, + "y_extent": 4, + }, + } + self.design += [self.cur_part] + self.clear_cur_part() + # print('exitBox') + pass + + def exitVector(self, ctx: PigeonParser.VectorContext): + self._has_vector = True + self._vector_label = self.name + + # Enter a parse tree produced by PigeonParser#label. + def enterLabel(self, ctx: PigeonParser.LabelContext): + print("enterLabel") + self.name = ctx.getText() + + # NORMAL REPRESSION ARCS + if self.gettingFromPart and self.cur_arc["type"] == "Repression": + # print('REPRESSION ARC - GETTING LABELS') + for i in self.design: + if i["name"] == self.name: + self.cur_arc["from_part"] = i self.gettingFromPart = False - self.haveFromPart = False - self.glyphToGlyphInd = False - self.arc_type = '' - self.ind_name = '' - self.rep2_name = '' - self.from_part = {} - self.to_part = {} - self.cur_arc = {'type': '', 'from_part': '', 'to_part': '', - 'opts': {'color': (0, 0, 0), 'linewidth': 1, - 'arc_height_start': 10, 'arc_height_end': 15, - 'label_y_offset': 0, 'label_size': 3.5}} - - - def __init__(self): - self.col_map['1'] = (0.6, 0.6, 1.0) # light blue - self.col_map['2'] = (0.0, 0.0, 0.9) # blue - - self.col_map['3'] = (0.6, 1.0, 0.6) # light green - self.col_map['4'] = (0.0, 0.8, 0.0) # green - - self.col_map['5'] = (1.0, 0.6, 0.6) # light red - self.col_map['6'] = (0.9, 0.0, 0.0) # red - - self.col_map['7'] = (1.0, 0.7, 0.5) # light orange - self.col_map['8'] = (1.0, 0.5, 0.0) # orange - - self.col_map['9'] = (0.8, 0.4, 0.8) # light purple - self.col_map['10'] = (0.45, 0.0, 0.45) # purple - - self.col_map['11'] = (1.0, 1.0, 0.4) # light yellow - self.col_map['12'] = (0.9, 0.9, 0.0) # yellow - - self.col_map['13'] = (0.7, 0.7, 0.7) # grey - self.col_map['14'] = (0.0, 0.0, 0.0) # black - - self.fwd = True - self.y_offset = 0 - - pass - - def getDesignList(self): - return self.design - - def getArcList(self): - return self.arcs - - - # Enter a parse tree produced by PigeonParser#script. - def enterScript(self, ctx:PigeonParser.ScriptContext): - # print('enterScript') - pass - - # Exit a parse tree produced by PigeonParser#script. - def exitScript(self, ctx: PigeonParser.ScriptContext): - # print('exitScript') - pass - - - # Enter a parse tree produced by PigeonParser#pigeoncommands. - def enterPigeoncommands(self, ctx:PigeonParser.PigeoncommandsContext): - # print('enterPigeoncommands') - pass - - # Exit a parse tree produced by PigeonParser#pigeoncommands. - def exitPigeoncommands(self, ctx:PigeonParser.PigeoncommandsContext): - # print('exitPigeoncommands') - pass - - # Enter a parse tree produced by PigeonParser#promoter. - def enterPromoter(self, ctx:PigeonParser.PromoterContext): - self.part_type = 'Promoter' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterPromoter') - pass - - # Exit a parse tree produced by PigeonParser#promoter. - def exitPromoter(self, ctx:PigeonParser.PromoterContext): - if(not self.fwd): - self.label_y_offset *= -1 - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts':{'color':self.color, 'label': self.name, - 'label_y_offset':self.label_y_offset, 'label_style':'italic', - 'label_size': 3.5, 'start_pad':4, 'end_pad':4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitPromoter') - pass - - # Enter a parse tree produced by PigeonParser#repressor. - def enterRepressor(self, ctx:PigeonParser.RepressorContext): - self.part_type = 'RBS' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterRepressor') - pass - - # Exit a parse tree produced by PigeonParser#repressor. - def exitRepressor(self, ctx:PigeonParser.RepressorContext): - if (not self.fwd): - self.label_y_offset *= -1 - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4, }} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitRepressor') - pass - - # Enter a parse tree produced by PigeonParser#codingseq. - def enterCodingseq(self, ctx:PigeonParser.CodingseqContext): - self.part_type = 'CDS' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = 0 - # print('enterCodingseq') - pass - - # Exit a parse tree produced by PigeonParser#codingseq. - def exitCodingseq(self, ctx: PigeonParser.CodingseqContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd,'scale': 5, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4, 'arrowhead_height': 0 - }, - } - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitCodingseq') - pass - - # Enter a parse tree produced by PigeonParser#transcription. - def enterTranscription(self, ctx:PigeonParser.TranscriptionContext): - self.part_type = 'Terminator' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterTranscription') - pass - - # Exit a parse tree produced by PigeonParser#transcription. - def exitTranscription(self, ctx:PigeonParser.TranscriptionContext): - if (not self.fwd): - self.label_y_offset *= -1 - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitTranscription') - pass - - # Enter a parse tree produced by PigeonParser#stop. - def enterStop(self, ctx:PigeonParser.StopContext): - self.part_type = 'Spacer' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterStop') - pass - - # Exit a parse tree produced by PigeonParser#stop. - def exitStop(self, ctx:PigeonParser.StopContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitStop') - pass - - # Enter a parse tree produced by PigeonParser#operator. - def enterOperator(self, ctx:PigeonParser.OperatorContext): - self.part_type = 'Operator' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = 0 - # print('enterOperator') - pass - - # Exit a parse tree produced by PigeonParser#operator. - def exitOperator(self, ctx:PigeonParser.OperatorContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitOperator') - pass - - # Enter a parse tree produced by PigeonParser#degredationtag. - def enterDegredationtag(self, ctx:PigeonParser.DegredationtagContext): - self.part_type = 'Degredation' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterDegredationtag') - pass - - # Exit a parse tree produced by PigeonParser#degredationtag. - def exitDegredationtag(self, ctx:PigeonParser.DegredationtagContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitDegredationtag') - pass - - # Enter a parse tree produced by PigeonParser#righttriangle. - def enterRighttriangle(self, ctx:PigeonParser.RighttriangleContext): - self.part_type = 'Triangle' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterRighttriangle') - pass - - # Exit a parse tree produced by PigeonParser#righttriangle. - def exitRighttriangle(self, ctx:PigeonParser.RighttriangleContext): - if (not self.fwd): - self.label_y_offset *= -1 - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitRighttriangle') - pass - - # Enter a parse tree produced by PigeonParser#lefttriangle. - def enterLefttriangle(self, ctx: PigeonParser.LefttriangleContext): - self.part_type = 'Triangle' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - self.fwd = False - # print('enterLefttriangle') - pass - - # Exit a parse tree produced by PigeonParser#lefttriangle. - def exitLefttriangle(self, ctx: PigeonParser.LefttriangleContext): - if (not self.fwd): - self.label_y_offset *= -1 - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitLefttriangle') - pass - - # Enter a parse tree produced by PigeonParser#invert. - def enterInvert(self, ctx: PigeonParser.InvertContext): - self.fwd = False - # self.label_y_offset = 5 # don't necessarily want to always do this - pass - - # Exit a parse tree produced by PigeonParser#invert. - def exitInvert(self, ctx: PigeonParser.InvertContext): - pass - - - # Enter a parse tree produced by PigeonParser#bar. - def enterBar(self, ctx: PigeonParser.BarContext): - self.part_type = 'Bar' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterBar') - pass - - # Exit a parse tree produced by PigeonParser#bar. - def exitBar(self, ctx: PigeonParser.BarContext): - if (not self.fwd): - self.label_y_offset *= -1 - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitBar') - pass - - def enterThree(self, ctx: PigeonParser.BarContext): - self.part_type = '3Overhang' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterThree') - pass - - # Exit a parse tree produced by PigeonParser#bar. - def exitThree(self, ctx: PigeonParser.BarContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4.0, 'end_pad': 4.0, - 'y_extent': 1.5, 'x_extent': 10, 'linewidth': 1.5}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitThree') - pass - - def enterFive(self, ctx: PigeonParser.BarContext): - self.part_type = '5Overhang' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterFive') - pass - - # Exit a parse tree produced by PigeonParser#bar. - def exitFive(self, ctx: PigeonParser.BarContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4.0, 'end_pad': 4.0, - 'y_extent': 1.5, 'x_extent': 10, 'linewidth': 1.5}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitFive') - pass - - def enterScar(self, ctx: PigeonParser.ScarContext): - self.part_type = 'Scar' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - - def exitScar(self, ctx: PigeonParser.ScarContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4.0, 'end_pad': 4.0, - 'y_extent': 1.5, 'x_extent': 10, 'linewidth': 1.5}} - self.design += [self.cur_part] - self.clear_cur_part() - - - def enterGene(self, ctx:PigeonParser.CodingseqContext): - self.part_type = 'CDS' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = 0 - # print('enterGene') - pass - - # Exit a parse tree produced by PigeonParser#codingseq. - def exitGene(self, ctx: PigeonParser.CodingseqContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4, - 'y_extent': 4, 'x_extent': 20}, - } - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitGene') - pass - - def enterFseq(self, ctx:PigeonParser.CodingseqContext): - self.part_type = 'FSequence' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = 0 - # print('enterFseq') - pass - - # Exit a parse tree produced by PigeonParser#codingseq. - def exitFseq(self, ctx: PigeonParser.CodingseqContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': 0, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4, - 'y_extent': 5, 'x_extent': 40}, - } - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitFseq') - pass - - - def enterZring(self, ctx:PigeonParser.DegredationtagContext): - self.part_type = 'ZRing' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterZring') - pass - - # Exit a parse tree produced by PigeonParser#degredationtag. - def exitZring(self, ctx:PigeonParser.DegredationtagContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitZring') - pass - - def enterXbar(self, ctx: PigeonParser.BarContext): - self.part_type = 'XBar' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - print('enterBar') - pass - - # Exit a parse tree produced by PigeonParser#bar. - def exitXbar(self, ctx: PigeonParser.BarContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4}} - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitBar') - pass - - def enterBox(self, ctx:PigeonParser.CodingseqContext): - self.part_type = 'CDS' - self.color = (0.0, 0.0, 0.0) - self.label_y_offset = -8 - # print('enterBox') - pass - - # Exit a parse tree produced by PigeonParser#codingseq. - def exitBox(self, ctx: PigeonParser.CodingseqContext): - self.cur_part = {'type': self.part_type, 'name': self.name, 'fwd': self.fwd, - 'opts': {'color': self.color, 'label': self.name, - 'label_y_offset': self.label_y_offset, 'label_style': 'italic', - 'label_size': 3.5, 'start_pad': 4, 'end_pad': 4, - 'arrowhead_height': 0, 'arrowhead_length': 0, - 'x_extent': 15, 'y_extent': 4}, - } - self.design += [self.cur_part] - self.clear_cur_part() - # print('exitBox') - pass - - def exitVector(self, ctx: PigeonParser.VectorContext): - self._has_vector = True - self._vector_label = self.name - - # Enter a parse tree produced by PigeonParser#label. - def enterLabel(self, ctx: PigeonParser.LabelContext): - print('enterLabel') - self.name = ctx.getText() - - # NORMAL REPRESSION ARCS - if(self.gettingFromPart and self.cur_arc['type'] == 'Repression'): - # print('REPRESSION ARC - GETTING LABELS') - for i in self.design: - if (i['name'] == self.name): - self.cur_arc['from_part'] = i - self.gettingFromPart = False - else: - for i in self.design: - if (i['name'] == self.name): - self.cur_arc['to_part'] = i - - # ACTIVATION ARCS - if (self.gettingFromPart and self.cur_arc['type'] == 'Activation'): - # print('ACTIVATION ARC - GETTING LABELS') - + else: + for i in self.design: + if i["name"] == self.name: + self.cur_arc["to_part"] = i + + # ACTIVATION ARCS + if self.gettingFromPart and self.cur_arc["type"] == "Activation": + # print('ACTIVATION ARC - GETTING LABELS') + + for i in self.design: + if i["name"] == self.name: + self.cur_arc["from_part"] = i + self.glyphToGlyphInd = True + print( + "from part name: " + self.cur_arc["from_part"]["name"] + ) + if not self.glyphToGlyphInd: + self.ind_name = self.name + self.gettingFromPart = False + else: + for i in self.design: + if i["name"] == self.name: + self.cur_arc["to_part"] = i + if ( + not self.glyphToGlyphInd + and self.cur_arc["type"] == "Activation" + ): + self.cur_arc["from_part"] = self.cur_arc["to_part"] + self.cur_arc[ + "type" + ] = "PointingActivation" # set the new type on the way out + self.cur_arc["opts"]["arc_label_name"] = self.ind_name + + # REPRESSION ARC TO REPRESSION ARC + if self.cur_arc["type"] == "RepToRep": + # print('REPRESSION ARC TO REPRESSION ARC - GETTING LABELS') + + if not self.gettingFromPart: + self.rep2_name = self.name + self.gettingFromPart = True + self.haveFromPart = False + elif self.gettingFromPart and not self.haveFromPart: for i in self.design: - if (i['name'] == self.name): - self.cur_arc['from_part'] = i - self.glyphToGlyphInd = True - print('from part name: ' + self.cur_arc['from_part']['name']) - if(not self.glyphToGlyphInd): - self.ind_name = self.name - self.gettingFromPart = False + if i["name"] == self.name: + self.cur_arc["from_part"] = i + self.haveFromPart = True else: for i in self.design: - if (i['name'] == self.name): - self.cur_arc['to_part'] = i - if (not self.glyphToGlyphInd and self.cur_arc['type'] == 'Activation'): - self.cur_arc['from_part'] = self.cur_arc['to_part'] - self.cur_arc['type'] = 'PointingActivation' # set the new type on the way out - self.cur_arc['opts']['arc_label_name'] = self.ind_name - - - - # REPRESSION ARC TO REPRESSION ARC - if(self.cur_arc['type'] == 'RepToRep'): - # print('REPRESSION ARC TO REPRESSION ARC - GETTING LABELS') - - if (not self.gettingFromPart): - self.rep2_name = self.name - self.gettingFromPart = True - self.haveFromPart = False - elif (self.gettingFromPart and not self.haveFromPart): - for i in self.design: - if (i['name'] == self.name): - self.cur_arc['from_part'] = i - self.haveFromPart = True - else: - for i in self.design: - if (i['name'] == self.name): - self.cur_arc['to_part'] = i - # print('to part name: ' + self.cur_arc['to_part']['name']) - self.cur_arc['opts']['arc_label_name'] = self.rep2_name - - - pass - - # Exit a parse tree produced by PigeonParser#label. - def exitLabel(self, ctx: PigeonParser.LabelContext): - print('exitLabel') - pass - - # Enter a parse tree produced by PigeonParser#color. - def enterColor(self, ctx: PigeonParser.ColorContext): - # print('enterColor') - self.color = self.col_map[ctx.getText()] - pass - - # Exit a parse tree produced by PigeonParser#color. - def exitColor(self, ctx: PigeonParser.ColorContext): - # print('exitColor') - pass - - # Enter a parse tree produced by PigeonParser#ignorecolor. - def enterIgnorecolor(self, ctx: PigeonParser.IgnorecolorContext): - self.color = (0.0, 0.0, 0.0) - self.name = '' - # print('enterIgnorecolor') - pass - - # Exit a parse tree produced by PigeonParser#ignorecolor. - def exitIgnorecolor(self, ctx: PigeonParser.IgnorecolorContext): - # print('exitIgnorecolor') - pass - - # Enter a parse tree produced by PigeonParser#arccommands. - def enterArccommands(self, ctx: PigeonParser.ArccommandsContext): - self.clear_cur_arc() - print('enterArccommands') - pass - - # Exit a parse tree produced by PigeonParser#arccommands. - def exitArccommands(self, ctx: PigeonParser.ArccommandsContext): - # if ((self.cur_arc['type'] != 'Activation') and ((self.cur_arc['from_part']['type'] != 'CDS') or (self.cur_arc['to_part']['type'] != 'Promoter'))): - # self.cur_arc = {} - # print("ERROR: Invalid Arc. Arcs must be drawn from a CDS (c) to a Promoter (p)") - # else: - self.arcs += [self.cur_arc] - self.clear_cur_arc() - print('exitArccommands') - pass - - def enterRep(self, ctx:PigeonParser.RepContext): - print('enterRep') - self.cur_arc['type'] = 'Repression' - self.gettingFromPart = True - pass - - - def exitRep(self, ctx:PigeonParser.RepContext): - print('exitRep') - pass - - def enterInd(self, ctx:PigeonParser.IndContext): - print('enterInd') - self.cur_arc['type'] = 'Activation' - self.gettingFromPart = True - - pass - - def exitInd(self, ctx:PigeonParser.IndContext): - print('exitInd') - pass - - def enterRep2(self, ctx:PigeonParser.Rep2Context): - print('enterRep2') - self.cur_arc['type'] = 'RepToRep' - self.gettingFromPart = False - pass - - def exitRep2(self, ctx:PigeonParser.Rep2Context): - print('exitRep2') - pass - - + if i["name"] == self.name: + self.cur_arc["to_part"] = i + # print('to part name: ' + self.cur_arc['to_part']['name']) + self.cur_arc["opts"]["arc_label_name"] = self.rep2_name + + pass + + # Exit a parse tree produced by PigeonParser#label. + def exitLabel(self, ctx: PigeonParser.LabelContext): + print("exitLabel") + pass + + # Enter a parse tree produced by PigeonParser#color. + def enterColor(self, ctx: PigeonParser.ColorContext): + # print('enterColor') + self.color = self.col_map[ctx.getText()] + pass + + # Exit a parse tree produced by PigeonParser#color. + def exitColor(self, ctx: PigeonParser.ColorContext): + # print('exitColor') + pass + + # Enter a parse tree produced by PigeonParser#ignorecolor. + def enterIgnorecolor(self, ctx: PigeonParser.IgnorecolorContext): + self.color = (0.0, 0.0, 0.0) + self.name = "" + # print('enterIgnorecolor') + pass + + # Exit a parse tree produced by PigeonParser#ignorecolor. + def exitIgnorecolor(self, ctx: PigeonParser.IgnorecolorContext): + # print('exitIgnorecolor') + pass + + # Enter a parse tree produced by PigeonParser#arccommands. + def enterArccommands(self, ctx: PigeonParser.ArccommandsContext): + self.clear_cur_arc() + print("enterArccommands") + pass + + # Exit a parse tree produced by PigeonParser#arccommands. + def exitArccommands(self, ctx: PigeonParser.ArccommandsContext): + # if ((self.cur_arc['type'] != 'Activation') and ((self.cur_arc['from_part']['type'] != 'CDS') or (self.cur_arc['to_part']['type'] != 'Promoter'))): + # self.cur_arc = {} + # print("ERROR: Invalid Arc. Arcs must be drawn from a CDS (c) to a Promoter (p)") + # else: + self.arcs += [self.cur_arc] + self.clear_cur_arc() + print("exitArccommands") + pass + + def enterRep(self, ctx: PigeonParser.RepContext): + print("enterRep") + self.cur_arc["type"] = "Repression" + self.gettingFromPart = True + pass + + def exitRep(self, ctx: PigeonParser.RepContext): + print("exitRep") + pass + + def enterInd(self, ctx: PigeonParser.IndContext): + print("enterInd") + self.cur_arc["type"] = "Activation" + self.gettingFromPart = True + + pass + + def exitInd(self, ctx: PigeonParser.IndContext): + print("exitInd") + pass + + def enterRep2(self, ctx: PigeonParser.Rep2Context): + print("enterRep2") + self.cur_arc["type"] = "RepToRep" + self.gettingFromPart = False + pass + + def exitRep2(self, ctx: PigeonParser.Rep2Context): + print("exitRep2") + pass diff --git a/Pigeon.py b/Pigeon.py index 277439d..ad0f946 100644 --- a/Pigeon.py +++ b/Pigeon.py @@ -10,11 +10,11 @@ # class to maintain pigeon script parsing and image generation class Pigeon(object): - format = '' + format = "" fig = plt.figure() # if no image format is specified when you instantiate the class it will use the default svg format - def __init__(self, format='svg'): + def __init__(self, format="svg"): self.format = format pass @@ -36,24 +36,31 @@ def parseAndGenerateImage(self, script_string): design = HtmlPigeonListener.getDesignList(htmlPigeon) arcs = HtmlPigeonListener.getArcList(htmlPigeon) - fig = plt.figure(figsize=(design.__len__()/3, 2)) + fig = plt.figure(figsize=(design.__len__() / 3, 2)) gs = gridspec.GridSpec(1, 1) axis = plt.subplot(gs[0]) print("Deisgn Length: " + str(design.__len__())) print("Arcs Length: " + str(arcs.__len__())) - start, end = dr.renderDNA(axis, design, part_renderers, regs = arcs, reg_renderers=dr.std_reg_renderers(), plot_vector=htmlPigeon.has_vector, vector_label=htmlPigeon.vector_label) + start, end = dr.renderDNA( + axis, + design, + part_renderers, + regs=arcs, + reg_renderers=dr.std_reg_renderers(), + plot_vector=htmlPigeon.has_vector, + vector_label=htmlPigeon.vector_label, + ) axis.set_xlim([start, end]) axis.set_ylim([-(30 + design.__len__()), (30 + design.__len__())]) - axis.set_aspect('equal') - axis.axis('off') + axis.set_aspect("equal") + axis.axis("off") self.fig = fig pass # Saves Pigeon's fig using the function input values for name and location def save(self, location, name): - save_path = location + name + '.' + self.format - self.fig.savefig(save_path, dpi=300) # Save as png file + save_path = location + name + "." + self.format + self.fig.savefig(save_path, dpi=300) # Save as png file pass - diff --git a/all_parts.svg b/all_parts.svg new file mode 100644 index 0000000..96c05e1 --- /dev/null +++ b/all_parts.svg @@ -0,0 +1,619 @@ + + + + + + + + + 2021-02-15T17:29:16.219000 + image/svg+xml + + + Matplotlib v3.3.4, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pigeon.g4 b/antlr_pigeon/Pigeon.g4 similarity index 98% rename from Pigeon.g4 rename to antlr_pigeon/Pigeon.g4 index 4e8f286..121fe1e 100644 --- a/Pigeon.g4 +++ b/antlr_pigeon/Pigeon.g4 @@ -79,7 +79,7 @@ arccommands rep : label WS 'rep' WS label NL+; rep2: label WS 'rep' WS label'-'label NL+; -ind : label WS 'ind' WS label NL+; +ind : label WS 'ing' WS label NL+; /* diff --git a/antlr_pigeon/Pigeon.interp b/antlr_pigeon/Pigeon.interp index 4cb9771..ced724f 100644 --- a/antlr_pigeon/Pigeon.interp +++ b/antlr_pigeon/Pigeon.interp @@ -22,7 +22,7 @@ null 'nl' 'rep' '-' -'ind' +'ing' null null null diff --git a/antlr_pigeon/Pigeon.tokens b/antlr_pigeon/Pigeon.tokens index fe6077a..6df72f2 100644 --- a/antlr_pigeon/Pigeon.tokens +++ b/antlr_pigeon/Pigeon.tokens @@ -48,4 +48,4 @@ NL=28 'nl'=20 'rep'=21 '-'=22 -'ind'=23 +'ing'=23 diff --git a/antlr_pigeon/PigeonLexer.interp b/antlr_pigeon/PigeonLexer.interp index 499efbd..4fd4ea4 100644 --- a/antlr_pigeon/PigeonLexer.interp +++ b/antlr_pigeon/PigeonLexer.interp @@ -22,7 +22,7 @@ null 'nl' 'rep' '-' -'ind' +'ing' null null null @@ -98,4 +98,4 @@ mode names: DEFAULT_MODE atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 30, 145, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 7, 25, 113, 10, 25, 12, 25, 14, 25, 116, 11, 25, 3, 26, 6, 26, 119, 10, 26, 13, 26, 14, 26, 120, 3, 27, 3, 27, 7, 27, 125, 10, 27, 12, 27, 14, 27, 128, 11, 27, 3, 27, 3, 27, 3, 28, 6, 28, 133, 10, 28, 13, 28, 14, 28, 134, 3, 29, 5, 29, 138, 10, 29, 3, 29, 3, 29, 6, 29, 142, 10, 29, 13, 29, 14, 29, 143, 2, 2, 30, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 3, 2, 6, 7, 2, 47, 47, 67, 93, 95, 95, 97, 97, 99, 124, 8, 2, 47, 47, 50, 59, 67, 93, 95, 95, 97, 97, 99, 124, 3, 2, 50, 59, 4, 2, 12, 12, 15, 15, 2, 151, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 3, 59, 3, 2, 2, 2, 5, 61, 3, 2, 2, 2, 7, 63, 3, 2, 2, 2, 9, 65, 3, 2, 2, 2, 11, 67, 3, 2, 2, 2, 13, 69, 3, 2, 2, 2, 15, 71, 3, 2, 2, 2, 17, 73, 3, 2, 2, 2, 19, 75, 3, 2, 2, 2, 21, 77, 3, 2, 2, 2, 23, 79, 3, 2, 2, 2, 25, 81, 3, 2, 2, 2, 27, 83, 3, 2, 2, 2, 29, 85, 3, 2, 2, 2, 31, 87, 3, 2, 2, 2, 33, 89, 3, 2, 2, 2, 35, 91, 3, 2, 2, 2, 37, 93, 3, 2, 2, 2, 39, 95, 3, 2, 2, 2, 41, 97, 3, 2, 2, 2, 43, 100, 3, 2, 2, 2, 45, 104, 3, 2, 2, 2, 47, 106, 3, 2, 2, 2, 49, 110, 3, 2, 2, 2, 51, 118, 3, 2, 2, 2, 53, 122, 3, 2, 2, 2, 55, 132, 3, 2, 2, 2, 57, 141, 3, 2, 2, 2, 59, 60, 7, 114, 2, 2, 60, 4, 3, 2, 2, 2, 61, 62, 7, 116, 2, 2, 62, 6, 3, 2, 2, 2, 63, 64, 7, 101, 2, 2, 64, 8, 3, 2, 2, 2, 65, 66, 7, 118, 2, 2, 66, 10, 3, 2, 2, 2, 67, 68, 7, 105, 2, 2, 68, 12, 3, 2, 2, 2, 69, 70, 7, 104, 2, 2, 70, 14, 3, 2, 2, 2, 71, 72, 7, 117, 2, 2, 72, 16, 3, 2, 2, 2, 73, 74, 7, 113, 2, 2, 74, 18, 3, 2, 2, 2, 75, 76, 7, 102, 2, 2, 76, 20, 3, 2, 2, 2, 77, 78, 7, 64, 2, 2, 78, 22, 3, 2, 2, 2, 79, 80, 7, 62, 2, 2, 80, 24, 3, 2, 2, 2, 81, 82, 7, 126, 2, 2, 82, 26, 3, 2, 2, 2, 83, 84, 7, 53, 2, 2, 84, 28, 3, 2, 2, 2, 85, 86, 7, 55, 2, 2, 86, 30, 3, 2, 2, 2, 87, 88, 7, 124, 2, 2, 88, 32, 3, 2, 2, 2, 89, 90, 7, 122, 2, 2, 90, 34, 3, 2, 2, 2, 91, 92, 7, 65, 2, 2, 92, 36, 3, 2, 2, 2, 93, 94, 7, 63, 2, 2, 94, 38, 3, 2, 2, 2, 95, 96, 7, 120, 2, 2, 96, 40, 3, 2, 2, 2, 97, 98, 7, 112, 2, 2, 98, 99, 7, 110, 2, 2, 99, 42, 3, 2, 2, 2, 100, 101, 7, 116, 2, 2, 101, 102, 7, 103, 2, 2, 102, 103, 7, 114, 2, 2, 103, 44, 3, 2, 2, 2, 104, 105, 7, 47, 2, 2, 105, 46, 3, 2, 2, 2, 106, 107, 7, 107, 2, 2, 107, 108, 7, 112, 2, 2, 108, 109, 7, 102, 2, 2, 109, 48, 3, 2, 2, 2, 110, 114, 9, 2, 2, 2, 111, 113, 9, 3, 2, 2, 112, 111, 3, 2, 2, 2, 113, 116, 3, 2, 2, 2, 114, 112, 3, 2, 2, 2, 114, 115, 3, 2, 2, 2, 115, 50, 3, 2, 2, 2, 116, 114, 3, 2, 2, 2, 117, 119, 9, 4, 2, 2, 118, 117, 3, 2, 2, 2, 119, 120, 3, 2, 2, 2, 120, 118, 3, 2, 2, 2, 120, 121, 3, 2, 2, 2, 121, 52, 3, 2, 2, 2, 122, 126, 7, 37, 2, 2, 123, 125, 10, 5, 2, 2, 124, 123, 3, 2, 2, 2, 125, 128, 3, 2, 2, 2, 126, 124, 3, 2, 2, 2, 126, 127, 3, 2, 2, 2, 127, 129, 3, 2, 2, 2, 128, 126, 3, 2, 2, 2, 129, 130, 8, 27, 2, 2, 130, 54, 3, 2, 2, 2, 131, 133, 7, 34, 2, 2, 132, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 132, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 135, 56, 3, 2, 2, 2, 136, 138, 7, 15, 2, 2, 137, 136, 3, 2, 2, 2, 137, 138, 3, 2, 2, 2, 138, 139, 3, 2, 2, 2, 139, 142, 7, 12, 2, 2, 140, 142, 7, 15, 2, 2, 141, 137, 3, 2, 2, 2, 141, 140, 3, 2, 2, 2, 142, 143, 3, 2, 2, 2, 143, 141, 3, 2, 2, 2, 143, 144, 3, 2, 2, 2, 144, 58, 3, 2, 2, 2, 10, 2, 114, 120, 126, 134, 137, 141, 143, 3, 8, 2, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 30, 145, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 7, 25, 113, 10, 25, 12, 25, 14, 25, 116, 11, 25, 3, 26, 6, 26, 119, 10, 26, 13, 26, 14, 26, 120, 3, 27, 3, 27, 7, 27, 125, 10, 27, 12, 27, 14, 27, 128, 11, 27, 3, 27, 3, 27, 3, 28, 6, 28, 133, 10, 28, 13, 28, 14, 28, 134, 3, 29, 5, 29, 138, 10, 29, 3, 29, 3, 29, 6, 29, 142, 10, 29, 13, 29, 14, 29, 143, 2, 2, 30, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 3, 2, 6, 7, 2, 47, 47, 67, 93, 95, 95, 97, 97, 99, 124, 8, 2, 47, 47, 50, 59, 67, 93, 95, 95, 97, 97, 99, 124, 3, 2, 50, 59, 4, 2, 12, 12, 15, 15, 2, 151, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 3, 59, 3, 2, 2, 2, 5, 61, 3, 2, 2, 2, 7, 63, 3, 2, 2, 2, 9, 65, 3, 2, 2, 2, 11, 67, 3, 2, 2, 2, 13, 69, 3, 2, 2, 2, 15, 71, 3, 2, 2, 2, 17, 73, 3, 2, 2, 2, 19, 75, 3, 2, 2, 2, 21, 77, 3, 2, 2, 2, 23, 79, 3, 2, 2, 2, 25, 81, 3, 2, 2, 2, 27, 83, 3, 2, 2, 2, 29, 85, 3, 2, 2, 2, 31, 87, 3, 2, 2, 2, 33, 89, 3, 2, 2, 2, 35, 91, 3, 2, 2, 2, 37, 93, 3, 2, 2, 2, 39, 95, 3, 2, 2, 2, 41, 97, 3, 2, 2, 2, 43, 100, 3, 2, 2, 2, 45, 104, 3, 2, 2, 2, 47, 106, 3, 2, 2, 2, 49, 110, 3, 2, 2, 2, 51, 118, 3, 2, 2, 2, 53, 122, 3, 2, 2, 2, 55, 132, 3, 2, 2, 2, 57, 141, 3, 2, 2, 2, 59, 60, 7, 114, 2, 2, 60, 4, 3, 2, 2, 2, 61, 62, 7, 116, 2, 2, 62, 6, 3, 2, 2, 2, 63, 64, 7, 101, 2, 2, 64, 8, 3, 2, 2, 2, 65, 66, 7, 118, 2, 2, 66, 10, 3, 2, 2, 2, 67, 68, 7, 105, 2, 2, 68, 12, 3, 2, 2, 2, 69, 70, 7, 104, 2, 2, 70, 14, 3, 2, 2, 2, 71, 72, 7, 117, 2, 2, 72, 16, 3, 2, 2, 2, 73, 74, 7, 113, 2, 2, 74, 18, 3, 2, 2, 2, 75, 76, 7, 102, 2, 2, 76, 20, 3, 2, 2, 2, 77, 78, 7, 64, 2, 2, 78, 22, 3, 2, 2, 2, 79, 80, 7, 62, 2, 2, 80, 24, 3, 2, 2, 2, 81, 82, 7, 126, 2, 2, 82, 26, 3, 2, 2, 2, 83, 84, 7, 53, 2, 2, 84, 28, 3, 2, 2, 2, 85, 86, 7, 55, 2, 2, 86, 30, 3, 2, 2, 2, 87, 88, 7, 124, 2, 2, 88, 32, 3, 2, 2, 2, 89, 90, 7, 122, 2, 2, 90, 34, 3, 2, 2, 2, 91, 92, 7, 65, 2, 2, 92, 36, 3, 2, 2, 2, 93, 94, 7, 63, 2, 2, 94, 38, 3, 2, 2, 2, 95, 96, 7, 120, 2, 2, 96, 40, 3, 2, 2, 2, 97, 98, 7, 112, 2, 2, 98, 99, 7, 110, 2, 2, 99, 42, 3, 2, 2, 2, 100, 101, 7, 116, 2, 2, 101, 102, 7, 103, 2, 2, 102, 103, 7, 114, 2, 2, 103, 44, 3, 2, 2, 2, 104, 105, 7, 47, 2, 2, 105, 46, 3, 2, 2, 2, 106, 107, 7, 107, 2, 2, 107, 108, 7, 112, 2, 2, 108, 109, 7, 105, 2, 2, 109, 48, 3, 2, 2, 2, 110, 114, 9, 2, 2, 2, 111, 113, 9, 3, 2, 2, 112, 111, 3, 2, 2, 2, 113, 116, 3, 2, 2, 2, 114, 112, 3, 2, 2, 2, 114, 115, 3, 2, 2, 2, 115, 50, 3, 2, 2, 2, 116, 114, 3, 2, 2, 2, 117, 119, 9, 4, 2, 2, 118, 117, 3, 2, 2, 2, 119, 120, 3, 2, 2, 2, 120, 118, 3, 2, 2, 2, 120, 121, 3, 2, 2, 2, 121, 52, 3, 2, 2, 2, 122, 126, 7, 37, 2, 2, 123, 125, 10, 5, 2, 2, 124, 123, 3, 2, 2, 2, 125, 128, 3, 2, 2, 2, 126, 124, 3, 2, 2, 2, 126, 127, 3, 2, 2, 2, 127, 129, 3, 2, 2, 2, 128, 126, 3, 2, 2, 2, 129, 130, 8, 27, 2, 2, 130, 54, 3, 2, 2, 2, 131, 133, 7, 34, 2, 2, 132, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 132, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 135, 56, 3, 2, 2, 2, 136, 138, 7, 15, 2, 2, 137, 136, 3, 2, 2, 2, 137, 138, 3, 2, 2, 2, 138, 139, 3, 2, 2, 2, 139, 142, 7, 12, 2, 2, 140, 142, 7, 15, 2, 2, 141, 137, 3, 2, 2, 2, 141, 140, 3, 2, 2, 2, 142, 143, 3, 2, 2, 2, 143, 141, 3, 2, 2, 2, 143, 144, 3, 2, 2, 2, 144, 58, 3, 2, 2, 2, 10, 2, 114, 120, 126, 134, 137, 141, 143, 3, 8, 2, 2] \ No newline at end of file diff --git a/antlr_pigeon/PigeonLexer.py b/antlr_pigeon/PigeonLexer.py index 3feb7b0..6e7f6a9 100644 --- a/antlr_pigeon/PigeonLexer.py +++ b/antlr_pigeon/PigeonLexer.py @@ -1,4 +1,4 @@ -# Generated from /Users/krishna/Documents/GitHub/pidgeon/Pigeon.g4 by ANTLR 4.8 +# Generated from Pigeon.g4 by ANTLR 4.9 from antlr4 import * from io import StringIO from typing.io import TextIO @@ -47,7 +47,7 @@ def serializedATN(): buf.write("\2\2WX\7|\2\2X \3\2\2\2YZ\7z\2\2Z\"\3\2\2\2[\\\7A\2\2") buf.write("\\$\3\2\2\2]^\7?\2\2^&\3\2\2\2_`\7x\2\2`(\3\2\2\2ab\7") buf.write("p\2\2bc\7n\2\2c*\3\2\2\2de\7t\2\2ef\7g\2\2fg\7r\2\2g,") - buf.write("\3\2\2\2hi\7/\2\2i.\3\2\2\2jk\7k\2\2kl\7p\2\2lm\7f\2\2") + buf.write("\3\2\2\2hi\7/\2\2i.\3\2\2\2jk\7k\2\2kl\7p\2\2lm\7i\2\2") buf.write("m\60\3\2\2\2nr\t\2\2\2oq\t\3\2\2po\3\2\2\2qt\3\2\2\2r") buf.write("p\3\2\2\2rs\3\2\2\2s\62\3\2\2\2tr\3\2\2\2uw\t\4\2\2vu") buf.write("\3\2\2\2wx\3\2\2\2xv\3\2\2\2xy\3\2\2\2y\64\3\2\2\2z~\7") @@ -106,7 +106,7 @@ class PigeonLexer(Lexer): literalNames = [ "", "'p'", "'r'", "'c'", "'t'", "'g'", "'f'", "'s'", "'o'", "'d'", "'>'", "'<'", "'|'", "'3'", "'5'", "'z'", "'x'", "'?'", "'='", - "'v'", "'nl'", "'rep'", "'-'", "'ind'" ] + "'v'", "'nl'", "'rep'", "'-'", "'ing'" ] symbolicNames = [ "", "ID", "INT", "LINE_COMMENT", "WS", "NL" ] @@ -121,7 +121,7 @@ class PigeonLexer(Lexer): def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) - self.checkVersion("4.8") + self.checkVersion("4.9") self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) self._actions = None self._predicates = None diff --git a/antlr_pigeon/PigeonLexer.tokens b/antlr_pigeon/PigeonLexer.tokens index fe6077a..6df72f2 100644 --- a/antlr_pigeon/PigeonLexer.tokens +++ b/antlr_pigeon/PigeonLexer.tokens @@ -48,4 +48,4 @@ NL=28 'nl'=20 'rep'=21 '-'=22 -'ind'=23 +'ing'=23 diff --git a/antlr_pigeon/PigeonListener.py b/antlr_pigeon/PigeonListener.py index 3b05849..0807e22 100644 --- a/antlr_pigeon/PigeonListener.py +++ b/antlr_pigeon/PigeonListener.py @@ -1,4 +1,4 @@ -# Generated from /Users/krishna/Documents/GitHub/pidgeon/Pigeon.g4 by ANTLR 4.8 +# Generated from Pigeon.g4 by ANTLR 4.9 from antlr4 import * if __name__ is not None and "." in __name__: from .PigeonParser import PigeonParser diff --git a/antlr_pigeon/PigeonParser.py b/antlr_pigeon/PigeonParser.py index 543e75e..de0c336 100644 --- a/antlr_pigeon/PigeonParser.py +++ b/antlr_pigeon/PigeonParser.py @@ -1,4 +1,4 @@ -# Generated from /Users/krishna/Documents/GitHub/pidgeon/Pigeon.g4 by ANTLR 4.8 +# Generated from Pigeon.g4 by ANTLR 4.9 # encoding: utf-8 from antlr4 import * from io import StringIO @@ -447,7 +447,7 @@ class PigeonParser ( Parser ): literalNames = [ "", "'p'", "'r'", "'c'", "'t'", "'g'", "'f'", "'s'", "'o'", "'d'", "'>'", "'<'", "'|'", "'3'", "'5'", "'z'", "'x'", "'?'", "'='", "'v'", "'nl'", "'rep'", - "'-'", "'ind'" ] + "'-'", "'ing'" ] symbolicNames = [ "", "", "", "", "", "", "", "", @@ -527,7 +527,7 @@ class PigeonParser ( Parser ): def __init__(self, input:TokenStream, output:TextIO = sys.stdout): super().__init__(input, output) - self.checkVersion("4.8") + self.checkVersion("4.9") self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) self._predicates = None @@ -568,12 +568,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitScript" ): listener.exitScript(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitScript" ): - return visitor.visitScript(self) - else: - return visitor.visitChildren(self) - @@ -720,12 +714,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitPigeoncommands" ): listener.exitPigeoncommands(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitPigeoncommands" ): - return visitor.visitPigeoncommands(self) - else: - return visitor.visitChildren(self) - @@ -906,12 +894,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitPromoter" ): listener.exitPromoter(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitPromoter" ): - return visitor.visitPromoter(self) - else: - return visitor.visitChildren(self) - @@ -1052,12 +1034,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitRepressor" ): listener.exitRepressor(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitRepressor" ): - return visitor.visitRepressor(self) - else: - return visitor.visitChildren(self) - @@ -1198,12 +1174,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitCodingseq" ): listener.exitCodingseq(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitCodingseq" ): - return visitor.visitCodingseq(self) - else: - return visitor.visitChildren(self) - @@ -1344,12 +1314,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitTranscription" ): listener.exitTranscription(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitTranscription" ): - return visitor.visitTranscription(self) - else: - return visitor.visitChildren(self) - @@ -1490,12 +1454,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitGene" ): listener.exitGene(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitGene" ): - return visitor.visitGene(self) - else: - return visitor.visitChildren(self) - @@ -1636,12 +1594,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitFseq" ): listener.exitFseq(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitFseq" ): - return visitor.visitFseq(self) - else: - return visitor.visitChildren(self) - @@ -1778,12 +1730,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitStop" ): listener.exitStop(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitStop" ): - return visitor.visitStop(self) - else: - return visitor.visitChildren(self) - @@ -1914,12 +1860,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitOperator" ): listener.exitOperator(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitOperator" ): - return visitor.visitOperator(self) - else: - return visitor.visitChildren(self) - @@ -2050,12 +1990,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitDegredationtag" ): listener.exitDegredationtag(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitDegredationtag" ): - return visitor.visitDegredationtag(self) - else: - return visitor.visitChildren(self) - @@ -2186,12 +2120,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitRighttriangle" ): listener.exitRighttriangle(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitRighttriangle" ): - return visitor.visitRighttriangle(self) - else: - return visitor.visitChildren(self) - @@ -2322,12 +2250,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitLefttriangle" ): listener.exitLefttriangle(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitLefttriangle" ): - return visitor.visitLefttriangle(self) - else: - return visitor.visitChildren(self) - @@ -2458,12 +2380,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitBar" ): listener.exitBar(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitBar" ): - return visitor.visitBar(self) - else: - return visitor.visitChildren(self) - @@ -2598,12 +2514,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitThree" ): listener.exitThree(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitThree" ): - return visitor.visitThree(self) - else: - return visitor.visitChildren(self) - @@ -2746,12 +2656,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitFive" ): listener.exitFive(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitFive" ): - return visitor.visitFive(self) - else: - return visitor.visitChildren(self) - @@ -2894,12 +2798,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitZring" ): listener.exitZring(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitZring" ): - return visitor.visitZring(self) - else: - return visitor.visitChildren(self) - @@ -3038,12 +2936,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitXbar" ): listener.exitXbar(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitXbar" ): - return visitor.visitXbar(self) - else: - return visitor.visitChildren(self) - @@ -3174,12 +3066,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitBox" ): listener.exitBox(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitBox" ): - return visitor.visitBox(self) - else: - return visitor.visitChildren(self) - @@ -3310,12 +3196,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitScar" ): listener.exitScar(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitScar" ): - return visitor.visitScar(self) - else: - return visitor.visitChildren(self) - @@ -3435,12 +3315,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitVector" ): listener.exitVector(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitVector" ): - return visitor.visitVector(self) - else: - return visitor.visitChildren(self) - @@ -3508,12 +3382,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitInvert" ): listener.exitInvert(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitInvert" ): - return visitor.visitInvert(self) - else: - return visitor.visitChildren(self) - @@ -3554,12 +3422,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitColor" ): listener.exitColor(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitColor" ): - return visitor.visitColor(self) - else: - return visitor.visitChildren(self) - @@ -3616,12 +3478,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitLabel" ): listener.exitLabel(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitLabel" ): - return visitor.visitLabel(self) - else: - return visitor.visitChildren(self) - @@ -3726,12 +3582,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitIgnorecolor" ): listener.exitIgnorecolor(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitIgnorecolor" ): - return visitor.visitIgnorecolor(self) - else: - return visitor.visitChildren(self) - @@ -3770,12 +3620,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitCommands" ): listener.exitCommands(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitCommands" ): - return visitor.visitCommands(self) - else: - return visitor.visitChildren(self) - @@ -3831,12 +3675,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitArccommands" ): listener.exitArccommands(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitArccommands" ): - return visitor.visitArccommands(self) - else: - return visitor.visitChildren(self) - @@ -3912,12 +3750,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitRep" ): listener.exitRep(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitRep" ): - return visitor.visitRep(self) - else: - return visitor.visitChildren(self) - @@ -3995,12 +3827,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitRep2" ): listener.exitRep2(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitRep2" ): - return visitor.visitRep2(self) - else: - return visitor.visitChildren(self) - @@ -4082,12 +3908,6 @@ def exitRule(self, listener:ParseTreeListener): if hasattr( listener, "exitInd" ): listener.exitInd(self) - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitInd" ): - return visitor.visitInd(self) - else: - return visitor.visitChildren(self) - diff --git a/antlr_pigeon/PigeonVisitor.py b/antlr_pigeon/PigeonVisitor.py index 2a139bb..0beedac 100644 --- a/antlr_pigeon/PigeonVisitor.py +++ b/antlr_pigeon/PigeonVisitor.py @@ -1,5 +1,6 @@ # Generated from /Users/krishna/Documents/GitHub/pidgeon/Pigeon.g4 by ANTLR 4.8 from antlr4 import * + if __name__ is not None and "." in __name__: from .PigeonParser import PigeonParser else: @@ -7,157 +8,128 @@ # This class defines a complete generic visitor for a parse tree produced by PigeonParser. + class PigeonVisitor(ParseTreeVisitor): # Visit a parse tree produced by PigeonParser#script. - def visitScript(self, ctx:PigeonParser.ScriptContext): + def visitScript(self, ctx: PigeonParser.ScriptContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#pigeoncommands. - def visitPigeoncommands(self, ctx:PigeonParser.PigeoncommandsContext): + def visitPigeoncommands(self, ctx: PigeonParser.PigeoncommandsContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#promoter. - def visitPromoter(self, ctx:PigeonParser.PromoterContext): + def visitPromoter(self, ctx: PigeonParser.PromoterContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#repressor. - def visitRepressor(self, ctx:PigeonParser.RepressorContext): + def visitRepressor(self, ctx: PigeonParser.RepressorContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#codingseq. - def visitCodingseq(self, ctx:PigeonParser.CodingseqContext): + def visitCodingseq(self, ctx: PigeonParser.CodingseqContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#transcription. - def visitTranscription(self, ctx:PigeonParser.TranscriptionContext): + def visitTranscription(self, ctx: PigeonParser.TranscriptionContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#gene. - def visitGene(self, ctx:PigeonParser.GeneContext): + def visitGene(self, ctx: PigeonParser.GeneContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#fseq. - def visitFseq(self, ctx:PigeonParser.FseqContext): + def visitFseq(self, ctx: PigeonParser.FseqContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#stop. - def visitStop(self, ctx:PigeonParser.StopContext): + def visitStop(self, ctx: PigeonParser.StopContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#operator. - def visitOperator(self, ctx:PigeonParser.OperatorContext): + def visitOperator(self, ctx: PigeonParser.OperatorContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#degredationtag. - def visitDegredationtag(self, ctx:PigeonParser.DegredationtagContext): + def visitDegredationtag(self, ctx: PigeonParser.DegredationtagContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#righttriangle. - def visitRighttriangle(self, ctx:PigeonParser.RighttriangleContext): + def visitRighttriangle(self, ctx: PigeonParser.RighttriangleContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#lefttriangle. - def visitLefttriangle(self, ctx:PigeonParser.LefttriangleContext): + def visitLefttriangle(self, ctx: PigeonParser.LefttriangleContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#bar. - def visitBar(self, ctx:PigeonParser.BarContext): + def visitBar(self, ctx: PigeonParser.BarContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#three. - def visitThree(self, ctx:PigeonParser.ThreeContext): + def visitThree(self, ctx: PigeonParser.ThreeContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#five. - def visitFive(self, ctx:PigeonParser.FiveContext): + def visitFive(self, ctx: PigeonParser.FiveContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#zring. - def visitZring(self, ctx:PigeonParser.ZringContext): + def visitZring(self, ctx: PigeonParser.ZringContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#xbar. - def visitXbar(self, ctx:PigeonParser.XbarContext): + def visitXbar(self, ctx: PigeonParser.XbarContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#box. - def visitBox(self, ctx:PigeonParser.BoxContext): + def visitBox(self, ctx: PigeonParser.BoxContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#scar. - def visitScar(self, ctx:PigeonParser.ScarContext): + def visitScar(self, ctx: PigeonParser.ScarContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#vector. - def visitVector(self, ctx:PigeonParser.VectorContext): + def visitVector(self, ctx: PigeonParser.VectorContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#invert. - def visitInvert(self, ctx:PigeonParser.InvertContext): + def visitInvert(self, ctx: PigeonParser.InvertContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#color. - def visitColor(self, ctx:PigeonParser.ColorContext): + def visitColor(self, ctx: PigeonParser.ColorContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#label. - def visitLabel(self, ctx:PigeonParser.LabelContext): + def visitLabel(self, ctx: PigeonParser.LabelContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#ignorecolor. - def visitIgnorecolor(self, ctx:PigeonParser.IgnorecolorContext): + def visitIgnorecolor(self, ctx: PigeonParser.IgnorecolorContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#commands. - def visitCommands(self, ctx:PigeonParser.CommandsContext): + def visitCommands(self, ctx: PigeonParser.CommandsContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#arccommands. - def visitArccommands(self, ctx:PigeonParser.ArccommandsContext): + def visitArccommands(self, ctx: PigeonParser.ArccommandsContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#rep. - def visitRep(self, ctx:PigeonParser.RepContext): + def visitRep(self, ctx: PigeonParser.RepContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#rep2. - def visitRep2(self, ctx:PigeonParser.Rep2Context): + def visitRep2(self, ctx: PigeonParser.Rep2Context): return self.visitChildren(ctx) - # Visit a parse tree produced by PigeonParser#ind. - def visitInd(self, ctx:PigeonParser.IndContext): + def visitInd(self, ctx: PigeonParser.IndContext): return self.visitChildren(ctx) - -del PigeonParser \ No newline at end of file +del PigeonParser diff --git a/cmdline.py b/cmdline.py index 3b887e1..b3716fd 100644 --- a/cmdline.py +++ b/cmdline.py @@ -1,41 +1,54 @@ import argparse import Pigeon -def main(): +def main(): parser = argparse.ArgumentParser() - parser.add_argument("pigeon_script", help="enter the path to the pigeon script text file to be parsed") - parser.add_argument("-location", "--location", help="enter the location where you want the image to be saved \n i.e. -location=/path/to/your/folder/") - parser.add_argument("-format", "--format", help="enter the format you want the image to be saved in \n i.e. -image_type=pdf \n options are svg, pdf, and png. Default is svg.") - parser.add_argument("-name", "--name", help="enter a name for the design that is being generated \n i.e. -name=my_image_name") + parser.add_argument( + "pigeon_script", + help="enter the path to the pigeon script text file to be parsed", + ) + parser.add_argument( + "-location", + "--location", + help="enter the location where you want the image to be saved \n i.e. -location=/path/to/your/folder/", + ) + parser.add_argument( + "-format", + "--format", + help="enter the format you want the image to be saved in \n i.e. -image_type=pdf \n options are svg, pdf, and png. Default is svg.", + ) + parser.add_argument( + "-name", + "--name", + help="enter a name for the design that is being generated \n i.e. -name=my_image_name", + ) args = parser.parse_args() # default values - imglocation = '' - imgformat = 'svg' - imgname = args.pigeon_script.split('.')[0] - + imglocation = "" + imgformat = "svg" + imgname = args.pigeon_script.split(".")[0] - if (args.location): + if args.location: imglocation = args.location - if (args.format): + if args.format: imgformat = args.format - if (args.name): + if args.name: imgname = args.name - with open (args.pigeon_script, "r") as myfile: - data=myfile.read() + with open(args.pigeon_script, "r") as myfile: + data = myfile.read() parser = Pigeon.Pigeon(imgformat) parser.parseAndGenerateImage(data) parser.save(imglocation, imgname) pass - -if __name__ == '__main__': - main() +if __name__ == "__main__": + main() diff --git a/dnaplotlib.py b/dnaplotlib.py index a3a296d..78e0d29 100755 --- a/dnaplotlib.py +++ b/dnaplotlib.py @@ -48,9 +48,11 @@ import math import csv from operator import itemgetter + # Set the backend to use (important for headless servers) import matplotlib -matplotlib.use('Agg') + +matplotlib.use("Agg") import matplotlib.pyplot as plt from matplotlib.patches import Polygon, Ellipse, Wedge, Circle, PathPatch from matplotlib.path import Path @@ -59,11 +61,11 @@ import matplotlib.patches as patches -__author__ = 'Thomas E. Gorochowski \n\ +__author__ = "Thomas E. Gorochowski \n\ Bryan Der \n\ - Emerson Glassey ' -__license__ = 'MIT' -__version__ = '1.0' + Emerson Glassey " +__license__ = "MIT" +__version__ = "1.0" ############################################################################### @@ -71,77 +73,93 @@ ############################################################################### -def write_label (ax, label_text, x_pos, opts=None): - """ Renders labels on parts. - """ +def write_label(ax, label_text, x_pos, opts=None): + """Renders labels on parts.""" zorder_add = 0.0 y_offset = 0.0 - label_style = 'normal' + label_style = "normal" label_size = 7 label_y_offset = 0 label_x_offset = 0 - label_color = (0,0,0) + label_color = (0, 0, 0) label_rotation = 0 if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'label_style' in list(opts.keys()): - label_style = opts['label_style'] - if 'label_size' in list(opts.keys()): - label_size = opts['label_size'] - if 'label_y_offset' in list(opts.keys()): - label_y_offset = opts['label_y_offset'] - if 'label_x_offset' in list(opts.keys()): - label_x_offset = opts['label_x_offset'] - if 'label_color' in list(opts.keys()): - label_color = opts['label_color'] - if 'label_rotation' in list(opts.keys()): - label_rotation = opts['label_rotation'] - ax.text(x_pos+label_x_offset, label_y_offset+y_offset, label_text, horizontalalignment='center', - verticalalignment='center', fontsize=label_size, fontstyle=label_style, - color=label_color, rotation=label_rotation, zorder=30+zorder_add) - -def write_arc_label (ax, label_text, x_pos, y_pos, opts=None): - """ Renders labels on parts. - """ + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "label_style" in list(opts.keys()): + label_style = opts["label_style"] + if "label_size" in list(opts.keys()): + label_size = opts["label_size"] + if "label_y_offset" in list(opts.keys()): + label_y_offset = opts["label_y_offset"] + if "label_x_offset" in list(opts.keys()): + label_x_offset = opts["label_x_offset"] + if "label_color" in list(opts.keys()): + label_color = opts["label_color"] + if "label_rotation" in list(opts.keys()): + label_rotation = opts["label_rotation"] + ax.text( + x_pos + label_x_offset, + label_y_offset + y_offset, + label_text, + horizontalalignment="center", + verticalalignment="center", + fontsize=label_size, + fontstyle=label_style, + color=label_color, + rotation=label_rotation, + zorder=30 + zorder_add, + ) + + +def write_arc_label(ax, label_text, x_pos, y_pos, opts=None): + """Renders labels on parts.""" zorder_add = 0.0 y_offset = 0.0 - label_style = 'normal' + label_style = "normal" label_size = 7 label_y_offset = 0 label_x_offset = 0 - label_color = (0,0,0) + label_color = (0, 0, 0) label_rotation = 0 if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'label_style' in list(opts.keys()): - label_style = opts['label_style'] - if 'label_size' in list(opts.keys()): - label_size = opts['label_size'] - if 'label_y_offset' in list(opts.keys()): - label_y_offset = opts['label_y_offset'] - if 'label_x_offset' in list(opts.keys()): - label_x_offset = opts['label_x_offset'] - if 'label_color' in list(opts.keys()): - label_color = opts['label_color'] - if 'label_rotation' in list(opts.keys()): - label_rotation = opts['label_rotation'] - ax.text(x_pos+label_x_offset, y_pos+label_y_offset+y_offset, label_text, horizontalalignment='center', - verticalalignment='center', fontsize=label_size, fontstyle=label_style, - color=label_color, rotation=label_rotation, zorder=30+zorder_add) - - -def sbol_promoter (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL promoter renderer. - """ + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "label_style" in list(opts.keys()): + label_style = opts["label_style"] + if "label_size" in list(opts.keys()): + label_size = opts["label_size"] + if "label_y_offset" in list(opts.keys()): + label_y_offset = opts["label_y_offset"] + if "label_x_offset" in list(opts.keys()): + label_x_offset = opts["label_x_offset"] + if "label_color" in list(opts.keys()): + label_color = opts["label_color"] + if "label_rotation" in list(opts.keys()): + label_rotation = opts["label_rotation"] + ax.text( + x_pos + label_x_offset, + y_pos + label_y_offset + y_offset, + label_text, + horizontalalignment="center", + verticalalignment="center", + fontsize=label_size, + fontstyle=label_style, + color=label_color, + rotation=label_rotation, + zorder=30 + zorder_add, + ) + + +def sbol_promoter(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL promoter renderer.""" # Default options zorder_add = 0.0 - color = (0.0,0.0,0.0) + color = (0.0, 0.0, 0.0) start_pad = 2.0 end_pad = 2.0 y_extent = 10 @@ -151,107 +169,139 @@ def sbol_promoter (ax, type, num, start, end, prev_end, scale, linewidth, opts): scale = 1 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 final_end = end final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the promoter symbol - l1 = Line2D([start,start],[0,dir_fac*y_extent], linewidth=linewidth, - color=color, zorder=9+zorder_add) - l2 = Line2D([start,start+dir_fac*x_extent-dir_fac*(arrowhead_length*0.5)], - [dir_fac*y_extent,dir_fac*y_extent], linewidth=linewidth, - color=color, zorder=10+zorder_add) + l1 = Line2D( + [start, start], + [0, dir_fac * y_extent], + linewidth=linewidth, + color=color, + zorder=9 + zorder_add, + ) + l2 = Line2D( + [ + start, + start + dir_fac * x_extent - dir_fac * (arrowhead_length * 0.5), + ], + [dir_fac * y_extent, dir_fac * y_extent], + linewidth=linewidth, + color=color, + zorder=10 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) - p1 = Polygon([(start+dir_fac*x_extent-dir_fac*arrowhead_length, - dir_fac*y_extent+(arrowhead_height)), - (start+dir_fac*x_extent, dir_fac*y_extent), - (start+dir_fac*x_extent-dir_fac*arrowhead_length, - dir_fac*y_extent-(arrowhead_height))], - facecolor=color, edgecolor=color, linewidth=linewidth, zorder=1+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0 + p1 = Polygon( + [ + ( + start + dir_fac * x_extent - dir_fac * arrowhead_length, + dir_fac * y_extent + (arrowhead_height), + ), + (start + dir_fac * x_extent, dir_fac * y_extent), + ( + start + dir_fac * x_extent - dir_fac * arrowhead_length, + dir_fac * y_extent - (arrowhead_height), + ), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=1 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0 ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_cds (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL coding sequence renderer. - """ +def sbol_cds(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL coding sequence renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" start_pad = 1.0 end_pad = 1.0 y_extent = 5 x_extent = 30 arrowhead_height = 4 arrowhead_length = 8 - edgecolor = (0,0,0) + edgecolor = (0, 0, 0) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'edge_color' in list(opts.keys()): - edgecolor = opts['edge_color'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "edge_color" in list(opts.keys()): + edgecolor = opts["edge_color"] # Check direction add start padding dir_fac = 1.0 @@ -259,44 +309,61 @@ def sbol_cds (ax, type, num, start, end, prev_end, scale, linewidth, opts): final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the CDS symbol - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (end-dir_fac*arrowhead_length, -y_extent), - (end-dir_fac*arrowhead_length, -y_extent-arrowhead_height), - (end, 0), - (end-dir_fac*arrowhead_length, y_extent+arrowhead_height), - (end-dir_fac*arrowhead_length, y_extent)], - edgecolor=edgecolor, facecolor=color, linewidth=linewidth, - hatch=hatch, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0 - + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (end - dir_fac * arrowhead_length, -y_extent), + (end - dir_fac * arrowhead_length, -y_extent - arrowhead_height), + (end, 0), + (end - dir_fac * arrowhead_length, y_extent + arrowhead_height), + (end - dir_fac * arrowhead_length, y_extent), + ], + edgecolor=edgecolor, + facecolor=color, + linewidth=linewidth, + hatch=hatch, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0 ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_terminator (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL terminator renderer. - """ +def sbol_terminator( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL terminator renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 10.0 @@ -304,595 +371,985 @@ def sbol_terminator (ax, type, num, start, end, prev_end, scale, linewidth, opts scale = 1.0 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 final_end = end final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the terminator symbol - l1 = Line2D([start+dir_fac*(x_extent/2.0),start+dir_fac*(x_extent/2.0)],[0,dir_fac*y_extent], linewidth=linewidth, - color=color, zorder=8+zorder_add) - l2 = Line2D([start,start+(dir_fac*x_extent)],[dir_fac*y_extent,dir_fac*y_extent], - linewidth=linewidth, color=color, zorder=9+zorder_add) + l1 = Line2D( + [ + start + dir_fac * (x_extent / 2.0), + start + dir_fac * (x_extent / 2.0), + ], + [0, dir_fac * y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + ) + l2 = Line2D( + [start, start + (dir_fac * x_extent)], + [dir_fac * y_extent, dir_fac * y_extent], + linewidth=linewidth, + color=color, + zorder=9 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_rbs (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL ribosome binding site renderer. - """ +def sbol_rbs(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL ribosome binding site renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) + color = (0.7, 0.7, 0.7) start_pad = 2.0 end_pad = 2.0 x_extent = 10.0 - edgecolor = (0,0,0) + edgecolor = (0, 0, 0) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'edge_color' in list(opts.keys()): - edgecolor = opts['edge_color'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "edge_color" in list(opts.keys()): + edgecolor = opts["edge_color"] # Check direction add start padding dir_fac = 1.0 final_end = end final_start = prev_end - rbs_center = (0,0) + rbs_center = (0, 0) if start > end: - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad - rbs_center = (end+((start-end)/2.0),0) - w1 = Wedge(rbs_center, x_extent/2.0, 180, 360, linewidth=linewidth, - facecolor=color, edgecolor=edgecolor, zorder=8+zorder_add) + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad + rbs_center = (end + ((start - end) / 2.0), 0) + w1 = Wedge( + rbs_center, + x_extent / 2.0, + 180, + 360, + linewidth=linewidth, + facecolor=color, + edgecolor=edgecolor, + zorder=8 + zorder_add, + ) ax.add_patch(w1) else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - rbs_center = (start+((end-start)/2.0),0) - w1 = Wedge(rbs_center, x_extent/2.0, 0, 180, linewidth=linewidth, - facecolor=color, edgecolor=edgecolor, zorder=8+zorder_add) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + rbs_center = (start + ((end - start) / 2.0), 0) + w1 = Wedge( + rbs_center, + x_extent / 2.0, + 0, + 180, + linewidth=linewidth, + facecolor=color, + edgecolor=edgecolor, + zorder=8 + zorder_add, + ) ax.add_patch(w1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_ribozyme (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL ribozyme renderer. - """ - return stick_figure(ax,type,num,start,end,prev_end,scale,linewidth,opts) +def sbol_ribozyme(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL ribozyme renderer.""" + return stick_figure( + ax, type, num, start, end, prev_end, scale, linewidth, opts + ) -def stick_figure (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ General function for drawing stick based parts (e.g., ribozyme and protease sites). - """ +def stick_figure(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """General function for drawing stick based parts (e.g., ribozyme and protease sites).""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 5.0 y_extent = 10.0 - linestyle = '-' - linetype = ""; - shapetype = ""; - if(type == "Ribozyme"): - linetype = 'dash' - headgroup = 'O' - elif(type == "Protease"): - linetype = 'dash' - headgroup = 'X' - elif(type == "ProteinStability"): - linetype = 'solid' - headgroup = 'O' - elif(type == "Ribonuclease"): - linetype = 'solid' - headgroup = 'X' + linestyle = "-" + linetype = "" + shapetype = "" + if type == "Ribozyme": + linetype = "dash" + headgroup = "O" + elif type == "Protease": + linetype = "dash" + headgroup = "X" + elif type == "ProteinStability": + linetype = "solid" + headgroup = "O" + elif type == "Ribonuclease": + linetype = "solid" + headgroup = "X" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end if start > end: - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad - rbs_center = (end+((start-end)/2.0),-y_extent) - c1 = Circle(rbs_center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=8+zorder_add) - x1 = Line2D([start,end],[-y_extent*1.25,-y_extent/1.5], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - x2 = Line2D([start,end],[-y_extent/1.5,-y_extent*1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - - dash1 = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,-y_extent/4], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - dash2 = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[-y_extent/2,-y_extent+(x_extent/2.0)], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - solidO = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,-y_extent+(x_extent/2.0)], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - solidX = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,-y_extent], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - - if(headgroup == "O" and linetype == "dash"): + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad + rbs_center = (end + ((start - end) / 2.0), -y_extent) + c1 = Circle( + rbs_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=8 + zorder_add, + ) + x1 = Line2D( + [start, end], + [-y_extent * 1.25, -y_extent / 1.5], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + x2 = Line2D( + [start, end], + [-y_extent / 1.5, -y_extent * 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + + dash1 = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, -y_extent / 4], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + dash2 = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [-y_extent / 2, -y_extent + (x_extent / 2.0)], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + solidO = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, -y_extent + (x_extent / 2.0)], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + solidX = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, -y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + + if headgroup == "O" and linetype == "dash": ax.add_patch(c1) ax.add_line(dash1) ax.add_line(dash2) - elif(headgroup == "X" and linetype == "dash"): + elif headgroup == "X" and linetype == "dash": ax.add_line(x1) ax.add_line(x2) ax.add_line(dash1) ax.add_line(dash2) - elif(headgroup == "O" and linetype == "solid"): + elif headgroup == "O" and linetype == "solid": ax.add_patch(c1) ax.add_line(solidO) - elif(headgroup == "X" and linetype == "solid"): + elif headgroup == "X" and linetype == "solid": ax.add_line(x1) ax.add_line(x2) ax.add_line(solidX) else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - rbs_center = (start+((end-start)/2.0),y_extent) - c1 = Circle(rbs_center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=8+zorder_add) - x1 = Line2D([start,end],[y_extent*1.25,y_extent/1.5], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - x2 = Line2D([start,end],[y_extent/1.5,y_extent*1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - - dash1 = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,y_extent/4], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - dash2 = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[y_extent/2,y_extent-(x_extent/2.0)], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - solidO = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,y_extent-(x_extent/2.0)], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - solidX = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,y_extent], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - - if(headgroup == 'O' and linetype == 'dash'): + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + rbs_center = (start + ((end - start) / 2.0), y_extent) + c1 = Circle( + rbs_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=8 + zorder_add, + ) + x1 = Line2D( + [start, end], + [y_extent * 1.25, y_extent / 1.5], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + x2 = Line2D( + [start, end], + [y_extent / 1.5, y_extent * 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + + dash1 = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, y_extent / 4], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + dash2 = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [y_extent / 2, y_extent - (x_extent / 2.0)], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + solidO = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, y_extent - (x_extent / 2.0)], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + solidX = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + + if headgroup == "O" and linetype == "dash": ax.add_patch(c1) ax.add_line(dash1) ax.add_line(dash2) - elif(headgroup == "X" and linetype == "dash"): + elif headgroup == "X" and linetype == "dash": ax.add_line(x1) ax.add_line(x2) ax.add_line(dash1) ax.add_line(dash2) - elif(headgroup == "O" and linetype == "solid"): + elif headgroup == "O" and linetype == "solid": ax.add_patch(c1) ax.add_line(solidO) - elif(headgroup == "X" and linetype == "solid"): + elif headgroup == "X" and linetype == "solid": ax.add_line(x1) ax.add_line(x2) ax.add_line(solidX) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_stem_top (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ General function for drawing stem-top parts (e.g., ribozyme and protease sites). - """ + +def sbol_stem_top(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """General function for drawing stem-top parts (e.g., ribozyme and protease sites).""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 5.0 y_extent = 10.0 - linestyle = '-' - shapetype = ""; + linestyle = "-" + shapetype = "" if type in ["DNACleavageSite"]: - stemtype = 'straight' - toptype = 'X' + stemtype = "straight" + toptype = "X" elif type in ["RNACleavageSite", "Ribonuclease"]: - stemtype = 'wavy' - toptype = 'X' + stemtype = "wavy" + toptype = "X" elif type in ["ProteinCleavageSite", "Protease"]: - stemtype = 'loopy' - toptype = 'X' + stemtype = "loopy" + toptype = "X" elif type in ["DNALocation"]: - stemtype = 'straight' - toptype = 'O' + stemtype = "straight" + toptype = "O" elif type in ["RNALocation"]: - stemtype = 'wavy' - toptype = 'O' + stemtype = "wavy" + toptype = "O" elif type in ["ProteinLocation"]: - stemtype = 'loopy' - toptype = 'O' + stemtype = "loopy" + toptype = "O" elif type in ["DNAStability"]: - stemtype = 'straight' - toptype = 'P' + stemtype = "straight" + toptype = "P" elif type in ["RNAStability"]: - stemtype = 'wavy' - toptype = 'P' + stemtype = "wavy" + toptype = "P" elif type in ["ProteinStability"]: - stemtype = 'loopy' - toptype = 'P' + stemtype = "loopy" + toptype = "P" elif type in ["StemTop"]: - stemtype = opts['stem'] - toptype = opts['top'] + stemtype = opts["stem"] + toptype = opts["top"] # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end if start > end: - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad # Patches and lines for top glyph # toptype=="X" - x1 = Line2D([start,end],[-y_extent*1.25,-y_extent/1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - x2 = Line2D([start,end],[-y_extent/1.25,-y_extent*1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') + x1 = Line2D( + [start, end], + [-y_extent * 1.25, -y_extent / 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + x2 = Line2D( + [start, end], + [-y_extent / 1.25, -y_extent * 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) # toptype=="O" - center = (end+((start-end)/2.0),-y_extent) - c1 = Circle(center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) + center = (end + ((start - end) / 2.0), -y_extent) + c1 = Circle( + center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) # toptype=='P' - pentagon_xy = [[end, -y_extent*1.25], - [end, -y_extent*0.87], - [(start + end)/2, -y_extent*0.68], - [start, -y_extent*0.87], - [start, -y_extent*1.25], - ] - p1 = Polygon(pentagon_xy, closed=True, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) + pentagon_xy = [ + [end, -y_extent * 1.25], + [end, -y_extent * 0.87], + [(start + end) / 2, -y_extent * 0.68], + [start, -y_extent * 0.87], + [start, -y_extent * 1.25], + ] + p1 = Polygon( + pentagon_xy, + closed=True, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) # Lines for stem glyph # stemtype=='straight' - straight_stem = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0, -y_extent], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) + straight_stem = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, -y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) # stemtype=='wavy' - wave_height = y_extent/6 - wave_start = (start + end)/2 - wave_bezier_amp = x_extent*0.2 - wave_bezier_dx = wave_bezier_amp*math.cos(math.pi/4) - wave_bezier_dy = wave_bezier_amp*math.sin(math.pi/4) - wavy_stem_path = Path(vertices=[[wave_start, 0], - [wave_start - wave_bezier_dx, -wave_bezier_dy], - [wave_start - wave_bezier_dx, -(wave_height - wave_bezier_dy)], - [wave_start, -wave_height], - [wave_start + wave_bezier_dx, -(wave_height + wave_bezier_dy)], - [wave_start + wave_bezier_dx, -(2*wave_height - wave_bezier_dy)], - [wave_start, -2*wave_height], - [wave_start - wave_bezier_dx, -(2*wave_height + wave_bezier_dy)], - [wave_start - wave_bezier_dx, -(3*wave_height - wave_bezier_dy)], - [wave_start, -3*wave_height], - [wave_start + wave_bezier_dx, -(3*wave_height + wave_bezier_dy)], - [wave_start + wave_bezier_dx, -(4*wave_height - wave_bezier_dy)], - [wave_start, -4*wave_height], - [wave_start - wave_bezier_dx, -(4*wave_height + wave_bezier_dy)], - [wave_start - wave_bezier_dx, -(5*wave_height - wave_bezier_dy)], - [wave_start, -5*wave_height], - [wave_start + wave_bezier_dx, -(5*wave_height + wave_bezier_dy)], - [wave_start + wave_bezier_dx, -(6*wave_height - wave_bezier_dy)], - [wave_start, -6*wave_height]], - codes=[1, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4]) - wavy_stem = PathPatch(wavy_stem_path, linewidth=linewidth, edgecolor=color, - facecolor='none', zorder=8+zorder_add, linestyle=linestyle) + wave_height = y_extent / 6 + wave_start = (start + end) / 2 + wave_bezier_amp = x_extent * 0.2 + wave_bezier_dx = wave_bezier_amp * math.cos(math.pi / 4) + wave_bezier_dy = wave_bezier_amp * math.sin(math.pi / 4) + wavy_stem_path = Path( + vertices=[ + [wave_start, 0], + [wave_start - wave_bezier_dx, -wave_bezier_dy], + [wave_start - wave_bezier_dx, -(wave_height - wave_bezier_dy)], + [wave_start, -wave_height], + [wave_start + wave_bezier_dx, -(wave_height + wave_bezier_dy)], + [ + wave_start + wave_bezier_dx, + -(2 * wave_height - wave_bezier_dy), + ], + [wave_start, -2 * wave_height], + [ + wave_start - wave_bezier_dx, + -(2 * wave_height + wave_bezier_dy), + ], + [ + wave_start - wave_bezier_dx, + -(3 * wave_height - wave_bezier_dy), + ], + [wave_start, -3 * wave_height], + [ + wave_start + wave_bezier_dx, + -(3 * wave_height + wave_bezier_dy), + ], + [ + wave_start + wave_bezier_dx, + -(4 * wave_height - wave_bezier_dy), + ], + [wave_start, -4 * wave_height], + [ + wave_start - wave_bezier_dx, + -(4 * wave_height + wave_bezier_dy), + ], + [ + wave_start - wave_bezier_dx, + -(5 * wave_height - wave_bezier_dy), + ], + [wave_start, -5 * wave_height], + [ + wave_start + wave_bezier_dx, + -(5 * wave_height + wave_bezier_dy), + ], + [ + wave_start + wave_bezier_dx, + -(6 * wave_height - wave_bezier_dy), + ], + [wave_start, -6 * wave_height], + ], + codes=[1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], + ) + wavy_stem = PathPatch( + wavy_stem_path, + linewidth=linewidth, + edgecolor=color, + facecolor="none", + zorder=8 + zorder_add, + linestyle=linestyle, + ) # stemtype=='loopy' - loop_offset_y = y_extent*0.015 - loop_height = (y_extent - 2*loop_offset_y)/4 - loop_start = (start + end)/2 + x_extent*0.05 - loop_end = end + x_extent*0.15 - loop_bezier_amp = y_extent*0.03 - loop_stem_path = Path(vertices=[[loop_start, -loop_offset_y], - [loop_start, -(loop_offset_y - loop_bezier_amp)], - [loop_end, -(loop_offset_y - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*0.5)], - [loop_end, -(loop_offset_y + loop_height + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height)], - [loop_start, -(loop_offset_y + loop_height - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*1.5)], - [loop_end, -(loop_offset_y + loop_height*2 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*2 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*2)], - [loop_start, -(loop_offset_y + loop_height*2 - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*2 - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*2.5)], - [loop_end, -(loop_offset_y + loop_height*3 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*3 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*3)], - [loop_start, -(loop_offset_y + loop_height*3 - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*3 - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*3.5)], - [loop_end, -(loop_offset_y + loop_height*4 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*4 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*4)], - ], - codes=[1, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4]) - loop_stem = PathPatch(loop_stem_path, linewidth=linewidth, edgecolor=color, - facecolor='none', zorder=8+zorder_add, linestyle=linestyle) + loop_offset_y = y_extent * 0.015 + loop_height = (y_extent - 2 * loop_offset_y) / 4 + loop_start = (start + end) / 2 + x_extent * 0.05 + loop_end = end + x_extent * 0.15 + loop_bezier_amp = y_extent * 0.03 + loop_stem_path = Path( + vertices=[ + [loop_start, -loop_offset_y], + [loop_start, -(loop_offset_y - loop_bezier_amp)], + [loop_end, -(loop_offset_y - loop_bezier_amp)], + [loop_end, -(loop_offset_y + loop_height * 0.5)], + [loop_end, -(loop_offset_y + loop_height + loop_bezier_amp)], + [loop_start, -(loop_offset_y + loop_height + loop_bezier_amp)], + [loop_start, -(loop_offset_y + loop_height)], + [loop_start, -(loop_offset_y + loop_height - loop_bezier_amp)], + [loop_end, -(loop_offset_y + loop_height - loop_bezier_amp)], + [loop_end, -(loop_offset_y + loop_height * 1.5)], + [ + loop_end, + -(loop_offset_y + loop_height * 2 + loop_bezier_amp), + ], + [ + loop_start, + -(loop_offset_y + loop_height * 2 + loop_bezier_amp), + ], + [loop_start, -(loop_offset_y + loop_height * 2)], + [ + loop_start, + -(loop_offset_y + loop_height * 2 - loop_bezier_amp), + ], + [ + loop_end, + -(loop_offset_y + loop_height * 2 - loop_bezier_amp), + ], + [loop_end, -(loop_offset_y + loop_height * 2.5)], + [ + loop_end, + -(loop_offset_y + loop_height * 3 + loop_bezier_amp), + ], + [ + loop_start, + -(loop_offset_y + loop_height * 3 + loop_bezier_amp), + ], + [loop_start, -(loop_offset_y + loop_height * 3)], + [ + loop_start, + -(loop_offset_y + loop_height * 3 - loop_bezier_amp), + ], + [ + loop_end, + -(loop_offset_y + loop_height * 3 - loop_bezier_amp), + ], + [loop_end, -(loop_offset_y + loop_height * 3.5)], + [ + loop_end, + -(loop_offset_y + loop_height * 4 + loop_bezier_amp), + ], + [ + loop_start, + -(loop_offset_y + loop_height * 4 + loop_bezier_amp), + ], + [loop_start, -(loop_offset_y + loop_height * 4)], + ], + codes=[ + 1, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + ], + ) + loop_stem = PathPatch( + loop_stem_path, + linewidth=linewidth, + edgecolor=color, + facecolor="none", + zorder=8 + zorder_add, + linestyle=linestyle, + ) else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Patches and lines for top glyph # toptype=="X" - x1 = Line2D([start,end],[y_extent*1.25,y_extent/1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - x2 = Line2D([start,end],[y_extent/1.25,y_extent*1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') + x1 = Line2D( + [start, end], + [y_extent * 1.25, y_extent / 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + x2 = Line2D( + [start, end], + [y_extent / 1.25, y_extent * 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) # toptype=="O" - center = (start+((end-start)/2.0),y_extent) - c1 = Circle(center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) + center = (start + ((end - start) / 2.0), y_extent) + c1 = Circle( + center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) # toptype=='P' - pentagon_xy = [[start, y_extent*1.25], - [start, y_extent*0.87], - [(start + end)/2, y_extent*0.68], - [end, y_extent*0.87], - [end, y_extent*1.25], - ] - p1 = Polygon(pentagon_xy, closed=True, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) + pentagon_xy = [ + [start, y_extent * 1.25], + [start, y_extent * 0.87], + [(start + end) / 2, y_extent * 0.68], + [end, y_extent * 0.87], + [end, y_extent * 1.25], + ] + p1 = Polygon( + pentagon_xy, + closed=True, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) # Lines for stem glyph # stemtype=='straight' - straight_stem = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,y_extent], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) + straight_stem = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) # stemtype=='wavy' - wave_height = y_extent/6 - wave_start = (start + end)/2 - wave_bezier_amp = x_extent*0.2 - wave_bezier_dx = wave_bezier_amp*math.cos(math.pi/4) - wave_bezier_dy = wave_bezier_amp*math.sin(math.pi/4) - wavy_stem_path = Path(vertices=[[wave_start, 0], - [wave_start + wave_bezier_dx, wave_bezier_dy], - [wave_start + wave_bezier_dx, wave_height - wave_bezier_dy], - [wave_start, wave_height], - [wave_start - wave_bezier_dx, wave_height + wave_bezier_dy], - [wave_start - wave_bezier_dx, 2*wave_height - wave_bezier_dy], - [wave_start, 2*wave_height], - [wave_start + wave_bezier_dx, 2*wave_height + wave_bezier_dy], - [wave_start + wave_bezier_dx, 3*wave_height - wave_bezier_dy], - [wave_start, 3*wave_height], - [wave_start - wave_bezier_dx, 3*wave_height + wave_bezier_dy], - [wave_start - wave_bezier_dx, 4*wave_height - wave_bezier_dy], - [wave_start, 4*wave_height], - [wave_start + wave_bezier_dx, 4*wave_height + wave_bezier_dy], - [wave_start + wave_bezier_dx, 5*wave_height - wave_bezier_dy], - [wave_start, 5*wave_height], - [wave_start - wave_bezier_dx, 5*wave_height + wave_bezier_dy], - [wave_start - wave_bezier_dx, 6*wave_height - wave_bezier_dy], - [wave_start, 6*wave_height]], - codes=[1, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4]) - wavy_stem = PathPatch(wavy_stem_path, linewidth=linewidth, edgecolor=color, - facecolor='none', zorder=8+zorder_add, linestyle=linestyle) + wave_height = y_extent / 6 + wave_start = (start + end) / 2 + wave_bezier_amp = x_extent * 0.2 + wave_bezier_dx = wave_bezier_amp * math.cos(math.pi / 4) + wave_bezier_dy = wave_bezier_amp * math.sin(math.pi / 4) + wavy_stem_path = Path( + vertices=[ + [wave_start, 0], + [wave_start + wave_bezier_dx, wave_bezier_dy], + [wave_start + wave_bezier_dx, wave_height - wave_bezier_dy], + [wave_start, wave_height], + [wave_start - wave_bezier_dx, wave_height + wave_bezier_dy], + [wave_start - wave_bezier_dx, 2 * wave_height - wave_bezier_dy], + [wave_start, 2 * wave_height], + [wave_start + wave_bezier_dx, 2 * wave_height + wave_bezier_dy], + [wave_start + wave_bezier_dx, 3 * wave_height - wave_bezier_dy], + [wave_start, 3 * wave_height], + [wave_start - wave_bezier_dx, 3 * wave_height + wave_bezier_dy], + [wave_start - wave_bezier_dx, 4 * wave_height - wave_bezier_dy], + [wave_start, 4 * wave_height], + [wave_start + wave_bezier_dx, 4 * wave_height + wave_bezier_dy], + [wave_start + wave_bezier_dx, 5 * wave_height - wave_bezier_dy], + [wave_start, 5 * wave_height], + [wave_start - wave_bezier_dx, 5 * wave_height + wave_bezier_dy], + [wave_start - wave_bezier_dx, 6 * wave_height - wave_bezier_dy], + [wave_start, 6 * wave_height], + ], + codes=[1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], + ) + wavy_stem = PathPatch( + wavy_stem_path, + linewidth=linewidth, + edgecolor=color, + facecolor="none", + zorder=8 + zorder_add, + linestyle=linestyle, + ) # stemtype=='loopy' - loop_offset_y = y_extent*0.015 - loop_height = (y_extent - 2*loop_offset_y)/4 - loop_start = (start + end)/2 - x_extent*0.05 - loop_end = end - x_extent*0.15 - loop_bezier_amp = y_extent*0.03 - loop_stem_path = Path(vertices=[[loop_start, loop_offset_y], - [loop_start, loop_offset_y - loop_bezier_amp], - [loop_end, loop_offset_y - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*0.5], - [loop_end, loop_offset_y + loop_height + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height], - [loop_start, loop_offset_y + loop_height - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*1.5], - [loop_end, loop_offset_y + loop_height*2 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*2 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*2], - [loop_start, loop_offset_y + loop_height*2 - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*2 - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*2.5], - [loop_end, loop_offset_y + loop_height*3 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*3 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*3], - [loop_start, loop_offset_y + loop_height*3 - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*3 - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*3.5], - [loop_end, loop_offset_y + loop_height*4 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*4 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*4], - ], - codes=[1, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4]) - loop_stem = PathPatch(loop_stem_path, linewidth=linewidth, edgecolor=color, - facecolor='none', zorder=8+zorder_add, linestyle=linestyle) + loop_offset_y = y_extent * 0.015 + loop_height = (y_extent - 2 * loop_offset_y) / 4 + loop_start = (start + end) / 2 - x_extent * 0.05 + loop_end = end - x_extent * 0.15 + loop_bezier_amp = y_extent * 0.03 + loop_stem_path = Path( + vertices=[ + [loop_start, loop_offset_y], + [loop_start, loop_offset_y - loop_bezier_amp], + [loop_end, loop_offset_y - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 0.5], + [loop_end, loop_offset_y + loop_height + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height], + [loop_start, loop_offset_y + loop_height - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 1.5], + [loop_end, loop_offset_y + loop_height * 2 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 2 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 2], + [loop_start, loop_offset_y + loop_height * 2 - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 2 - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 2.5], + [loop_end, loop_offset_y + loop_height * 3 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 3 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 3], + [loop_start, loop_offset_y + loop_height * 3 - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 3 - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 3.5], + [loop_end, loop_offset_y + loop_height * 4 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 4 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 4], + ], + codes=[ + 1, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + ], + ) + loop_stem = PathPatch( + loop_stem_path, + linewidth=linewidth, + edgecolor=color, + facecolor="none", + zorder=8 + zorder_add, + linestyle=linestyle, + ) # Add stem patches and/or lines - if stemtype == 'straight': + if stemtype == "straight": ax.add_line(straight_stem) - elif stemtype == 'wavy': + elif stemtype == "wavy": ax.add_line(wavy_stem) - elif stemtype == 'loopy': + elif stemtype == "loopy": ax.add_line(loop_stem) # Add top patches and/or lines - if toptype == 'O': + if toptype == "O": ax.add_patch(c1) - elif toptype == 'X': + elif toptype == "X": ax.add_line(x1) ax.add_line(x2) - elif toptype == 'P': + elif toptype == "P": ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_scar (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL scar renderer. - """ + +def sbol_scar(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL scar renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 6.0 y_extent = 1.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - l_top = Line2D([start,start+x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l_bottom = Line2D([start,start+x_extent],[-1*y_extent,-1*y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + l_top = Line2D( + [start, start + x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l_bottom = Line2D( + [start, start + x_extent], + [-1 * y_extent, -1 * y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) ax.add_line(l_top) ax.add_line(l_bottom) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -900,93 +1357,134 @@ def sbol_scar (ax, type, num, start, end, prev_end, scale, linewidth, opts): return prev_end, final_end -def sbol_empty_space (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in empty space renderer. - """ +def sbol_empty_space( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in empty space renderer.""" # Default options zorder_add = 0.0 x_extent = 12.0 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] # Check direction add start padding final_start = prev_end - final_end = final_start+x_extent + final_end = final_start + x_extent - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_5_overhang (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL 5' overhang renderer. - """ +def sbol_5_overhang( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL 5' overhang renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 0.0 end_pad = 2.0 x_extent = 6.0 y_extent = 1.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - l_top = Line2D([start,start+x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l_bottom = Line2D([start+(x_extent/2.0),start+x_extent],[-1*y_extent,-1*y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + l_top = Line2D( + [start, start + x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l_bottom = Line2D( + [start + (x_extent / 2.0), start + x_extent], + [-1 * y_extent, -1 * y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) ax.add_line(l_top) ax.add_line(l_bottom) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -994,67 +1492,97 @@ def sbol_5_overhang (ax, type, num, start, end, prev_end, scale, linewidth, opts return prev_end, final_end -def sbol_3_overhang (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL 3' overhang renderer. - """ +def sbol_3_overhang( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL 3' overhang renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 0.0 x_extent = 6.0 y_extent = 1.0 - linestyle = '-' + linestyle = "-" scale = 1 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - l_top = Line2D([start,start+x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l_bottom = Line2D([start,start+(x_extent/2.0)],[-1*y_extent,-1*y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + l_top = Line2D( + [start, start + x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l_bottom = Line2D( + [start, start + (x_extent / 2.0)], + [-1 * y_extent, -1 * y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) ax.add_line(l_top) ax.add_line(l_bottom) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1062,41 +1590,42 @@ def sbol_3_overhang (ax, type, num, start, end, prev_end, scale, linewidth, opts return prev_end, final_end -def sbol_blunt_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL blunt-end restriction site renderer. - """ +def sbol_blunt_restriction_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL blunt-end restriction site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 4.0 x_extent = 1.5 site_space = 1.5 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'site_space' in list(opts.keys()): - site_space = opts['site_space'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "site_space" in list(opts.keys()): + site_space = opts["site_space"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + # Direction is meaningless for this part => start is always < end if start > end: temp_end = end @@ -1106,24 +1635,60 @@ def sbol_blunt_restriction_site (ax, type, num, start, end, prev_end, scale, lin # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent+site_space+x_extent - final_end = end+end_pad - - l1 = Line2D([start+x_extent,start+x_extent],[-y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_top = Line2D([start,start+x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_bottom = Line2D([start,start+x_extent],[-y_extent,-y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - - l2 = Line2D([end-x_extent,end-x_extent],[-y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l2_top = Line2D([end,end-x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l2_bottom = Line2D([end,end-x_extent],[-y_extent,-y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - + start = prev_end + start_pad + end = start + x_extent + site_space + x_extent + final_end = end + end_pad + + l1 = Line2D( + [start + x_extent, start + x_extent], + [-y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_top = Line2D( + [start, start + x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_bottom = Line2D( + [start, start + x_extent], + [-y_extent, -y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + + l2 = Line2D( + [end - x_extent, end - x_extent], + [-y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l2_top = Line2D( + [end, end - x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l2_bottom = Line2D( + [end, end - x_extent], + [-y_extent, -y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + ax.add_line(l1) ax.add_line(l1_top) ax.add_line(l1_bottom) @@ -1131,53 +1696,59 @@ def sbol_blunt_restriction_site (ax, type, num, start, end, prev_end, scale, lin ax.add_line(l2_top) ax.add_line(l2_bottom) - if opts != None and 'label' in list(opts.keys()): - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + if opts != None and "label" in list(opts.keys()): + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) return final_start, final_end -def sbol_primer_binding_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL primer binding site renderer. - """ +def sbol_primer_binding_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL primer binding site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 2.0 y_offset = 1.5 x_extent = 8.0 arrowhead_length = 2.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - - direction = 'F' + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + + direction = "F" if start > end: - direction = 'R' + direction = "R" temp_end = end end = start start = temp_end @@ -1185,35 +1756,59 @@ def sbol_primer_binding_site (ax, type, num, start, end, prev_end, scale, linewi final_end = prev_end final_start = prev_end - if direction == 'F': + if direction == "F": final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad else: final_start = prev_end - end = prev_end+end_pad - start = end+x_extent - final_start = start+start_pad - - if direction == 'F': - verts = [(start, y_offset), (end, y_offset), (end-arrowhead_length, y_offset+y_extent)] + end = prev_end + end_pad + start = end + x_extent + final_start = start + start_pad + + if direction == "F": + verts = [ + (start, y_offset), + (end, y_offset), + (end - arrowhead_length, y_offset + y_extent), + ] codes = [Path.MOVETO, Path.LINETO, Path.LINETO] path = Path(verts, codes) - patch = PathPatch(path, lw=linewidth, edgecolor=color, facecolor=(1,1,1), zorder=1+zorder_add) + patch = PathPatch( + path, + lw=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=1 + zorder_add, + ) ax.add_patch(patch) else: - verts = [(start, -y_offset), (end, -y_offset), (end+arrowhead_length, -y_offset-y_extent)] + verts = [ + (start, -y_offset), + (end, -y_offset), + (end + arrowhead_length, -y_offset - y_extent), + ] codes = [Path.MOVETO, Path.LINETO, Path.LINETO] path = Path(verts, codes) - patch = PathPatch(path, lw=linewidth, edgecolor=color, facecolor=(1,1,1), zorder=1+zorder_add) + patch = PathPatch( + path, + lw=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=1 + zorder_add, + ) ax.add_patch(patch) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start > end: - write_label(ax, opts['label'], end+((start-end)/2.0), opts=opts) + write_label( + ax, opts["label"], end + ((start - end) / 2.0), opts=opts + ) else: - write_label(ax, opts['label'], start+((end-start)/2.0), opts=opts) + write_label( + ax, opts["label"], start + ((end - start) / 2.0), opts=opts + ) if final_start > final_end: return prev_end, final_start @@ -1221,41 +1816,42 @@ def sbol_primer_binding_site (ax, type, num, start, end, prev_end, scale, linewi return prev_end, final_end -def sbol_5_sticky_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL 5' sticky-end restriction site renderer. - """ +def sbol_5_sticky_restriction_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL 5' sticky-end restriction site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 4.0 x_extent = 8.0 end_space = 1.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'end_space' in list(opts.keys()): - end_space = opts['end_space'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "end_space" in list(opts.keys()): + end_space = opts["end_space"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + # Direction is meaningless for this part => start is always < end if start > end: temp_end = end @@ -1265,71 +1861,102 @@ def sbol_5_sticky_restriction_site (ax, type, num, start, end, prev_end, scale, # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+end_space+x_extent+end_space - final_end = end+end_pad - - l1 = Line2D([start+end_space,start+end_space+x_extent],[0,0], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_top = Line2D([start+end_space,start+end_space],[0,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_bottom = Line2D([start+end_space+x_extent,start+end_space+x_extent],[0,-y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + start = prev_end + start_pad + end = start + end_space + x_extent + end_space + final_end = end + end_pad + + l1 = Line2D( + [start + end_space, start + end_space + x_extent], + [0, 0], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_top = Line2D( + [start + end_space, start + end_space], + [0, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_bottom = Line2D( + [start + end_space + x_extent, start + end_space + x_extent], + [0, -y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(l1) ax.add_line(l1_top) ax.add_line(l1_bottom) # White rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (end, -y_extent), - (end, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (end, -y_extent), + (end, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + if opts != None and "label" in list(opts.keys()): + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) return final_start, final_end -def sbol_3_sticky_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL 3' sticky-end restriction site renderer. - """ +def sbol_3_sticky_restriction_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL 3' sticky-end restriction site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 4.0 x_extent = 8.0 end_space = 1.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'end_space' in list(opts.keys()): - end_space = opts['end_space'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "end_space" in list(opts.keys()): + end_space = opts["end_space"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + # Direction is meaningless for this part => start is always < end if start > end: temp_end = end @@ -1339,93 +1966,141 @@ def sbol_3_sticky_restriction_site (ax, type, num, start, end, prev_end, scale, # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+end_space+x_extent+end_space - final_end = end+end_pad - - l1 = Line2D([start+end_space,start+end_space+x_extent],[0,0], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_top = Line2D([start+end_space+x_extent,start+end_space+x_extent],[0,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_bottom = Line2D([start+end_space,start+end_space],[0,-y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + start = prev_end + start_pad + end = start + end_space + x_extent + end_space + final_end = end + end_pad + + l1 = Line2D( + [start + end_space, start + end_space + x_extent], + [0, 0], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_top = Line2D( + [start + end_space + x_extent, start + end_space + x_extent], + [0, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_bottom = Line2D( + [start + end_space, start + end_space], + [0, -y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(l1) ax.add_line(l1_top) ax.add_line(l1_bottom) # White rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (end, -y_extent), - (end, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (end, -y_extent), + (end, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + if opts != None and "label" in list(opts.keys()): + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) return final_start, final_end -def sbol_user_defined (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL user-defined element renderer. - """ +def sbol_user_defined( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL user-defined element renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 12.0 y_extent = 3.0 - linestyle = '-' - fill_color = (1,1,1) + linestyle = "-" + fill_color = (1, 1, 1) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'fill_color' in list(opts.keys()): - fill_color = opts['fill_color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "fill_color" in list(opts.keys()): + fill_color = opts["fill_color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=color, facecolor=fill_color, linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=color, + facecolor=fill_color, + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1433,44 +2108,43 @@ def sbol_user_defined (ax, type, num, start, end, prev_end, scale, linewidth, o return prev_end, final_end -def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL signature renderer. - """ +def sbol_signature(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL signature renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 12.0 y_extent = 3.0 - linestyle = '-' - fill_color = (1,1,1) + linestyle = "-" + fill_color = (1, 1, 1) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'fill_color' in list(opts.keys()): - fill_color = opts['fill_color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - - direction = 'F' + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "fill_color" in list(opts.keys()): + fill_color = opts["fill_color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + + direction = "F" if start > end: - direction = 'R' + direction = "R" temp_end = end end = start start = temp_end @@ -1478,27 +2152,34 @@ def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts final_end = prev_end final_start = prev_end - if direction == 'F': + if direction == "F": final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad else: final_start = prev_end - end = prev_end+end_pad - start = end+x_extent - final_start = start+start_pad - - indent_fac = (y_extent*2.0)*0.3 - cross_width = (y_extent*2.0)*0.7 - - if direction == 'F': - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=color, facecolor=fill_color, linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + end = prev_end + end_pad + start = end + x_extent + final_start = start + start_pad + + indent_fac = (y_extent * 2.0) * 0.3 + cross_width = (y_extent * 2.0) * 0.7 + + if direction == "F": + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=color, + facecolor=fill_color, + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) top1x = start + indent_fac top1y = y_extent - indent_fac @@ -1508,22 +2189,47 @@ def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts bot1y = -y_extent + indent_fac bot2x = start + cross_width bot2y = -y_extent + indent_fac - lcross1 = Line2D([top1x,bot2x],[top1y,bot2y], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - lcross2 = Line2D([top2x,bot1x],[top2y,bot1y], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + lcross1 = Line2D( + [top1x, bot2x], + [top1y, bot2y], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + lcross2 = Line2D( + [top2x, bot1x], + [top2y, bot1y], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(lcross1) ax.add_line(lcross2) - lsign = Line2D([bot2x+indent_fac,end-indent_fac],[-y_extent+indent_fac,-y_extent+indent_fac], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + lsign = Line2D( + [bot2x + indent_fac, end - indent_fac], + [-y_extent + indent_fac, -y_extent + indent_fac], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(lsign) else: - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start-x_extent, -y_extent), - (start-x_extent, y_extent)], - edgecolor=color, facecolor=fill_color, linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start - x_extent, -y_extent), + (start - x_extent, y_extent), + ], + edgecolor=color, + facecolor=fill_color, + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) top1x = start - indent_fac top1y = y_extent - indent_fac @@ -1533,21 +2239,49 @@ def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts bot1y = -y_extent + indent_fac bot2x = start - cross_width bot2y = -y_extent + indent_fac - lcross1 = Line2D([top1x,bot2x],[top1y,bot2y], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - lcross2 = Line2D([top2x,bot1x],[top2y,bot1y], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + lcross1 = Line2D( + [top1x, bot2x], + [top1y, bot2y], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + lcross2 = Line2D( + [top2x, bot1x], + [top2y, bot1y], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(lcross1) ax.add_line(lcross2) - lsign = Line2D([bot2x-indent_fac,end+indent_fac],[y_extent-indent_fac,y_extent-indent_fac], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + lsign = Line2D( + [bot2x - indent_fac, end + indent_fac], + [y_extent - indent_fac, y_extent - indent_fac], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(lsign) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1555,51 +2289,68 @@ def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts return prev_end, final_end -def sbol_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL restriction site renderer. - """ +def sbol_restriction_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL restriction site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 4.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad + start = prev_end + start_pad end = start + linewidth - final_end = end+end_pad - - l1 = Line2D([start,start],[-y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + final_end = end + end_pad + + l1 = Line2D( + [start, start], + [-y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(l1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1607,69 +2358,96 @@ def sbol_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth return prev_end, final_end -def sbol_spacer (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL spacer renderer. - """ +def sbol_spacer(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL spacer renderer.""" # Default options zorder_add = 0.0 - color = (1,1,1) - edgecolor = (0,0,0) + color = (1, 1, 1) + edgecolor = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 6.0 y_extent = 6.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'edgecolor' in list(opts.keys()): - edgecolor = opts['edgecolor'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "edgecolor" in list(opts.keys()): + edgecolor = opts["edgecolor"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - rbs_center = (start+((end-start)/2.0),0) - center_x = start+(end-start)/2.0 - radius = x_extent/2 + + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + rbs_center = (start + ((end - start) / 2.0), 0) + center_x = start + (end - start) / 2.0 + radius = x_extent / 2 delta = radius - 0.5 * radius * math.sqrt(2) - l1 = Line2D([start+delta,end-delta],[radius-delta,-1*radius+delta], - linewidth=linewidth, color=edgecolor, zorder=12+zorder_add, linestyle=linestyle) - l2 = Line2D([start+delta,end-delta],[-1*radius+delta,radius-delta], - linewidth=linewidth, color=edgecolor, zorder=12+zorder_add, linestyle=linestyle) - c1 = Circle(rbs_center, x_extent/2.0, linewidth=linewidth, edgecolor=edgecolor, - facecolor=color, zorder=12+zorder_add) - + l1 = Line2D( + [start + delta, end - delta], + [radius - delta, -1 * radius + delta], + linewidth=linewidth, + color=edgecolor, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l2 = Line2D( + [start + delta, end - delta], + [-1 * radius + delta, radius - delta], + linewidth=linewidth, + color=edgecolor, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + c1 = Circle( + rbs_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=edgecolor, + facecolor=color, + zorder=12 + zorder_add, + ) + ax.add_patch(c1) ax.add_line(l1) ax.add_line(l2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1677,56 +2455,71 @@ def sbol_spacer (ax, type, num, start, end, prev_end, scale, linewidth, opts): return prev_end, final_end -def sbol_origin (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL origin renderer. - """ +def sbol_origin(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL origin renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 10.0 y_extent = 10.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - ori_center = (start+((end-start)/2.0),0) - - c1 = Circle(ori_center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) - + + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + ori_center = (start + ((end - start) / 2.0), 0) + + c1 = Circle( + ori_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) + ax.add_patch(c1) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1734,61 +2527,77 @@ def sbol_origin (ax, type, num, start, end, prev_end, scale, linewidth, opts): return prev_end, final_end -def sbol_operator (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL operator renderer. - """ +def sbol_operator(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL operator renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 6.0 y_extent = 3.0 - linestyle = '-' + linestyle = "-" scale = 1 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - #white rectangle overlays backbone line - p1 = Polygon([(start , y_extent), - (start, -y_extent), - ((start+x_extent) , -y_extent), - ((start+x_extent), y_extent)], - edgecolor=(0,0,0), facecolor=color, linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + ((start + x_extent), -y_extent), + ((start + x_extent), y_extent), + ], + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1796,122 +2605,145 @@ def sbol_operator (ax, type, num, start, end, prev_end, scale, linewidth, opts): return prev_end, final_end -def sbol_insulator (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL insulator renderer. - """ +def sbol_insulator(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL insulator renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 8.0 y_extent = 4.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=(0,0,0), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=(0, 0, 0), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) bits = 5.0 - gap_size = ((end-start)/bits) + gap_size = (end - start) / bits x_inset_start = start + gap_size - x_inset_end = start + ((bits-1.0)*gap_size) + x_inset_end = start + ((bits - 1.0) * gap_size) # Inside rectangle - p2 = Polygon([(x_inset_start, y_extent-gap_size), - (x_inset_start, -y_extent+gap_size), - (x_inset_end, -y_extent+gap_size), - (x_inset_end, y_extent-gap_size)], - edgecolor=(0,0,0), facecolor=(1,1,1), linewidth=linewidth, zorder=12+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (x_inset_start, y_extent - gap_size), + (x_inset_start, -y_extent + gap_size), + (x_inset_end, -y_extent + gap_size), + (x_inset_end, y_extent - gap_size), + ], + edgecolor=(0, 0, 0), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=12 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) ax.add_patch(p2) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end + # added by Ben Laskaris 4/11/20 def sbol_triangle(ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL coding sequence renderer. - """ + """Built-in SBOL coding sequence renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" start_pad = 1.0 end_pad = 1.0 y_extent = 5 x_extent = 13 arrowhead_height = 4 arrowhead_length = 8 - edgecolor = (0,0,0) + edgecolor = (0, 0, 0) scale = 1 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'edge_color' in list(opts.keys()): - edgecolor = opts['edge_color'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "edge_color" in list(opts.keys()): + edgecolor = opts["edge_color"] # Check direction add start padding dir_fac = 1.0 @@ -1919,35 +2751,50 @@ def sbol_triangle(ax, type, num, start, end, prev_end, scale, linewidth, opts): final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the CDS symbol - p1 = Polygon([(start , y_extent), - (start, -y_extent), - (end, 0)], - edgecolor=edgecolor, facecolor=color, linewidth=linewidth, - hatch=hatch, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0 + p1 = Polygon( + [(start, y_extent), (start, -y_extent), (end, 0)], + edgecolor=edgecolor, + facecolor=color, + linewidth=linewidth, + hatch=hatch, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0 ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end + # added by Ben Laskaris 4/11/20 -def sbol_degredation(ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL spacer renderer. - """ +def sbol_degredation( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL spacer renderer.""" # Default options zorder_add = 0.0 color = (1, 1, 1) @@ -1956,29 +2803,29 @@ def sbol_degredation(ax, type, num, start, end, prev_end, scale, linewidth, opts end_pad = 2.0 x_extent = 3.0 y_extent = 3.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'edgecolor' in list(opts.keys()): - edgecolor = opts['edgecolor'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "edgecolor" in list(opts.keys()): + edgecolor = opts["edgecolor"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end @@ -1992,64 +2839,79 @@ def sbol_degredation(ax, type, num, start, end, prev_end, scale, linewidth, opts delta = radius - 0.5 * radius * math.sqrt(2) - c1 = Circle(rbs_center, x_extent / 2.0, linewidth=linewidth, edgecolor=edgecolor, - facecolor=color, zorder=12 + zorder_add) + c1 = Circle( + rbs_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=edgecolor, + facecolor=color, + zorder=12 + zorder_add, + ) ax.add_patch(c1) - - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end + ((final_start - final_end) / 2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start + ((final_end - final_start) / 2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end + # added by Ben Laskaris 4/11/20 -def sbol_bar (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL coding sequence renderer. - """ +def sbol_bar(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL coding sequence renderer.""" # Default options # zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" start_pad = 1.0 end_pad = 1.0 y_extent = 20 x_extent = 2.5 arrowhead_height = 4 arrowhead_length = 8 - edgecolor = (0,0,0) + edgecolor = (0, 0, 0) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'edge_color' in list(opts.keys()): - edgecolor = opts['edge_color'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "edge_color" in list(opts.keys()): + edgecolor = opts["edge_color"] # Check direction add start padding dir_fac = 1.0 @@ -2057,73 +2919,91 @@ def sbol_bar (ax, type, num, start, end, prev_end, scale, linewidth, opts): final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the CDS symbol - p1 = Polygon([(start, y_extent), - (start, 0), - (end, 0), - (end, y_extent),], - edgecolor=color, facecolor=color, linewidth=linewidth, - hatch=hatch, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0 + p1 = Polygon( + [ + (start, y_extent), + (start, 0), + (end, 0), + (end, y_extent), + ], + edgecolor=color, + facecolor=color, + linewidth=linewidth, + hatch=hatch, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0 ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end + # added by Ben Laskaris 4/11/20 -def sbol_f_sequence(ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL coding sequence renderer. - """ +def sbol_f_sequence( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL coding sequence renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" start_pad = 1.0 end_pad = 1.0 y_extent = 5 x_extent = 40 arrowhead_height = 0 arrowhead_length = 8 - edgecolor = (0,0,0) + edgecolor = (0, 0, 0) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'edge_color' in list(opts.keys()): - edgecolor = opts['edge_color'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "edge_color" in list(opts.keys()): + edgecolor = opts["edge_color"] # Check direction add start padding dir_fac = 1.0 @@ -2131,49 +3011,72 @@ def sbol_f_sequence(ax, type, num, start, end, prev_end, scale, linewidth, opts) final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the CDS symbol - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (end-dir_fac*arrowhead_length, -y_extent), - (end-dir_fac*arrowhead_length, -y_extent-arrowhead_height), - (end, 0), - (end-dir_fac*arrowhead_length, y_extent+arrowhead_height), - (end-dir_fac*arrowhead_length, y_extent)], - edgecolor=edgecolor, facecolor=color, linewidth=linewidth, - hatch=hatch, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")])# This is a work around for matplotlib < 1.4.0 - p2 = Polygon([(start, y_extent), - (start, -y_extent), - (end - dir_fac*(2*x_extent)/3 , -y_extent), - (end - dir_fac*(2*x_extent)/3 , y_extent),], - edgecolor=edgecolor, facecolor=(0, 0, 0), linewidth=linewidth, - hatch=hatch, zorder=11 + zorder_add, - path_effects=[Stroke(joinstyle="miter")]) - + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (end - dir_fac * arrowhead_length, -y_extent), + (end - dir_fac * arrowhead_length, -y_extent - arrowhead_height), + (end, 0), + (end - dir_fac * arrowhead_length, y_extent + arrowhead_height), + (end - dir_fac * arrowhead_length, y_extent), + ], + edgecolor=edgecolor, + facecolor=color, + linewidth=linewidth, + hatch=hatch, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0 + p2 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (end - dir_fac * (2 * x_extent) / 3, -y_extent), + (end - dir_fac * (2 * x_extent) / 3, y_extent), + ], + edgecolor=edgecolor, + facecolor=(0, 0, 0), + linewidth=linewidth, + hatch=hatch, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) ax.add_patch(p1) ax.add_patch(p2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end + # added by Ben Laskaris 4/11/20 def sbol_zring(ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL spacer renderer. - """ + """Built-in SBOL spacer renderer.""" # Default options zorder_add = 0.0 color = (1, 1, 1) @@ -2182,29 +3085,29 @@ def sbol_zring(ax, type, num, start, end, prev_end, scale, linewidth, opts): end_pad = 2.0 x_extent = 6.0 y_extent = 6.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'edgecolor' in list(opts.keys()): - edgecolor = opts['edgecolor'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "edgecolor" in list(opts.keys()): + edgecolor = opts["edgecolor"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end @@ -2218,21 +3121,42 @@ def sbol_zring(ax, type, num, start, end, prev_end, scale, linewidth, opts): delta = radius - 0.5 * radius * math.sqrt(2) - - c1 = Circle(rbs_center, x_extent / 2.0, linewidth=linewidth, edgecolor=color, - facecolor=color, zorder=12 + zorder_add) - - c2 = Circle(rbs_center, x_extent / 3.0, linewidth=linewidth, edgecolor=(1,1,1), - facecolor=(1,1,1), zorder=12 + zorder_add) + c1 = Circle( + rbs_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=color, + zorder=12 + zorder_add, + ) + + c2 = Circle( + rbs_center, + x_extent / 3.0, + linewidth=linewidth, + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) ax.add_patch(c1) ax.add_patch(c2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end + ((final_start - final_end) / 2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start + ((final_end - final_start) / 2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -2240,48 +3164,46 @@ def sbol_zring(ax, type, num, start, end, prev_end, scale, linewidth, opts): return prev_end, final_end - -def sbol_xbar (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL coding sequence renderer. - """ +def sbol_xbar(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL coding sequence renderer.""" # Default options # zorder_add = 0.0 zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" start_pad = 1.0 end_pad = 1.0 y_extent = 4 x_extent = 2 arrowhead_height = 4 arrowhead_length = 8 - edgecolor = (0,0,0) + edgecolor = (0, 0, 0) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'edge_color' in list(opts.keys()): - edgecolor = opts['edge_color'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "edge_color" in list(opts.keys()): + edgecolor = opts["edge_color"] # Check direction add start padding dir_fac = 1.0 @@ -2289,39 +3211,57 @@ def sbol_xbar (ax, type, num, start, end, prev_end, scale, linewidth, opts): final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the CDS symbol - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (end, -y_extent), - (end, y_extent),], - edgecolor=color, facecolor=color, linewidth=linewidth, - hatch=hatch, zorder=12 + zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0 + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (end, -y_extent), + (end, y_extent), + ], + edgecolor=color, + facecolor=color, + linewidth=linewidth, + hatch=hatch, + zorder=12 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0 ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end - # Not used at present -def temporary_repressor (ax, type, num, start, end, prev_end, scale, linewidth, opts): +def temporary_repressor( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) + color = (0.7, 0.7, 0.7) start_pad = 2.0 end_pad = 2.0 y_extent = 10 @@ -2330,47 +3270,63 @@ def temporary_repressor (ax, type, num, start, end, prev_end, scale, linewidth, arrowhead_length = 4 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 final_end = end final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - e1center = (start+((end-start)/2.0),0) - e2center = (start+((end-start)/2.0)+x_extent/3.75,0) - - e1 = Ellipse(e1center, y_extent/2, y_extent, edgecolor=(0,0,0), facecolor=color, - linewidth=linewidth, fill=True, zorder=12+zorder_add) - e2 = Ellipse(e2center, y_extent/2, y_extent, edgecolor=(0,0,0), facecolor=color, - linewidth=linewidth, fill=True, zorder=11+zorder_add) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + e1center = (start + ((end - start) / 2.0), 0) + e2center = (start + ((end - start) / 2.0) + x_extent / 3.75, 0) + + e1 = Ellipse( + e1center, + y_extent / 2, + y_extent, + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + fill=True, + zorder=12 + zorder_add, + ) + e2 = Ellipse( + e2center, + y_extent / 2, + y_extent, + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + fill=True, + zorder=11 + zorder_add, + ) ax.add_patch(e1) ax.add_patch(e2) @@ -2385,82 +3341,128 @@ def temporary_repressor (ax, type, num, start, end, prev_end, scale, linewidth, # Regulation renderers ############################################################################### -def indicate (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Standard repression regulation renderer. - """ - regulation(ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts) - - -def repress (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Standard repression regulation renderer. - """ - regulation(ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts) - - -def induce (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Standard induction regulation renderer. - """ - regulation(ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts) - - -def connect (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Standard induction regulation renderer. - """ - regulation(ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts) - - -def regulation (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ General function for drawing regulation arcs. - """ - print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`') - print('Type: ' + str(type)) - print('From Part: ' + str(from_part['name'])) - print('To Part: ' + str(to_part['name'])) - print('Arc Height Index: ' + str(arc_height_index)) - color = (0.0,0.0,0.0) +def indicate( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Standard repression regulation renderer.""" + regulation( + ax, + type, + num, + from_part, + to_part, + scale, + linewidth, + arc_height_index, + opts, + ) + + +def repress( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Standard repression regulation renderer.""" + regulation( + ax, + type, + num, + from_part, + to_part, + scale, + linewidth, + arc_height_index, + opts, + ) + + +def induce( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Standard induction regulation renderer.""" + regulation( + ax, + type, + num, + from_part, + to_part, + scale, + linewidth, + arc_height_index, + opts, + ) + + +def connect( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Standard induction regulation renderer.""" + regulation( + ax, + type, + num, + from_part, + to_part, + scale, + linewidth, + arc_height_index, + opts, + ) + + +def regulation( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """General function for drawing regulation arcs.""" + print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`") + print("Type: " + str(type)) + print("From Part: " + str(from_part["name"])) + print("To Part: " + str(to_part["name"])) + print("Arc Height Index: " + str(arc_height_index)) + + color = (0.0, 0.0, 0.0) arrowhead_length = 3 - linestyle = '-' + linestyle = "-" arcHeightConst = 15 arcHeightSpacing = 5 arcHeightStart = 10 - arcHeight = arcHeightConst + arc_height_index*arcHeightSpacing - arcHeightEnd = arcHeightStart*1.5 + arcHeight = arcHeightConst + arc_height_index * arcHeightSpacing + arcHeightEnd = arcHeightStart * 1.5 arc_start_x_offset = 0.0 arc_end_x_offset = 0.0 - + # Reset defaults if provided if opts != None: - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'arc_height' in list(opts.keys()): - arcHeight = opts['arc_height'] - if 'arc_height_const' in list(opts.keys()): - arcHeightConst = opts['arc_height_const'] - if 'arc_height_spacing' in list(opts.keys()): - arcHeightSpacing = opts['arc_height_spacing'] - if 'arc_height_start' in list(opts.keys()): - arcHeightStart = opts['arc_height_start'] - if 'arc_height_end' in list(opts.keys()): - arcHeightEnd = opts['arc_height_end'] - if 'arc_start_x_offset' in list(opts.keys()): - arc_start_x_offset = opts['arc_start_x_offset'] - if 'arc_end_x_offset' in list(opts.keys()): - arc_end_x_offset = opts['arc_end_x_offset'] - - if opts == None or 'arc_height' not in list(opts.keys()): - arcHeight = arcHeightConst + arc_height_index*arcHeightSpacing + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "color" in list(opts.keys()): + color = opts["color"] + if "arc_height" in list(opts.keys()): + arcHeight = opts["arc_height"] + if "arc_height_const" in list(opts.keys()): + arcHeightConst = opts["arc_height_const"] + if "arc_height_spacing" in list(opts.keys()): + arcHeightSpacing = opts["arc_height_spacing"] + if "arc_height_start" in list(opts.keys()): + arcHeightStart = opts["arc_height_start"] + if "arc_height_end" in list(opts.keys()): + arcHeightEnd = opts["arc_height_end"] + if "arc_start_x_offset" in list(opts.keys()): + arc_start_x_offset = opts["arc_start_x_offset"] + if "arc_end_x_offset" in list(opts.keys()): + arc_end_x_offset = opts["arc_end_x_offset"] + + if opts == None or "arc_height" not in list(opts.keys()): + arcHeight = arcHeightConst + arc_height_index * arcHeightSpacing startHeight = arcHeightStart - start = ((from_part['start'] + from_part['end']) / 2) + arc_start_x_offset - end = ((to_part['start'] + to_part['end']) / 2) + arc_end_x_offset - middle = (start + end)/2 + start = ((from_part["start"] + from_part["end"]) / 2) + arc_start_x_offset + end = ((to_part["start"] + to_part["end"]) / 2) + arc_end_x_offset + middle = (start + end) / 2 midRepOffset = 3 arcLabelOffset = 5 @@ -2469,75 +3471,137 @@ def regulation (ax, type, num, from_part, to_part, scale, linewidth, arc_height_ indHeight = arrowhead_length corr = linewidth - if to_part['fwd'] == False: - base = -1*startHeight + if to_part["fwd"] == False: + base = -1 * startHeight arcHeightEnd = -arcHeightEnd - top = -1*arcHeight - indHeight = -1*arrowhead_length + top = -1 * arcHeight + indHeight = -1 * arrowhead_length corr *= -1 midRepOffset *= -1 arcLabelOffset *= -1 - - line_away = Line2D([start,start],[base,top], - linewidth=linewidth, color=color, zorder=12, linestyle=linestyle) - line_across = Line2D([start,end],[top,top], - linewidth=linewidth, color=color, zorder=12, linestyle=linestyle) - line_toward = Line2D([end,end],[top,arcHeightEnd+corr], - linewidth=linewidth, color=color, zorder=12, linestyle=linestyle) - line_rep = Line2D([end-arrowhead_length,end+arrowhead_length],[arcHeightEnd,arcHeightEnd], - linewidth=linewidth, color=color, zorder=12, linestyle='-') - line_ind1 = Line2D([end-arrowhead_length,end],[arcHeightEnd+indHeight,arcHeightEnd], - linewidth=linewidth, color=color, zorder=12, linestyle='-') - line_ind2 = Line2D([end+arrowhead_length,end],[arcHeightEnd+indHeight,arcHeightEnd], - linewidth=linewidth, color=color, zorder=12, linestyle='-') + line_away = Line2D( + [start, start], + [base, top], + linewidth=linewidth, + color=color, + zorder=12, + linestyle=linestyle, + ) + line_across = Line2D( + [start, end], + [top, top], + linewidth=linewidth, + color=color, + zorder=12, + linestyle=linestyle, + ) + line_toward = Line2D( + [end, end], + [top, arcHeightEnd + corr], + linewidth=linewidth, + color=color, + zorder=12, + linestyle=linestyle, + ) + line_rep = Line2D( + [end - arrowhead_length, end + arrowhead_length], + [arcHeightEnd, arcHeightEnd], + linewidth=linewidth, + color=color, + zorder=12, + linestyle="-", + ) + line_ind1 = Line2D( + [end - arrowhead_length, end], + [arcHeightEnd + indHeight, arcHeightEnd], + linewidth=linewidth, + color=color, + zorder=12, + linestyle="-", + ) + line_ind2 = Line2D( + [end + arrowhead_length, end], + [arcHeightEnd + indHeight, arcHeightEnd], + linewidth=linewidth, + color=color, + zorder=12, + linestyle="-", + ) # added by Ben Laskaris 4/15/20 - tall_line_toward = Line2D([end, end], [top + arcHeightEnd, arcHeightEnd + corr], - linewidth=linewidth, color=color, zorder=12, linestyle=linestyle) - - mid_line_toward = Line2D([middle, middle], [top - midRepOffset , top + arcHeightEnd + corr], - linewidth=linewidth, color=color, zorder=12, linestyle=linestyle) - - mid_line_rep = Line2D([middle-arrowhead_length,middle+arrowhead_length],[top - midRepOffset ,top - midRepOffset], - linewidth=linewidth, color=color, zorder=12, linestyle='-') - - - if(type == 'Repression'): + tall_line_toward = Line2D( + [end, end], + [top + arcHeightEnd, arcHeightEnd + corr], + linewidth=linewidth, + color=color, + zorder=12, + linestyle=linestyle, + ) + + mid_line_toward = Line2D( + [middle, middle], + [top - midRepOffset, top + arcHeightEnd + corr], + linewidth=linewidth, + color=color, + zorder=12, + linestyle=linestyle, + ) + + mid_line_rep = Line2D( + [middle - arrowhead_length, middle + arrowhead_length], + [top - midRepOffset, top - midRepOffset], + linewidth=linewidth, + color=color, + zorder=12, + linestyle="-", + ) + + if type == "Repression": ax.add_line(line_rep) ax.add_line(line_away) ax.add_line(line_across) ax.add_line(line_toward) - # added by Ben Laskaris 4/15/20 - if (type == 'RepToRep'): + if type == "RepToRep": ax.add_line(mid_line_toward) ax.add_line(mid_line_rep) - write_arc_label(ax, opts['arc_label_name'], middle, top + arcHeightEnd + arcLabelOffset, opts=opts) - - - if(type == 'Activation'): + write_arc_label( + ax, + opts["arc_label_name"], + middle, + top + arcHeightEnd + arcLabelOffset, + opts=opts, + ) + + if type == "Activation": ax.add_line(line_ind1) ax.add_line(line_ind2) ax.add_line(line_away) ax.add_line(line_across) ax.add_line(line_toward) - - if(type == 'Connection'): - verts = [ (start, base), (start, top), (end, top), (end, base) ] + if type == "Connection": + verts = [(start, base), (start, top), (end, top), (end, base)] codes = [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4] path1 = Path(verts, codes) - patch = patches.PathPatch(path1, facecolor='none', lw=linewidth, edgecolor=color) + patch = patches.PathPatch( + path1, facecolor="none", lw=linewidth, edgecolor=color + ) ax.add_patch(patch) - - if (type == 'PointingActivation'): + if type == "PointingActivation": ax.add_line(line_ind1) ax.add_line(line_ind2) ax.add_line(tall_line_toward) - write_arc_label(ax, opts['arc_label_name'], end, top + arcHeightEnd + arcLabelOffset, opts=opts) + write_arc_label( + ax, + opts["arc_label_name"], + end, + top + arcHeightEnd + arcLabelOffset, + opts=opts, + ) ############################################################################### @@ -2545,12 +3609,13 @@ def regulation (ax, type, num, from_part, to_part, scale, linewidth, arc_height_ ############################################################################### -def trace_promoter_start (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based promoter renderer. - """ +def trace_promoter_start( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based promoter renderer.""" # Default options zorder_add = 0.0 - color = (0.0,0.0,1.0) + color = (0.0, 0.0, 1.0) y_offset = 0.0 y_extent = 6.0 x_extent = 30.0 @@ -2559,70 +3624,122 @@ def trace_promoter_start (ax, type, num, start_bp, end_bp, prev_end, scale, line highlight_y_extent = 0.8 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'highlight_y_extent' in list(opts.keys()): - highlight_y_extent = opts['highlight_y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "highlight_y_extent" in list(opts.keys()): + highlight_y_extent = opts["highlight_y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 y_offset = -y_offset # Draw the promoter symbol - l1 = Line2D([start_bp,start_bp],[0+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, - color=color, zorder=14+zorder_add) - l2 = Line2D([start_bp,start_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*0.5*scale], - [dir_fac*y_extent+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, - color=color, zorder=14+zorder_add) + l1 = Line2D( + [start_bp, start_bp], + [0 + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) + l2 = Line2D( + [ + start_bp, + start_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * 0.5 * scale, + ], + [dir_fac * y_extent + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) - p1 = Polygon([(start_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*scale, - dir_fac*y_extent+(arrowhead_height)+y_offset), - (start_bp+dir_fac*(x_extent*scale), dir_fac*y_extent+y_offset), - (start_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*scale, - dir_fac*y_extent-(arrowhead_height)+y_offset)], - facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + ( + start_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * scale, + dir_fac * y_extent + (arrowhead_height) + y_offset, + ), + ( + start_bp + dir_fac * (x_extent * scale), + dir_fac * y_extent + y_offset, + ), + ( + start_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * scale, + dir_fac * y_extent - (arrowhead_height) + y_offset, + ), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) # Shade the promoter area (normally smaller than symbol extent) - p2 = Polygon([(start_bp, -highlight_y_extent+y_offset), - (start_bp, highlight_y_extent+y_offset), - (end_bp, highlight_y_extent+y_offset), - (end_bp, -highlight_y_extent+y_offset)], facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (start_bp, -highlight_y_extent + y_offset), + (start_bp, highlight_y_extent + y_offset), + (end_bp, highlight_y_extent + y_offset), + (end_bp, -highlight_y_extent + y_offset), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_promoter (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based promoter renderer with arrow at TSS. - """ + +def trace_promoter( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based promoter renderer with arrow at TSS.""" # Default options zorder_add = 0.0 - color = (0.0,0.0,1.0) + color = (0.0, 0.0, 1.0) y_offset = 0.0 y_extent = 6.0 x_extent = 30.0 @@ -2631,334 +3748,498 @@ def trace_promoter (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, highlight_y_extent = 0.8 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'highlight_y_extent' in list(opts.keys()): - highlight_y_extent = opts['highlight_y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "highlight_y_extent" in list(opts.keys()): + highlight_y_extent = opts["highlight_y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 y_offset = -y_offset # Draw the promoter symbol - l1 = Line2D([end_bp,end_bp],[0+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, - color=color, zorder=14+zorder_add) - l2 = Line2D([end_bp,end_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*0.5*scale], - [dir_fac*y_extent+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, - color=color, zorder=14+zorder_add) + l1 = Line2D( + [end_bp, end_bp], + [0 + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) + l2 = Line2D( + [ + end_bp, + end_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * 0.5 * scale, + ], + [dir_fac * y_extent + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) - p1 = Polygon([(end_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*scale, - dir_fac*y_extent+(arrowhead_height)+y_offset), - (end_bp+dir_fac*(x_extent*scale), dir_fac*y_extent+y_offset), - (end_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*scale, - dir_fac*y_extent-(arrowhead_height)+y_offset)], - facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + ( + end_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * scale, + dir_fac * y_extent + (arrowhead_height) + y_offset, + ), + ( + end_bp + dir_fac * (x_extent * scale), + dir_fac * y_extent + y_offset, + ), + ( + end_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * scale, + dir_fac * y_extent - (arrowhead_height) + y_offset, + ), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) # Shade the promoter area (normally smaller than symbol extent) - p2 = Polygon([(start_bp, -highlight_y_extent+y_offset), - (start_bp, highlight_y_extent+y_offset), - (end_bp, highlight_y_extent+y_offset), - (end_bp, -highlight_y_extent+y_offset)], facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (start_bp, -highlight_y_extent + y_offset), + (start_bp, highlight_y_extent + y_offset), + (end_bp, highlight_y_extent + y_offset), + (end_bp, -highlight_y_extent + y_offset), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_rbs (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based ribosome binding site renderer. - """ +def trace_rbs( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based ribosome binding site renderer.""" # Default options zorder_add = 0.0 - color = (0.16,0.68,0.15) + color = (0.16, 0.68, 0.15) y_offset = 0.0 y_extent = 3.5 x_extent = 10.0 highlight_y_extent = 0.8 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'highlight_y_extent' in list(opts.keys()): - highlight_y_extent = opts['highlight_y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "highlight_y_extent" in list(opts.keys()): + highlight_y_extent = opts["highlight_y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 # Draw the RBS symbol - l1 = Line2D([start_bp,start_bp],[0+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, color=color, zorder=14+zorder_add) + l1 = Line2D( + [start_bp, start_bp], + [0 + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) ax.add_line(l1) - c1 = Ellipse((start_bp,dir_fac*y_extent+y_offset),width=(x_extent*scale),height=y_extent*0.4,color=color, zorder=14+zorder_add) + c1 = Ellipse( + (start_bp, dir_fac * y_extent + y_offset), + width=(x_extent * scale), + height=y_extent * 0.4, + color=color, + zorder=14 + zorder_add, + ) ax.add_artist(c1) # Shade the promoter area (normally smaller than symbol extent) - p2 = Polygon([(start_bp, -highlight_y_extent+y_offset), - (start_bp, highlight_y_extent+y_offset), - (end_bp, highlight_y_extent+y_offset), - (end_bp, -highlight_y_extent+y_offset)], facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (start_bp, -highlight_y_extent + y_offset), + (start_bp, highlight_y_extent + y_offset), + (end_bp, highlight_y_extent + y_offset), + (end_bp, -highlight_y_extent + y_offset), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_user_defined (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based user defined region renderer. - """ +def trace_user_defined( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based user defined region renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" y_offset = 0.0 y_extent = 1.5 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 # Draw the CDS symbol - p1 = Polygon([(start_bp, y_extent+y_offset), - (start_bp, -y_extent+y_offset), - (end_bp-dir_fac*scale, -y_extent+y_offset), - (end_bp-dir_fac*scale, y_extent+y_offset)], - edgecolor=(0.0,0.0,0.0), facecolor=color, linewidth=linewidth, - hatch=hatch, zorder=15+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start_bp, y_extent + y_offset), + (start_bp, -y_extent + y_offset), + (end_bp - dir_fac * scale, -y_extent + y_offset), + (end_bp - dir_fac * scale, y_extent + y_offset), + ], + edgecolor=(0.0, 0.0, 0.0), + facecolor=color, + linewidth=linewidth, + hatch=hatch, + zorder=15 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_cds (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based coding sequence renderer. - """ +def trace_cds( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based coding sequence renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" y_offset = 0.0 y_extent = 1.5 arrowhead_height = 1.0 arrowhead_length = 30.0 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 # Draw the CDS symbol - p1 = Polygon([(start_bp, y_extent+y_offset), - (start_bp, -y_extent+y_offset), - (end_bp-dir_fac*arrowhead_length*scale, -y_extent+y_offset), - (end_bp-dir_fac*arrowhead_length*scale, -y_extent-arrowhead_height+y_offset), - (end_bp, 0+y_offset), - (end_bp-dir_fac*arrowhead_length*scale, y_extent+arrowhead_height+y_offset), - (end_bp-dir_fac*arrowhead_length*scale, y_extent+y_offset)], - edgecolor=(0.0,0.0,0.0), facecolor=color, linewidth=linewidth, - hatch=hatch, zorder=15+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start_bp, y_extent + y_offset), + (start_bp, -y_extent + y_offset), + (end_bp - dir_fac * arrowhead_length * scale, -y_extent + y_offset), + ( + end_bp - dir_fac * arrowhead_length * scale, + -y_extent - arrowhead_height + y_offset, + ), + (end_bp, 0 + y_offset), + ( + end_bp - dir_fac * arrowhead_length * scale, + y_extent + arrowhead_height + y_offset, + ), + (end_bp - dir_fac * arrowhead_length * scale, y_extent + y_offset), + ], + edgecolor=(0.0, 0.0, 0.0), + facecolor=color, + linewidth=linewidth, + hatch=hatch, + zorder=15 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_terminator (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based terminator renderer. - """ +def trace_terminator( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based terminator renderer.""" # Default options zorder_add = 0.0 - color = (1.0,0.0,0.0) + color = (1.0, 0.0, 0.0) y_offset = 0.0 y_extent = 3.5 x_extent = 10.0 highlight_y_extent = 0.8 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'highlight_y_extent' in list(opts.keys()): - highlight_y_extent = opts['highlight_y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "highlight_y_extent" in list(opts.keys()): + highlight_y_extent = opts["highlight_y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 # Draw the terminator symbol - l1 = Line2D([start_bp,start_bp],[0+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, color=color, zorder=8+zorder_add) - l2 = Line2D([start_bp-(x_extent*scale),start_bp+(x_extent*scale)],[dir_fac*y_extent+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, color=color, zorder=14+zorder_add) + l1 = Line2D( + [start_bp, start_bp], + [0 + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + ) + l2 = Line2D( + [start_bp - (x_extent * scale), start_bp + (x_extent * scale)], + [dir_fac * y_extent + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) # Shade the terminator area (normally smaller than symbol extent) - p2 = Polygon([(start_bp, -highlight_y_extent+y_offset), - (start_bp, highlight_y_extent+y_offset), - (end_bp, highlight_y_extent+y_offset), - (end_bp, -highlight_y_extent+y_offset)], facecolor=color, edgecolor=color, linewidth=linewidth, zorder=13, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (start_bp, -highlight_y_extent + y_offset), + (start_bp, highlight_y_extent + y_offset), + (end_bp, highlight_y_extent + y_offset), + (end_bp, -highlight_y_extent + y_offset), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=13, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp + ############################################################################### # The DNA renderer ############################################################################### class DNARenderer: - """ Class defining the DNA rendering funtionality. - """ + """Class defining the DNA rendering funtionality.""" # Standard part types - STD_PART_TYPES = ['Promoter', - 'CDS', - 'Terminator', - 'RBS', - 'Scar', - 'Spacer', - 'EmptySpace', - 'Ribozyme', - 'Ribonuclease', - 'Protease', - 'DNACleavageSite', - 'RNACleavageSite', - 'ProteinCleavageSite', - 'DNALocation', - 'RNALocation', - 'ProteinLocation', - 'DNAStability', - 'RNAStability', - 'ProteinStability', - 'StemTop', - 'Operator', - 'Origin', - 'Insulator', - '5Overhang', - '3Overhang', - 'RestrictionSite', - 'BluntRestrictionSite', - 'PrimerBindingSite', - '5StickyRestrictionSite', - '3StickyRestrictionSite', - 'UserDefined', - 'Signature'] + STD_PART_TYPES = [ + "Promoter", + "CDS", + "Terminator", + "RBS", + "Scar", + "Spacer", + "EmptySpace", + "Ribozyme", + "Ribonuclease", + "Protease", + "DNACleavageSite", + "RNACleavageSite", + "ProteinCleavageSite", + "DNALocation", + "RNALocation", + "ProteinLocation", + "DNAStability", + "RNAStability", + "ProteinStability", + "StemTop", + "Operator", + "Origin", + "Insulator", + "5Overhang", + "3Overhang", + "RestrictionSite", + "BluntRestrictionSite", + "PrimerBindingSite", + "5StickyRestrictionSite", + "3StickyRestrictionSite", + "UserDefined", + "Signature", + ] # Standard regulatory types - STD_REG_TYPES = ['Repression', - 'RepToRep', - 'Activation', - 'PointingActivation', - 'Connection',] - - def __init__(self, scale=1.0, linewidth=1.0, linecolor=(0,0,0), - backbone_pad_left=0.0, backbone_pad_right=0.0): - """ Constructor to generate an empty DNARenderer. + STD_REG_TYPES = [ + "Repression", + "RepToRep", + "Activation", + "PointingActivation", + "Connection", + ] + + def __init__( + self, + scale=1.0, + linewidth=1.0, + linecolor=(0, 0, 0), + backbone_pad_left=0.0, + backbone_pad_right=0.0, + ): + """Constructor to generate an empty DNARenderer. Parameters ---------- @@ -2981,72 +4262,82 @@ def __init__(self, scale=1.0, linewidth=1.0, linecolor=(0,0,0), self.backbone_pad_right = backbone_pad_right self.reg_height = 15 - def SBOL_part_renderers (self): - """ Return dictionary of all standard built-in SBOL part renderers. - """ + def SBOL_part_renderers(self): + """Return dictionary of all standard built-in SBOL part renderers.""" return { - 'Promoter' :sbol_promoter, - 'CDS' :sbol_cds, - 'Terminator' :sbol_terminator, - 'RBS' :sbol_rbs, - 'Scar' :sbol_scar, - 'Spacer' :sbol_spacer, - 'EmptySpace' :sbol_empty_space, - 'Ribozyme' :sbol_ribozyme, - 'Ribonuclease' :sbol_stem_top, - 'Protease' :sbol_stem_top, - 'DNACleavageSite' :sbol_stem_top, - 'RNACleavageSite' :sbol_stem_top, - 'ProteinCleavageSite':sbol_stem_top, - 'DNALocation' :sbol_stem_top, - 'RNALocation' :sbol_stem_top, - 'ProteinLocation' :sbol_stem_top, - 'DNAStability' :sbol_stem_top, - 'RNAStability' :sbol_stem_top, - 'ProteinStability' :sbol_stem_top, - 'StemTop' :sbol_stem_top, - 'Operator' :sbol_operator, - 'Origin' :sbol_origin, - 'Insulator' :sbol_insulator, - '5Overhang' :sbol_5_overhang, - '3Overhang' :sbol_3_overhang, - 'RestrictionSite' :sbol_restriction_site, - 'BluntRestrictionSite' :sbol_blunt_restriction_site, - 'PrimerBindingSite' :sbol_primer_binding_site, - '5StickyRestrictionSite' :sbol_5_sticky_restriction_site, - '3StickyRestrictionSite' :sbol_3_sticky_restriction_site, - 'UserDefined' :sbol_user_defined, - 'Signature' :sbol_signature, + "Promoter": sbol_promoter, + "CDS": sbol_cds, + "Terminator": sbol_terminator, + "RBS": sbol_rbs, + "Scar": sbol_scar, + "Spacer": sbol_spacer, + "EmptySpace": sbol_empty_space, + "Ribozyme": sbol_ribozyme, + "Ribonuclease": sbol_stem_top, + "Protease": sbol_stem_top, + "DNACleavageSite": sbol_stem_top, + "RNACleavageSite": sbol_stem_top, + "ProteinCleavageSite": sbol_stem_top, + "DNALocation": sbol_stem_top, + "RNALocation": sbol_stem_top, + "ProteinLocation": sbol_stem_top, + "DNAStability": sbol_stem_top, + "RNAStability": sbol_stem_top, + "ProteinStability": sbol_stem_top, + "StemTop": sbol_stem_top, + "Operator": sbol_operator, + "Origin": sbol_origin, + "Insulator": sbol_insulator, + "5Overhang": sbol_5_overhang, + "3Overhang": sbol_3_overhang, + "RestrictionSite": sbol_restriction_site, + "BluntRestrictionSite": sbol_blunt_restriction_site, + "PrimerBindingSite": sbol_primer_binding_site, + "5StickyRestrictionSite": sbol_5_sticky_restriction_site, + "3StickyRestrictionSite": sbol_3_sticky_restriction_site, + "UserDefined": sbol_user_defined, + "Signature": sbol_signature, # added by Ben Laskaris 4/11/20 - 'Triangle' :sbol_triangle, - 'Degredation' :sbol_degredation, - 'Bar' :sbol_bar, - 'FSequence' :sbol_f_sequence, - 'ZRing' :sbol_zring, - 'XBar' :sbol_xbar} - - def trace_part_renderers (self): - """ Return dictionary of all standard built-in trace part renderers. - """ + "Triangle": sbol_triangle, + "Degredation": sbol_degredation, + "Bar": sbol_bar, + "FSequence": sbol_f_sequence, + "ZRing": sbol_zring, + "XBar": sbol_xbar, + } + + def trace_part_renderers(self): + """Return dictionary of all standard built-in trace part renderers.""" return { - 'Promoter' :trace_promoter, - 'CDS' :trace_cds, - 'Terminator' :trace_terminator, - 'RBS' :trace_rbs, - 'UserDefined' :trace_user_defined} - - def std_reg_renderers (self): - """ Return dictionary of all standard built-in regulation renderers. - """ + "Promoter": trace_promoter, + "CDS": trace_cds, + "Terminator": trace_terminator, + "RBS": trace_rbs, + "UserDefined": trace_user_defined, + } + + def std_reg_renderers(self): + """Return dictionary of all standard built-in regulation renderers.""" return { - 'Repression' :repress, - 'RepToRep' :repress, - 'Activation' :induce, - 'PointingActivation':induce, - 'Connection' :connect} - - def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, plot_backbone=True, plot_vector = False, vector_label=None): - """ Render the parts on the DNA and regulation. + "Repression": repress, + "RepToRep": repress, + "Activation": induce, + "PointingActivation": induce, + "Connection": connect, + } + + def renderDNA( + self, + ax, + parts, + part_renderers, + regs=None, + reg_renderers=None, + plot_backbone=True, + plot_vector=False, + vector_label=None, + ): + """Render the parts on the DNA and regulation. Parameters ---------- @@ -3057,7 +4348,7 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p The design to draw. This is a list of dicts, where each dict relates to a part and must contain the following keys: - name (string) - - type (string) + - type (string) - fwd (bool) - start (float, optional) - end (float, optional) @@ -3071,12 +4362,12 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p Regulation present in the design. This is a list of dicts, where each dict relates to a single regulation arc and must contain the following keys: - type (string) - - from_part (part object dict) + - from_part (part object dict) - to_part (part object dict) These will then be drawn in accordance with the renders selected. reg_renderers : dict(functions) (default=None) - Dict of functions where the key in the regulation type and the dictionary + Dict of functions where the key in the regulation type and the dictionary returns the function to be used to draw that regulation type. Returns @@ -3088,12 +4379,12 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p The x-point in the axis space that drawing ends. """ # Update the matplotlib rendering default for drawing the parts (we want mitered edges) - matplotlib.rcParams['lines.dash_joinstyle'] = 'miter' - matplotlib.rcParams['lines.dash_capstyle'] = 'butt' - matplotlib.rcParams['lines.solid_joinstyle'] = 'miter' - matplotlib.rcParams['lines.solid_capstyle'] = 'projecting' + matplotlib.rcParams["lines.dash_joinstyle"] = "miter" + matplotlib.rcParams["lines.dash_capstyle"] = "butt" + matplotlib.rcParams["lines.solid_joinstyle"] = "miter" + matplotlib.rcParams["lines.solid_capstyle"] = "projecting" # Make text editable in Adobe Illustrator - matplotlib.rcParams['pdf.fonttype'] = 42 + matplotlib.rcParams["pdf.fonttype"] = 42 # Plot the parts to the axis part_num = 0 prev_end = 0 @@ -3104,39 +4395,46 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p keys = list(part.keys()) # Check the part has minimal details required - if 'type' in keys: - if 'fwd' not in keys: - part['fwd'] = True - elif part['fwd'] == False and 'start' in keys and 'end' in keys: - start = part['start'] - end = part['end'] - part['end'] = start - part['start'] = end - if 'start' not in keys: - if part['fwd'] == True: - part['start'] = part_num + if "type" in keys: + if "fwd" not in keys: + part["fwd"] = True + elif part["fwd"] == False and "start" in keys and "end" in keys: + start = part["start"] + end = part["end"] + part["end"] = start + part["start"] = end + if "start" not in keys: + if part["fwd"] == True: + part["start"] = part_num else: - part['start'] = part_num+1 - if 'end' not in keys: - if part['fwd'] == True: - part['end'] = part_num+1 + part["start"] = part_num + 1 + if "end" not in keys: + if part["fwd"] == True: + part["end"] = part_num + 1 else: - part['end'] = part_num + part["end"] = part_num # Extract custom part options (if available) part_opts = None - if 'opts' in list(part.keys()): - part_opts = part['opts'] + if "opts" in list(part.keys()): + part_opts = part["opts"] # Use the correct renderer - if 'renderer' in list(part.keys()): + if "renderer" in list(part.keys()): # Use custom renderer - prev_start, prev_end = part['renderer'](ax, part['type'], part_num, - part['start'], part['end'], prev_end, - self.scale, self.linewidth, - opts=part_opts) - - #update start,end for regulation - #part['start'] = prev_start - #part['end'] = prev_end + prev_start, prev_end = part["renderer"]( + ax, + part["type"], + part_num, + part["start"], + part["end"], + prev_end, + self.scale, + self.linewidth, + opts=part_opts, + ) + + # update start,end for regulation + # part['start'] = prev_start + # part['end'] = prev_end if first_part == True: first_start = prev_start @@ -3144,26 +4442,32 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p else: # Use standard renderer, if one exists - if part['type'] in list(part_renderers.keys()): - prev_start, prev_end = part_renderers[part['type']](ax, - part['type'], part_num, - part['start'], part['end'], - prev_end, self.scale, - self.linewidth, opts=part_opts) - - #update start,end for regulation [TEG] - if part['fwd'] == True: - part['start'] = prev_start - part['end'] = prev_end + if part["type"] in list(part_renderers.keys()): + prev_start, prev_end = part_renderers[part["type"]]( + ax, + part["type"], + part_num, + part["start"], + part["end"], + prev_end, + self.scale, + self.linewidth, + opts=part_opts, + ) + + # update start,end for regulation [TEG] + if part["fwd"] == True: + part["start"] = prev_start + part["end"] = prev_end else: - part['start'] = prev_end - part['end'] = prev_start - + part["start"] = prev_end + part["end"] = prev_start + if first_part == True: first_start = prev_start first_part = False part_num += 1 - + # first pass to get all of the arcranges if regs != None: @@ -3171,29 +4475,33 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p keys = list(reg.keys()) # Check the part has minimal details required - if 'type' in keys and 'from_part' in keys and 'to_part' in keys: + if "type" in keys and "from_part" in keys and "to_part" in keys: # Extract custom part options (if available) reg_opts = None - if 'opts' in list(reg.keys()): - reg_opts = reg['opts'] - - if reg['type'] in list(reg_renderers.keys()): - + if "opts" in list(reg.keys()): + reg_opts = reg["opts"] + + if reg["type"] in list(reg_renderers.keys()): + ############################################################################## - arcstart = (reg['from_part']['start'] + reg['from_part']['end']) / 2 - arcend = (reg['to_part']['start'] + reg['to_part']['end']) / 2 - arcrange = [arcstart,arcend] - reg['arclength'] = math.fabs(arcstart-arcend) - reg['arc_height_index'] = 1 + arcstart = ( + reg["from_part"]["start"] + reg["from_part"]["end"] + ) / 2 + arcend = ( + reg["to_part"]["start"] + reg["to_part"]["end"] + ) / 2 + arcrange = [arcstart, arcend] + reg["arclength"] = math.fabs(arcstart - arcend) + reg["arc_height_index"] = 1 ############################################################################## - #sort regs by arc ranges from shortest to longest - regs.sort(key=lambda x: x['arclength'], reverse=False) + # sort regs by arc ranges from shortest to longest + regs.sort(key=lambda x: x["arclength"], reverse=False) reg_num = 0 - pos_arc_ranges = [] # arc above DNA backbone if to_part is fwd - neg_arc_ranges = [] # arc below DNA backbone if to_part is reverse + pos_arc_ranges = [] # arc above DNA backbone if to_part is fwd + neg_arc_ranges = [] # arc below DNA backbone if to_part is reverse current_max = 1 # second pass to render all the arcs @@ -3201,131 +4509,171 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p keys = list(reg.keys()) # Check the part has minimal details required - if 'type' in keys and 'from_part' in keys and 'to_part' in keys: + if "type" in keys and "from_part" in keys and "to_part" in keys: # Extract custom part options (if available) reg_opts = None - if 'opts' in list(reg.keys()): - reg_opts = reg['opts'] - - if reg['type'] in list(reg_renderers.keys()): - + if "opts" in list(reg.keys()): + reg_opts = reg["opts"] + + if reg["type"] in list(reg_renderers.keys()): + ############################################################################## # arc height algorithm: greedy from left-to-right on DNA design - - arcstart = (reg['from_part']['start'] + reg['from_part']['end']) / 2 - arcend = (reg['to_part']['start'] + reg['to_part']['end']) / 2 - - arcmin = min(arcstart,arcend) - arcmax = max(arcstart,arcend) - arcrange = [arcmin,arcmax,reg['arc_height_index']] + + arcstart = ( + reg["from_part"]["start"] + reg["from_part"]["end"] + ) / 2 + arcend = ( + reg["to_part"]["start"] + reg["to_part"]["end"] + ) / 2 + + arcmin = min(arcstart, arcend) + arcmax = max(arcstart, arcend) + arcrange = [arcmin, arcmax, reg["arc_height_index"]] arc_height_index = 1 - + # arc above if to_part is fwd - if(reg['to_part']['fwd'] == True): + if reg["to_part"]["fwd"] == True: # find max arc height index of ONLY the prior arcs that clash with the current arc current_max = 1 for r in pos_arc_ranges: - if (arcrange[0] > r[0] and arcrange[0] < r[1]): - if(r[2] > current_max): + if arcrange[0] > r[0] and arcrange[0] < r[1]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[0] > r[1] and arcrange[0] < r[0]): - if(r[2] > current_max): + elif arcrange[0] > r[1] and arcrange[0] < r[0]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[1] > r[0] and arcrange[0] < r[1]): - if(r[2] > current_max): + elif arcrange[1] > r[0] and arcrange[0] < r[1]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[1] > r[1] and arcrange[0] < r[0]): - if(r[2] > current_max): + elif arcrange[1] > r[1] and arcrange[0] < r[0]: + if r[2] > current_max: current_max = r[2] - + # if arcs cross over, increment the arc height index for r in pos_arc_ranges: - if (arcrange[0] > r[0] and arcrange[0] < r[1]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[0] > r[1] and arcrange[0] < r[0]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[1] > r[0] and arcrange[0] < r[1]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[1] > r[1] and arcrange[0] < r[0]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] + if arcrange[0] > r[0] and arcrange[0] < r[1]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[0] > r[1] and arcrange[0] < r[0]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[1] > r[0] and arcrange[0] < r[1]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[1] > r[1] and arcrange[0] < r[0]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] pos_arc_ranges.append(arcrange) - + # arc below if to_part is reverse else: # find max arc height index current_max = 1 for r in neg_arc_ranges: - if (arcrange[0] > r[0] and arcrange[0] < r[1]): - if(r[2] > current_max): + if arcrange[0] > r[0] and arcrange[0] < r[1]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[0] > r[1] and arcrange[0] < r[0]): - if(r[2] > current_max): + elif arcrange[0] > r[1] and arcrange[0] < r[0]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[1] > r[0] and arcrange[0] < r[1]): - if(r[2] > current_max): + elif arcrange[1] > r[0] and arcrange[0] < r[1]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[1] > r[1] and arcrange[0] < r[0]): - if(r[2] > current_max): + elif arcrange[1] > r[1] and arcrange[0] < r[0]: + if r[2] > current_max: current_max = r[2] - + # if arcs cross over, increment the arc height index for r in neg_arc_ranges: - if (arcrange[0] > r[0] and arcrange[0] < r[1]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[0] > r[1] and arcrange[0] < r[0]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[1] > r[0] and arcrange[0] < r[1]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[1] > r[1] and arcrange[0] < r[0]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] + if arcrange[0] > r[0] and arcrange[0] < r[1]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[0] > r[1] and arcrange[0] < r[0]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[1] > r[0] and arcrange[0] < r[1]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[1] > r[1] and arcrange[0] < r[0]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] neg_arc_ranges.append(arcrange) ############################################################################## - reg_renderers[reg['type']](ax, reg['type'], - reg_num, reg['from_part'], - reg['to_part'], self.scale, - self.linewidth, reg['arc_height_index'], opts=reg_opts) + reg_renderers[reg["type"]]( + ax, + reg["type"], + reg_num, + reg["from_part"], + reg["to_part"], + self.scale, + self.linewidth, + reg["arc_height_index"], + opts=reg_opts, + ) reg_num += 1 # Plot the backbone (z=1) if plot_backbone == True: - l1 = Line2D([first_start-self.backbone_pad_left,prev_end+self.backbone_pad_right],[0,0], - linewidth=self.linewidth, color=self.linecolor, zorder=10) + l1 = Line2D( + [ + first_start - self.backbone_pad_left, + prev_end + self.backbone_pad_right, + ], + [0, 0], + linewidth=self.linewidth, + color=self.linecolor, + zorder=10, + ) ax.add_line(l1) if plot_vector == True: - lv1 = Line2D([first_start-self.backbone_pad_left,first_start-self.backbone_pad_left,prev_end+self.backbone_pad_right, prev_end+self.backbone_pad_right],[0,-20,-20,0], - linewidth=self.linewidth, color=self.linecolor, zorder=10) + lv1 = Line2D( + [ + first_start - self.backbone_pad_left, + first_start - self.backbone_pad_left, + prev_end + self.backbone_pad_right, + prev_end + self.backbone_pad_right, + ], + [0, -20, -20, 0], + linewidth=self.linewidth, + color=self.linecolor, + zorder=10, + ) ax.add_line(lv1) if vector_label is not None: opt = dict() - opt['label_size'] = 4 - write_arc_label(ax, vector_label, 0.5*(first_start + prev_end),-16, opt) - + opt["label_size"] = 4 + write_arc_label( + ax, + vector_label, + 0.5 * (first_start + prev_end), + -16, + opt, + ) + return first_start, prev_end - def annotate (self, ax, part_renderers, part, annotate_zorder=1000): - """ Annotate a plot at a user specified location and offset. - """ + def annotate(self, ax, part_renderers, part, annotate_zorder=1000): + """Annotate a plot at a user specified location and offset.""" # Annotations show be placed on top of existing design - if 'opts' not in list(part.keys()): - part['opts'] = {'zorder_add': annotate_zorder} + if "opts" not in list(part.keys()): + part["opts"] = {"zorder_add": annotate_zorder} else: - part['opts']['zorder_add'] = annotate_zorder + part["opts"]["zorder_add"] = annotate_zorder # Draw the part - part_renderers[part['type']](ax, - part['type'], 1, - part['start'], part['end'], - part['start'], self.scale, - self.linewidth, opts=part['opts']) + part_renderers[part["type"]]( + ax, + part["type"], + 1, + part["start"], + part["end"], + part["start"], + self.scale, + self.linewidth, + opts=part["opts"], + ) ############################################################################### @@ -3333,13 +4681,15 @@ def annotate (self, ax, part_renderers, part, annotate_zorder=1000): ############################################################################### -def plot_sbol_designs (axes, dna_designs, regulations=None, plot_params={}, plot_names=None): - """ Plot SBOL designs to axes. +def plot_sbol_designs( + axes, dna_designs, regulations=None, plot_params={}, plot_names=None +): + """Plot SBOL designs to axes. Parameters ---------- axes : list(matplotlib.axis) - List of axis objects to plot the designs to. + List of axis objects to plot the designs to. dna_designs : list(dict(design_information)) List of designs to plot. @@ -3362,25 +4712,28 @@ def plot_sbol_designs (axes, dna_designs, regulations=None, plot_params={}, plot The y-axis range for each axis. """ # Standard plotting parameters - if 'axis_y' not in list(plot_params.keys()): - plot_params['axis_y'] = 35 + if "axis_y" not in list(plot_params.keys()): + plot_params["axis_y"] = 35 left_pad = 0.0 right_pad = 0.0 scale = 1.0 linewidth = 1.0 fig_y = 5.0 fig_x = 5.0 - if 'backbone_pad_left' in list(plot_params.keys()): - left_pad = plot_params['backbone_pad_left'] - if 'backbone_pad_right' in list(plot_params.keys()): - right_pad = plot_params['backbone_pad_right'] - if 'scale' in list(plot_params.keys()): - scale = plot_params['scale'] - if 'linewidth' in list(plot_params.keys()): - linewidth = plot_params['linewidth'] - dr = DNARenderer(scale=scale, linewidth=linewidth, - backbone_pad_left=left_pad, - backbone_pad_right=right_pad) + if "backbone_pad_left" in list(plot_params.keys()): + left_pad = plot_params["backbone_pad_left"] + if "backbone_pad_right" in list(plot_params.keys()): + right_pad = plot_params["backbone_pad_right"] + if "scale" in list(plot_params.keys()): + scale = plot_params["scale"] + if "linewidth" in list(plot_params.keys()): + linewidth = plot_params["linewidth"] + dr = DNARenderer( + scale=scale, + linewidth=linewidth, + backbone_pad_left=left_pad, + backbone_pad_right=right_pad, + ) # We default to the standard regulation renderers reg_renderers = dr.std_reg_renderers() @@ -3394,17 +4747,19 @@ def plot_sbol_designs (axes, dna_designs, regulations=None, plot_params={}, plot # Create axis for the design and plot regs = None - if(regulations != None): - regs = regulations[i] - design = dna_designs[i] + if regulations != None: + regs = regulations[i] + design = dna_designs[i] ax = axes[i] if plot_names != None: ax.set_title(plot_names[i], fontsize=8) - start, end = dr.renderDNA(ax, design, part_renderers, regs, reg_renderers) + start, end = dr.renderDNA( + ax, design, part_renderers, regs, reg_renderers + ) - dna_len = end-start + dna_len = end - start if max_dna_len < dna_len: max_dna_len = dna_len @@ -3413,18 +4768,31 @@ def plot_sbol_designs (axes, dna_designs, regulations=None, plot_params={}, plot ax.set_xticks([]) ax.set_yticks([]) # Set bounds - ax.set_xlim([(-0.01*max_dna_len)-left_pad, - max_dna_len+(0.01*max_dna_len)+right_pad]) - ax.set_ylim([-plot_params['axis_y'],plot_params['axis_y']]) - ax.set_aspect('equal') + ax.set_xlim( + [ + (-0.01 * max_dna_len) - left_pad, + max_dna_len + (0.01 * max_dna_len) + right_pad, + ] + ) + ax.set_ylim([-plot_params["axis_y"], plot_params["axis_y"]]) + ax.set_aspect("equal") ax.set_axis_off() # xlims, ylims are returned - return max_dna_len, [(-0.01*max_dna_len)-left_pad, max_dna_len+(0.01*max_dna_len)+right_pad], [-plot_params['axis_y'],plot_params['axis_y']] + return ( + max_dna_len, + [ + (-0.01 * max_dna_len) - left_pad, + max_dna_len + (0.01 * max_dna_len) + right_pad, + ], + [-plot_params["axis_y"], plot_params["axis_y"]], + ) -def save_sbol_designs (filename, dna_designs, regulations=None, plot_params={}, plot_names=None): - """ Plot SBOL designs to axes. +def save_sbol_designs( + filename, dna_designs, regulations=None, plot_params={}, plot_names=None +): + """Plot SBOL designs to axes. Parameters ---------- @@ -3446,30 +4814,36 @@ def save_sbol_designs (filename, dna_designs, regulations=None, plot_params={}, """ # Create the figure - fig = plt.figure(figsize=(10,10)) - fig.patch.set_facecolor('white') + fig = plt.figure(figsize=(10, 10)) + fig.patch.set_facecolor("white") # Create all the axes required axes = [] for i in range(len(dna_designs)): - ax = fig.add_subplot(len(dna_designs),1,i+1, axisbg='white') + ax = fig.add_subplot(len(dna_designs), 1, i + 1, axisbg="white") axes.append(ax) # Plot design to the axes - max_dna_len, lims, params = plot_sbol_designs (axes, dna_designs, regulations=regulations, plot_params=plot_params, plot_names=plot_names) + max_dna_len, lims, params = plot_sbol_designs( + axes, + dna_designs, + regulations=regulations, + plot_params=plot_params, + plot_names=plot_names, + ) # Update the size of the figure to fit the constructs drawn - fig_x_dim = max_dna_len/70.0 + fig_x_dim = max_dna_len / 70.0 if fig_x_dim < 1.0: fig_x_dim = 1.0 - fig_y_dim = 1.2*len(axes) - plt.gcf().set_size_inches( (fig_x_dim, fig_y_dim) ) + fig_y_dim = 1.2 * len(axes) + plt.gcf().set_size_inches((fig_x_dim, fig_y_dim)) # Save the figure plt.tight_layout() fig.savefig(filename, transparent=True, dpi=300) # Clear the plotting cache - plt.close('all') + plt.close("all") ############################################################################### @@ -3477,14 +4851,23 @@ def save_sbol_designs (filename, dna_designs, regulations=None, plot_params={}, ############################################################################### -def convert_attrib (attrib): - if attrib[0] == '(' and attrib[-1] == ')' and len(attrib.split(',')) == 3: - col_parts = attrib[1:-1].split(',') - new_col = (float(col_parts[0]), float(col_parts[1]), float(col_parts[2])) +def convert_attrib(attrib): + if attrib[0] == "(" and attrib[-1] == ")" and len(attrib.split(",")) == 3: + col_parts = attrib[1:-1].split(",") + new_col = ( + float(col_parts[0]), + float(col_parts[1]), + float(col_parts[2]), + ) return new_col - if attrib[0] == '(' and attrib[-1] == ')' and len(attrib.split(',')) == 4: - col_parts = attrib[1:-1].split(',') - new_col = (float(col_parts[0]), float(col_parts[1]), float(col_parts[2]), float(col_parts[3])) + if attrib[0] == "(" and attrib[-1] == ")" and len(attrib.split(",")) == 4: + col_parts = attrib[1:-1].split(",") + new_col = ( + float(col_parts[0]), + float(col_parts[1]), + float(col_parts[2]), + float(col_parts[3]), + ) return new_col try: # See if a number @@ -3494,16 +4877,20 @@ def convert_attrib (attrib): return attrib -dpl_default_type_map = {'gene': 'CDS', - 'promoter': 'Promoter', - 'terminator': 'Terminator', - 'rbs': 'RBS'} +dpl_default_type_map = { + "gene": "CDS", + "promoter": "Promoter", + "terminator": "Terminator", + "rbs": "RBS", +} -def load_design_from_gff (filename, chrom, type_map=dpl_default_type_map, region=None): +def load_design_from_gff( + filename, chrom, type_map=dpl_default_type_map, region=None +): # Load the GFF data gff = [] - data_reader = csv.reader(open(filename, 'rU'), delimiter='\t') + data_reader = csv.reader(open(filename, "rU"), delimiter="\t") for row in data_reader: if len(row) == 9: cur_chrom = row[0] @@ -3512,46 +4899,63 @@ def load_design_from_gff (filename, chrom, type_map=dpl_default_type_map, region end_bp = int(row[4]) part_dir = row[6] part_attribs = {} - split_attribs = row[8].split(';') + split_attribs = row[8].split(";") part_name = None for attrib in split_attribs: - key_value = attrib.split('=') + key_value = attrib.split("=") if len(key_value) == 2: - if key_value[0] == 'Name': + if key_value[0] == "Name": part_name = key_value[1] else: - part_attribs[key_value[0]] = convert_attrib(key_value[1]) - if part_name != None and cur_chrom == chrom and part_type in list(type_map.keys()): + part_attribs[key_value[0]] = convert_attrib( + key_value[1] + ) + if ( + part_name != None + and cur_chrom == chrom + and part_type in list(type_map.keys()) + ): # Check feature start falls in region - if region != None and (start_bp > region[0] and start_bp < region[1]): - gff.append([part_name, type_map[part_type], part_dir, start_bp, end_bp, part_attribs]) + if region != None and ( + start_bp > region[0] and start_bp < region[1] + ): + gff.append( + [ + part_name, + type_map[part_type], + part_dir, + start_bp, + end_bp, + part_attribs, + ] + ) # Convert to DNAplotlib design (sort on start position first) design = [] for gff_el in sorted(gff, key=itemgetter(3)): new_part = {} - new_part['name'] = gff_el[0] - new_part['type'] = gff_el[1] - if gff_el[2] == '+': - new_part['fwd'] = True + new_part["name"] = gff_el[0] + new_part["type"] = gff_el[1] + if gff_el[2] == "+": + new_part["fwd"] = True else: - new_part['fwd'] = False - new_part['start'] = gff_el[3] - new_part['end'] = gff_el[4] - new_part['opts'] = gff_el[5] + new_part["fwd"] = False + new_part["start"] = gff_el[3] + new_part["end"] = gff_el[4] + new_part["opts"] = gff_el[5] design.append(new_part) # Return the sorted design return design -def load_profile_from_bed (filename, chrom, region): - region_len = region[1]-region[0] - profile = [0]*region_len - data_reader = csv.reader(open(filename, 'rU'), delimiter='\t') +def load_profile_from_bed(filename, chrom, region): + region_len = region[1] - region[0] + profile = [0] * region_len + data_reader = csv.reader(open(filename, "rU"), delimiter="\t") for row in data_reader: if len(row) == 5: cur_chrom = row[0] cur_start_bp = int(row[1]) cur_end_bp = int(row[2]) if cur_start_bp == region[0] and cur_end_bp == region[1]: - profile[int(row[3])-1] = float(row[4]) + profile[int(row[3]) - 1] = float(row[4]) return profile diff --git a/dnaplotlib/apps/library_plot 2.py b/dnaplotlib/apps/library_plot 2.py index b07123d..edc70d9 100644 --- a/dnaplotlib/apps/library_plot 2.py +++ b/dnaplotlib/apps/library_plot 2.py @@ -15,7 +15,8 @@ # Set the backend to use (important for headless servers) import matplotlib -matplotlib.use('Agg') + +matplotlib.use("Agg") import sys import getopt @@ -25,266 +26,334 @@ from argparse import ArgumentParser import os.path -__author__ = 'Thomas E. Gorochowski , Voigt Lab, MIT\n\ - Bryan Der , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' - -def make_float_if_needed (s): - try: - float(s) - return float(s) - except ValueError: - return s - -def load_plot_parameters (filename): - plot_params = {} - param_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(param_reader) - # Process all parameters - for row in param_reader: - if len(row) >= 2: - if row[1] != '': - plot_params[row[0]] = make_float_if_needed(row[1]) - return plot_params - -def load_part_information (filename): - part_info = {} - parts_reader = csv.reader(open(filename, 'rU'), delimiter=',') - header = next(parts_reader) - header_map = {} - for i in range(len(header)): - header_map[header[i]] = i - attrib_keys = [k for k in list(header_map.keys()) if k not in ['part_name', 'type']] - for row in parts_reader: - # Make the attributes map - part_attribs_map = {} - for k in attrib_keys: - if row[header_map[k]] != '': - if k == 'color' or k == 'label_color': - part_attribs_map[k] = [float(x) for x in row[header_map[k]].split(';')] - else: - part_attribs_map[k] = make_float_if_needed(row[header_map[k]]) - part_name = row[header_map['part_name']] - part_type = row[header_map['type']] - part_info[part_name] = [part_name, part_type, part_attribs_map] - return part_info - -def load_dna_designs (filename, part_info, reverse_char='r'): - dna_designs = {} - design_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(design_reader) - # Process all parameters - for row in design_reader: - if len(row[0]) != '': - part_list = [] - for i in range(1,len(row)): - # Handle reverse parts - fwd = True - part_name = row[i] - if len(part_name) != 0: - if part_name[0] == reverse_char: - part_name = part_name[1:] - fwd = False - # Store the design - part_design = {} - cur_part_info = part_info[part_name] - part_design['type'] = cur_part_info[1] - part_design['name'] = part_name #needed to add part name for regulation - part_design['fwd'] = fwd #needed to add fwd for regulation - if fwd == True: - part_design['start'] = i - part_design['end'] = i+1 - else: - part_design['end'] = i - part_design['start'] = i+1 - part_design['opts'] = cur_part_info[2] - part_list.append(part_design) - dna_designs[row[0]] = part_list - return dna_designs - -def load_regulatory_information (filename, part_info, dna_designs): - regs_info = {} - - reg_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(reg_reader) - header_map = {} - for i in range(len(header)): - header_map[header[i]] = i - attrib_keys = [k for k in list(header_map.keys()) if k not in ['from_partname', 'type', 'to_partname']] - - #reg_reader can only be read once? - rows = [] - for row in reg_reader: - rows.append(row) - - design_list = sorted(dna_designs.keys()) - num_of_designs = len(design_list) - - #outer loop: for each design - for i in range(num_of_designs): - regs_info[i]=[] - design = dna_designs[design_list[i]] - - #middle loop: for each regulation - for row in rows: - - #opts - reg_attribs_map = {} - for k in attrib_keys: - if row[header_map[k]] != '': - if k == 'color': - reg_attribs_map[k] = [float(x) for x in row[header_map[k]].split(';')] - else: - reg_attribs_map[k] = make_float_if_needed(row[header_map[k]]) - - #from, type, to - type = row[header_map['type']] - from_partname = row[header_map['from_partname']] - to_partname = row[header_map['to_partname']] - from_part = None; - to_part = None; - - #inner loop: loop through parts to find 'from' and 'to' parts - for part1 in design: #loop through once to find the cds - if(part1['name'] == from_partname): - start_part = part1 - for part2 in design: #loop through again to find the promoter - if(part2['name'] == to_partname): - end_part = part2 - #found from-to, save regulation arc - reg_info = {} - reg_info['from_part'] = start_part - reg_info['type'] = row[header_map['type']] - reg_info['to_part'] = end_part - reg_info['opts'] = reg_attribs_map - regs_info[i].append(reg_info) - return regs_info - -def plot_dna (dna_designs, out_filename, plot_params, regs_info): - # Create the renderer - if 'axis_y' not in list(plot_params.keys()): - plot_params['axis_y'] = 35 - left_pad = 0.0 - right_pad = 0.0 - scale = 1.0 - linewidth = 1.0 - fig_y = 5.0 - fig_x = 5.0 - if 'backbone_pad_left' in list(plot_params.keys()): - left_pad = plot_params['backbone_pad_left'] - if 'backbone_pad_right' in list(plot_params.keys()): - right_pad = plot_params['backbone_pad_right'] - if 'scale' in list(plot_params.keys()): - scale = plot_params['scale'] - if 'linewidth' in list(plot_params.keys()): - linewidth = plot_params['linewidth'] - if 'fig_y' in list(plot_params.keys()): - fig_y = plot_params['fig_y'] - if 'fig_x' in list(plot_params.keys()): - fig_x = plot_params['fig_x'] - dr = dpl.DNARenderer(scale=scale, linewidth=linewidth, - backbone_pad_left=left_pad, - backbone_pad_right=right_pad) - - # We default to the standard regulation renderers - reg_renderers = dr.std_reg_renderers() - # We default to the SBOL part renderers - part_renderers = dr.SBOL_part_renderers() +__author__ = "Thomas E. Gorochowski , Voigt Lab, MIT\n\ + Bryan Der , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" + + +def make_float_if_needed(s): + try: + float(s) + return float(s) + except ValueError: + return s + + +def load_plot_parameters(filename): + plot_params = {} + param_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(param_reader) + # Process all parameters + for row in param_reader: + if len(row) >= 2: + if row[1] != "": + plot_params[row[0]] = make_float_if_needed(row[1]) + return plot_params + + +def load_part_information(filename): + part_info = {} + parts_reader = csv.reader(open(filename, "rU"), delimiter=",") + header = next(parts_reader) + header_map = {} + for i in range(len(header)): + header_map[header[i]] = i + attrib_keys = [ + k for k in list(header_map.keys()) if k not in ["part_name", "type"] + ] + for row in parts_reader: + # Make the attributes map + part_attribs_map = {} + for k in attrib_keys: + if row[header_map[k]] != "": + if k == "color" or k == "label_color": + part_attribs_map[k] = [ + float(x) for x in row[header_map[k]].split(";") + ] + else: + part_attribs_map[k] = make_float_if_needed( + row[header_map[k]] + ) + part_name = row[header_map["part_name"]] + part_type = row[header_map["type"]] + part_info[part_name] = [part_name, part_type, part_attribs_map] + return part_info + + +def load_dna_designs(filename, part_info, reverse_char="r"): + dna_designs = {} + design_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(design_reader) + # Process all parameters + for row in design_reader: + if len(row[0]) != "": + part_list = [] + for i in range(1, len(row)): + # Handle reverse parts + fwd = True + part_name = row[i] + if len(part_name) != 0: + if part_name[0] == reverse_char: + part_name = part_name[1:] + fwd = False + # Store the design + part_design = {} + cur_part_info = part_info[part_name] + part_design["type"] = cur_part_info[1] + part_design[ + "name" + ] = part_name # needed to add part name for regulation + part_design["fwd"] = fwd # needed to add fwd for regulation + if fwd == True: + part_design["start"] = i + part_design["end"] = i + 1 + else: + part_design["end"] = i + part_design["start"] = i + 1 + part_design["opts"] = cur_part_info[2] + part_list.append(part_design) + dna_designs[row[0]] = part_list + return dna_designs + + +def load_regulatory_information(filename, part_info, dna_designs): + regs_info = {} + + reg_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(reg_reader) + header_map = {} + for i in range(len(header)): + header_map[header[i]] = i + attrib_keys = [ + k + for k in list(header_map.keys()) + if k not in ["from_partname", "type", "to_partname"] + ] + + # reg_reader can only be read once? + rows = [] + for row in reg_reader: + rows.append(row) + + design_list = sorted(dna_designs.keys()) + num_of_designs = len(design_list) + + # outer loop: for each design + for i in range(num_of_designs): + regs_info[i] = [] + design = dna_designs[design_list[i]] + + # middle loop: for each regulation + for row in rows: + + # opts + reg_attribs_map = {} + for k in attrib_keys: + if row[header_map[k]] != "": + if k == "color": + reg_attribs_map[k] = [ + float(x) for x in row[header_map[k]].split(";") + ] + else: + reg_attribs_map[k] = make_float_if_needed( + row[header_map[k]] + ) + + # from, type, to + type = row[header_map["type"]] + from_partname = row[header_map["from_partname"]] + to_partname = row[header_map["to_partname"]] + from_part = None + to_part = None + + # inner loop: loop through parts to find 'from' and 'to' parts + for part1 in design: # loop through once to find the cds + if part1["name"] == from_partname: + start_part = part1 + for ( + part2 + ) in design: # loop through again to find the promoter + if part2["name"] == to_partname: + end_part = part2 + # found from-to, save regulation arc + reg_info = {} + reg_info["from_part"] = start_part + reg_info["type"] = row[header_map["type"]] + reg_info["to_part"] = end_part + reg_info["opts"] = reg_attribs_map + regs_info[i].append(reg_info) + return regs_info + + +def plot_dna(dna_designs, out_filename, plot_params, regs_info): + # Create the renderer + if "axis_y" not in list(plot_params.keys()): + plot_params["axis_y"] = 35 + left_pad = 0.0 + right_pad = 0.0 + scale = 1.0 + linewidth = 1.0 + fig_y = 5.0 + fig_x = 5.0 + if "backbone_pad_left" in list(plot_params.keys()): + left_pad = plot_params["backbone_pad_left"] + if "backbone_pad_right" in list(plot_params.keys()): + right_pad = plot_params["backbone_pad_right"] + if "scale" in list(plot_params.keys()): + scale = plot_params["scale"] + if "linewidth" in list(plot_params.keys()): + linewidth = plot_params["linewidth"] + if "fig_y" in list(plot_params.keys()): + fig_y = plot_params["fig_y"] + if "fig_x" in list(plot_params.keys()): + fig_x = plot_params["fig_x"] + dr = dpl.DNARenderer( + scale=scale, + linewidth=linewidth, + backbone_pad_left=left_pad, + backbone_pad_right=right_pad, + ) + + # We default to the standard regulation renderers + reg_renderers = dr.std_reg_renderers() + # We default to the SBOL part renderers + part_renderers = dr.SBOL_part_renderers() # Create the figure - fig = plt.figure(figsize=(fig_x,fig_y)) - - # Cycle through the designs an plot on individual axes - design_list = sorted(dna_designs.keys()) - if(regs_info != None): - regs_list = sorted(regs_info.keys()) - - num_of_designs = len(design_list) - ax_list = [] - max_dna_len = 0.0 - for i in range(num_of_designs): - # Create axis for the design and plot - regs = None - if(regs_info != None): - regs = regs_info[i] - design = dna_designs[design_list[i]] - - ax = fig.add_subplot(num_of_designs,1,i+1) - if 'show_title' in list(plot_params.keys()) and plot_params['show_title'] == 'Y': - ax.set_title(design_list[i], fontsize=8) - start, end = dr.renderDNA(ax, design, part_renderers, regs, reg_renderers) - - dna_len = end-start - if max_dna_len < dna_len: - max_dna_len = dna_len - ax_list.append(ax) - for ax in ax_list: - ax.set_xticks([]) - ax.set_yticks([]) - # Set bounds - ax.set_xlim([(-0.01*max_dna_len)-left_pad, - max_dna_len+(0.01*max_dna_len)+right_pad]) - ax.set_ylim([-plot_params['axis_y'],plot_params['axis_y']]) - ax.set_aspect('equal') - ax.set_axis_off() - - # Update the size of the figure to fit the constructs drawn - fig_x_dim = max_dna_len/70.0 - if fig_x_dim < 1.0: - fig_x_dim = 1.0 - fig_y_dim = 1.2*len(ax_list) - plt.gcf().set_size_inches( (fig_x_dim, fig_y_dim) ) - - # Save the figure - plt.tight_layout() - fig.savefig(out_filename, transparent=True, dpi=300) - # Clear the plotting cache - plt.close('all') + fig = plt.figure(figsize=(fig_x, fig_y)) + + # Cycle through the designs an plot on individual axes + design_list = sorted(dna_designs.keys()) + if regs_info != None: + regs_list = sorted(regs_info.keys()) + + num_of_designs = len(design_list) + ax_list = [] + max_dna_len = 0.0 + for i in range(num_of_designs): + # Create axis for the design and plot + regs = None + if regs_info != None: + regs = regs_info[i] + design = dna_designs[design_list[i]] + + ax = fig.add_subplot(num_of_designs, 1, i + 1) + if ( + "show_title" in list(plot_params.keys()) + and plot_params["show_title"] == "Y" + ): + ax.set_title(design_list[i], fontsize=8) + start, end = dr.renderDNA( + ax, design, part_renderers, regs, reg_renderers + ) + + dna_len = end - start + if max_dna_len < dna_len: + max_dna_len = dna_len + ax_list.append(ax) + for ax in ax_list: + ax.set_xticks([]) + ax.set_yticks([]) + # Set bounds + ax.set_xlim( + [ + (-0.01 * max_dna_len) - left_pad, + max_dna_len + (0.01 * max_dna_len) + right_pad, + ] + ) + ax.set_ylim([-plot_params["axis_y"], plot_params["axis_y"]]) + ax.set_aspect("equal") + ax.set_axis_off() + + # Update the size of the figure to fit the constructs drawn + fig_x_dim = max_dna_len / 70.0 + if fig_x_dim < 1.0: + fig_x_dim = 1.0 + fig_y_dim = 1.2 * len(ax_list) + plt.gcf().set_size_inches((fig_x_dim, fig_y_dim)) + + # Save the figure + plt.tight_layout() + fig.savefig(out_filename, transparent=True, dpi=300) + # Clear the plotting cache + plt.close("all") + def is_valid_file(parser, arg): if not os.path.exists(arg): parser.error("The file %s does not exist!" % arg) else: - return open(arg, 'r') # return an open file handle - -def main(): - # Parse the arguments - parser = ArgumentParser(description="file paths as arguments") - parser.add_argument("-params", dest="params", required=True, - help="plot_params.csv", metavar="FILE", - type=lambda x: is_valid_file(parser, x)) - parser.add_argument("-parts", dest="parts", required=True, - help="parts_information.csv", metavar="FILE", - type=lambda x: is_valid_file(parser, x)) - parser.add_argument("-regulation", dest="regulation", required=False, - help="reg_information.csv", metavar="FILE", - type=lambda x: is_valid_file(parser, x)) - parser.add_argument("-designs", dest="designs", required=True, - help="dna_designs.csv", metavar="FILE", - type=lambda x: is_valid_file(parser, x)) - parser.add_argument("-output", dest="output_pdf", required=True, - help="output pdf filename") - parser.add_argument("-reverse_char", dest="reverse_char", required=False, - help="character to denote reverse orientation") - args = parser.parse_args() - - # Process arguments - cur_reverse_char = 'r' - if(args.reverse_char): - cur_reverse_char = args.reverse_char - plot_params = load_plot_parameters(args.params.name) - part_info = load_part_information(args.parts.name) - dna_designs = load_dna_designs (args.designs.name, part_info, reverse_char=cur_reverse_char) - - regs_info = None - if(args.regulation): - regs_info = load_regulatory_information(args.regulation.name, part_info, dna_designs) - - plot_dna(dna_designs, args.output_pdf, plot_params, regs_info) + return open(arg, "r") # return an open file handle + + +def main(): + # Parse the arguments + parser = ArgumentParser(description="file paths as arguments") + parser.add_argument( + "-params", + dest="params", + required=True, + help="plot_params.csv", + metavar="FILE", + type=lambda x: is_valid_file(parser, x), + ) + parser.add_argument( + "-parts", + dest="parts", + required=True, + help="parts_information.csv", + metavar="FILE", + type=lambda x: is_valid_file(parser, x), + ) + parser.add_argument( + "-regulation", + dest="regulation", + required=False, + help="reg_information.csv", + metavar="FILE", + type=lambda x: is_valid_file(parser, x), + ) + parser.add_argument( + "-designs", + dest="designs", + required=True, + help="dna_designs.csv", + metavar="FILE", + type=lambda x: is_valid_file(parser, x), + ) + parser.add_argument( + "-output", dest="output_pdf", required=True, help="output pdf filename" + ) + parser.add_argument( + "-reverse_char", + dest="reverse_char", + required=False, + help="character to denote reverse orientation", + ) + args = parser.parse_args() + + # Process arguments + cur_reverse_char = "r" + if args.reverse_char: + cur_reverse_char = args.reverse_char + plot_params = load_plot_parameters(args.params.name) + part_info = load_part_information(args.parts.name) + dna_designs = load_dna_designs( + args.designs.name, part_info, reverse_char=cur_reverse_char + ) + + regs_info = None + if args.regulation: + regs_info = load_regulatory_information( + args.regulation.name, part_info, dna_designs + ) + + plot_dna(dna_designs, args.output_pdf, plot_params, regs_info) + if __name__ == "__main__": - main() + main() diff --git a/dnaplotlib/apps/library_plot.py b/dnaplotlib/apps/library_plot.py index b07123d..edc70d9 100755 --- a/dnaplotlib/apps/library_plot.py +++ b/dnaplotlib/apps/library_plot.py @@ -15,7 +15,8 @@ # Set the backend to use (important for headless servers) import matplotlib -matplotlib.use('Agg') + +matplotlib.use("Agg") import sys import getopt @@ -25,266 +26,334 @@ from argparse import ArgumentParser import os.path -__author__ = 'Thomas E. Gorochowski , Voigt Lab, MIT\n\ - Bryan Der , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' - -def make_float_if_needed (s): - try: - float(s) - return float(s) - except ValueError: - return s - -def load_plot_parameters (filename): - plot_params = {} - param_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(param_reader) - # Process all parameters - for row in param_reader: - if len(row) >= 2: - if row[1] != '': - plot_params[row[0]] = make_float_if_needed(row[1]) - return plot_params - -def load_part_information (filename): - part_info = {} - parts_reader = csv.reader(open(filename, 'rU'), delimiter=',') - header = next(parts_reader) - header_map = {} - for i in range(len(header)): - header_map[header[i]] = i - attrib_keys = [k for k in list(header_map.keys()) if k not in ['part_name', 'type']] - for row in parts_reader: - # Make the attributes map - part_attribs_map = {} - for k in attrib_keys: - if row[header_map[k]] != '': - if k == 'color' or k == 'label_color': - part_attribs_map[k] = [float(x) for x in row[header_map[k]].split(';')] - else: - part_attribs_map[k] = make_float_if_needed(row[header_map[k]]) - part_name = row[header_map['part_name']] - part_type = row[header_map['type']] - part_info[part_name] = [part_name, part_type, part_attribs_map] - return part_info - -def load_dna_designs (filename, part_info, reverse_char='r'): - dna_designs = {} - design_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(design_reader) - # Process all parameters - for row in design_reader: - if len(row[0]) != '': - part_list = [] - for i in range(1,len(row)): - # Handle reverse parts - fwd = True - part_name = row[i] - if len(part_name) != 0: - if part_name[0] == reverse_char: - part_name = part_name[1:] - fwd = False - # Store the design - part_design = {} - cur_part_info = part_info[part_name] - part_design['type'] = cur_part_info[1] - part_design['name'] = part_name #needed to add part name for regulation - part_design['fwd'] = fwd #needed to add fwd for regulation - if fwd == True: - part_design['start'] = i - part_design['end'] = i+1 - else: - part_design['end'] = i - part_design['start'] = i+1 - part_design['opts'] = cur_part_info[2] - part_list.append(part_design) - dna_designs[row[0]] = part_list - return dna_designs - -def load_regulatory_information (filename, part_info, dna_designs): - regs_info = {} - - reg_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(reg_reader) - header_map = {} - for i in range(len(header)): - header_map[header[i]] = i - attrib_keys = [k for k in list(header_map.keys()) if k not in ['from_partname', 'type', 'to_partname']] - - #reg_reader can only be read once? - rows = [] - for row in reg_reader: - rows.append(row) - - design_list = sorted(dna_designs.keys()) - num_of_designs = len(design_list) - - #outer loop: for each design - for i in range(num_of_designs): - regs_info[i]=[] - design = dna_designs[design_list[i]] - - #middle loop: for each regulation - for row in rows: - - #opts - reg_attribs_map = {} - for k in attrib_keys: - if row[header_map[k]] != '': - if k == 'color': - reg_attribs_map[k] = [float(x) for x in row[header_map[k]].split(';')] - else: - reg_attribs_map[k] = make_float_if_needed(row[header_map[k]]) - - #from, type, to - type = row[header_map['type']] - from_partname = row[header_map['from_partname']] - to_partname = row[header_map['to_partname']] - from_part = None; - to_part = None; - - #inner loop: loop through parts to find 'from' and 'to' parts - for part1 in design: #loop through once to find the cds - if(part1['name'] == from_partname): - start_part = part1 - for part2 in design: #loop through again to find the promoter - if(part2['name'] == to_partname): - end_part = part2 - #found from-to, save regulation arc - reg_info = {} - reg_info['from_part'] = start_part - reg_info['type'] = row[header_map['type']] - reg_info['to_part'] = end_part - reg_info['opts'] = reg_attribs_map - regs_info[i].append(reg_info) - return regs_info - -def plot_dna (dna_designs, out_filename, plot_params, regs_info): - # Create the renderer - if 'axis_y' not in list(plot_params.keys()): - plot_params['axis_y'] = 35 - left_pad = 0.0 - right_pad = 0.0 - scale = 1.0 - linewidth = 1.0 - fig_y = 5.0 - fig_x = 5.0 - if 'backbone_pad_left' in list(plot_params.keys()): - left_pad = plot_params['backbone_pad_left'] - if 'backbone_pad_right' in list(plot_params.keys()): - right_pad = plot_params['backbone_pad_right'] - if 'scale' in list(plot_params.keys()): - scale = plot_params['scale'] - if 'linewidth' in list(plot_params.keys()): - linewidth = plot_params['linewidth'] - if 'fig_y' in list(plot_params.keys()): - fig_y = plot_params['fig_y'] - if 'fig_x' in list(plot_params.keys()): - fig_x = plot_params['fig_x'] - dr = dpl.DNARenderer(scale=scale, linewidth=linewidth, - backbone_pad_left=left_pad, - backbone_pad_right=right_pad) - - # We default to the standard regulation renderers - reg_renderers = dr.std_reg_renderers() - # We default to the SBOL part renderers - part_renderers = dr.SBOL_part_renderers() +__author__ = "Thomas E. Gorochowski , Voigt Lab, MIT\n\ + Bryan Der , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" + + +def make_float_if_needed(s): + try: + float(s) + return float(s) + except ValueError: + return s + + +def load_plot_parameters(filename): + plot_params = {} + param_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(param_reader) + # Process all parameters + for row in param_reader: + if len(row) >= 2: + if row[1] != "": + plot_params[row[0]] = make_float_if_needed(row[1]) + return plot_params + + +def load_part_information(filename): + part_info = {} + parts_reader = csv.reader(open(filename, "rU"), delimiter=",") + header = next(parts_reader) + header_map = {} + for i in range(len(header)): + header_map[header[i]] = i + attrib_keys = [ + k for k in list(header_map.keys()) if k not in ["part_name", "type"] + ] + for row in parts_reader: + # Make the attributes map + part_attribs_map = {} + for k in attrib_keys: + if row[header_map[k]] != "": + if k == "color" or k == "label_color": + part_attribs_map[k] = [ + float(x) for x in row[header_map[k]].split(";") + ] + else: + part_attribs_map[k] = make_float_if_needed( + row[header_map[k]] + ) + part_name = row[header_map["part_name"]] + part_type = row[header_map["type"]] + part_info[part_name] = [part_name, part_type, part_attribs_map] + return part_info + + +def load_dna_designs(filename, part_info, reverse_char="r"): + dna_designs = {} + design_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(design_reader) + # Process all parameters + for row in design_reader: + if len(row[0]) != "": + part_list = [] + for i in range(1, len(row)): + # Handle reverse parts + fwd = True + part_name = row[i] + if len(part_name) != 0: + if part_name[0] == reverse_char: + part_name = part_name[1:] + fwd = False + # Store the design + part_design = {} + cur_part_info = part_info[part_name] + part_design["type"] = cur_part_info[1] + part_design[ + "name" + ] = part_name # needed to add part name for regulation + part_design["fwd"] = fwd # needed to add fwd for regulation + if fwd == True: + part_design["start"] = i + part_design["end"] = i + 1 + else: + part_design["end"] = i + part_design["start"] = i + 1 + part_design["opts"] = cur_part_info[2] + part_list.append(part_design) + dna_designs[row[0]] = part_list + return dna_designs + + +def load_regulatory_information(filename, part_info, dna_designs): + regs_info = {} + + reg_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(reg_reader) + header_map = {} + for i in range(len(header)): + header_map[header[i]] = i + attrib_keys = [ + k + for k in list(header_map.keys()) + if k not in ["from_partname", "type", "to_partname"] + ] + + # reg_reader can only be read once? + rows = [] + for row in reg_reader: + rows.append(row) + + design_list = sorted(dna_designs.keys()) + num_of_designs = len(design_list) + + # outer loop: for each design + for i in range(num_of_designs): + regs_info[i] = [] + design = dna_designs[design_list[i]] + + # middle loop: for each regulation + for row in rows: + + # opts + reg_attribs_map = {} + for k in attrib_keys: + if row[header_map[k]] != "": + if k == "color": + reg_attribs_map[k] = [ + float(x) for x in row[header_map[k]].split(";") + ] + else: + reg_attribs_map[k] = make_float_if_needed( + row[header_map[k]] + ) + + # from, type, to + type = row[header_map["type"]] + from_partname = row[header_map["from_partname"]] + to_partname = row[header_map["to_partname"]] + from_part = None + to_part = None + + # inner loop: loop through parts to find 'from' and 'to' parts + for part1 in design: # loop through once to find the cds + if part1["name"] == from_partname: + start_part = part1 + for ( + part2 + ) in design: # loop through again to find the promoter + if part2["name"] == to_partname: + end_part = part2 + # found from-to, save regulation arc + reg_info = {} + reg_info["from_part"] = start_part + reg_info["type"] = row[header_map["type"]] + reg_info["to_part"] = end_part + reg_info["opts"] = reg_attribs_map + regs_info[i].append(reg_info) + return regs_info + + +def plot_dna(dna_designs, out_filename, plot_params, regs_info): + # Create the renderer + if "axis_y" not in list(plot_params.keys()): + plot_params["axis_y"] = 35 + left_pad = 0.0 + right_pad = 0.0 + scale = 1.0 + linewidth = 1.0 + fig_y = 5.0 + fig_x = 5.0 + if "backbone_pad_left" in list(plot_params.keys()): + left_pad = plot_params["backbone_pad_left"] + if "backbone_pad_right" in list(plot_params.keys()): + right_pad = plot_params["backbone_pad_right"] + if "scale" in list(plot_params.keys()): + scale = plot_params["scale"] + if "linewidth" in list(plot_params.keys()): + linewidth = plot_params["linewidth"] + if "fig_y" in list(plot_params.keys()): + fig_y = plot_params["fig_y"] + if "fig_x" in list(plot_params.keys()): + fig_x = plot_params["fig_x"] + dr = dpl.DNARenderer( + scale=scale, + linewidth=linewidth, + backbone_pad_left=left_pad, + backbone_pad_right=right_pad, + ) + + # We default to the standard regulation renderers + reg_renderers = dr.std_reg_renderers() + # We default to the SBOL part renderers + part_renderers = dr.SBOL_part_renderers() # Create the figure - fig = plt.figure(figsize=(fig_x,fig_y)) - - # Cycle through the designs an plot on individual axes - design_list = sorted(dna_designs.keys()) - if(regs_info != None): - regs_list = sorted(regs_info.keys()) - - num_of_designs = len(design_list) - ax_list = [] - max_dna_len = 0.0 - for i in range(num_of_designs): - # Create axis for the design and plot - regs = None - if(regs_info != None): - regs = regs_info[i] - design = dna_designs[design_list[i]] - - ax = fig.add_subplot(num_of_designs,1,i+1) - if 'show_title' in list(plot_params.keys()) and plot_params['show_title'] == 'Y': - ax.set_title(design_list[i], fontsize=8) - start, end = dr.renderDNA(ax, design, part_renderers, regs, reg_renderers) - - dna_len = end-start - if max_dna_len < dna_len: - max_dna_len = dna_len - ax_list.append(ax) - for ax in ax_list: - ax.set_xticks([]) - ax.set_yticks([]) - # Set bounds - ax.set_xlim([(-0.01*max_dna_len)-left_pad, - max_dna_len+(0.01*max_dna_len)+right_pad]) - ax.set_ylim([-plot_params['axis_y'],plot_params['axis_y']]) - ax.set_aspect('equal') - ax.set_axis_off() - - # Update the size of the figure to fit the constructs drawn - fig_x_dim = max_dna_len/70.0 - if fig_x_dim < 1.0: - fig_x_dim = 1.0 - fig_y_dim = 1.2*len(ax_list) - plt.gcf().set_size_inches( (fig_x_dim, fig_y_dim) ) - - # Save the figure - plt.tight_layout() - fig.savefig(out_filename, transparent=True, dpi=300) - # Clear the plotting cache - plt.close('all') + fig = plt.figure(figsize=(fig_x, fig_y)) + + # Cycle through the designs an plot on individual axes + design_list = sorted(dna_designs.keys()) + if regs_info != None: + regs_list = sorted(regs_info.keys()) + + num_of_designs = len(design_list) + ax_list = [] + max_dna_len = 0.0 + for i in range(num_of_designs): + # Create axis for the design and plot + regs = None + if regs_info != None: + regs = regs_info[i] + design = dna_designs[design_list[i]] + + ax = fig.add_subplot(num_of_designs, 1, i + 1) + if ( + "show_title" in list(plot_params.keys()) + and plot_params["show_title"] == "Y" + ): + ax.set_title(design_list[i], fontsize=8) + start, end = dr.renderDNA( + ax, design, part_renderers, regs, reg_renderers + ) + + dna_len = end - start + if max_dna_len < dna_len: + max_dna_len = dna_len + ax_list.append(ax) + for ax in ax_list: + ax.set_xticks([]) + ax.set_yticks([]) + # Set bounds + ax.set_xlim( + [ + (-0.01 * max_dna_len) - left_pad, + max_dna_len + (0.01 * max_dna_len) + right_pad, + ] + ) + ax.set_ylim([-plot_params["axis_y"], plot_params["axis_y"]]) + ax.set_aspect("equal") + ax.set_axis_off() + + # Update the size of the figure to fit the constructs drawn + fig_x_dim = max_dna_len / 70.0 + if fig_x_dim < 1.0: + fig_x_dim = 1.0 + fig_y_dim = 1.2 * len(ax_list) + plt.gcf().set_size_inches((fig_x_dim, fig_y_dim)) + + # Save the figure + plt.tight_layout() + fig.savefig(out_filename, transparent=True, dpi=300) + # Clear the plotting cache + plt.close("all") + def is_valid_file(parser, arg): if not os.path.exists(arg): parser.error("The file %s does not exist!" % arg) else: - return open(arg, 'r') # return an open file handle - -def main(): - # Parse the arguments - parser = ArgumentParser(description="file paths as arguments") - parser.add_argument("-params", dest="params", required=True, - help="plot_params.csv", metavar="FILE", - type=lambda x: is_valid_file(parser, x)) - parser.add_argument("-parts", dest="parts", required=True, - help="parts_information.csv", metavar="FILE", - type=lambda x: is_valid_file(parser, x)) - parser.add_argument("-regulation", dest="regulation", required=False, - help="reg_information.csv", metavar="FILE", - type=lambda x: is_valid_file(parser, x)) - parser.add_argument("-designs", dest="designs", required=True, - help="dna_designs.csv", metavar="FILE", - type=lambda x: is_valid_file(parser, x)) - parser.add_argument("-output", dest="output_pdf", required=True, - help="output pdf filename") - parser.add_argument("-reverse_char", dest="reverse_char", required=False, - help="character to denote reverse orientation") - args = parser.parse_args() - - # Process arguments - cur_reverse_char = 'r' - if(args.reverse_char): - cur_reverse_char = args.reverse_char - plot_params = load_plot_parameters(args.params.name) - part_info = load_part_information(args.parts.name) - dna_designs = load_dna_designs (args.designs.name, part_info, reverse_char=cur_reverse_char) - - regs_info = None - if(args.regulation): - regs_info = load_regulatory_information(args.regulation.name, part_info, dna_designs) - - plot_dna(dna_designs, args.output_pdf, plot_params, regs_info) + return open(arg, "r") # return an open file handle + + +def main(): + # Parse the arguments + parser = ArgumentParser(description="file paths as arguments") + parser.add_argument( + "-params", + dest="params", + required=True, + help="plot_params.csv", + metavar="FILE", + type=lambda x: is_valid_file(parser, x), + ) + parser.add_argument( + "-parts", + dest="parts", + required=True, + help="parts_information.csv", + metavar="FILE", + type=lambda x: is_valid_file(parser, x), + ) + parser.add_argument( + "-regulation", + dest="regulation", + required=False, + help="reg_information.csv", + metavar="FILE", + type=lambda x: is_valid_file(parser, x), + ) + parser.add_argument( + "-designs", + dest="designs", + required=True, + help="dna_designs.csv", + metavar="FILE", + type=lambda x: is_valid_file(parser, x), + ) + parser.add_argument( + "-output", dest="output_pdf", required=True, help="output pdf filename" + ) + parser.add_argument( + "-reverse_char", + dest="reverse_char", + required=False, + help="character to denote reverse orientation", + ) + args = parser.parse_args() + + # Process arguments + cur_reverse_char = "r" + if args.reverse_char: + cur_reverse_char = args.reverse_char + plot_params = load_plot_parameters(args.params.name) + part_info = load_part_information(args.parts.name) + dna_designs = load_dna_designs( + args.designs.name, part_info, reverse_char=cur_reverse_char + ) + + regs_info = None + if args.regulation: + regs_info = load_regulatory_information( + args.regulation.name, part_info, dna_designs + ) + + plot_dna(dna_designs, args.output_pdf, plot_params, regs_info) + if __name__ == "__main__": - main() + main() diff --git a/dnaplotlib/apps/quick 2.py b/dnaplotlib/apps/quick 2.py index c89e4f9..83f1c18 100644 --- a/dnaplotlib/apps/quick 2.py +++ b/dnaplotlib/apps/quick 2.py @@ -26,141 +26,164 @@ # Set the backend to use (important for headless servers) import matplotlib -matplotlib.use('Agg') + +matplotlib.use("Agg") # Other modules we require import argparse import dnaplotlib as dpl import matplotlib.pyplot as plt -__author__ = 'Thomas E. Gorochowski , Voigt Lab, MIT\n\ - Bryan Der , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' - -def process_arguments (input): - # Types mapping - types = {} - types['p'] = 'Promoter' - types['i'] = 'Ribozyme' - types['r'] = 'RBS' - types['c'] = 'CDS' - types['t'] = 'Terminator' - types['s'] = 'Spacer' - types['='] = 'Scar' - - # Colours mapping - colors = {} - colors['white'] = (1.00,1.00,1.00) - colors['black'] = (0.00,0.00,0.00) - colors['gray'] = (0.60,0.60,0.60) - colors['red'] = (0.89,0.10,0.11) - colors['orange'] = (1.00,0.50,0.00) - colors['yellow'] = (1.00,1.00,0.00) - colors['green'] = (0.20,0.63,0.17) - colors['blue'] = (0.12,0.47,0.71) - colors['purple'] = (0.42,0.24,0.60) - colors['lightred'] = (0.98,0.60,0.60) - colors['lightorange'] = (0.99,0.75,0.44) - colors['lightyellow'] = (1.00,1.00,0.60) - colors['lightgreen'] = (0.70,0.87,0.54) - colors['lightblue'] = (0.65,0.81,0.89) - colors['lightpurple'] = (0.79,0.70,0.84) - - # Generate the parts list from the arguments - part_list = [] - part_idx = 1 - for el in input.split(' '): - if el != '': - part_parts = el.split('.') - # Only type and colour provided - if len(part_parts) == 2: - part_short_type = part_parts[0] - part_fwd = True - if part_short_type[0] == '-': - part_fwd = False - part_short_type = part_short_type[1:] - if part_short_type in list(types.keys()): - part_type = types[part_short_type] - part_color = part_parts[1] - part_rgb = (0,0,0) - if part_color in list(colors.keys()): - part_rgb = colors[part_color] - part_list.append( {'name' : str(part_idx), - 'type' : part_type, - 'fwd' : part_fwd, - 'opts' : {'color': part_rgb}} ) - # Type, label and colour provided - if len(part_parts) == 3: - part_short_type = part_parts[0] - part_fwd = True - if part_short_type[0] == '-': - part_fwd = False - part_short_type = part_short_type[1:] - if part_short_type in list(types.keys()): - part_type = types[part_short_type] - part_label = part_parts[1] - part_color = part_parts[2] - part_rgb = (0,0,0) - if part_color in list(colors.keys()): - part_rgb = colors[part_color] - part_list.append( {'name' : str(part_idx), - 'type' : part_type, - 'fwd' : part_fwd, - 'opts' : {'color': part_rgb, - 'label': part_label, - 'label_size': 8, - 'label_y_offset': -17}} ) - return part_list +__author__ = "Thomas E. Gorochowski , Voigt Lab, MIT\n\ + Bryan Der , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" + + +def process_arguments(input): + # Types mapping + types = {} + types["p"] = "Promoter" + types["i"] = "Ribozyme" + types["r"] = "RBS" + types["c"] = "CDS" + types["t"] = "Terminator" + types["s"] = "Spacer" + types["="] = "Scar" + + # Colours mapping + colors = {} + colors["white"] = (1.00, 1.00, 1.00) + colors["black"] = (0.00, 0.00, 0.00) + colors["gray"] = (0.60, 0.60, 0.60) + colors["red"] = (0.89, 0.10, 0.11) + colors["orange"] = (1.00, 0.50, 0.00) + colors["yellow"] = (1.00, 1.00, 0.00) + colors["green"] = (0.20, 0.63, 0.17) + colors["blue"] = (0.12, 0.47, 0.71) + colors["purple"] = (0.42, 0.24, 0.60) + colors["lightred"] = (0.98, 0.60, 0.60) + colors["lightorange"] = (0.99, 0.75, 0.44) + colors["lightyellow"] = (1.00, 1.00, 0.60) + colors["lightgreen"] = (0.70, 0.87, 0.54) + colors["lightblue"] = (0.65, 0.81, 0.89) + colors["lightpurple"] = (0.79, 0.70, 0.84) + + # Generate the parts list from the arguments + part_list = [] + part_idx = 1 + for el in input.split(" "): + if el != "": + part_parts = el.split(".") + # Only type and colour provided + if len(part_parts) == 2: + part_short_type = part_parts[0] + part_fwd = True + if part_short_type[0] == "-": + part_fwd = False + part_short_type = part_short_type[1:] + if part_short_type in list(types.keys()): + part_type = types[part_short_type] + part_color = part_parts[1] + part_rgb = (0, 0, 0) + if part_color in list(colors.keys()): + part_rgb = colors[part_color] + part_list.append( + { + "name": str(part_idx), + "type": part_type, + "fwd": part_fwd, + "opts": {"color": part_rgb}, + } + ) + # Type, label and colour provided + if len(part_parts) == 3: + part_short_type = part_parts[0] + part_fwd = True + if part_short_type[0] == "-": + part_fwd = False + part_short_type = part_short_type[1:] + if part_short_type in list(types.keys()): + part_type = types[part_short_type] + part_label = part_parts[1] + part_color = part_parts[2] + part_rgb = (0, 0, 0) + if part_color in list(colors.keys()): + part_rgb = colors[part_color] + part_list.append( + { + "name": str(part_idx), + "type": part_type, + "fwd": part_fwd, + "opts": { + "color": part_rgb, + "label": part_label, + "label_size": 8, + "label_y_offset": -17, + }, + } + ) + return part_list def main(): - # Parse the command line inputs - parser = argparse.ArgumentParser(description="one line quick plot") - parser.add_argument("-input", dest="input", required=True, help="\"p.gray p.lightblue i.lightred r.green c.orange t.purple -t.black -c.yellow -p.yellow\"", metavar="string") - parser.add_argument("-output", dest="output", required=False, help="output pdf filename") - args = parser.parse_args() - - # Process the arguments - design = process_arguments(args.input) - - # Create objects for plotting (dnaplotlib) - dr = dpl.DNARenderer(linewidth=1.15, backbone_pad_left=3, backbone_pad_right=3) - reg_renderers = dr.std_reg_renderers() - part_renderers = dr.SBOL_part_renderers() - regs = None - - # Generate the figure - fig = plt.figure(figsize=(5.0,5.0)) - ax = fig.add_subplot(1,1,1) - - # Plot the design - dna_start, dna_end = dr.renderDNA(ax, design, part_renderers, regs, reg_renderers) - max_dna_len = dna_end-dna_start - - # Format the axis - ax.set_xticks([]) - ax.set_yticks([]) - - # Set bounds - ax.set_xlim([(-0.01*max_dna_len), - max_dna_len+(0.01*max_dna_len)]) - ax.set_ylim([-35,35]) - ax.set_aspect('equal') - ax.set_axis_off() - - # Update the size of the figure to fit the constructs drawn - fig_x_dim = max_dna_len/60.0 - if fig_x_dim < 1.0: - fig_x_dim = 1.0 - fig_y_dim = 1.2 - plt.gcf().set_size_inches( (fig_x_dim, fig_y_dim) ) - - # Save the figure - plt.tight_layout() - fig.savefig(args.output, transparent=True, dpi=300) - - -# Enable the script to be run from the command line + # Parse the command line inputs + parser = argparse.ArgumentParser(description="one line quick plot") + parser.add_argument( + "-input", + dest="input", + required=True, + help='"p.gray p.lightblue i.lightred r.green c.orange t.purple -t.black -c.yellow -p.yellow"', + metavar="string", + ) + parser.add_argument( + "-output", dest="output", required=False, help="output pdf filename" + ) + args = parser.parse_args() + + # Process the arguments + design = process_arguments(args.input) + + # Create objects for plotting (dnaplotlib) + dr = dpl.DNARenderer( + linewidth=1.15, backbone_pad_left=3, backbone_pad_right=3 + ) + reg_renderers = dr.std_reg_renderers() + part_renderers = dr.SBOL_part_renderers() + regs = None + + # Generate the figure + fig = plt.figure(figsize=(5.0, 5.0)) + ax = fig.add_subplot(1, 1, 1) + + # Plot the design + dna_start, dna_end = dr.renderDNA( + ax, design, part_renderers, regs, reg_renderers + ) + max_dna_len = dna_end - dna_start + + # Format the axis + ax.set_xticks([]) + ax.set_yticks([]) + + # Set bounds + ax.set_xlim([(-0.01 * max_dna_len), max_dna_len + (0.01 * max_dna_len)]) + ax.set_ylim([-35, 35]) + ax.set_aspect("equal") + ax.set_axis_off() + + # Update the size of the figure to fit the constructs drawn + fig_x_dim = max_dna_len / 60.0 + if fig_x_dim < 1.0: + fig_x_dim = 1.0 + fig_y_dim = 1.2 + plt.gcf().set_size_inches((fig_x_dim, fig_y_dim)) + + # Save the figure + plt.tight_layout() + fig.savefig(args.output, transparent=True, dpi=300) + + +# Enable the script to be run from the command line if __name__ == "__main__": - main() + main() diff --git a/dnaplotlib/apps/quick.py b/dnaplotlib/apps/quick.py index c89e4f9..83f1c18 100755 --- a/dnaplotlib/apps/quick.py +++ b/dnaplotlib/apps/quick.py @@ -26,141 +26,164 @@ # Set the backend to use (important for headless servers) import matplotlib -matplotlib.use('Agg') + +matplotlib.use("Agg") # Other modules we require import argparse import dnaplotlib as dpl import matplotlib.pyplot as plt -__author__ = 'Thomas E. Gorochowski , Voigt Lab, MIT\n\ - Bryan Der , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' - -def process_arguments (input): - # Types mapping - types = {} - types['p'] = 'Promoter' - types['i'] = 'Ribozyme' - types['r'] = 'RBS' - types['c'] = 'CDS' - types['t'] = 'Terminator' - types['s'] = 'Spacer' - types['='] = 'Scar' - - # Colours mapping - colors = {} - colors['white'] = (1.00,1.00,1.00) - colors['black'] = (0.00,0.00,0.00) - colors['gray'] = (0.60,0.60,0.60) - colors['red'] = (0.89,0.10,0.11) - colors['orange'] = (1.00,0.50,0.00) - colors['yellow'] = (1.00,1.00,0.00) - colors['green'] = (0.20,0.63,0.17) - colors['blue'] = (0.12,0.47,0.71) - colors['purple'] = (0.42,0.24,0.60) - colors['lightred'] = (0.98,0.60,0.60) - colors['lightorange'] = (0.99,0.75,0.44) - colors['lightyellow'] = (1.00,1.00,0.60) - colors['lightgreen'] = (0.70,0.87,0.54) - colors['lightblue'] = (0.65,0.81,0.89) - colors['lightpurple'] = (0.79,0.70,0.84) - - # Generate the parts list from the arguments - part_list = [] - part_idx = 1 - for el in input.split(' '): - if el != '': - part_parts = el.split('.') - # Only type and colour provided - if len(part_parts) == 2: - part_short_type = part_parts[0] - part_fwd = True - if part_short_type[0] == '-': - part_fwd = False - part_short_type = part_short_type[1:] - if part_short_type in list(types.keys()): - part_type = types[part_short_type] - part_color = part_parts[1] - part_rgb = (0,0,0) - if part_color in list(colors.keys()): - part_rgb = colors[part_color] - part_list.append( {'name' : str(part_idx), - 'type' : part_type, - 'fwd' : part_fwd, - 'opts' : {'color': part_rgb}} ) - # Type, label and colour provided - if len(part_parts) == 3: - part_short_type = part_parts[0] - part_fwd = True - if part_short_type[0] == '-': - part_fwd = False - part_short_type = part_short_type[1:] - if part_short_type in list(types.keys()): - part_type = types[part_short_type] - part_label = part_parts[1] - part_color = part_parts[2] - part_rgb = (0,0,0) - if part_color in list(colors.keys()): - part_rgb = colors[part_color] - part_list.append( {'name' : str(part_idx), - 'type' : part_type, - 'fwd' : part_fwd, - 'opts' : {'color': part_rgb, - 'label': part_label, - 'label_size': 8, - 'label_y_offset': -17}} ) - return part_list +__author__ = "Thomas E. Gorochowski , Voigt Lab, MIT\n\ + Bryan Der , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" + + +def process_arguments(input): + # Types mapping + types = {} + types["p"] = "Promoter" + types["i"] = "Ribozyme" + types["r"] = "RBS" + types["c"] = "CDS" + types["t"] = "Terminator" + types["s"] = "Spacer" + types["="] = "Scar" + + # Colours mapping + colors = {} + colors["white"] = (1.00, 1.00, 1.00) + colors["black"] = (0.00, 0.00, 0.00) + colors["gray"] = (0.60, 0.60, 0.60) + colors["red"] = (0.89, 0.10, 0.11) + colors["orange"] = (1.00, 0.50, 0.00) + colors["yellow"] = (1.00, 1.00, 0.00) + colors["green"] = (0.20, 0.63, 0.17) + colors["blue"] = (0.12, 0.47, 0.71) + colors["purple"] = (0.42, 0.24, 0.60) + colors["lightred"] = (0.98, 0.60, 0.60) + colors["lightorange"] = (0.99, 0.75, 0.44) + colors["lightyellow"] = (1.00, 1.00, 0.60) + colors["lightgreen"] = (0.70, 0.87, 0.54) + colors["lightblue"] = (0.65, 0.81, 0.89) + colors["lightpurple"] = (0.79, 0.70, 0.84) + + # Generate the parts list from the arguments + part_list = [] + part_idx = 1 + for el in input.split(" "): + if el != "": + part_parts = el.split(".") + # Only type and colour provided + if len(part_parts) == 2: + part_short_type = part_parts[0] + part_fwd = True + if part_short_type[0] == "-": + part_fwd = False + part_short_type = part_short_type[1:] + if part_short_type in list(types.keys()): + part_type = types[part_short_type] + part_color = part_parts[1] + part_rgb = (0, 0, 0) + if part_color in list(colors.keys()): + part_rgb = colors[part_color] + part_list.append( + { + "name": str(part_idx), + "type": part_type, + "fwd": part_fwd, + "opts": {"color": part_rgb}, + } + ) + # Type, label and colour provided + if len(part_parts) == 3: + part_short_type = part_parts[0] + part_fwd = True + if part_short_type[0] == "-": + part_fwd = False + part_short_type = part_short_type[1:] + if part_short_type in list(types.keys()): + part_type = types[part_short_type] + part_label = part_parts[1] + part_color = part_parts[2] + part_rgb = (0, 0, 0) + if part_color in list(colors.keys()): + part_rgb = colors[part_color] + part_list.append( + { + "name": str(part_idx), + "type": part_type, + "fwd": part_fwd, + "opts": { + "color": part_rgb, + "label": part_label, + "label_size": 8, + "label_y_offset": -17, + }, + } + ) + return part_list def main(): - # Parse the command line inputs - parser = argparse.ArgumentParser(description="one line quick plot") - parser.add_argument("-input", dest="input", required=True, help="\"p.gray p.lightblue i.lightred r.green c.orange t.purple -t.black -c.yellow -p.yellow\"", metavar="string") - parser.add_argument("-output", dest="output", required=False, help="output pdf filename") - args = parser.parse_args() - - # Process the arguments - design = process_arguments(args.input) - - # Create objects for plotting (dnaplotlib) - dr = dpl.DNARenderer(linewidth=1.15, backbone_pad_left=3, backbone_pad_right=3) - reg_renderers = dr.std_reg_renderers() - part_renderers = dr.SBOL_part_renderers() - regs = None - - # Generate the figure - fig = plt.figure(figsize=(5.0,5.0)) - ax = fig.add_subplot(1,1,1) - - # Plot the design - dna_start, dna_end = dr.renderDNA(ax, design, part_renderers, regs, reg_renderers) - max_dna_len = dna_end-dna_start - - # Format the axis - ax.set_xticks([]) - ax.set_yticks([]) - - # Set bounds - ax.set_xlim([(-0.01*max_dna_len), - max_dna_len+(0.01*max_dna_len)]) - ax.set_ylim([-35,35]) - ax.set_aspect('equal') - ax.set_axis_off() - - # Update the size of the figure to fit the constructs drawn - fig_x_dim = max_dna_len/60.0 - if fig_x_dim < 1.0: - fig_x_dim = 1.0 - fig_y_dim = 1.2 - plt.gcf().set_size_inches( (fig_x_dim, fig_y_dim) ) - - # Save the figure - plt.tight_layout() - fig.savefig(args.output, transparent=True, dpi=300) - - -# Enable the script to be run from the command line + # Parse the command line inputs + parser = argparse.ArgumentParser(description="one line quick plot") + parser.add_argument( + "-input", + dest="input", + required=True, + help='"p.gray p.lightblue i.lightred r.green c.orange t.purple -t.black -c.yellow -p.yellow"', + metavar="string", + ) + parser.add_argument( + "-output", dest="output", required=False, help="output pdf filename" + ) + args = parser.parse_args() + + # Process the arguments + design = process_arguments(args.input) + + # Create objects for plotting (dnaplotlib) + dr = dpl.DNARenderer( + linewidth=1.15, backbone_pad_left=3, backbone_pad_right=3 + ) + reg_renderers = dr.std_reg_renderers() + part_renderers = dr.SBOL_part_renderers() + regs = None + + # Generate the figure + fig = plt.figure(figsize=(5.0, 5.0)) + ax = fig.add_subplot(1, 1, 1) + + # Plot the design + dna_start, dna_end = dr.renderDNA( + ax, design, part_renderers, regs, reg_renderers + ) + max_dna_len = dna_end - dna_start + + # Format the axis + ax.set_xticks([]) + ax.set_yticks([]) + + # Set bounds + ax.set_xlim([(-0.01 * max_dna_len), max_dna_len + (0.01 * max_dna_len)]) + ax.set_ylim([-35, 35]) + ax.set_aspect("equal") + ax.set_axis_off() + + # Update the size of the figure to fit the constructs drawn + fig_x_dim = max_dna_len / 60.0 + if fig_x_dim < 1.0: + fig_x_dim = 1.0 + fig_y_dim = 1.2 + plt.gcf().set_size_inches((fig_x_dim, fig_y_dim)) + + # Save the figure + plt.tight_layout() + fig.savefig(args.output, transparent=True, dpi=300) + + +# Enable the script to be run from the command line if __name__ == "__main__": - main() + main() diff --git a/dnaplotlib/dnaplotlib/dnaplotlib.py b/dnaplotlib/dnaplotlib/dnaplotlib.py index 1ad2b91..da152c9 100755 --- a/dnaplotlib/dnaplotlib/dnaplotlib.py +++ b/dnaplotlib/dnaplotlib/dnaplotlib.py @@ -48,9 +48,11 @@ import math import csv from operator import itemgetter + # Set the backend to use (important for headless servers) import matplotlib -matplotlib.use('Agg') + +matplotlib.use("Agg") import matplotlib.pyplot as plt from matplotlib.patches import Polygon, Ellipse, Wedge, Circle, PathPatch from matplotlib.path import Path @@ -59,11 +61,11 @@ import matplotlib.patches as patches -__author__ = 'Thomas E. Gorochowski \n\ +__author__ = "Thomas E. Gorochowski \n\ Bryan Der \n\ - Emerson Glassey ' -__license__ = 'MIT' -__version__ = '1.0' + Emerson Glassey " +__license__ = "MIT" +__version__ = "1.0" ############################################################################### @@ -71,45 +73,52 @@ ############################################################################### -def write_label (ax, label_text, x_pos, opts=None): - """ Renders labels on parts. - """ +def write_label(ax, label_text, x_pos, opts=None): + """Renders labels on parts.""" zorder_add = 0.0 y_offset = 0.0 - label_style = 'normal' + label_style = "normal" label_size = 7 label_y_offset = 0 label_x_offset = 0 - label_color = (0,0,0) + label_color = (0, 0, 0) label_rotation = 0 if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'label_style' in list(opts.keys()): - label_style = opts['label_style'] - if 'label_size' in list(opts.keys()): - label_size = opts['label_size'] - if 'label_y_offset' in list(opts.keys()): - label_y_offset = opts['label_y_offset'] - if 'label_x_offset' in list(opts.keys()): - label_x_offset = opts['label_x_offset'] - if 'label_color' in list(opts.keys()): - label_color = opts['label_color'] - if 'label_rotation' in list(opts.keys()): - label_rotation = opts['label_rotation'] - ax.text(x_pos+label_x_offset, label_y_offset+y_offset, label_text, horizontalalignment='center', - verticalalignment='center', fontsize=label_size, fontstyle=label_style, - color=label_color, rotation=label_rotation, zorder=30+zorder_add) - - -def sbol_promoter (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL promoter renderer. - """ + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "label_style" in list(opts.keys()): + label_style = opts["label_style"] + if "label_size" in list(opts.keys()): + label_size = opts["label_size"] + if "label_y_offset" in list(opts.keys()): + label_y_offset = opts["label_y_offset"] + if "label_x_offset" in list(opts.keys()): + label_x_offset = opts["label_x_offset"] + if "label_color" in list(opts.keys()): + label_color = opts["label_color"] + if "label_rotation" in list(opts.keys()): + label_rotation = opts["label_rotation"] + ax.text( + x_pos + label_x_offset, + label_y_offset + y_offset, + label_text, + horizontalalignment="center", + verticalalignment="center", + fontsize=label_size, + fontstyle=label_style, + color=label_color, + rotation=label_rotation, + zorder=30 + zorder_add, + ) + + +def sbol_promoter(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL promoter renderer.""" # Default options zorder_add = 0.0 - color = (0.0,0.0,0.0) + color = (0.0, 0.0, 0.0) start_pad = 2.0 end_pad = 2.0 y_extent = 10 @@ -118,106 +127,138 @@ def sbol_promoter (ax, type, num, start, end, prev_end, scale, linewidth, opts): arrowhead_length = 4 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 final_end = end final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the promoter symbol - l1 = Line2D([start,start],[0,dir_fac*y_extent], linewidth=linewidth, - color=color, zorder=9+zorder_add) - l2 = Line2D([start,start+dir_fac*x_extent-dir_fac*(arrowhead_length*0.5)], - [dir_fac*y_extent,dir_fac*y_extent], linewidth=linewidth, - color=color, zorder=10+zorder_add) + l1 = Line2D( + [start, start], + [0, dir_fac * y_extent], + linewidth=linewidth, + color=color, + zorder=9 + zorder_add, + ) + l2 = Line2D( + [ + start, + start + dir_fac * x_extent - dir_fac * (arrowhead_length * 0.5), + ], + [dir_fac * y_extent, dir_fac * y_extent], + linewidth=linewidth, + color=color, + zorder=10 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) - p1 = Polygon([(start+dir_fac*x_extent-dir_fac*arrowhead_length, - dir_fac*y_extent+(arrowhead_height)), - (start+dir_fac*x_extent, dir_fac*y_extent), - (start+dir_fac*x_extent-dir_fac*arrowhead_length, - dir_fac*y_extent-(arrowhead_height))], - facecolor=color, edgecolor=color, linewidth=linewidth, zorder=1+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0 + p1 = Polygon( + [ + ( + start + dir_fac * x_extent - dir_fac * arrowhead_length, + dir_fac * y_extent + (arrowhead_height), + ), + (start + dir_fac * x_extent, dir_fac * y_extent), + ( + start + dir_fac * x_extent - dir_fac * arrowhead_length, + dir_fac * y_extent - (arrowhead_height), + ), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=1 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0 ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_cds (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL coding sequence renderer. - """ +def sbol_cds(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL coding sequence renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" start_pad = 1.0 end_pad = 1.0 y_extent = 5 x_extent = 30 arrowhead_height = 4 arrowhead_length = 8 - edgecolor = (0,0,0) + edgecolor = (0, 0, 0) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'edge_color' in list(opts.keys()): - edgecolor = opts['edge_color'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "edge_color" in list(opts.keys()): + edgecolor = opts["edge_color"] # Check direction add start padding dir_fac = 1.0 @@ -225,637 +266,1045 @@ def sbol_cds (ax, type, num, start, end, prev_end, scale, linewidth, opts): final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the CDS symbol - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (end-dir_fac*arrowhead_length, -y_extent), - (end-dir_fac*arrowhead_length, -y_extent-arrowhead_height), - (end, 0), - (end-dir_fac*arrowhead_length, y_extent+arrowhead_height), - (end-dir_fac*arrowhead_length, y_extent)], - edgecolor=edgecolor, facecolor=color, linewidth=linewidth, - hatch=hatch, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0 + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (end - dir_fac * arrowhead_length, -y_extent), + (end - dir_fac * arrowhead_length, -y_extent - arrowhead_height), + (end, 0), + (end - dir_fac * arrowhead_length, y_extent + arrowhead_height), + (end - dir_fac * arrowhead_length, y_extent), + ], + edgecolor=edgecolor, + facecolor=color, + linewidth=linewidth, + hatch=hatch, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0 ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_terminator (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL terminator renderer. - """ +def sbol_terminator( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL terminator renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 10.0 x_extent = 8.0 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 final_end = end final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Draw the terminator symbol - l1 = Line2D([start+dir_fac*(x_extent/2.0),start+dir_fac*(x_extent/2.0)],[0,dir_fac*y_extent], linewidth=linewidth, - color=color, zorder=8+zorder_add) - l2 = Line2D([start,start+(dir_fac*x_extent)],[dir_fac*y_extent,dir_fac*y_extent], - linewidth=linewidth, color=color, zorder=9+zorder_add) + l1 = Line2D( + [ + start + dir_fac * (x_extent / 2.0), + start + dir_fac * (x_extent / 2.0), + ], + [0, dir_fac * y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + ) + l2 = Line2D( + [start, start + (dir_fac * x_extent)], + [dir_fac * y_extent, dir_fac * y_extent], + linewidth=linewidth, + color=color, + zorder=9 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_rbs (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL ribosome binding site renderer. - """ +def sbol_rbs(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL ribosome binding site renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) + color = (0.7, 0.7, 0.7) start_pad = 2.0 end_pad = 2.0 x_extent = 10.0 - edgecolor = (0,0,0) + edgecolor = (0, 0, 0) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'edge_color' in list(opts.keys()): - edgecolor = opts['edge_color'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "edge_color" in list(opts.keys()): + edgecolor = opts["edge_color"] # Check direction add start padding dir_fac = 1.0 final_end = end final_start = prev_end - rbs_center = (0,0) + rbs_center = (0, 0) if start > end: - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad - rbs_center = (end+((start-end)/2.0),0) - w1 = Wedge(rbs_center, x_extent/2.0, 180, 360, linewidth=linewidth, - facecolor=color, edgecolor=edgecolor, zorder=8+zorder_add) + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad + rbs_center = (end + ((start - end) / 2.0), 0) + w1 = Wedge( + rbs_center, + x_extent / 2.0, + 180, + 360, + linewidth=linewidth, + facecolor=color, + edgecolor=edgecolor, + zorder=8 + zorder_add, + ) ax.add_patch(w1) else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - rbs_center = (start+((end-start)/2.0),0) - w1 = Wedge(rbs_center, x_extent/2.0, 0, 180, linewidth=linewidth, - facecolor=color, edgecolor=edgecolor, zorder=8+zorder_add) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + rbs_center = (start + ((end - start) / 2.0), 0) + w1 = Wedge( + rbs_center, + x_extent / 2.0, + 0, + 180, + linewidth=linewidth, + facecolor=color, + edgecolor=edgecolor, + zorder=8 + zorder_add, + ) ax.add_patch(w1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_ribozyme (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL ribozyme renderer. - """ - return stick_figure(ax,type,num,start,end,prev_end,scale,linewidth,opts) +def sbol_ribozyme(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL ribozyme renderer.""" + return stick_figure( + ax, type, num, start, end, prev_end, scale, linewidth, opts + ) -def stick_figure (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ General function for drawing stick based parts (e.g., ribozyme and protease sites). - """ +def stick_figure(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """General function for drawing stick based parts (e.g., ribozyme and protease sites).""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 5.0 y_extent = 10.0 - linestyle = '-' - linetype = ""; - shapetype = ""; - if(type == "Ribozyme"): - linetype = 'dash' - headgroup = 'O' - elif(type == "Protease"): - linetype = 'dash' - headgroup = 'X' - elif(type == "ProteinStability"): - linetype = 'solid' - headgroup = 'O' - elif(type == "Ribonuclease"): - linetype = 'solid' - headgroup = 'X' + linestyle = "-" + linetype = "" + shapetype = "" + if type == "Ribozyme": + linetype = "dash" + headgroup = "O" + elif type == "Protease": + linetype = "dash" + headgroup = "X" + elif type == "ProteinStability": + linetype = "solid" + headgroup = "O" + elif type == "Ribonuclease": + linetype = "solid" + headgroup = "X" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end if start > end: - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad - rbs_center = (end+((start-end)/2.0),-y_extent) - c1 = Circle(rbs_center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=8+zorder_add) - x1 = Line2D([start,end],[-y_extent*1.25,-y_extent/1.5], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - x2 = Line2D([start,end],[-y_extent/1.5,-y_extent*1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - - dash1 = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,-y_extent/4], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - dash2 = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[-y_extent/2,-y_extent+(x_extent/2.0)], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - solidO = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,-y_extent+(x_extent/2.0)], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - solidX = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,-y_extent], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - - if(headgroup == "O" and linetype == "dash"): + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad + rbs_center = (end + ((start - end) / 2.0), -y_extent) + c1 = Circle( + rbs_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=8 + zorder_add, + ) + x1 = Line2D( + [start, end], + [-y_extent * 1.25, -y_extent / 1.5], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + x2 = Line2D( + [start, end], + [-y_extent / 1.5, -y_extent * 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + + dash1 = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, -y_extent / 4], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + dash2 = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [-y_extent / 2, -y_extent + (x_extent / 2.0)], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + solidO = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, -y_extent + (x_extent / 2.0)], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + solidX = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, -y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + + if headgroup == "O" and linetype == "dash": ax.add_patch(c1) ax.add_line(dash1) ax.add_line(dash2) - elif(headgroup == "X" and linetype == "dash"): + elif headgroup == "X" and linetype == "dash": ax.add_line(x1) ax.add_line(x2) ax.add_line(dash1) ax.add_line(dash2) - elif(headgroup == "O" and linetype == "solid"): + elif headgroup == "O" and linetype == "solid": ax.add_patch(c1) ax.add_line(solidO) - elif(headgroup == "X" and linetype == "solid"): + elif headgroup == "X" and linetype == "solid": ax.add_line(x1) ax.add_line(x2) ax.add_line(solidX) else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - rbs_center = (start+((end-start)/2.0),y_extent) - c1 = Circle(rbs_center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=8+zorder_add) - x1 = Line2D([start,end],[y_extent*1.25,y_extent/1.5], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - x2 = Line2D([start,end],[y_extent/1.5,y_extent*1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - - dash1 = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,y_extent/4], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - dash2 = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[y_extent/2,y_extent-(x_extent/2.0)], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - solidO = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,y_extent-(x_extent/2.0)], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - solidX = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,y_extent], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) - - if(headgroup == 'O' and linetype == 'dash'): + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + rbs_center = (start + ((end - start) / 2.0), y_extent) + c1 = Circle( + rbs_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=8 + zorder_add, + ) + x1 = Line2D( + [start, end], + [y_extent * 1.25, y_extent / 1.5], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + x2 = Line2D( + [start, end], + [y_extent / 1.5, y_extent * 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + + dash1 = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, y_extent / 4], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + dash2 = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [y_extent / 2, y_extent - (x_extent / 2.0)], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + solidO = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, y_extent - (x_extent / 2.0)], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + solidX = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) + + if headgroup == "O" and linetype == "dash": ax.add_patch(c1) ax.add_line(dash1) ax.add_line(dash2) - elif(headgroup == "X" and linetype == "dash"): + elif headgroup == "X" and linetype == "dash": ax.add_line(x1) ax.add_line(x2) ax.add_line(dash1) ax.add_line(dash2) - elif(headgroup == "O" and linetype == "solid"): + elif headgroup == "O" and linetype == "solid": ax.add_patch(c1) ax.add_line(solidO) - elif(headgroup == "X" and linetype == "solid"): + elif headgroup == "X" and linetype == "solid": ax.add_line(x1) ax.add_line(x2) ax.add_line(solidX) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_stem_top (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ General function for drawing stem-top parts (e.g., ribozyme and protease sites). - """ + +def sbol_stem_top(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """General function for drawing stem-top parts (e.g., ribozyme and protease sites).""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 5.0 y_extent = 10.0 - linestyle = '-' - shapetype = ""; + linestyle = "-" + shapetype = "" if type in ["DNACleavageSite"]: - stemtype = 'straight' - toptype = 'X' + stemtype = "straight" + toptype = "X" elif type in ["RNACleavageSite", "Ribonuclease"]: - stemtype = 'wavy' - toptype = 'X' + stemtype = "wavy" + toptype = "X" elif type in ["ProteinCleavageSite", "Protease"]: - stemtype = 'loopy' - toptype = 'X' + stemtype = "loopy" + toptype = "X" elif type in ["DNALocation"]: - stemtype = 'straight' - toptype = 'O' + stemtype = "straight" + toptype = "O" elif type in ["RNALocation"]: - stemtype = 'wavy' - toptype = 'O' + stemtype = "wavy" + toptype = "O" elif type in ["ProteinLocation"]: - stemtype = 'loopy' - toptype = 'O' + stemtype = "loopy" + toptype = "O" elif type in ["DNAStability"]: - stemtype = 'straight' - toptype = 'P' + stemtype = "straight" + toptype = "P" elif type in ["RNAStability"]: - stemtype = 'wavy' - toptype = 'P' + stemtype = "wavy" + toptype = "P" elif type in ["ProteinStability"]: - stemtype = 'loopy' - toptype = 'P' + stemtype = "loopy" + toptype = "P" elif type in ["StemTop"]: - stemtype = opts['stem'] - toptype = opts['top'] + stemtype = opts["stem"] + toptype = opts["top"] # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end if start > end: - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad # Patches and lines for top glyph # toptype=="X" - x1 = Line2D([start,end],[-y_extent*1.25,-y_extent/1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - x2 = Line2D([start,end],[-y_extent/1.25,-y_extent*1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') + x1 = Line2D( + [start, end], + [-y_extent * 1.25, -y_extent / 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + x2 = Line2D( + [start, end], + [-y_extent / 1.25, -y_extent * 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) # toptype=="O" - center = (end+((start-end)/2.0),-y_extent) - c1 = Circle(center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) + center = (end + ((start - end) / 2.0), -y_extent) + c1 = Circle( + center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) # toptype=='P' - pentagon_xy = [[end, -y_extent*1.25], - [end, -y_extent*0.87], - [(start + end)/2, -y_extent*0.68], - [start, -y_extent*0.87], - [start, -y_extent*1.25], - ] - p1 = Polygon(pentagon_xy, closed=True, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) + pentagon_xy = [ + [end, -y_extent * 1.25], + [end, -y_extent * 0.87], + [(start + end) / 2, -y_extent * 0.68], + [start, -y_extent * 0.87], + [start, -y_extent * 1.25], + ] + p1 = Polygon( + pentagon_xy, + closed=True, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) # Lines for stem glyph # stemtype=='straight' - straight_stem = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0, -y_extent], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) + straight_stem = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, -y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) # stemtype=='wavy' - wave_height = y_extent/6 - wave_start = (start + end)/2 - wave_bezier_amp = x_extent*0.2 - wave_bezier_dx = wave_bezier_amp*math.cos(math.pi/4) - wave_bezier_dy = wave_bezier_amp*math.sin(math.pi/4) - wavy_stem_path = Path(vertices=[[wave_start, 0], - [wave_start - wave_bezier_dx, -wave_bezier_dy], - [wave_start - wave_bezier_dx, -(wave_height - wave_bezier_dy)], - [wave_start, -wave_height], - [wave_start + wave_bezier_dx, -(wave_height + wave_bezier_dy)], - [wave_start + wave_bezier_dx, -(2*wave_height - wave_bezier_dy)], - [wave_start, -2*wave_height], - [wave_start - wave_bezier_dx, -(2*wave_height + wave_bezier_dy)], - [wave_start - wave_bezier_dx, -(3*wave_height - wave_bezier_dy)], - [wave_start, -3*wave_height], - [wave_start + wave_bezier_dx, -(3*wave_height + wave_bezier_dy)], - [wave_start + wave_bezier_dx, -(4*wave_height - wave_bezier_dy)], - [wave_start, -4*wave_height], - [wave_start - wave_bezier_dx, -(4*wave_height + wave_bezier_dy)], - [wave_start - wave_bezier_dx, -(5*wave_height - wave_bezier_dy)], - [wave_start, -5*wave_height], - [wave_start + wave_bezier_dx, -(5*wave_height + wave_bezier_dy)], - [wave_start + wave_bezier_dx, -(6*wave_height - wave_bezier_dy)], - [wave_start, -6*wave_height]], - codes=[1, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4]) - wavy_stem = PathPatch(wavy_stem_path, linewidth=linewidth, edgecolor=color, - facecolor='none', zorder=8+zorder_add, linestyle=linestyle) + wave_height = y_extent / 6 + wave_start = (start + end) / 2 + wave_bezier_amp = x_extent * 0.2 + wave_bezier_dx = wave_bezier_amp * math.cos(math.pi / 4) + wave_bezier_dy = wave_bezier_amp * math.sin(math.pi / 4) + wavy_stem_path = Path( + vertices=[ + [wave_start, 0], + [wave_start - wave_bezier_dx, -wave_bezier_dy], + [wave_start - wave_bezier_dx, -(wave_height - wave_bezier_dy)], + [wave_start, -wave_height], + [wave_start + wave_bezier_dx, -(wave_height + wave_bezier_dy)], + [ + wave_start + wave_bezier_dx, + -(2 * wave_height - wave_bezier_dy), + ], + [wave_start, -2 * wave_height], + [ + wave_start - wave_bezier_dx, + -(2 * wave_height + wave_bezier_dy), + ], + [ + wave_start - wave_bezier_dx, + -(3 * wave_height - wave_bezier_dy), + ], + [wave_start, -3 * wave_height], + [ + wave_start + wave_bezier_dx, + -(3 * wave_height + wave_bezier_dy), + ], + [ + wave_start + wave_bezier_dx, + -(4 * wave_height - wave_bezier_dy), + ], + [wave_start, -4 * wave_height], + [ + wave_start - wave_bezier_dx, + -(4 * wave_height + wave_bezier_dy), + ], + [ + wave_start - wave_bezier_dx, + -(5 * wave_height - wave_bezier_dy), + ], + [wave_start, -5 * wave_height], + [ + wave_start + wave_bezier_dx, + -(5 * wave_height + wave_bezier_dy), + ], + [ + wave_start + wave_bezier_dx, + -(6 * wave_height - wave_bezier_dy), + ], + [wave_start, -6 * wave_height], + ], + codes=[1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], + ) + wavy_stem = PathPatch( + wavy_stem_path, + linewidth=linewidth, + edgecolor=color, + facecolor="none", + zorder=8 + zorder_add, + linestyle=linestyle, + ) # stemtype=='loopy' - loop_offset_y = y_extent*0.015 - loop_height = (y_extent - 2*loop_offset_y)/4 - loop_start = (start + end)/2 + x_extent*0.05 - loop_end = end + x_extent*0.15 - loop_bezier_amp = y_extent*0.03 - loop_stem_path = Path(vertices=[[loop_start, -loop_offset_y], - [loop_start, -(loop_offset_y - loop_bezier_amp)], - [loop_end, -(loop_offset_y - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*0.5)], - [loop_end, -(loop_offset_y + loop_height + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height)], - [loop_start, -(loop_offset_y + loop_height - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*1.5)], - [loop_end, -(loop_offset_y + loop_height*2 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*2 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*2)], - [loop_start, -(loop_offset_y + loop_height*2 - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*2 - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*2.5)], - [loop_end, -(loop_offset_y + loop_height*3 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*3 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*3)], - [loop_start, -(loop_offset_y + loop_height*3 - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*3 - loop_bezier_amp)], - [loop_end, -(loop_offset_y + loop_height*3.5)], - [loop_end, -(loop_offset_y + loop_height*4 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*4 + loop_bezier_amp)], - [loop_start, -(loop_offset_y + loop_height*4)], - ], - codes=[1, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4]) - loop_stem = PathPatch(loop_stem_path, linewidth=linewidth, edgecolor=color, - facecolor='none', zorder=8+zorder_add, linestyle=linestyle) + loop_offset_y = y_extent * 0.015 + loop_height = (y_extent - 2 * loop_offset_y) / 4 + loop_start = (start + end) / 2 + x_extent * 0.05 + loop_end = end + x_extent * 0.15 + loop_bezier_amp = y_extent * 0.03 + loop_stem_path = Path( + vertices=[ + [loop_start, -loop_offset_y], + [loop_start, -(loop_offset_y - loop_bezier_amp)], + [loop_end, -(loop_offset_y - loop_bezier_amp)], + [loop_end, -(loop_offset_y + loop_height * 0.5)], + [loop_end, -(loop_offset_y + loop_height + loop_bezier_amp)], + [loop_start, -(loop_offset_y + loop_height + loop_bezier_amp)], + [loop_start, -(loop_offset_y + loop_height)], + [loop_start, -(loop_offset_y + loop_height - loop_bezier_amp)], + [loop_end, -(loop_offset_y + loop_height - loop_bezier_amp)], + [loop_end, -(loop_offset_y + loop_height * 1.5)], + [ + loop_end, + -(loop_offset_y + loop_height * 2 + loop_bezier_amp), + ], + [ + loop_start, + -(loop_offset_y + loop_height * 2 + loop_bezier_amp), + ], + [loop_start, -(loop_offset_y + loop_height * 2)], + [ + loop_start, + -(loop_offset_y + loop_height * 2 - loop_bezier_amp), + ], + [ + loop_end, + -(loop_offset_y + loop_height * 2 - loop_bezier_amp), + ], + [loop_end, -(loop_offset_y + loop_height * 2.5)], + [ + loop_end, + -(loop_offset_y + loop_height * 3 + loop_bezier_amp), + ], + [ + loop_start, + -(loop_offset_y + loop_height * 3 + loop_bezier_amp), + ], + [loop_start, -(loop_offset_y + loop_height * 3)], + [ + loop_start, + -(loop_offset_y + loop_height * 3 - loop_bezier_amp), + ], + [ + loop_end, + -(loop_offset_y + loop_height * 3 - loop_bezier_amp), + ], + [loop_end, -(loop_offset_y + loop_height * 3.5)], + [ + loop_end, + -(loop_offset_y + loop_height * 4 + loop_bezier_amp), + ], + [ + loop_start, + -(loop_offset_y + loop_height * 4 + loop_bezier_amp), + ], + [loop_start, -(loop_offset_y + loop_height * 4)], + ], + codes=[ + 1, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + ], + ) + loop_stem = PathPatch( + loop_stem_path, + linewidth=linewidth, + edgecolor=color, + facecolor="none", + zorder=8 + zorder_add, + linestyle=linestyle, + ) else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad # Patches and lines for top glyph # toptype=="X" - x1 = Line2D([start,end],[y_extent*1.25,y_extent/1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') - x2 = Line2D([start,end],[y_extent/1.25,y_extent*1.25], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle='-') + x1 = Line2D( + [start, end], + [y_extent * 1.25, y_extent / 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) + x2 = Line2D( + [start, end], + [y_extent / 1.25, y_extent * 1.25], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle="-", + ) # toptype=="O" - center = (start+((end-start)/2.0),y_extent) - c1 = Circle(center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) + center = (start + ((end - start) / 2.0), y_extent) + c1 = Circle( + center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) # toptype=='P' - pentagon_xy = [[start, y_extent*1.25], - [start, y_extent*0.87], - [(start + end)/2, y_extent*0.68], - [end, y_extent*0.87], - [end, y_extent*1.25], - ] - p1 = Polygon(pentagon_xy, closed=True, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) + pentagon_xy = [ + [start, y_extent * 1.25], + [start, y_extent * 0.87], + [(start + end) / 2, y_extent * 0.68], + [end, y_extent * 0.87], + [end, y_extent * 1.25], + ] + p1 = Polygon( + pentagon_xy, + closed=True, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) # Lines for stem glyph # stemtype=='straight' - straight_stem = Line2D([end+((start-end)/2.0),end+((start-end)/2.0)],[0,y_extent], - linewidth=linewidth, color=color, zorder=8+zorder_add, linestyle=linestyle) + straight_stem = Line2D( + [end + ((start - end) / 2.0), end + ((start - end) / 2.0)], + [0, y_extent], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + linestyle=linestyle, + ) # stemtype=='wavy' - wave_height = y_extent/6 - wave_start = (start + end)/2 - wave_bezier_amp = x_extent*0.2 - wave_bezier_dx = wave_bezier_amp*math.cos(math.pi/4) - wave_bezier_dy = wave_bezier_amp*math.sin(math.pi/4) - wavy_stem_path = Path(vertices=[[wave_start, 0], - [wave_start + wave_bezier_dx, wave_bezier_dy], - [wave_start + wave_bezier_dx, wave_height - wave_bezier_dy], - [wave_start, wave_height], - [wave_start - wave_bezier_dx, wave_height + wave_bezier_dy], - [wave_start - wave_bezier_dx, 2*wave_height - wave_bezier_dy], - [wave_start, 2*wave_height], - [wave_start + wave_bezier_dx, 2*wave_height + wave_bezier_dy], - [wave_start + wave_bezier_dx, 3*wave_height - wave_bezier_dy], - [wave_start, 3*wave_height], - [wave_start - wave_bezier_dx, 3*wave_height + wave_bezier_dy], - [wave_start - wave_bezier_dx, 4*wave_height - wave_bezier_dy], - [wave_start, 4*wave_height], - [wave_start + wave_bezier_dx, 4*wave_height + wave_bezier_dy], - [wave_start + wave_bezier_dx, 5*wave_height - wave_bezier_dy], - [wave_start, 5*wave_height], - [wave_start - wave_bezier_dx, 5*wave_height + wave_bezier_dy], - [wave_start - wave_bezier_dx, 6*wave_height - wave_bezier_dy], - [wave_start, 6*wave_height]], - codes=[1, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4]) - wavy_stem = PathPatch(wavy_stem_path, linewidth=linewidth, edgecolor=color, - facecolor='none', zorder=8+zorder_add, linestyle=linestyle) + wave_height = y_extent / 6 + wave_start = (start + end) / 2 + wave_bezier_amp = x_extent * 0.2 + wave_bezier_dx = wave_bezier_amp * math.cos(math.pi / 4) + wave_bezier_dy = wave_bezier_amp * math.sin(math.pi / 4) + wavy_stem_path = Path( + vertices=[ + [wave_start, 0], + [wave_start + wave_bezier_dx, wave_bezier_dy], + [wave_start + wave_bezier_dx, wave_height - wave_bezier_dy], + [wave_start, wave_height], + [wave_start - wave_bezier_dx, wave_height + wave_bezier_dy], + [wave_start - wave_bezier_dx, 2 * wave_height - wave_bezier_dy], + [wave_start, 2 * wave_height], + [wave_start + wave_bezier_dx, 2 * wave_height + wave_bezier_dy], + [wave_start + wave_bezier_dx, 3 * wave_height - wave_bezier_dy], + [wave_start, 3 * wave_height], + [wave_start - wave_bezier_dx, 3 * wave_height + wave_bezier_dy], + [wave_start - wave_bezier_dx, 4 * wave_height - wave_bezier_dy], + [wave_start, 4 * wave_height], + [wave_start + wave_bezier_dx, 4 * wave_height + wave_bezier_dy], + [wave_start + wave_bezier_dx, 5 * wave_height - wave_bezier_dy], + [wave_start, 5 * wave_height], + [wave_start - wave_bezier_dx, 5 * wave_height + wave_bezier_dy], + [wave_start - wave_bezier_dx, 6 * wave_height - wave_bezier_dy], + [wave_start, 6 * wave_height], + ], + codes=[1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], + ) + wavy_stem = PathPatch( + wavy_stem_path, + linewidth=linewidth, + edgecolor=color, + facecolor="none", + zorder=8 + zorder_add, + linestyle=linestyle, + ) # stemtype=='loopy' - loop_offset_y = y_extent*0.015 - loop_height = (y_extent - 2*loop_offset_y)/4 - loop_start = (start + end)/2 - x_extent*0.05 - loop_end = end - x_extent*0.15 - loop_bezier_amp = y_extent*0.03 - loop_stem_path = Path(vertices=[[loop_start, loop_offset_y], - [loop_start, loop_offset_y - loop_bezier_amp], - [loop_end, loop_offset_y - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*0.5], - [loop_end, loop_offset_y + loop_height + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height], - [loop_start, loop_offset_y + loop_height - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*1.5], - [loop_end, loop_offset_y + loop_height*2 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*2 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*2], - [loop_start, loop_offset_y + loop_height*2 - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*2 - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*2.5], - [loop_end, loop_offset_y + loop_height*3 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*3 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*3], - [loop_start, loop_offset_y + loop_height*3 - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*3 - loop_bezier_amp], - [loop_end, loop_offset_y + loop_height*3.5], - [loop_end, loop_offset_y + loop_height*4 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*4 + loop_bezier_amp], - [loop_start, loop_offset_y + loop_height*4], - ], - codes=[1, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4, 4,4,4]) - loop_stem = PathPatch(loop_stem_path, linewidth=linewidth, edgecolor=color, - facecolor='none', zorder=8+zorder_add, linestyle=linestyle) + loop_offset_y = y_extent * 0.015 + loop_height = (y_extent - 2 * loop_offset_y) / 4 + loop_start = (start + end) / 2 - x_extent * 0.05 + loop_end = end - x_extent * 0.15 + loop_bezier_amp = y_extent * 0.03 + loop_stem_path = Path( + vertices=[ + [loop_start, loop_offset_y], + [loop_start, loop_offset_y - loop_bezier_amp], + [loop_end, loop_offset_y - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 0.5], + [loop_end, loop_offset_y + loop_height + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height], + [loop_start, loop_offset_y + loop_height - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 1.5], + [loop_end, loop_offset_y + loop_height * 2 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 2 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 2], + [loop_start, loop_offset_y + loop_height * 2 - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 2 - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 2.5], + [loop_end, loop_offset_y + loop_height * 3 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 3 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 3], + [loop_start, loop_offset_y + loop_height * 3 - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 3 - loop_bezier_amp], + [loop_end, loop_offset_y + loop_height * 3.5], + [loop_end, loop_offset_y + loop_height * 4 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 4 + loop_bezier_amp], + [loop_start, loop_offset_y + loop_height * 4], + ], + codes=[ + 1, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + ], + ) + loop_stem = PathPatch( + loop_stem_path, + linewidth=linewidth, + edgecolor=color, + facecolor="none", + zorder=8 + zorder_add, + linestyle=linestyle, + ) # Add stem patches and/or lines - if stemtype == 'straight': + if stemtype == "straight": ax.add_line(straight_stem) - elif stemtype == 'wavy': + elif stemtype == "wavy": ax.add_line(wavy_stem) - elif stemtype == 'loopy': + elif stemtype == "loopy": ax.add_line(loop_stem) # Add top patches and/or lines - if toptype == 'O': + if toptype == "O": ax.add_patch(c1) - elif toptype == 'X': + elif toptype == "X": ax.add_line(x1) ax.add_line(x2) - elif toptype == 'P': + elif toptype == "P": ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_scar (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL scar renderer. - """ + +def sbol_scar(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL scar renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 6.0 y_extent = 1.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - l_top = Line2D([start,start+x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l_bottom = Line2D([start,start+x_extent],[-1*y_extent,-1*y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + l_top = Line2D( + [start, start + x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l_bottom = Line2D( + [start, start + x_extent], + [-1 * y_extent, -1 * y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) ax.add_line(l_top) ax.add_line(l_bottom) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -863,93 +1312,134 @@ def sbol_scar (ax, type, num, start, end, prev_end, scale, linewidth, opts): return prev_end, final_end -def sbol_empty_space (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in empty space renderer. - """ +def sbol_empty_space( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in empty space renderer.""" # Default options zorder_add = 0.0 x_extent = 12.0 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] # Check direction add start padding final_start = prev_end - final_end = final_start+x_extent + final_end = final_start + x_extent - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start else: return prev_end, final_end -def sbol_5_overhang (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL 5' overhang renderer. - """ +def sbol_5_overhang( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL 5' overhang renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 0.0 end_pad = 2.0 x_extent = 6.0 y_extent = 1.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - l_top = Line2D([start,start+x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l_bottom = Line2D([start+(x_extent/2.0),start+x_extent],[-1*y_extent,-1*y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + l_top = Line2D( + [start, start + x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l_bottom = Line2D( + [start + (x_extent / 2.0), start + x_extent], + [-1 * y_extent, -1 * y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) ax.add_line(l_top) ax.add_line(l_bottom) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -957,66 +1447,96 @@ def sbol_5_overhang (ax, type, num, start, end, prev_end, scale, linewidth, opts return prev_end, final_end -def sbol_3_overhang (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL 3' overhang renderer. - """ +def sbol_3_overhang( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL 3' overhang renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 0.0 x_extent = 6.0 y_extent = 1.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - l_top = Line2D([start,start+x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l_bottom = Line2D([start,start+(x_extent/2.0)],[-1*y_extent,-1*y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + l_top = Line2D( + [start, start + x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l_bottom = Line2D( + [start, start + (x_extent / 2.0)], + [-1 * y_extent, -1 * y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) ax.add_line(l_top) ax.add_line(l_bottom) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1024,41 +1544,42 @@ def sbol_3_overhang (ax, type, num, start, end, prev_end, scale, linewidth, opts return prev_end, final_end -def sbol_blunt_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL blunt-end restriction site renderer. - """ +def sbol_blunt_restriction_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL blunt-end restriction site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 4.0 x_extent = 1.5 site_space = 1.5 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'site_space' in list(opts.keys()): - site_space = opts['site_space'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "site_space" in list(opts.keys()): + site_space = opts["site_space"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + # Direction is meaningless for this part => start is always < end if start > end: temp_end = end @@ -1068,24 +1589,60 @@ def sbol_blunt_restriction_site (ax, type, num, start, end, prev_end, scale, lin # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent+site_space+x_extent - final_end = end+end_pad - - l1 = Line2D([start+x_extent,start+x_extent],[-y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_top = Line2D([start,start+x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_bottom = Line2D([start,start+x_extent],[-y_extent,-y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - - l2 = Line2D([end-x_extent,end-x_extent],[-y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l2_top = Line2D([end,end-x_extent],[y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l2_bottom = Line2D([end,end-x_extent],[-y_extent,-y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - + start = prev_end + start_pad + end = start + x_extent + site_space + x_extent + final_end = end + end_pad + + l1 = Line2D( + [start + x_extent, start + x_extent], + [-y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_top = Line2D( + [start, start + x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_bottom = Line2D( + [start, start + x_extent], + [-y_extent, -y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + + l2 = Line2D( + [end - x_extent, end - x_extent], + [-y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l2_top = Line2D( + [end, end - x_extent], + [y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l2_bottom = Line2D( + [end, end - x_extent], + [-y_extent, -y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + ax.add_line(l1) ax.add_line(l1_top) ax.add_line(l1_bottom) @@ -1093,53 +1650,59 @@ def sbol_blunt_restriction_site (ax, type, num, start, end, prev_end, scale, lin ax.add_line(l2_top) ax.add_line(l2_bottom) - if opts != None and 'label' in list(opts.keys()): - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + if opts != None and "label" in list(opts.keys()): + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) return final_start, final_end -def sbol_primer_binding_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL primer binding site renderer. - """ +def sbol_primer_binding_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL primer binding site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 2.0 y_offset = 1.5 x_extent = 8.0 arrowhead_length = 2.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - - direction = 'F' + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + + direction = "F" if start > end: - direction = 'R' + direction = "R" temp_end = end end = start start = temp_end @@ -1147,35 +1710,59 @@ def sbol_primer_binding_site (ax, type, num, start, end, prev_end, scale, linewi final_end = prev_end final_start = prev_end - if direction == 'F': + if direction == "F": final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad else: final_start = prev_end - end = prev_end+end_pad - start = end+x_extent - final_start = start+start_pad - - if direction == 'F': - verts = [(start, y_offset), (end, y_offset), (end-arrowhead_length, y_offset+y_extent)] + end = prev_end + end_pad + start = end + x_extent + final_start = start + start_pad + + if direction == "F": + verts = [ + (start, y_offset), + (end, y_offset), + (end - arrowhead_length, y_offset + y_extent), + ] codes = [Path.MOVETO, Path.LINETO, Path.LINETO] path = Path(verts, codes) - patch = PathPatch(path, lw=linewidth, edgecolor=color, facecolor=(1,1,1), zorder=1+zorder_add) + patch = PathPatch( + path, + lw=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=1 + zorder_add, + ) ax.add_patch(patch) else: - verts = [(start, -y_offset), (end, -y_offset), (end+arrowhead_length, -y_offset-y_extent)] + verts = [ + (start, -y_offset), + (end, -y_offset), + (end + arrowhead_length, -y_offset - y_extent), + ] codes = [Path.MOVETO, Path.LINETO, Path.LINETO] path = Path(verts, codes) - patch = PathPatch(path, lw=linewidth, edgecolor=color, facecolor=(1,1,1), zorder=1+zorder_add) + patch = PathPatch( + path, + lw=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=1 + zorder_add, + ) ax.add_patch(patch) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start > end: - write_label(ax, opts['label'], end+((start-end)/2.0), opts=opts) + write_label( + ax, opts["label"], end + ((start - end) / 2.0), opts=opts + ) else: - write_label(ax, opts['label'], start+((end-start)/2.0), opts=opts) + write_label( + ax, opts["label"], start + ((end - start) / 2.0), opts=opts + ) if final_start > final_end: return prev_end, final_start @@ -1183,41 +1770,42 @@ def sbol_primer_binding_site (ax, type, num, start, end, prev_end, scale, linewi return prev_end, final_end -def sbol_5_sticky_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL 5' sticky-end restriction site renderer. - """ +def sbol_5_sticky_restriction_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL 5' sticky-end restriction site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 4.0 x_extent = 8.0 end_space = 1.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'end_space' in list(opts.keys()): - end_space = opts['end_space'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "end_space" in list(opts.keys()): + end_space = opts["end_space"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + # Direction is meaningless for this part => start is always < end if start > end: temp_end = end @@ -1227,71 +1815,102 @@ def sbol_5_sticky_restriction_site (ax, type, num, start, end, prev_end, scale, # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+end_space+x_extent+end_space - final_end = end+end_pad - - l1 = Line2D([start+end_space,start+end_space+x_extent],[0,0], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_top = Line2D([start+end_space,start+end_space],[0,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_bottom = Line2D([start+end_space+x_extent,start+end_space+x_extent],[0,-y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + start = prev_end + start_pad + end = start + end_space + x_extent + end_space + final_end = end + end_pad + + l1 = Line2D( + [start + end_space, start + end_space + x_extent], + [0, 0], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_top = Line2D( + [start + end_space, start + end_space], + [0, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_bottom = Line2D( + [start + end_space + x_extent, start + end_space + x_extent], + [0, -y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(l1) ax.add_line(l1_top) ax.add_line(l1_bottom) # White rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (end, -y_extent), - (end, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (end, -y_extent), + (end, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + if opts != None and "label" in list(opts.keys()): + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) return final_start, final_end -def sbol_3_sticky_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL 3' sticky-end restriction site renderer. - """ +def sbol_3_sticky_restriction_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL 3' sticky-end restriction site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 4.0 x_extent = 8.0 end_space = 1.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'end_space' in list(opts.keys()): - end_space = opts['end_space'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "end_space" in list(opts.keys()): + end_space = opts["end_space"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + # Direction is meaningless for this part => start is always < end if start > end: temp_end = end @@ -1301,93 +1920,141 @@ def sbol_3_sticky_restriction_site (ax, type, num, start, end, prev_end, scale, # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+end_space+x_extent+end_space - final_end = end+end_pad - - l1 = Line2D([start+end_space,start+end_space+x_extent],[0,0], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_top = Line2D([start+end_space+x_extent,start+end_space+x_extent],[0,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - l1_bottom = Line2D([start+end_space,start+end_space],[0,-y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + start = prev_end + start_pad + end = start + end_space + x_extent + end_space + final_end = end + end_pad + + l1 = Line2D( + [start + end_space, start + end_space + x_extent], + [0, 0], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_top = Line2D( + [start + end_space + x_extent, start + end_space + x_extent], + [0, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l1_bottom = Line2D( + [start + end_space, start + end_space], + [0, -y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(l1) ax.add_line(l1_top) ax.add_line(l1_bottom) # White rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (end, -y_extent), - (end, y_extent)], - edgecolor=(1,1,1), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (end, -y_extent), + (end, y_extent), + ], + edgecolor=(1, 1, 1), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + if opts != None and "label" in list(opts.keys()): + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) return final_start, final_end -def sbol_user_defined (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL user-defined element renderer. - """ +def sbol_user_defined( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL user-defined element renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 12.0 y_extent = 3.0 - linestyle = '-' - fill_color = (1,1,1) + linestyle = "-" + fill_color = (1, 1, 1) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'fill_color' in list(opts.keys()): - fill_color = opts['fill_color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "fill_color" in list(opts.keys()): + fill_color = opts["fill_color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=color, facecolor=fill_color, linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=color, + facecolor=fill_color, + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1395,44 +2062,43 @@ def sbol_user_defined (ax, type, num, start, end, prev_end, scale, linewidth, o return prev_end, final_end -def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL signature renderer. - """ +def sbol_signature(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL signature renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 12.0 y_extent = 3.0 - linestyle = '-' - fill_color = (1,1,1) + linestyle = "-" + fill_color = (1, 1, 1) # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'fill_color' in list(opts.keys()): - fill_color = opts['fill_color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - - direction = 'F' + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "fill_color" in list(opts.keys()): + fill_color = opts["fill_color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + + direction = "F" if start > end: - direction = 'R' + direction = "R" temp_end = end end = start start = temp_end @@ -1440,27 +2106,34 @@ def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts final_end = prev_end final_start = prev_end - if direction == 'F': + if direction == "F": final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad else: final_start = prev_end - end = prev_end+end_pad - start = end+x_extent - final_start = start+start_pad - - indent_fac = (y_extent*2.0)*0.3 - cross_width = (y_extent*2.0)*0.7 - - if direction == 'F': - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=color, facecolor=fill_color, linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + end = prev_end + end_pad + start = end + x_extent + final_start = start + start_pad + + indent_fac = (y_extent * 2.0) * 0.3 + cross_width = (y_extent * 2.0) * 0.7 + + if direction == "F": + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=color, + facecolor=fill_color, + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) top1x = start + indent_fac top1y = y_extent - indent_fac @@ -1470,22 +2143,47 @@ def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts bot1y = -y_extent + indent_fac bot2x = start + cross_width bot2y = -y_extent + indent_fac - lcross1 = Line2D([top1x,bot2x],[top1y,bot2y], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - lcross2 = Line2D([top2x,bot1x],[top2y,bot1y], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + lcross1 = Line2D( + [top1x, bot2x], + [top1y, bot2y], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + lcross2 = Line2D( + [top2x, bot1x], + [top2y, bot1y], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(lcross1) ax.add_line(lcross2) - lsign = Line2D([bot2x+indent_fac,end-indent_fac],[-y_extent+indent_fac,-y_extent+indent_fac], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + lsign = Line2D( + [bot2x + indent_fac, end - indent_fac], + [-y_extent + indent_fac, -y_extent + indent_fac], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(lsign) else: - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start-x_extent, -y_extent), - (start-x_extent, y_extent)], - edgecolor=color, facecolor=fill_color, linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start - x_extent, -y_extent), + (start - x_extent, y_extent), + ], + edgecolor=color, + facecolor=fill_color, + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) top1x = start - indent_fac top1y = y_extent - indent_fac @@ -1495,21 +2193,49 @@ def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts bot1y = -y_extent + indent_fac bot2x = start - cross_width bot2y = -y_extent + indent_fac - lcross1 = Line2D([top1x,bot2x],[top1y,bot2y], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) - lcross2 = Line2D([top2x,bot1x],[top2y,bot1y], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + lcross1 = Line2D( + [top1x, bot2x], + [top1y, bot2y], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + lcross2 = Line2D( + [top2x, bot1x], + [top2y, bot1y], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(lcross1) ax.add_line(lcross2) - lsign = Line2D([bot2x-indent_fac,end+indent_fac],[y_extent-indent_fac,y_extent-indent_fac], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + lsign = Line2D( + [bot2x - indent_fac, end + indent_fac], + [y_extent - indent_fac, y_extent - indent_fac], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(lsign) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1517,51 +2243,68 @@ def sbol_signature (ax, type, num, start, end, prev_end, scale, linewidth, opts return prev_end, final_end -def sbol_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL restriction site renderer. - """ +def sbol_restriction_site( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """Built-in SBOL restriction site renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 y_extent = 4.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad + start = prev_end + start_pad end = start + linewidth - final_end = end+end_pad - - l1 = Line2D([start,start],[-y_extent,y_extent], - linewidth=linewidth, color=color, zorder=12+zorder_add, linestyle=linestyle) + final_end = end + end_pad + + l1 = Line2D( + [start, start], + [-y_extent, y_extent], + linewidth=linewidth, + color=color, + zorder=12 + zorder_add, + linestyle=linestyle, + ) ax.add_line(l1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1569,69 +2312,96 @@ def sbol_restriction_site (ax, type, num, start, end, prev_end, scale, linewidth return prev_end, final_end -def sbol_spacer (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL spacer renderer. - """ +def sbol_spacer(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL spacer renderer.""" # Default options zorder_add = 0.0 - color = (1,1,1) - edgecolor = (0,0,0) + color = (1, 1, 1) + edgecolor = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 6.0 y_extent = 6.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'edgecolor' in list(opts.keys()): - edgecolor = opts['edgecolor'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "edgecolor" in list(opts.keys()): + edgecolor = opts["edgecolor"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - rbs_center = (start+((end-start)/2.0),0) - center_x = start+(end-start)/2.0 - radius = x_extent/2 + + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + rbs_center = (start + ((end - start) / 2.0), 0) + center_x = start + (end - start) / 2.0 + radius = x_extent / 2 delta = radius - 0.5 * radius * math.sqrt(2) - l1 = Line2D([start+delta,end-delta],[radius-delta,-1*radius+delta], - linewidth=linewidth, color=edgecolor, zorder=12+zorder_add, linestyle=linestyle) - l2 = Line2D([start+delta,end-delta],[-1*radius+delta,radius-delta], - linewidth=linewidth, color=edgecolor, zorder=12+zorder_add, linestyle=linestyle) - c1 = Circle(rbs_center, x_extent/2.0, linewidth=linewidth, edgecolor=edgecolor, - facecolor=color, zorder=12+zorder_add) - + l1 = Line2D( + [start + delta, end - delta], + [radius - delta, -1 * radius + delta], + linewidth=linewidth, + color=edgecolor, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + l2 = Line2D( + [start + delta, end - delta], + [-1 * radius + delta, radius - delta], + linewidth=linewidth, + color=edgecolor, + zorder=12 + zorder_add, + linestyle=linestyle, + ) + c1 = Circle( + rbs_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=edgecolor, + facecolor=color, + zorder=12 + zorder_add, + ) + ax.add_patch(c1) ax.add_line(l1) ax.add_line(l2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1639,56 +2409,71 @@ def sbol_spacer (ax, type, num, start, end, prev_end, scale, linewidth, opts): return prev_end, final_end -def sbol_origin (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL origin renderer. - """ +def sbol_origin(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL origin renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 10.0 y_extent = 10.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - ori_center = (start+((end-start)/2.0),0) - - c1 = Circle(ori_center, x_extent/2.0, linewidth=linewidth, edgecolor=color, - facecolor=(1,1,1), zorder=12+zorder_add) - + + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + ori_center = (start + ((end - start) / 2.0), 0) + + c1 = Circle( + ori_center, + x_extent / 2.0, + linewidth=linewidth, + edgecolor=color, + facecolor=(1, 1, 1), + zorder=12 + zorder_add, + ) + ax.add_patch(c1) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1696,60 +2481,76 @@ def sbol_origin (ax, type, num, start, end, prev_end, scale, linewidth, opts): return prev_end, final_end -def sbol_operator (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL operator renderer. - """ +def sbol_operator(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL operator renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 6.0 y_extent = 3.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=(0,0,0), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=(0, 0, 0), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1757,74 +2558,97 @@ def sbol_operator (ax, type, num, start, end, prev_end, scale, linewidth, opts): return prev_end, final_end -def sbol_insulator (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ Built-in SBOL insulator renderer. - """ +def sbol_insulator(ax, type, num, start, end, prev_end, scale, linewidth, opts): + """Built-in SBOL insulator renderer.""" # Default options zorder_add = 0.0 - color = (0,0,0) + color = (0, 0, 0) start_pad = 2.0 end_pad = 2.0 x_extent = 8.0 y_extent = 4.0 - linestyle = '-' + linestyle = "-" # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + # Check direction add start padding final_end = end final_start = prev_end - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - #white rectangle overlays backbone line - p1 = Polygon([(start, y_extent), - (start, -y_extent), - (start+x_extent, -y_extent), - (start+x_extent, y_extent)], - edgecolor=(0,0,0), facecolor=(1,1,1), linewidth=linewidth, zorder=11+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + # white rectangle overlays backbone line + p1 = Polygon( + [ + (start, y_extent), + (start, -y_extent), + (start + x_extent, -y_extent), + (start + x_extent, y_extent), + ], + edgecolor=(0, 0, 0), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=11 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) bits = 5.0 - gap_size = ((end-start)/bits) + gap_size = (end - start) / bits x_inset_start = start + gap_size - x_inset_end = start + ((bits-1.0)*gap_size) + x_inset_end = start + ((bits - 1.0) * gap_size) # Inside rectangle - p2 = Polygon([(x_inset_start, y_extent-gap_size), - (x_inset_start, -y_extent+gap_size), - (x_inset_end, -y_extent+gap_size), - (x_inset_end, y_extent-gap_size)], - edgecolor=(0,0,0), facecolor=(1,1,1), linewidth=linewidth, zorder=12+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (x_inset_start, y_extent - gap_size), + (x_inset_start, -y_extent + gap_size), + (x_inset_end, -y_extent + gap_size), + (x_inset_end, y_extent - gap_size), + ], + edgecolor=(0, 0, 0), + facecolor=(1, 1, 1), + linewidth=linewidth, + zorder=12 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) ax.add_patch(p2) - - if opts != None and 'label' in list(opts.keys()): + + if opts != None and "label" in list(opts.keys()): if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) if final_start > final_end: return prev_end, final_start @@ -1833,10 +2657,12 @@ def sbol_insulator (ax, type, num, start, end, prev_end, scale, linewidth, opts) # Not used at present -def temporary_repressor (ax, type, num, start, end, prev_end, scale, linewidth, opts): +def temporary_repressor( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) + color = (0.7, 0.7, 0.7) start_pad = 2.0 end_pad = 2.0 y_extent = 10 @@ -1845,47 +2671,63 @@ def temporary_repressor (ax, type, num, start, end, prev_end, scale, linewidth, arrowhead_length = 4 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 final_end = end final_start = prev_end if start > end: dir_fac = -1.0 - start = prev_end+end_pad+x_extent - end = prev_end+end_pad - final_end = start+start_pad + start = prev_end + end_pad + x_extent + end = prev_end + end_pad + final_end = start + start_pad else: - start = prev_end+start_pad - end = start+x_extent - final_end = end+end_pad - - e1center = (start+((end-start)/2.0),0) - e2center = (start+((end-start)/2.0)+x_extent/3.75,0) - - e1 = Ellipse(e1center, y_extent/2, y_extent, edgecolor=(0,0,0), facecolor=color, - linewidth=linewidth, fill=True, zorder=12+zorder_add) - e2 = Ellipse(e2center, y_extent/2, y_extent, edgecolor=(0,0,0), facecolor=color, - linewidth=linewidth, fill=True, zorder=11+zorder_add) + start = prev_end + start_pad + end = start + x_extent + final_end = end + end_pad + + e1center = (start + ((end - start) / 2.0), 0) + e2center = (start + ((end - start) / 2.0) + x_extent / 3.75, 0) + + e1 = Ellipse( + e1center, + y_extent / 2, + y_extent, + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + fill=True, + zorder=12 + zorder_add, + ) + e2 = Ellipse( + e2center, + y_extent / 2, + y_extent, + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + fill=True, + zorder=11 + zorder_add, + ) ax.add_patch(e1) ax.add_patch(e2) @@ -1901,115 +2743,186 @@ def temporary_repressor (ax, type, num, start, end, prev_end, scale, linewidth, ############################################################################### -def repress (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Standard repression regulation renderer. - """ - regulation(ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts) - - -def induce (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Standard induction regulation renderer. - """ - regulation(ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts) - - -def connect (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Standard induction regulation renderer. - """ - regulation(ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts) - - -def regulation (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ General function for drawing regulation arcs. - """ - - color = (0.0,0.0,0.0) +def repress( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Standard repression regulation renderer.""" + regulation( + ax, + type, + num, + from_part, + to_part, + scale, + linewidth, + arc_height_index, + opts, + ) + + +def induce( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Standard induction regulation renderer.""" + regulation( + ax, + type, + num, + from_part, + to_part, + scale, + linewidth, + arc_height_index, + opts, + ) + + +def connect( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Standard induction regulation renderer.""" + regulation( + ax, + type, + num, + from_part, + to_part, + scale, + linewidth, + arc_height_index, + opts, + ) + + +def regulation( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """General function for drawing regulation arcs.""" + + color = (0.0, 0.0, 0.0) arrowhead_length = 3 - linestyle = '-' + linestyle = "-" arcHeightConst = 15 arcHeightSpacing = 5 arcHeightStart = 10 - arcHeight = arcHeightConst + arc_height_index*arcHeightSpacing - arcHeightEnd = arcHeightStart*1.5 + arcHeight = arcHeightConst + arc_height_index * arcHeightSpacing + arcHeightEnd = arcHeightStart * 1.5 arc_start_x_offset = 0.0 arc_end_x_offset = 0.0 - + # Reset defaults if provided if opts != None: - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'arc_height' in list(opts.keys()): - arcHeight = opts['arc_height'] - if 'arc_height_const' in list(opts.keys()): - arcHeightConst = opts['arc_height_const'] - if 'arc_height_spacing' in list(opts.keys()): - arcHeightSpacing = opts['arc_height_spacing'] - if 'arc_height_start' in list(opts.keys()): - arcHeightStart = opts['arc_height_start'] - if 'arc_height_end' in list(opts.keys()): - arcHeightEnd = opts['arc_height_end'] - if 'arc_start_x_offset' in list(opts.keys()): - arc_start_x_offset = opts['arc_start_x_offset'] - if 'arc_end_x_offset' in list(opts.keys()): - arc_end_x_offset = opts['arc_end_x_offset'] - - if opts == None or 'arc_height' not in list(opts.keys()): - arcHeight = arcHeightConst + arc_height_index*arcHeightSpacing + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "color" in list(opts.keys()): + color = opts["color"] + if "arc_height" in list(opts.keys()): + arcHeight = opts["arc_height"] + if "arc_height_const" in list(opts.keys()): + arcHeightConst = opts["arc_height_const"] + if "arc_height_spacing" in list(opts.keys()): + arcHeightSpacing = opts["arc_height_spacing"] + if "arc_height_start" in list(opts.keys()): + arcHeightStart = opts["arc_height_start"] + if "arc_height_end" in list(opts.keys()): + arcHeightEnd = opts["arc_height_end"] + if "arc_start_x_offset" in list(opts.keys()): + arc_start_x_offset = opts["arc_start_x_offset"] + if "arc_end_x_offset" in list(opts.keys()): + arc_end_x_offset = opts["arc_end_x_offset"] + + if opts == None or "arc_height" not in list(opts.keys()): + arcHeight = arcHeightConst + arc_height_index * arcHeightSpacing startHeight = arcHeightStart - start = ((from_part['start'] + from_part['end']) / 2) + arc_start_x_offset - end = ((to_part['start'] + to_part['end']) / 2) + arc_end_x_offset + start = ((from_part["start"] + from_part["end"]) / 2) + arc_start_x_offset + end = ((to_part["start"] + to_part["end"]) / 2) + arc_end_x_offset - top = arcHeight; - base = startHeight; + top = arcHeight + base = startHeight indHeight = arrowhead_length corr = linewidth - if to_part['fwd'] == False: - base = -1*startHeight + if to_part["fwd"] == False: + base = -1 * startHeight arcHeightEnd = -arcHeightEnd - top = -1*arcHeight - indHeight = -1*arrowhead_length + top = -1 * arcHeight + indHeight = -1 * arrowhead_length corr *= -1 - - line_away = Line2D([start,start],[base,top], - linewidth=linewidth, color=color, zorder=12, linestyle=linestyle) - line_across = Line2D([start,end],[top,top], - linewidth=linewidth, color=color, zorder=12, linestyle=linestyle) - line_toward = Line2D([end,end],[top,arcHeightEnd+corr], - linewidth=linewidth, color=color, zorder=12, linestyle=linestyle) - line_rep = Line2D([end-arrowhead_length,end+arrowhead_length],[arcHeightEnd,arcHeightEnd], - linewidth=linewidth, color=color, zorder=12, linestyle='-') - line_ind1 = Line2D([end-arrowhead_length,end],[arcHeightEnd+indHeight,arcHeightEnd], - linewidth=linewidth, color=color, zorder=12, linestyle='-') - line_ind2 = Line2D([end+arrowhead_length,end],[arcHeightEnd+indHeight,arcHeightEnd], - linewidth=linewidth, color=color, zorder=12, linestyle='-') - - if(type == 'Repression'): + line_away = Line2D( + [start, start], + [base, top], + linewidth=linewidth, + color=color, + zorder=12, + linestyle=linestyle, + ) + line_across = Line2D( + [start, end], + [top, top], + linewidth=linewidth, + color=color, + zorder=12, + linestyle=linestyle, + ) + line_toward = Line2D( + [end, end], + [top, arcHeightEnd + corr], + linewidth=linewidth, + color=color, + zorder=12, + linestyle=linestyle, + ) + line_rep = Line2D( + [end - arrowhead_length, end + arrowhead_length], + [arcHeightEnd, arcHeightEnd], + linewidth=linewidth, + color=color, + zorder=12, + linestyle="-", + ) + line_ind1 = Line2D( + [end - arrowhead_length, end], + [arcHeightEnd + indHeight, arcHeightEnd], + linewidth=linewidth, + color=color, + zorder=12, + linestyle="-", + ) + line_ind2 = Line2D( + [end + arrowhead_length, end], + [arcHeightEnd + indHeight, arcHeightEnd], + linewidth=linewidth, + color=color, + zorder=12, + linestyle="-", + ) + + if type == "Repression": ax.add_line(line_rep) ax.add_line(line_away) ax.add_line(line_across) ax.add_line(line_toward) - if(type == 'Activation'): + if type == "Activation": ax.add_line(line_ind1) ax.add_line(line_ind2) ax.add_line(line_away) ax.add_line(line_across) ax.add_line(line_toward) - if(type == 'Connection'): - verts = [ (start, base), (start, top), (end, top), (end, base) ] + if type == "Connection": + verts = [(start, base), (start, top), (end, top), (end, base)] codes = [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4] path1 = Path(verts, codes) - patch = patches.PathPatch(path1, facecolor='none', lw=linewidth, edgecolor=color) + patch = patches.PathPatch( + path1, facecolor="none", lw=linewidth, edgecolor=color + ) ax.add_patch(patch) @@ -2018,12 +2931,13 @@ def regulation (ax, type, num, from_part, to_part, scale, linewidth, arc_height_ ############################################################################### -def trace_promoter_start (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based promoter renderer. - """ +def trace_promoter_start( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based promoter renderer.""" # Default options zorder_add = 0.0 - color = (0.0,0.0,1.0) + color = (0.0, 0.0, 1.0) y_offset = 0.0 y_extent = 6.0 x_extent = 30.0 @@ -2032,70 +2946,122 @@ def trace_promoter_start (ax, type, num, start_bp, end_bp, prev_end, scale, line highlight_y_extent = 0.8 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'highlight_y_extent' in list(opts.keys()): - highlight_y_extent = opts['highlight_y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "highlight_y_extent" in list(opts.keys()): + highlight_y_extent = opts["highlight_y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 y_offset = -y_offset # Draw the promoter symbol - l1 = Line2D([start_bp,start_bp],[0+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, - color=color, zorder=14+zorder_add) - l2 = Line2D([start_bp,start_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*0.5*scale], - [dir_fac*y_extent+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, - color=color, zorder=14+zorder_add) + l1 = Line2D( + [start_bp, start_bp], + [0 + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) + l2 = Line2D( + [ + start_bp, + start_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * 0.5 * scale, + ], + [dir_fac * y_extent + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) - p1 = Polygon([(start_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*scale, - dir_fac*y_extent+(arrowhead_height)+y_offset), - (start_bp+dir_fac*(x_extent*scale), dir_fac*y_extent+y_offset), - (start_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*scale, - dir_fac*y_extent-(arrowhead_height)+y_offset)], - facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + ( + start_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * scale, + dir_fac * y_extent + (arrowhead_height) + y_offset, + ), + ( + start_bp + dir_fac * (x_extent * scale), + dir_fac * y_extent + y_offset, + ), + ( + start_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * scale, + dir_fac * y_extent - (arrowhead_height) + y_offset, + ), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) # Shade the promoter area (normally smaller than symbol extent) - p2 = Polygon([(start_bp, -highlight_y_extent+y_offset), - (start_bp, highlight_y_extent+y_offset), - (end_bp, highlight_y_extent+y_offset), - (end_bp, -highlight_y_extent+y_offset)], facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (start_bp, -highlight_y_extent + y_offset), + (start_bp, highlight_y_extent + y_offset), + (end_bp, highlight_y_extent + y_offset), + (end_bp, -highlight_y_extent + y_offset), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_promoter (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based promoter renderer with arrow at TSS. - """ + +def trace_promoter( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based promoter renderer with arrow at TSS.""" # Default options zorder_add = 0.0 - color = (0.0,0.0,1.0) + color = (0.0, 0.0, 1.0) y_offset = 0.0 y_extent = 6.0 x_extent = 30.0 @@ -2104,332 +3070,492 @@ def trace_promoter (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, highlight_y_extent = 0.8 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'highlight_y_extent' in list(opts.keys()): - highlight_y_extent = opts['highlight_y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "highlight_y_extent" in list(opts.keys()): + highlight_y_extent = opts["highlight_y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 y_offset = -y_offset # Draw the promoter symbol - l1 = Line2D([end_bp,end_bp],[0+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, - color=color, zorder=14+zorder_add) - l2 = Line2D([end_bp,end_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*0.5*scale], - [dir_fac*y_extent+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, - color=color, zorder=14+zorder_add) + l1 = Line2D( + [end_bp, end_bp], + [0 + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) + l2 = Line2D( + [ + end_bp, + end_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * 0.5 * scale, + ], + [dir_fac * y_extent + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) - p1 = Polygon([(end_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*scale, - dir_fac*y_extent+(arrowhead_height)+y_offset), - (end_bp+dir_fac*(x_extent*scale), dir_fac*y_extent+y_offset), - (end_bp+dir_fac*x_extent*scale-dir_fac*arrowhead_length*scale, - dir_fac*y_extent-(arrowhead_height)+y_offset)], - facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + ( + end_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * scale, + dir_fac * y_extent + (arrowhead_height) + y_offset, + ), + ( + end_bp + dir_fac * (x_extent * scale), + dir_fac * y_extent + y_offset, + ), + ( + end_bp + + dir_fac * x_extent * scale + - dir_fac * arrowhead_length * scale, + dir_fac * y_extent - (arrowhead_height) + y_offset, + ), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) # Shade the promoter area (normally smaller than symbol extent) - p2 = Polygon([(start_bp, -highlight_y_extent+y_offset), - (start_bp, highlight_y_extent+y_offset), - (end_bp, highlight_y_extent+y_offset), - (end_bp, -highlight_y_extent+y_offset)], facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (start_bp, -highlight_y_extent + y_offset), + (start_bp, highlight_y_extent + y_offset), + (end_bp, highlight_y_extent + y_offset), + (end_bp, -highlight_y_extent + y_offset), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_rbs (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based ribosome binding site renderer. - """ +def trace_rbs( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based ribosome binding site renderer.""" # Default options zorder_add = 0.0 - color = (0.16,0.68,0.15) + color = (0.16, 0.68, 0.15) y_offset = 0.0 y_extent = 3.5 x_extent = 10.0 highlight_y_extent = 0.8 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'highlight_y_extent' in list(opts.keys()): - highlight_y_extent = opts['highlight_y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "highlight_y_extent" in list(opts.keys()): + highlight_y_extent = opts["highlight_y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 # Draw the RBS symbol - l1 = Line2D([start_bp,start_bp],[0+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, color=color, zorder=14+zorder_add) + l1 = Line2D( + [start_bp, start_bp], + [0 + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) ax.add_line(l1) - c1 = Ellipse((start_bp,dir_fac*y_extent+y_offset),width=(x_extent*scale),height=y_extent*0.4,color=color, zorder=14+zorder_add) + c1 = Ellipse( + (start_bp, dir_fac * y_extent + y_offset), + width=(x_extent * scale), + height=y_extent * 0.4, + color=color, + zorder=14 + zorder_add, + ) ax.add_artist(c1) # Shade the promoter area (normally smaller than symbol extent) - p2 = Polygon([(start_bp, -highlight_y_extent+y_offset), - (start_bp, highlight_y_extent+y_offset), - (end_bp, highlight_y_extent+y_offset), - (end_bp, -highlight_y_extent+y_offset)], facecolor=color, edgecolor=color, linewidth=linewidth, zorder=14+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (start_bp, -highlight_y_extent + y_offset), + (start_bp, highlight_y_extent + y_offset), + (end_bp, highlight_y_extent + y_offset), + (end_bp, -highlight_y_extent + y_offset), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=14 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_user_defined (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based user defined region renderer. - """ +def trace_user_defined( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based user defined region renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" y_offset = 0.0 y_extent = 1.5 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 # Draw the CDS symbol - p1 = Polygon([(start_bp, y_extent+y_offset), - (start_bp, -y_extent+y_offset), - (end_bp-dir_fac*scale, -y_extent+y_offset), - (end_bp-dir_fac*scale, y_extent+y_offset)], - edgecolor=(0.0,0.0,0.0), facecolor=color, linewidth=linewidth, - hatch=hatch, zorder=15+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start_bp, y_extent + y_offset), + (start_bp, -y_extent + y_offset), + (end_bp - dir_fac * scale, -y_extent + y_offset), + (end_bp - dir_fac * scale, y_extent + y_offset), + ], + edgecolor=(0.0, 0.0, 0.0), + facecolor=color, + linewidth=linewidth, + hatch=hatch, + zorder=15 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_cds (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based coding sequence renderer. - """ +def trace_cds( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based coding sequence renderer.""" # Default options zorder_add = 0.0 - color = (0.7,0.7,0.7) - hatch = '' + color = (0.7, 0.7, 0.7) + hatch = "" y_offset = 0.0 y_extent = 1.5 arrowhead_height = 1.0 arrowhead_length = 30.0 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'hatch' in list(opts.keys()): - hatch = opts['hatch'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'arrowhead_height' in list(opts.keys()): - arrowhead_height = opts['arrowhead_height'] - if 'arrowhead_length' in list(opts.keys()): - arrowhead_length = opts['arrowhead_length'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "hatch" in list(opts.keys()): + hatch = opts["hatch"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "arrowhead_height" in list(opts.keys()): + arrowhead_height = opts["arrowhead_height"] + if "arrowhead_length" in list(opts.keys()): + arrowhead_length = opts["arrowhead_length"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 # Draw the CDS symbol - p1 = Polygon([(start_bp, y_extent+y_offset), - (start_bp, -y_extent+y_offset), - (end_bp-dir_fac*arrowhead_length*scale, -y_extent+y_offset), - (end_bp-dir_fac*arrowhead_length*scale, -y_extent-arrowhead_height+y_offset), - (end_bp, 0+y_offset), - (end_bp-dir_fac*arrowhead_length*scale, y_extent+arrowhead_height+y_offset), - (end_bp-dir_fac*arrowhead_length*scale, y_extent+y_offset)], - edgecolor=(0.0,0.0,0.0), facecolor=color, linewidth=linewidth, - hatch=hatch, zorder=15+zorder_add, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p1 = Polygon( + [ + (start_bp, y_extent + y_offset), + (start_bp, -y_extent + y_offset), + (end_bp - dir_fac * arrowhead_length * scale, -y_extent + y_offset), + ( + end_bp - dir_fac * arrowhead_length * scale, + -y_extent - arrowhead_height + y_offset, + ), + (end_bp, 0 + y_offset), + ( + end_bp - dir_fac * arrowhead_length * scale, + y_extent + arrowhead_height + y_offset, + ), + (end_bp - dir_fac * arrowhead_length * scale, y_extent + y_offset), + ], + edgecolor=(0.0, 0.0, 0.0), + facecolor=color, + linewidth=linewidth, + hatch=hatch, + zorder=15 + zorder_add, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p1) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp -def trace_terminator (ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts): - """ Built-in trace-based terminator renderer. - """ +def trace_terminator( + ax, type, num, start_bp, end_bp, prev_end, scale, linewidth, opts +): + """Built-in trace-based terminator renderer.""" # Default options zorder_add = 0.0 - color = (1.0,0.0,0.0) + color = (1.0, 0.0, 0.0) y_offset = 0.0 y_extent = 3.5 x_extent = 10.0 highlight_y_extent = 0.8 # Reset defaults if provided if opts != None: - if 'zorder_add' in list(opts.keys()): - zorder_add = opts['zorder_add'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'highlight_y_extent' in list(opts.keys()): - highlight_y_extent = opts['highlight_y_extent'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] + if "zorder_add" in list(opts.keys()): + zorder_add = opts["zorder_add"] + if "color" in list(opts.keys()): + color = opts["color"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "highlight_y_extent" in list(opts.keys()): + highlight_y_extent = opts["highlight_y_extent"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] # Check direction add start padding dir_fac = 1.0 if start_bp > end_bp: dir_fac = -1.0 # Draw the terminator symbol - l1 = Line2D([start_bp,start_bp],[0+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, color=color, zorder=8+zorder_add) - l2 = Line2D([start_bp-(x_extent*scale),start_bp+(x_extent*scale)],[dir_fac*y_extent+y_offset,dir_fac*y_extent+y_offset], linewidth=linewidth, color=color, zorder=14+zorder_add) + l1 = Line2D( + [start_bp, start_bp], + [0 + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=8 + zorder_add, + ) + l2 = Line2D( + [start_bp - (x_extent * scale), start_bp + (x_extent * scale)], + [dir_fac * y_extent + y_offset, dir_fac * y_extent + y_offset], + linewidth=linewidth, + color=color, + zorder=14 + zorder_add, + ) ax.add_line(l1) ax.add_line(l2) # Shade the terminator area (normally smaller than symbol extent) - p2 = Polygon([(start_bp, -highlight_y_extent+y_offset), - (start_bp, highlight_y_extent+y_offset), - (end_bp, highlight_y_extent+y_offset), - (end_bp, -highlight_y_extent+y_offset)], facecolor=color, edgecolor=color, linewidth=linewidth, zorder=13, - path_effects=[Stroke(joinstyle="miter")]) # This is a work around for matplotlib < 1.4.0) + p2 = Polygon( + [ + (start_bp, -highlight_y_extent + y_offset), + (start_bp, highlight_y_extent + y_offset), + (end_bp, highlight_y_extent + y_offset), + (end_bp, -highlight_y_extent + y_offset), + ], + facecolor=color, + edgecolor=color, + linewidth=linewidth, + zorder=13, + path_effects=[Stroke(joinstyle="miter")], + ) # This is a work around for matplotlib < 1.4.0) ax.add_patch(p2) - if opts != None and 'label' in list(opts.keys()): + if opts != None and "label" in list(opts.keys()): if start_bp > end_bp: - write_label(ax, opts['label'], end_bp+((start_bp-end_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + end_bp + ((start_bp - end_bp) / 2.0), + opts=opts, + ) else: - write_label(ax, opts['label'], start_bp+((end_bp-start_bp)/2.0), opts=opts) + write_label( + ax, + opts["label"], + start_bp + ((end_bp - start_bp) / 2.0), + opts=opts, + ) if start_bp > end_bp: return end_bp, start_bp else: return start_bp, end_bp + ############################################################################### # The DNA renderer ############################################################################### class DNARenderer: - """ Class defining the DNA rendering funtionality. - """ + """Class defining the DNA rendering funtionality.""" # Standard part types - STD_PART_TYPES = ['Promoter', - 'CDS', - 'Terminator', - 'RBS', - 'Scar', - 'Spacer', - 'EmptySpace', - 'Ribozyme', - 'Ribonuclease', - 'Protease', - 'DNACleavageSite', - 'RNACleavageSite', - 'ProteinCleavageSite', - 'DNALocation', - 'RNALocation', - 'ProteinLocation', - 'DNAStability', - 'RNAStability', - 'ProteinStability', - 'StemTop', - 'Operator', - 'Origin', - 'Insulator', - '5Overhang', - '3Overhang', - 'RestrictionSite', - 'BluntRestrictionSite', - 'PrimerBindingSite', - '5StickyRestrictionSite', - '3StickyRestrictionSite', - 'UserDefined', - 'Signature'] + STD_PART_TYPES = [ + "Promoter", + "CDS", + "Terminator", + "RBS", + "Scar", + "Spacer", + "EmptySpace", + "Ribozyme", + "Ribonuclease", + "Protease", + "DNACleavageSite", + "RNACleavageSite", + "ProteinCleavageSite", + "DNALocation", + "RNALocation", + "ProteinLocation", + "DNAStability", + "RNAStability", + "ProteinStability", + "StemTop", + "Operator", + "Origin", + "Insulator", + "5Overhang", + "3Overhang", + "RestrictionSite", + "BluntRestrictionSite", + "PrimerBindingSite", + "5StickyRestrictionSite", + "3StickyRestrictionSite", + "UserDefined", + "Signature", + ] # Standard regulatory types - STD_REG_TYPES = ['Repression', - 'Activation', - 'Connection'] - - def __init__(self, scale=1.0, linewidth=1.0, linecolor=(0,0,0), - backbone_pad_left=0.0, backbone_pad_right=0.0): - """ Constructor to generate an empty DNARenderer. + STD_REG_TYPES = ["Repression", "Activation", "Connection"] + + def __init__( + self, + scale=1.0, + linewidth=1.0, + linecolor=(0, 0, 0), + backbone_pad_left=0.0, + backbone_pad_right=0.0, + ): + """Constructor to generate an empty DNARenderer. Parameters ---------- @@ -2452,63 +3578,71 @@ def __init__(self, scale=1.0, linewidth=1.0, linecolor=(0,0,0), self.backbone_pad_right = backbone_pad_right self.reg_height = 15 - def SBOL_part_renderers (self): - """ Return dictionary of all standard built-in SBOL part renderers. - """ + def SBOL_part_renderers(self): + """Return dictionary of all standard built-in SBOL part renderers.""" return { - 'Promoter' :sbol_promoter, - 'CDS' :sbol_cds, - 'Terminator' :sbol_terminator, - 'RBS' :sbol_rbs, - 'Scar' :sbol_scar, - 'Spacer' :sbol_spacer, - 'EmptySpace' :sbol_empty_space, - 'Ribozyme' :sbol_ribozyme, - 'Ribonuclease' :sbol_stem_top, - 'Protease' :sbol_stem_top, - 'DNACleavageSite' :sbol_stem_top, - 'RNACleavageSite' :sbol_stem_top, - 'ProteinCleavageSite':sbol_stem_top, - 'DNALocation' :sbol_stem_top, - 'RNALocation' :sbol_stem_top, - 'ProteinLocation' :sbol_stem_top, - 'DNAStability' :sbol_stem_top, - 'RNAStability' :sbol_stem_top, - 'ProteinStability' :sbol_stem_top, - 'StemTop' :sbol_stem_top, - 'Operator' :sbol_operator, - 'Origin' :sbol_origin, - 'Insulator' :sbol_insulator, - '5Overhang' :sbol_5_overhang, - '3Overhang' :sbol_3_overhang, - 'RestrictionSite' :sbol_restriction_site, - 'BluntRestrictionSite' :sbol_blunt_restriction_site, - 'PrimerBindingSite' :sbol_primer_binding_site, - '5StickyRestrictionSite' :sbol_5_sticky_restriction_site, - '3StickyRestrictionSite' :sbol_3_sticky_restriction_site, - 'UserDefined' :sbol_user_defined, - 'Signature' :sbol_signature} - - def trace_part_renderers (self): - """ Return dictionary of all standard built-in trace part renderers. - """ + "Promoter": sbol_promoter, + "CDS": sbol_cds, + "Terminator": sbol_terminator, + "RBS": sbol_rbs, + "Scar": sbol_scar, + "Spacer": sbol_spacer, + "EmptySpace": sbol_empty_space, + "Ribozyme": sbol_ribozyme, + "Ribonuclease": sbol_stem_top, + "Protease": sbol_stem_top, + "DNACleavageSite": sbol_stem_top, + "RNACleavageSite": sbol_stem_top, + "ProteinCleavageSite": sbol_stem_top, + "DNALocation": sbol_stem_top, + "RNALocation": sbol_stem_top, + "ProteinLocation": sbol_stem_top, + "DNAStability": sbol_stem_top, + "RNAStability": sbol_stem_top, + "ProteinStability": sbol_stem_top, + "StemTop": sbol_stem_top, + "Operator": sbol_operator, + "Origin": sbol_origin, + "Insulator": sbol_insulator, + "5Overhang": sbol_5_overhang, + "3Overhang": sbol_3_overhang, + "RestrictionSite": sbol_restriction_site, + "BluntRestrictionSite": sbol_blunt_restriction_site, + "PrimerBindingSite": sbol_primer_binding_site, + "5StickyRestrictionSite": sbol_5_sticky_restriction_site, + "3StickyRestrictionSite": sbol_3_sticky_restriction_site, + "UserDefined": sbol_user_defined, + "Signature": sbol_signature, + } + + def trace_part_renderers(self): + """Return dictionary of all standard built-in trace part renderers.""" return { - 'Promoter' :trace_promoter, - 'CDS' :trace_cds, - 'Terminator' :trace_terminator, - 'RBS' :trace_rbs, - 'UserDefined' :trace_user_defined} - - def std_reg_renderers (self): - """ Return dictionary of all standard built-in regulation renderers. - """ + "Promoter": trace_promoter, + "CDS": trace_cds, + "Terminator": trace_terminator, + "RBS": trace_rbs, + "UserDefined": trace_user_defined, + } + + def std_reg_renderers(self): + """Return dictionary of all standard built-in regulation renderers.""" return { - 'Repression' :repress, - 'Activation' :induce, - 'Connection' :connect} - - def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, plot_backbone=True): - """ Render the parts on the DNA and regulation. + "Repression": repress, + "Activation": induce, + "Connection": connect, + } + + def renderDNA( + self, + ax, + parts, + part_renderers, + regs=None, + reg_renderers=None, + plot_backbone=True, + ): + """Render the parts on the DNA and regulation. Parameters ---------- @@ -2519,7 +3653,7 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p The design to draw. This is a list of dicts, where each dict relates to a part and must contain the following keys: - name (string) - - type (string) + - type (string) - fwd (bool) - start (float, optional) - end (float, optional) @@ -2533,12 +3667,12 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p Regulation present in the design. This is a list of dicts, where each dict relates to a single regulation arc and must contain the following keys: - type (string) - - from_part (part object dict) + - from_part (part object dict) - to_part (part object dict) These will then be drawn in accordance with the renders selected. reg_renderers : dict(functions) (default=None) - Dict of functions where the key in the regulation type and the dictionary + Dict of functions where the key in the regulation type and the dictionary returns the function to be used to draw that regulation type. Returns @@ -2550,12 +3684,12 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p The x-point in the axis space that drawing ends. """ # Update the matplotlib rendering default for drawing the parts (we want mitered edges) - matplotlib.rcParams['lines.dash_joinstyle'] = 'miter' - matplotlib.rcParams['lines.dash_capstyle'] = 'butt' - matplotlib.rcParams['lines.solid_joinstyle'] = 'miter' - matplotlib.rcParams['lines.solid_capstyle'] = 'projecting' + matplotlib.rcParams["lines.dash_joinstyle"] = "miter" + matplotlib.rcParams["lines.dash_capstyle"] = "butt" + matplotlib.rcParams["lines.solid_joinstyle"] = "miter" + matplotlib.rcParams["lines.solid_capstyle"] = "projecting" # Make text editable in Adobe Illustrator - matplotlib.rcParams['pdf.fonttype'] = 42 + matplotlib.rcParams["pdf.fonttype"] = 42 # Plot the parts to the axis part_num = 0 prev_end = 0 @@ -2566,65 +3700,78 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p keys = list(part.keys()) # Check the part has minimal details required - if 'type' in keys: - if 'fwd' not in keys: - part['fwd'] = True - elif part['fwd'] == False and 'start' in keys and 'end' in keys: - start = part['start'] - end = part['end'] - part['end'] = start - part['start'] = end - if 'start' not in keys: - if part['fwd'] == True: - part['start'] = part_num + if "type" in keys: + if "fwd" not in keys: + part["fwd"] = True + elif part["fwd"] == False and "start" in keys and "end" in keys: + start = part["start"] + end = part["end"] + part["end"] = start + part["start"] = end + if "start" not in keys: + if part["fwd"] == True: + part["start"] = part_num else: - part['start'] = part_num+1 - if 'end' not in keys: - if part['fwd'] == True: - part['end'] = part_num+1 + part["start"] = part_num + 1 + if "end" not in keys: + if part["fwd"] == True: + part["end"] = part_num + 1 else: - part['end'] = part_num + part["end"] = part_num # Extract custom part options (if available) part_opts = None - if 'opts' in list(part.keys()): - part_opts = part['opts'] + if "opts" in list(part.keys()): + part_opts = part["opts"] # Use the correct renderer - if 'renderer' in list(part.keys()): + if "renderer" in list(part.keys()): # Use custom renderer - prev_start, prev_end = part['renderer'](ax, part['type'], part_num, - part['start'], part['end'], prev_end, - self.scale, self.linewidth, - opts=part_opts) - - #update start,end for regulation - #part['start'] = prev_start - #part['end'] = prev_end + prev_start, prev_end = part["renderer"]( + ax, + part["type"], + part_num, + part["start"], + part["end"], + prev_end, + self.scale, + self.linewidth, + opts=part_opts, + ) + + # update start,end for regulation + # part['start'] = prev_start + # part['end'] = prev_end if first_part == True: first_start = prev_start first_part = False else: # Use standard renderer, if one exists - if part['type'] in list(part_renderers.keys()): - prev_start, prev_end = part_renderers[part['type']](ax, - part['type'], part_num, - part['start'], part['end'], - prev_end, self.scale, - self.linewidth, opts=part_opts) - - #update start,end for regulation [TEG] - if part['fwd'] == True: - part['start'] = prev_start - part['end'] = prev_end + if part["type"] in list(part_renderers.keys()): + prev_start, prev_end = part_renderers[part["type"]]( + ax, + part["type"], + part_num, + part["start"], + part["end"], + prev_end, + self.scale, + self.linewidth, + opts=part_opts, + ) + + # update start,end for regulation [TEG] + if part["fwd"] == True: + part["start"] = prev_start + part["end"] = prev_end else: - part['start'] = prev_end - part['end'] = prev_start - + part["start"] = prev_end + part["end"] = prev_start + if first_part == True: first_start = prev_start first_part = False part_num += 1 - + # first pass to get all of the arcranges if regs != None: @@ -2632,29 +3779,33 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p keys = list(reg.keys()) # Check the part has minimal details required - if 'type' in keys and 'from_part' in keys and 'to_part' in keys: + if "type" in keys and "from_part" in keys and "to_part" in keys: # Extract custom part options (if available) reg_opts = None - if 'opts' in list(reg.keys()): - reg_opts = reg['opts'] - - if reg['type'] in list(reg_renderers.keys()): - + if "opts" in list(reg.keys()): + reg_opts = reg["opts"] + + if reg["type"] in list(reg_renderers.keys()): + ############################################################################## - arcstart = (reg['from_part']['start'] + reg['from_part']['end']) / 2 - arcend = (reg['to_part']['start'] + reg['to_part']['end']) / 2 - arcrange = [arcstart,arcend] - reg['arclength'] = math.fabs(arcstart-arcend) - reg['arc_height_index'] = 1 + arcstart = ( + reg["from_part"]["start"] + reg["from_part"]["end"] + ) / 2 + arcend = ( + reg["to_part"]["start"] + reg["to_part"]["end"] + ) / 2 + arcrange = [arcstart, arcend] + reg["arclength"] = math.fabs(arcstart - arcend) + reg["arc_height_index"] = 1 ############################################################################## - #sort regs by arc ranges from shortest to longest - regs.sort(key=lambda x: x['arclength'], reverse=False) + # sort regs by arc ranges from shortest to longest + regs.sort(key=lambda x: x["arclength"], reverse=False) reg_num = 0 - pos_arc_ranges = [] # arc above DNA backbone if to_part is fwd - neg_arc_ranges = [] # arc below DNA backbone if to_part is reverse + pos_arc_ranges = [] # arc above DNA backbone if to_part is fwd + neg_arc_ranges = [] # arc below DNA backbone if to_part is reverse current_max = 1 # second pass to render all the arcs @@ -2662,120 +3813,144 @@ def renderDNA (self, ax, parts, part_renderers, regs=None, reg_renderers=None, p keys = list(reg.keys()) # Check the part has minimal details required - if 'type' in keys and 'from_part' in keys and 'to_part' in keys: + if "type" in keys and "from_part" in keys and "to_part" in keys: # Extract custom part options (if available) reg_opts = None - if 'opts' in list(reg.keys()): - reg_opts = reg['opts'] - - if reg['type'] in list(reg_renderers.keys()): - + if "opts" in list(reg.keys()): + reg_opts = reg["opts"] + + if reg["type"] in list(reg_renderers.keys()): + ############################################################################## # arc height algorithm: greedy from left-to-right on DNA design - - arcstart = (reg['from_part']['start'] + reg['from_part']['end']) / 2 - arcend = (reg['to_part']['start'] + reg['to_part']['end']) / 2 - - arcmin = min(arcstart,arcend) - arcmax = max(arcstart,arcend) - arcrange = [arcmin,arcmax,reg['arc_height_index']] + + arcstart = ( + reg["from_part"]["start"] + reg["from_part"]["end"] + ) / 2 + arcend = ( + reg["to_part"]["start"] + reg["to_part"]["end"] + ) / 2 + + arcmin = min(arcstart, arcend) + arcmax = max(arcstart, arcend) + arcrange = [arcmin, arcmax, reg["arc_height_index"]] arc_height_index = 1 - + # arc above if to_part is fwd - if(reg['to_part']['fwd'] == True): + if reg["to_part"]["fwd"] == True: # find max arc height index of ONLY the prior arcs that clash with the current arc current_max = 1 for r in pos_arc_ranges: - if (arcrange[0] > r[0] and arcrange[0] < r[1]): - if(r[2] > current_max): + if arcrange[0] > r[0] and arcrange[0] < r[1]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[0] > r[1] and arcrange[0] < r[0]): - if(r[2] > current_max): + elif arcrange[0] > r[1] and arcrange[0] < r[0]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[1] > r[0] and arcrange[0] < r[1]): - if(r[2] > current_max): + elif arcrange[1] > r[0] and arcrange[0] < r[1]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[1] > r[1] and arcrange[0] < r[0]): - if(r[2] > current_max): + elif arcrange[1] > r[1] and arcrange[0] < r[0]: + if r[2] > current_max: current_max = r[2] - + # if arcs cross over, increment the arc height index for r in pos_arc_ranges: - if (arcrange[0] > r[0] and arcrange[0] < r[1]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[0] > r[1] and arcrange[0] < r[0]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[1] > r[0] and arcrange[0] < r[1]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[1] > r[1] and arcrange[0] < r[0]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] + if arcrange[0] > r[0] and arcrange[0] < r[1]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[0] > r[1] and arcrange[0] < r[0]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[1] > r[0] and arcrange[0] < r[1]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[1] > r[1] and arcrange[0] < r[0]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] pos_arc_ranges.append(arcrange) - + # arc below if to_part is reverse else: # find max arc height index current_max = 1 for r in neg_arc_ranges: - if (arcrange[0] > r[0] and arcrange[0] < r[1]): - if(r[2] > current_max): + if arcrange[0] > r[0] and arcrange[0] < r[1]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[0] > r[1] and arcrange[0] < r[0]): - if(r[2] > current_max): + elif arcrange[0] > r[1] and arcrange[0] < r[0]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[1] > r[0] and arcrange[0] < r[1]): - if(r[2] > current_max): + elif arcrange[1] > r[0] and arcrange[0] < r[1]: + if r[2] > current_max: current_max = r[2] - elif(arcrange[1] > r[1] and arcrange[0] < r[0]): - if(r[2] > current_max): + elif arcrange[1] > r[1] and arcrange[0] < r[0]: + if r[2] > current_max: current_max = r[2] - + # if arcs cross over, increment the arc height index for r in neg_arc_ranges: - if (arcrange[0] > r[0] and arcrange[0] < r[1]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[0] > r[1] and arcrange[0] < r[0]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[1] > r[0] and arcrange[0] < r[1]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] - elif(arcrange[1] > r[1] and arcrange[0] < r[0]): - reg['arc_height_index'] = current_max + 1 - arcrange[2] = reg['arc_height_index'] + if arcrange[0] > r[0] and arcrange[0] < r[1]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[0] > r[1] and arcrange[0] < r[0]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[1] > r[0] and arcrange[0] < r[1]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] + elif arcrange[1] > r[1] and arcrange[0] < r[0]: + reg["arc_height_index"] = current_max + 1 + arcrange[2] = reg["arc_height_index"] neg_arc_ranges.append(arcrange) ############################################################################## - reg_renderers[reg['type']](ax, reg['type'], - reg_num, reg['from_part'], - reg['to_part'], self.scale, - self.linewidth, reg['arc_height_index'], opts=reg_opts) + reg_renderers[reg["type"]]( + ax, + reg["type"], + reg_num, + reg["from_part"], + reg["to_part"], + self.scale, + self.linewidth, + reg["arc_height_index"], + opts=reg_opts, + ) reg_num += 1 # Plot the backbone (z=1) if plot_backbone == True: - l1 = Line2D([first_start-self.backbone_pad_left,prev_end+self.backbone_pad_right],[0,0], - linewidth=self.linewidth, color=self.linecolor, zorder=10) + l1 = Line2D( + [ + first_start - self.backbone_pad_left, + prev_end + self.backbone_pad_right, + ], + [0, 0], + linewidth=self.linewidth, + color=self.linecolor, + zorder=10, + ) ax.add_line(l1) return first_start, prev_end - def annotate (self, ax, part_renderers, part, annotate_zorder=1000): - """ Annotate a plot at a user specified location and offset. - """ + def annotate(self, ax, part_renderers, part, annotate_zorder=1000): + """Annotate a plot at a user specified location and offset.""" # Annotations show be placed on top of existing design - if 'opts' not in list(part.keys()): - part['opts'] = {'zorder_add': annotate_zorder} + if "opts" not in list(part.keys()): + part["opts"] = {"zorder_add": annotate_zorder} else: - part['opts']['zorder_add'] = annotate_zorder + part["opts"]["zorder_add"] = annotate_zorder # Draw the part - part_renderers[part['type']](ax, - part['type'], 1, - part['start'], part['end'], - part['start'], self.scale, - self.linewidth, opts=part['opts']) + part_renderers[part["type"]]( + ax, + part["type"], + 1, + part["start"], + part["end"], + part["start"], + self.scale, + self.linewidth, + opts=part["opts"], + ) ############################################################################### @@ -2783,13 +3958,15 @@ def annotate (self, ax, part_renderers, part, annotate_zorder=1000): ############################################################################### -def plot_sbol_designs (axes, dna_designs, regulations=None, plot_params={}, plot_names=None): - """ Plot SBOL designs to axes. +def plot_sbol_designs( + axes, dna_designs, regulations=None, plot_params={}, plot_names=None +): + """Plot SBOL designs to axes. Parameters ---------- axes : list(matplotlib.axis) - List of axis objects to plot the designs to. + List of axis objects to plot the designs to. dna_designs : list(dict(design_information)) List of designs to plot. @@ -2812,25 +3989,28 @@ def plot_sbol_designs (axes, dna_designs, regulations=None, plot_params={}, plot The y-axis range for each axis. """ # Standard plotting parameters - if 'axis_y' not in list(plot_params.keys()): - plot_params['axis_y'] = 35 + if "axis_y" not in list(plot_params.keys()): + plot_params["axis_y"] = 35 left_pad = 0.0 right_pad = 0.0 scale = 1.0 linewidth = 1.0 fig_y = 5.0 fig_x = 5.0 - if 'backbone_pad_left' in list(plot_params.keys()): - left_pad = plot_params['backbone_pad_left'] - if 'backbone_pad_right' in list(plot_params.keys()): - right_pad = plot_params['backbone_pad_right'] - if 'scale' in list(plot_params.keys()): - scale = plot_params['scale'] - if 'linewidth' in list(plot_params.keys()): - linewidth = plot_params['linewidth'] - dr = DNARenderer(scale=scale, linewidth=linewidth, - backbone_pad_left=left_pad, - backbone_pad_right=right_pad) + if "backbone_pad_left" in list(plot_params.keys()): + left_pad = plot_params["backbone_pad_left"] + if "backbone_pad_right" in list(plot_params.keys()): + right_pad = plot_params["backbone_pad_right"] + if "scale" in list(plot_params.keys()): + scale = plot_params["scale"] + if "linewidth" in list(plot_params.keys()): + linewidth = plot_params["linewidth"] + dr = DNARenderer( + scale=scale, + linewidth=linewidth, + backbone_pad_left=left_pad, + backbone_pad_right=right_pad, + ) # We default to the standard regulation renderers reg_renderers = dr.std_reg_renderers() @@ -2844,17 +4024,19 @@ def plot_sbol_designs (axes, dna_designs, regulations=None, plot_params={}, plot # Create axis for the design and plot regs = None - if(regulations != None): - regs = regulations[i] - design = dna_designs[i] + if regulations != None: + regs = regulations[i] + design = dna_designs[i] ax = axes[i] if plot_names != None: ax.set_title(plot_names[i], fontsize=8) - start, end = dr.renderDNA(ax, design, part_renderers, regs, reg_renderers) + start, end = dr.renderDNA( + ax, design, part_renderers, regs, reg_renderers + ) - dna_len = end-start + dna_len = end - start if max_dna_len < dna_len: max_dna_len = dna_len @@ -2863,18 +4045,31 @@ def plot_sbol_designs (axes, dna_designs, regulations=None, plot_params={}, plot ax.set_xticks([]) ax.set_yticks([]) # Set bounds - ax.set_xlim([(-0.01*max_dna_len)-left_pad, - max_dna_len+(0.01*max_dna_len)+right_pad]) - ax.set_ylim([-plot_params['axis_y'],plot_params['axis_y']]) - ax.set_aspect('equal') + ax.set_xlim( + [ + (-0.01 * max_dna_len) - left_pad, + max_dna_len + (0.01 * max_dna_len) + right_pad, + ] + ) + ax.set_ylim([-plot_params["axis_y"], plot_params["axis_y"]]) + ax.set_aspect("equal") ax.set_axis_off() # xlims, ylims are returned - return max_dna_len, [(-0.01*max_dna_len)-left_pad, max_dna_len+(0.01*max_dna_len)+right_pad], [-plot_params['axis_y'],plot_params['axis_y']] + return ( + max_dna_len, + [ + (-0.01 * max_dna_len) - left_pad, + max_dna_len + (0.01 * max_dna_len) + right_pad, + ], + [-plot_params["axis_y"], plot_params["axis_y"]], + ) -def save_sbol_designs (filename, dna_designs, regulations=None, plot_params={}, plot_names=None): - """ Plot SBOL designs to axes. +def save_sbol_designs( + filename, dna_designs, regulations=None, plot_params={}, plot_names=None +): + """Plot SBOL designs to axes. Parameters ---------- @@ -2896,30 +4091,36 @@ def save_sbol_designs (filename, dna_designs, regulations=None, plot_params={}, """ # Create the figure - fig = plt.figure(figsize=(10,10)) - fig.patch.set_facecolor('white') + fig = plt.figure(figsize=(10, 10)) + fig.patch.set_facecolor("white") # Create all the axes required axes = [] for i in range(len(dna_designs)): - ax = fig.add_subplot(len(dna_designs),1,i+1, axisbg='white') + ax = fig.add_subplot(len(dna_designs), 1, i + 1, axisbg="white") axes.append(ax) # Plot design to the axes - max_dna_len, lims, params = plot_sbol_designs (axes, dna_designs, regulations=regulations, plot_params=plot_params, plot_names=plot_names) + max_dna_len, lims, params = plot_sbol_designs( + axes, + dna_designs, + regulations=regulations, + plot_params=plot_params, + plot_names=plot_names, + ) # Update the size of the figure to fit the constructs drawn - fig_x_dim = max_dna_len/70.0 + fig_x_dim = max_dna_len / 70.0 if fig_x_dim < 1.0: fig_x_dim = 1.0 - fig_y_dim = 1.2*len(axes) - plt.gcf().set_size_inches( (fig_x_dim, fig_y_dim) ) + fig_y_dim = 1.2 * len(axes) + plt.gcf().set_size_inches((fig_x_dim, fig_y_dim)) # Save the figure plt.tight_layout() fig.savefig(filename, transparent=True, dpi=300) # Clear the plotting cache - plt.close('all') + plt.close("all") ############################################################################### @@ -2927,14 +4128,23 @@ def save_sbol_designs (filename, dna_designs, regulations=None, plot_params={}, ############################################################################### -def convert_attrib (attrib): - if attrib[0] == '(' and attrib[-1] == ')' and len(attrib.split(',')) == 3: - col_parts = attrib[1:-1].split(',') - new_col = (float(col_parts[0]), float(col_parts[1]), float(col_parts[2])) +def convert_attrib(attrib): + if attrib[0] == "(" and attrib[-1] == ")" and len(attrib.split(",")) == 3: + col_parts = attrib[1:-1].split(",") + new_col = ( + float(col_parts[0]), + float(col_parts[1]), + float(col_parts[2]), + ) return new_col - if attrib[0] == '(' and attrib[-1] == ')' and len(attrib.split(',')) == 4: - col_parts = attrib[1:-1].split(',') - new_col = (float(col_parts[0]), float(col_parts[1]), float(col_parts[2]), float(col_parts[3])) + if attrib[0] == "(" and attrib[-1] == ")" and len(attrib.split(",")) == 4: + col_parts = attrib[1:-1].split(",") + new_col = ( + float(col_parts[0]), + float(col_parts[1]), + float(col_parts[2]), + float(col_parts[3]), + ) return new_col try: # See if a number @@ -2944,16 +4154,20 @@ def convert_attrib (attrib): return attrib -dpl_default_type_map = {'gene': 'CDS', - 'promoter': 'Promoter', - 'terminator': 'Terminator', - 'rbs': 'RBS'} +dpl_default_type_map = { + "gene": "CDS", + "promoter": "Promoter", + "terminator": "Terminator", + "rbs": "RBS", +} -def load_design_from_gff (filename, chrom, type_map=dpl_default_type_map, region=None): +def load_design_from_gff( + filename, chrom, type_map=dpl_default_type_map, region=None +): # Load the GFF data gff = [] - data_reader = csv.reader(open(filename, 'rU'), delimiter='\t') + data_reader = csv.reader(open(filename, "rU"), delimiter="\t") for row in data_reader: if len(row) == 9: cur_chrom = row[0] @@ -2962,46 +4176,63 @@ def load_design_from_gff (filename, chrom, type_map=dpl_default_type_map, region end_bp = int(row[4]) part_dir = row[6] part_attribs = {} - split_attribs = row[8].split(';') + split_attribs = row[8].split(";") part_name = None for attrib in split_attribs: - key_value = attrib.split('=') + key_value = attrib.split("=") if len(key_value) == 2: - if key_value[0] == 'Name': + if key_value[0] == "Name": part_name = key_value[1] else: - part_attribs[key_value[0]] = convert_attrib(key_value[1]) - if part_name != None and cur_chrom == chrom and part_type in list(type_map.keys()): + part_attribs[key_value[0]] = convert_attrib( + key_value[1] + ) + if ( + part_name != None + and cur_chrom == chrom + and part_type in list(type_map.keys()) + ): # Check feature start falls in region - if region != None and (start_bp > region[0] and start_bp < region[1]): - gff.append([part_name, type_map[part_type], part_dir, start_bp, end_bp, part_attribs]) + if region != None and ( + start_bp > region[0] and start_bp < region[1] + ): + gff.append( + [ + part_name, + type_map[part_type], + part_dir, + start_bp, + end_bp, + part_attribs, + ] + ) # Convert to DNAplotlib design (sort on start position first) design = [] for gff_el in sorted(gff, key=itemgetter(3)): new_part = {} - new_part['name'] = gff_el[0] - new_part['type'] = gff_el[1] - if gff_el[2] == '+': - new_part['fwd'] = True + new_part["name"] = gff_el[0] + new_part["type"] = gff_el[1] + if gff_el[2] == "+": + new_part["fwd"] = True else: - new_part['fwd'] = False - new_part['start'] = gff_el[3] - new_part['end'] = gff_el[4] - new_part['opts'] = gff_el[5] + new_part["fwd"] = False + new_part["start"] = gff_el[3] + new_part["end"] = gff_el[4] + new_part["opts"] = gff_el[5] design.append(new_part) # Return the sorted design return design -def load_profile_from_bed (filename, chrom, region): - region_len = region[1]-region[0] - profile = [0]*region_len - data_reader = csv.reader(open(filename, 'rU'), delimiter='\t') +def load_profile_from_bed(filename, chrom, region): + region_len = region[1] - region[0] + profile = [0] * region_len + data_reader = csv.reader(open(filename, "rU"), delimiter="\t") for row in data_reader: if len(row) == 5: cur_chrom = row[0] cur_start_bp = int(row[1]) cur_end_bp = int(row[2]) if cur_start_bp == region[0] and cur_end_bp == region[1]: - profile[int(row[3])-1] = float(row[4]) + profile[int(row[3]) - 1] = float(row[4]) return profile diff --git a/dnaplotlib/dnaplotlib/sbol/__init__.py b/dnaplotlib/dnaplotlib/sbol/__init__.py index a0a8dba..c82b511 100755 --- a/dnaplotlib/dnaplotlib/sbol/__init__.py +++ b/dnaplotlib/dnaplotlib/sbol/__init__.py @@ -1,3 +1 @@ - - from .sbolplotlib import * diff --git a/dnaplotlib/dnaplotlib/sbol/sbolplotlib.py b/dnaplotlib/dnaplotlib/sbol/sbolplotlib.py index 60c97a7..6e6186d 100755 --- a/dnaplotlib/dnaplotlib/sbol/sbolplotlib.py +++ b/dnaplotlib/dnaplotlib/sbol/sbolplotlib.py @@ -18,7 +18,14 @@ import matplotlib import matplotlib.pyplot as plt -from matplotlib.patches import Polygon, Ellipse, Wedge, Circle, PathPatch, Rectangle +from matplotlib.patches import ( + Polygon, + Ellipse, + Wedge, + Circle, + PathPatch, + Rectangle, +) from matplotlib.path import Path from matplotlib.lines import Line2D from matplotlib.patheffects import Stroke @@ -28,44 +35,50 @@ import dnaplotlib as dpl import sbol -__author__ = 'Bryan Bartley \n\ - Thomas E. Gorochowski ' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Bryan Bartley \n\ + Thomas E. Gorochowski " +__license__ = "MIT" +__version__ = "1.0" -class SBOLRenderer(dpl.DNARenderer): +class SBOLRenderer(dpl.DNARenderer): def SO_terms(self): - """ Return dictionary of all standard built-in SBOL part renderers referenced by Sequence Ontology term - """ + """Return dictionary of all standard built-in SBOL part renderers referenced by Sequence Ontology term""" return { - 'SO_0000167': 'Promoter', - 'SO_0000316': 'CDS', - 'SO_0000141': 'Terminator', - 'SO_0000552': 'RBS', - 'SO_0001953': 'Scar', - # No SO Term : 'Spacer', - # No SO Term : 'EmptySpace', - 'SO_000037': 'Ribozyme', - 'SO_0001977': 'Ribonuclease', - 'SO_0001955': 'ProteinStability', - 'SO_0001956': 'Protease', - 'SO_0000057': 'Operator', - # SO term insulator does not have same semantics : 'Insulator', - 'SO_0000296': 'Origin', - 'SO_0001932': '5Overhang', - 'SO_0001933': '3Overhang', - 'SO_0001687': 'RestrictionSite', - 'SO_0000299': 'RecombinaseSite', - 'SO_0001691': 'BluntRestrictionSite', - 'SO_0005850': 'PrimerBindingSite', - 'SO_0001694': '5StickyRestrictionSite', - 'SO_0001690': '3StickyRestrictionSite', - 'SO_0000001': 'UserDefined', - 'SO_0001978': 'Signature', + "SO_0000167": "Promoter", + "SO_0000316": "CDS", + "SO_0000141": "Terminator", + "SO_0000552": "RBS", + "SO_0001953": "Scar", + # No SO Term : 'Spacer', + # No SO Term : 'EmptySpace', + "SO_000037": "Ribozyme", + "SO_0001977": "Ribonuclease", + "SO_0001955": "ProteinStability", + "SO_0001956": "Protease", + "SO_0000057": "Operator", + # SO term insulator does not have same semantics : 'Insulator', + "SO_0000296": "Origin", + "SO_0001932": "5Overhang", + "SO_0001933": "3Overhang", + "SO_0001687": "RestrictionSite", + "SO_0000299": "RecombinaseSite", + "SO_0001691": "BluntRestrictionSite", + "SO_0005850": "PrimerBindingSite", + "SO_0001694": "5StickyRestrictionSite", + "SO_0001690": "3StickyRestrictionSite", + "SO_0000001": "UserDefined", + "SO_0001978": "Signature", } - def renderSBOL(self, ax, target_component, part_renderers, opts=None, plot_backbone=True): + def renderSBOL( + self, + ax, + target_component, + part_renderers, + opts=None, + plot_backbone=True, + ): """ Render a design from an SBOL DNA Component @@ -90,35 +103,47 @@ def renderSBOL(self, ax, target_component, part_renderers, opts=None, plot_backb end : float The x-point in the axis space that drawing ends. """ - dpl_design = [] # The SBOL data will be converted to a list of dictionaries used by DNAPlotLib - sbol_design = [] # Contains a list of DNA components corresponding to the items in dpl_design + dpl_design = ( + [] + ) # The SBOL data will be converted to a list of dictionaries used by DNAPlotLib + sbol_design = ( + [] + ) # Contains a list of DNA components corresponding to the items in dpl_design try: current_ann = target_component.annotations[0] except: - print("Target DNAComponent does not have any SequenceAnnotations. Cannot render SBOL.") + print( + "Target DNAComponent does not have any SequenceAnnotations. Cannot render SBOL." + ) END_OF_DESIGN = False while not END_OF_DESIGN: try: subcomponent = current_ann.subcomponent except: - print("DNAComponent does not have subcomponents. Cannot render SBOL.") + print( + "DNAComponent does not have subcomponents. Cannot render SBOL." + ) # Translate from SBOL data model to DNAPlotLib dictionary specification for designs - SO_term = subcomponent.part_type.split('/')[-1] + SO_term = subcomponent.part_type.split("/")[-1] if SO_term in list(self.SO_terms().keys()): part = {} - part['type'] = self.SO_terms()[SO_term] - part['name'] = subcomponent.display_id - part['fwd'] = True + part["type"] = self.SO_terms()[SO_term] + part["name"] = subcomponent.display_id + part["fwd"] = True if opts: - part['opts'] = opts + part["opts"] = opts dpl_design.append(part) sbol_design.append(subcomponent) # TODO else if SO term of DNAComponent is not recognized, default to a USER_DEFINED sbol symbol if len(current_ann.precedes) == 0: END_OF_DESIGN = True else: - current_ann = current_ann.precedes[0] # Iterate to the next downstream annotation - - start, end = self.renderDNA(ax, dpl_design, part_renderers, plot_backbone=plot_backbone) + current_ann = current_ann.precedes[ + 0 + ] # Iterate to the next downstream annotation + + start, end = self.renderDNA( + ax, dpl_design, part_renderers, plot_backbone=plot_backbone + ) return start, end diff --git a/dnaplotlib/gallery/annotate_design/annotate_design 2.py b/dnaplotlib/gallery/annotate_design/annotate_design 2.py index 88696e2..a8aa8d2 100644 --- a/dnaplotlib/gallery/annotate_design/annotate_design 2.py +++ b/dnaplotlib/gallery/annotate_design/annotate_design 2.py @@ -7,52 +7,104 @@ import matplotlib.pyplot as plt from matplotlib import gridspec -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Create the DNAplotlib renderer dr = dpl.DNARenderer() part_renderers = dr.SBOL_part_renderers() # Create the construct programmably to plot -sp = {'type':'EmptySpace', 'name':'S1', 'fwd':True, 'opts':{'x_extent':1}} -prom = {'type':'Promoter', 'name':'prom', 'fwd':True} -ins = {'type':'Insulator', 'name':'ins', 'fwd':True} -ribo_f = {'type':'Ribozyme', 'name':'ribo', 'fwd':True} -rbs_f = {'type':'RBS', 'name':'rbs', 'fwd':True, 'opts':{'color':(0.0,0.0,0.0)}} -cds_f = {'type':'CDS', 'name':'cds', 'fwd':True, 'opts':{'color':(0.5,0.5,0.5), 'x_extent':80}} -term = {'type':'Terminator', 'name':'term', 'fwd':True} +sp = {"type": "EmptySpace", "name": "S1", "fwd": True, "opts": {"x_extent": 1}} +prom = {"type": "Promoter", "name": "prom", "fwd": True} +ins = {"type": "Insulator", "name": "ins", "fwd": True} +ribo_f = {"type": "Ribozyme", "name": "ribo", "fwd": True} +rbs_f = { + "type": "RBS", + "name": "rbs", + "fwd": True, + "opts": {"color": (0.0, 0.0, 0.0)}, +} +cds_f = { + "type": "CDS", + "name": "cds", + "fwd": True, + "opts": {"color": (0.5, 0.5, 0.5), "x_extent": 80}, +} +term = {"type": "Terminator", "name": "term", "fwd": True} # Create the baseline design design1 = [sp, prom, ins, ribo_f, rbs_f, cds_f, term, sp] # Create the figure -fig = plt.figure(figsize=(2.2,0.6)) +fig = plt.figure(figsize=(2.2, 0.6)) gs = gridspec.GridSpec(1, 1) ax_dna = plt.subplot(gs[0]) # Redender the DNA to axis start, end = dr.renderDNA(ax_dna, design1, part_renderers) ax_dna.set_xlim([start, end]) -ax_dna.set_ylim([-15,28]) -ax_dna.set_aspect('equal') +ax_dna.set_ylim([-15, 28]) +ax_dna.set_aspect("equal") ax_dna.set_xticks([]) ax_dna.set_yticks([]) -ax_dna.axis('off') +ax_dna.axis("off") # Annotate the design -primer_f_opts = {'color':(1.0,0.0,0.0), 'y_offset':10} -primer_f_opts2 = {'color':(1.0,0.0,0.0), 'y_offset':15} -primer_r_opts = {'color':(1.0,0.0,0.0), 'y_offset':10} -rbs2_f_opts = {'color':(1.0,0.0,0.0), 'x_extent':7.5} -rbs3_f_opts = {'color':(1.0,0.0,0.0), 'x_extent':5} -primer1_f = {'type':'PrimerBindingSite', 'start': cds_f['start'], 'end': cds_f['end'], 'name':'pri1f', 'fwd':True, 'opts':primer_f_opts} -primer2_f = {'type':'PrimerBindingSite', 'start': cds_f['start']+10, 'end': cds_f['end'], 'name':'pri2f', 'fwd':True, 'opts':primer_f_opts2} -primer3_f = {'type':'PrimerBindingSite', 'start': cds_f['start']+50, 'end': cds_f['end'], 'name':'pri3f', 'fwd':True, 'opts':primer_f_opts} -primer4_r = {'type':'PrimerBindingSite', 'start': cds_f['end']-25, 'end': cds_f['end']-35, 'name':'pri4r', 'fwd':False, 'opts':primer_r_opts} -rbs2_f = {'type':'RBS', 'start': cds_f['start']+40, 'end': cds_f['start']+41, 'name':'rbs2f', 'fwd':True, 'opts':rbs2_f_opts} -rbs3_f = {'type':'RBS', 'start': cds_f['start']+70, 'end': cds_f['start']+71, 'name':'rbs3f', 'fwd':True, 'opts':rbs3_f_opts} +primer_f_opts = {"color": (1.0, 0.0, 0.0), "y_offset": 10} +primer_f_opts2 = {"color": (1.0, 0.0, 0.0), "y_offset": 15} +primer_r_opts = {"color": (1.0, 0.0, 0.0), "y_offset": 10} +rbs2_f_opts = {"color": (1.0, 0.0, 0.0), "x_extent": 7.5} +rbs3_f_opts = {"color": (1.0, 0.0, 0.0), "x_extent": 5} +primer1_f = { + "type": "PrimerBindingSite", + "start": cds_f["start"], + "end": cds_f["end"], + "name": "pri1f", + "fwd": True, + "opts": primer_f_opts, +} +primer2_f = { + "type": "PrimerBindingSite", + "start": cds_f["start"] + 10, + "end": cds_f["end"], + "name": "pri2f", + "fwd": True, + "opts": primer_f_opts2, +} +primer3_f = { + "type": "PrimerBindingSite", + "start": cds_f["start"] + 50, + "end": cds_f["end"], + "name": "pri3f", + "fwd": True, + "opts": primer_f_opts, +} +primer4_r = { + "type": "PrimerBindingSite", + "start": cds_f["end"] - 25, + "end": cds_f["end"] - 35, + "name": "pri4r", + "fwd": False, + "opts": primer_r_opts, +} +rbs2_f = { + "type": "RBS", + "start": cds_f["start"] + 40, + "end": cds_f["start"] + 41, + "name": "rbs2f", + "fwd": True, + "opts": rbs2_f_opts, +} +rbs3_f = { + "type": "RBS", + "start": cds_f["start"] + 70, + "end": cds_f["start"] + 71, + "name": "rbs3f", + "fwd": True, + "opts": rbs3_f_opts, +} # Call the annotate function for the renderer dr.annotate(ax_dna, part_renderers, primer1_f) @@ -66,8 +118,8 @@ plt.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01) # Save the figure -fig.savefig('annotate_design.pdf', transparent=True) -fig.savefig('annotate_design.png', dpi=300) +fig.savefig("annotate_design.pdf", transparent=True) +fig.savefig("annotate_design.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/annotate_design/annotate_design.py b/dnaplotlib/gallery/annotate_design/annotate_design.py index 88696e2..a8aa8d2 100755 --- a/dnaplotlib/gallery/annotate_design/annotate_design.py +++ b/dnaplotlib/gallery/annotate_design/annotate_design.py @@ -7,52 +7,104 @@ import matplotlib.pyplot as plt from matplotlib import gridspec -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Create the DNAplotlib renderer dr = dpl.DNARenderer() part_renderers = dr.SBOL_part_renderers() # Create the construct programmably to plot -sp = {'type':'EmptySpace', 'name':'S1', 'fwd':True, 'opts':{'x_extent':1}} -prom = {'type':'Promoter', 'name':'prom', 'fwd':True} -ins = {'type':'Insulator', 'name':'ins', 'fwd':True} -ribo_f = {'type':'Ribozyme', 'name':'ribo', 'fwd':True} -rbs_f = {'type':'RBS', 'name':'rbs', 'fwd':True, 'opts':{'color':(0.0,0.0,0.0)}} -cds_f = {'type':'CDS', 'name':'cds', 'fwd':True, 'opts':{'color':(0.5,0.5,0.5), 'x_extent':80}} -term = {'type':'Terminator', 'name':'term', 'fwd':True} +sp = {"type": "EmptySpace", "name": "S1", "fwd": True, "opts": {"x_extent": 1}} +prom = {"type": "Promoter", "name": "prom", "fwd": True} +ins = {"type": "Insulator", "name": "ins", "fwd": True} +ribo_f = {"type": "Ribozyme", "name": "ribo", "fwd": True} +rbs_f = { + "type": "RBS", + "name": "rbs", + "fwd": True, + "opts": {"color": (0.0, 0.0, 0.0)}, +} +cds_f = { + "type": "CDS", + "name": "cds", + "fwd": True, + "opts": {"color": (0.5, 0.5, 0.5), "x_extent": 80}, +} +term = {"type": "Terminator", "name": "term", "fwd": True} # Create the baseline design design1 = [sp, prom, ins, ribo_f, rbs_f, cds_f, term, sp] # Create the figure -fig = plt.figure(figsize=(2.2,0.6)) +fig = plt.figure(figsize=(2.2, 0.6)) gs = gridspec.GridSpec(1, 1) ax_dna = plt.subplot(gs[0]) # Redender the DNA to axis start, end = dr.renderDNA(ax_dna, design1, part_renderers) ax_dna.set_xlim([start, end]) -ax_dna.set_ylim([-15,28]) -ax_dna.set_aspect('equal') +ax_dna.set_ylim([-15, 28]) +ax_dna.set_aspect("equal") ax_dna.set_xticks([]) ax_dna.set_yticks([]) -ax_dna.axis('off') +ax_dna.axis("off") # Annotate the design -primer_f_opts = {'color':(1.0,0.0,0.0), 'y_offset':10} -primer_f_opts2 = {'color':(1.0,0.0,0.0), 'y_offset':15} -primer_r_opts = {'color':(1.0,0.0,0.0), 'y_offset':10} -rbs2_f_opts = {'color':(1.0,0.0,0.0), 'x_extent':7.5} -rbs3_f_opts = {'color':(1.0,0.0,0.0), 'x_extent':5} -primer1_f = {'type':'PrimerBindingSite', 'start': cds_f['start'], 'end': cds_f['end'], 'name':'pri1f', 'fwd':True, 'opts':primer_f_opts} -primer2_f = {'type':'PrimerBindingSite', 'start': cds_f['start']+10, 'end': cds_f['end'], 'name':'pri2f', 'fwd':True, 'opts':primer_f_opts2} -primer3_f = {'type':'PrimerBindingSite', 'start': cds_f['start']+50, 'end': cds_f['end'], 'name':'pri3f', 'fwd':True, 'opts':primer_f_opts} -primer4_r = {'type':'PrimerBindingSite', 'start': cds_f['end']-25, 'end': cds_f['end']-35, 'name':'pri4r', 'fwd':False, 'opts':primer_r_opts} -rbs2_f = {'type':'RBS', 'start': cds_f['start']+40, 'end': cds_f['start']+41, 'name':'rbs2f', 'fwd':True, 'opts':rbs2_f_opts} -rbs3_f = {'type':'RBS', 'start': cds_f['start']+70, 'end': cds_f['start']+71, 'name':'rbs3f', 'fwd':True, 'opts':rbs3_f_opts} +primer_f_opts = {"color": (1.0, 0.0, 0.0), "y_offset": 10} +primer_f_opts2 = {"color": (1.0, 0.0, 0.0), "y_offset": 15} +primer_r_opts = {"color": (1.0, 0.0, 0.0), "y_offset": 10} +rbs2_f_opts = {"color": (1.0, 0.0, 0.0), "x_extent": 7.5} +rbs3_f_opts = {"color": (1.0, 0.0, 0.0), "x_extent": 5} +primer1_f = { + "type": "PrimerBindingSite", + "start": cds_f["start"], + "end": cds_f["end"], + "name": "pri1f", + "fwd": True, + "opts": primer_f_opts, +} +primer2_f = { + "type": "PrimerBindingSite", + "start": cds_f["start"] + 10, + "end": cds_f["end"], + "name": "pri2f", + "fwd": True, + "opts": primer_f_opts2, +} +primer3_f = { + "type": "PrimerBindingSite", + "start": cds_f["start"] + 50, + "end": cds_f["end"], + "name": "pri3f", + "fwd": True, + "opts": primer_f_opts, +} +primer4_r = { + "type": "PrimerBindingSite", + "start": cds_f["end"] - 25, + "end": cds_f["end"] - 35, + "name": "pri4r", + "fwd": False, + "opts": primer_r_opts, +} +rbs2_f = { + "type": "RBS", + "start": cds_f["start"] + 40, + "end": cds_f["start"] + 41, + "name": "rbs2f", + "fwd": True, + "opts": rbs2_f_opts, +} +rbs3_f = { + "type": "RBS", + "start": cds_f["start"] + 70, + "end": cds_f["start"] + 71, + "name": "rbs3f", + "fwd": True, + "opts": rbs3_f_opts, +} # Call the annotate function for the renderer dr.annotate(ax_dna, part_renderers, primer1_f) @@ -66,8 +118,8 @@ plt.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01) # Save the figure -fig.savefig('annotate_design.pdf', transparent=True) -fig.savefig('annotate_design.png', dpi=300) +fig.savefig("annotate_design.pdf", transparent=True) +fig.savefig("annotate_design.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/input_bed/input_bed 2.py b/dnaplotlib/gallery/input_bed/input_bed 2.py index c97d22c..88d3b7f 100644 --- a/dnaplotlib/gallery/input_bed/input_bed 2.py +++ b/dnaplotlib/gallery/input_bed/input_bed 2.py @@ -8,44 +8,64 @@ from matplotlib import gridspec import numpy as np -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Load the design from a GFF file cur_region = [1700, 15880] -design = dpl.load_design_from_gff('plasmid.gff', 'chrom1', region=cur_region) -profile_fwd = dpl.load_profile_from_bed('plasmid_fwd_profile.txt', 'chrom1', [0, 22953]) -profile_rev = dpl.load_profile_from_bed('plasmid_rev_profile.txt', 'chrom1', [0, 22953]) +design = dpl.load_design_from_gff("plasmid.gff", "chrom1", region=cur_region) +profile_fwd = dpl.load_profile_from_bed( + "plasmid_fwd_profile.txt", "chrom1", [0, 22953] +) +profile_rev = dpl.load_profile_from_bed( + "plasmid_rev_profile.txt", "chrom1", [0, 22953] +) # Create the DNAplotlib renderer dr = dpl.DNARenderer(scale=10.0) part_renderers = dr.trace_part_renderers() # Create the figure -fig = plt.figure(figsize=(3.5,2.0)) +fig = plt.figure(figsize=(3.5, 2.0)) gs = gridspec.GridSpec(2, 1, height_ratios=[1, 0.2]) ax_dna = plt.subplot(gs[1]) # Redender the DNA to axis start, end = dr.renderDNA(ax_dna, design, part_renderers) ax_dna.set_xlim(cur_region) -ax_dna.set_ylim([-5,8]) -ax_dna.axis('off') +ax_dna.set_ylim([-5, 8]) +ax_dna.axis("off") ax_profile = plt.subplot(gs[0]) -ax_profile.fill_between(list(range(cur_region[0],cur_region[1])), profile_fwd[cur_region[0]:cur_region[1]], np.zeros(cur_region[1]-cur_region[0]), color=(0.5,0.5,0.5), edgecolor=(0.5,0.5,0.5), linewidth=1, zorder=1.5) -ax_profile.fill_between(list(range(cur_region[0],cur_region[1])), np.array(profile_rev[cur_region[0]:cur_region[1]])*-1.0, np.zeros(cur_region[1]-cur_region[0]), color=(1,0,0), edgecolor=(1,0,0), linewidth=1, zorder=1.5) -ax_profile.plot(cur_region, [0,0], color=(0,0,0), zorder=10) +ax_profile.fill_between( + list(range(cur_region[0], cur_region[1])), + profile_fwd[cur_region[0] : cur_region[1]], + np.zeros(cur_region[1] - cur_region[0]), + color=(0.5, 0.5, 0.5), + edgecolor=(0.5, 0.5, 0.5), + linewidth=1, + zorder=1.5, +) +ax_profile.fill_between( + list(range(cur_region[0], cur_region[1])), + np.array(profile_rev[cur_region[0] : cur_region[1]]) * -1.0, + np.zeros(cur_region[1] - cur_region[0]), + color=(1, 0, 0), + edgecolor=(1, 0, 0), + linewidth=1, + zorder=1.5, +) +ax_profile.plot(cur_region, [0, 0], color=(0, 0, 0), zorder=10) ax_profile.set_xlim(cur_region) -ax_profile.axis('off') +ax_profile.axis("off") # Update subplot spacing plt.subplots_adjust(hspace=0.001, left=0.01, right=0.99, top=0.99, bottom=0.01) # Save the figure -fig.savefig('input_bed.pdf', transparent=True) -fig.savefig('input_bed.png', dpi=300) +fig.savefig("input_bed.pdf", transparent=True) +fig.savefig("input_bed.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/input_bed/input_bed.py b/dnaplotlib/gallery/input_bed/input_bed.py index c97d22c..88d3b7f 100755 --- a/dnaplotlib/gallery/input_bed/input_bed.py +++ b/dnaplotlib/gallery/input_bed/input_bed.py @@ -8,44 +8,64 @@ from matplotlib import gridspec import numpy as np -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Load the design from a GFF file cur_region = [1700, 15880] -design = dpl.load_design_from_gff('plasmid.gff', 'chrom1', region=cur_region) -profile_fwd = dpl.load_profile_from_bed('plasmid_fwd_profile.txt', 'chrom1', [0, 22953]) -profile_rev = dpl.load_profile_from_bed('plasmid_rev_profile.txt', 'chrom1', [0, 22953]) +design = dpl.load_design_from_gff("plasmid.gff", "chrom1", region=cur_region) +profile_fwd = dpl.load_profile_from_bed( + "plasmid_fwd_profile.txt", "chrom1", [0, 22953] +) +profile_rev = dpl.load_profile_from_bed( + "plasmid_rev_profile.txt", "chrom1", [0, 22953] +) # Create the DNAplotlib renderer dr = dpl.DNARenderer(scale=10.0) part_renderers = dr.trace_part_renderers() # Create the figure -fig = plt.figure(figsize=(3.5,2.0)) +fig = plt.figure(figsize=(3.5, 2.0)) gs = gridspec.GridSpec(2, 1, height_ratios=[1, 0.2]) ax_dna = plt.subplot(gs[1]) # Redender the DNA to axis start, end = dr.renderDNA(ax_dna, design, part_renderers) ax_dna.set_xlim(cur_region) -ax_dna.set_ylim([-5,8]) -ax_dna.axis('off') +ax_dna.set_ylim([-5, 8]) +ax_dna.axis("off") ax_profile = plt.subplot(gs[0]) -ax_profile.fill_between(list(range(cur_region[0],cur_region[1])), profile_fwd[cur_region[0]:cur_region[1]], np.zeros(cur_region[1]-cur_region[0]), color=(0.5,0.5,0.5), edgecolor=(0.5,0.5,0.5), linewidth=1, zorder=1.5) -ax_profile.fill_between(list(range(cur_region[0],cur_region[1])), np.array(profile_rev[cur_region[0]:cur_region[1]])*-1.0, np.zeros(cur_region[1]-cur_region[0]), color=(1,0,0), edgecolor=(1,0,0), linewidth=1, zorder=1.5) -ax_profile.plot(cur_region, [0,0], color=(0,0,0), zorder=10) +ax_profile.fill_between( + list(range(cur_region[0], cur_region[1])), + profile_fwd[cur_region[0] : cur_region[1]], + np.zeros(cur_region[1] - cur_region[0]), + color=(0.5, 0.5, 0.5), + edgecolor=(0.5, 0.5, 0.5), + linewidth=1, + zorder=1.5, +) +ax_profile.fill_between( + list(range(cur_region[0], cur_region[1])), + np.array(profile_rev[cur_region[0] : cur_region[1]]) * -1.0, + np.zeros(cur_region[1] - cur_region[0]), + color=(1, 0, 0), + edgecolor=(1, 0, 0), + linewidth=1, + zorder=1.5, +) +ax_profile.plot(cur_region, [0, 0], color=(0, 0, 0), zorder=10) ax_profile.set_xlim(cur_region) -ax_profile.axis('off') +ax_profile.axis("off") # Update subplot spacing plt.subplots_adjust(hspace=0.001, left=0.01, right=0.99, top=0.99, bottom=0.01) # Save the figure -fig.savefig('input_bed.pdf', transparent=True) -fig.savefig('input_bed.png', dpi=300) +fig.savefig("input_bed.pdf", transparent=True) +fig.savefig("input_bed.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/input_gff/input_gff 2.py b/dnaplotlib/gallery/input_gff/input_gff 2.py index e28d5cc..a941930 100644 --- a/dnaplotlib/gallery/input_gff/input_gff 2.py +++ b/dnaplotlib/gallery/input_gff/input_gff 2.py @@ -7,36 +7,36 @@ import matplotlib.pyplot as plt from matplotlib import gridspec -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Load the design from a GFF file -design = dpl.load_design_from_gff('plasmid.gff', 'chrom1', region=[1700, 15880]) +design = dpl.load_design_from_gff("plasmid.gff", "chrom1", region=[1700, 15880]) # Create the DNAplotlib renderer dr = dpl.DNARenderer() part_renderers = dr.SBOL_part_renderers() # Create the figure -fig = plt.figure(figsize=(5.0,0.6)) +fig = plt.figure(figsize=(5.0, 0.6)) gs = gridspec.GridSpec(1, 1) ax_dna = plt.subplot(gs[0]) # Redender the DNA to axis start, end = dr.renderDNA(ax_dna, design, part_renderers) ax_dna.set_xlim([start, end]) -ax_dna.set_ylim([-15,15]) -ax_dna.set_aspect('equal') -ax_dna.axis('off') +ax_dna.set_ylim([-15, 15]) +ax_dna.set_aspect("equal") +ax_dna.axis("off") # Update subplot spacing plt.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01) # Save the figure -fig.savefig('input_gff.pdf', transparent=True) -fig.savefig('input_gff.png', dpi=300) +fig.savefig("input_gff.pdf", transparent=True) +fig.savefig("input_gff.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/input_gff/input_gff.py b/dnaplotlib/gallery/input_gff/input_gff.py index e28d5cc..a941930 100755 --- a/dnaplotlib/gallery/input_gff/input_gff.py +++ b/dnaplotlib/gallery/input_gff/input_gff.py @@ -7,36 +7,36 @@ import matplotlib.pyplot as plt from matplotlib import gridspec -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Load the design from a GFF file -design = dpl.load_design_from_gff('plasmid.gff', 'chrom1', region=[1700, 15880]) +design = dpl.load_design_from_gff("plasmid.gff", "chrom1", region=[1700, 15880]) # Create the DNAplotlib renderer dr = dpl.DNARenderer() part_renderers = dr.SBOL_part_renderers() # Create the figure -fig = plt.figure(figsize=(5.0,0.6)) +fig = plt.figure(figsize=(5.0, 0.6)) gs = gridspec.GridSpec(1, 1) ax_dna = plt.subplot(gs[0]) # Redender the DNA to axis start, end = dr.renderDNA(ax_dna, design, part_renderers) ax_dna.set_xlim([start, end]) -ax_dna.set_ylim([-15,15]) -ax_dna.set_aspect('equal') -ax_dna.axis('off') +ax_dna.set_ylim([-15, 15]) +ax_dna.set_aspect("equal") +ax_dna.axis("off") # Update subplot spacing plt.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01) # Save the figure -fig.savefig('input_gff.pdf', transparent=True) -fig.savefig('input_gff.png', dpi=300) +fig.savefig("input_gff.pdf", transparent=True) +fig.savefig("input_gff.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/multiple_traces/multiple_traces 2.py b/dnaplotlib/gallery/multiple_traces/multiple_traces 2.py index df2d88d..1567ae9 100644 --- a/dnaplotlib/gallery/multiple_traces/multiple_traces 2.py +++ b/dnaplotlib/gallery/multiple_traces/multiple_traces 2.py @@ -9,174 +9,398 @@ import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Calculates a lighter color -def lighten_color (col, fac): - r = col[0] + (fac*(1.0-col[0])) - g = col[1] + (fac*(1.0-col[1])) - b = col[2] + (fac*(1.0-col[2])) - return (r,g,b) +def lighten_color(col, fac): + r = col[0] + (fac * (1.0 - col[0])) + g = col[1] + (fac * (1.0 - col[1])) + b = col[2] + (fac * (1.0 - col[2])) + return (r, g, b) + # Color maps for formatting col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) -col_map['yellow'] = (0.98, 0.97, 0.35) -col_map['grey'] = (0.70, 0.70, 0.70) -col_map['dark_grey'] = (0.60, 0.60, 0.60) -col_map['light_grey'] = (0.9, 0.9, 0.9) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) +col_map["yellow"] = (0.98, 0.97, 0.35) +col_map["grey"] = (0.70, 0.70, 0.70) +col_map["dark_grey"] = (0.60, 0.60, 0.60) +col_map["light_grey"] = (0.9, 0.9, 0.9) # CDS formatting options -opt_CDS1 = {'label':'nifV', 'label_style':'italic', 'label_y_offset':-5, 'color':col_map['light_grey']} -opt_CDS2 = {'label':'nifS', 'label_style':'italic', 'label_y_offset':-5, 'color':col_map['dark_grey']} -opt_CDS3 = {'label':'nifZ', 'label_style':'italic', 'label_y_offset':-5, 'color':col_map['light_grey']} -opt_CDS4 = {'label':'nifM', 'label_style':'italic', 'label_y_offset':-5, 'color':col_map['light_grey']} +opt_CDS1 = { + "label": "nifV", + "label_style": "italic", + "label_y_offset": -5, + "color": col_map["light_grey"], +} +opt_CDS2 = { + "label": "nifS", + "label_style": "italic", + "label_y_offset": -5, + "color": col_map["dark_grey"], +} +opt_CDS3 = { + "label": "nifZ", + "label_style": "italic", + "label_y_offset": -5, + "color": col_map["light_grey"], +} +opt_CDS4 = { + "label": "nifM", + "label_style": "italic", + "label_y_offset": -5, + "color": col_map["light_grey"], +} # Design of the construct -P1 = {'type':'Promoter', 'name':'P1', 'start':0, 'end':23, 'fwd':True, 'opts':{'color':col_map['green']}} -P2 = {'type':'Promoter', 'name':'P2', 'start':2643, 'end':2666, 'fwd':True, 'opts':{'color':col_map['green']}} -P3 = {'type':'Promoter', 'name':'P3', 'start':3320, 'end':3297, 'fwd':False, 'opts':{'color':col_map['green']}} -P4 = {'type':'Promoter', 'name':'P4', 'start':4336, 'end':4313, 'fwd':False, 'opts':{'color':col_map['green']}} -RBS1 = {'type':'RBS', 'name':'RBS1', 'start':72, 'end':106, 'fwd':True, 'opts':{'color':col_map['blue']}} -RBS2 = {'type':'RBS', 'name':'RBS2', 'start':1353, 'end':1392, 'fwd':True, 'opts':{'color':col_map['blue']}} -RBS3 = {'type':'RBS', 'name':'RBS4', 'start':3248, 'end':3217, 'fwd':False, 'opts':{'color':col_map['blue']}} -RBS4 = {'type':'RBS', 'name':'RBS3', 'start':4209, 'end':4175, 'fwd':False, 'opts':{'color':col_map['blue']}} -CDS1 = {'type':'CDS', 'name':'CDS1', 'start':106, 'end':1249, 'fwd':True, 'opts':opt_CDS1} -CDS2 = {'type':'CDS', 'name':'CDS2', 'start':1392, 'end':2595, 'fwd':True, 'opts':opt_CDS2} -CDS3 = {'type':'CDS', 'name':'CDS3', 'start':3217, 'end':2770, 'fwd':False, 'opts':opt_CDS3} -CDS4 = {'type':'CDS', 'name':'CDS4', 'start':4175, 'end':3374, 'fwd':False, 'opts':opt_CDS4} -T1 = {'type':'Terminator', 'name':'T1', 'start':2595, 'end':2643, 'fwd':True, 'opts':{'color':col_map['red']}} +P1 = { + "type": "Promoter", + "name": "P1", + "start": 0, + "end": 23, + "fwd": True, + "opts": {"color": col_map["green"]}, +} +P2 = { + "type": "Promoter", + "name": "P2", + "start": 2643, + "end": 2666, + "fwd": True, + "opts": {"color": col_map["green"]}, +} +P3 = { + "type": "Promoter", + "name": "P3", + "start": 3320, + "end": 3297, + "fwd": False, + "opts": {"color": col_map["green"]}, +} +P4 = { + "type": "Promoter", + "name": "P4", + "start": 4336, + "end": 4313, + "fwd": False, + "opts": {"color": col_map["green"]}, +} +RBS1 = { + "type": "RBS", + "name": "RBS1", + "start": 72, + "end": 106, + "fwd": True, + "opts": {"color": col_map["blue"]}, +} +RBS2 = { + "type": "RBS", + "name": "RBS2", + "start": 1353, + "end": 1392, + "fwd": True, + "opts": {"color": col_map["blue"]}, +} +RBS3 = { + "type": "RBS", + "name": "RBS4", + "start": 3248, + "end": 3217, + "fwd": False, + "opts": {"color": col_map["blue"]}, +} +RBS4 = { + "type": "RBS", + "name": "RBS3", + "start": 4209, + "end": 4175, + "fwd": False, + "opts": {"color": col_map["blue"]}, +} +CDS1 = { + "type": "CDS", + "name": "CDS1", + "start": 106, + "end": 1249, + "fwd": True, + "opts": opt_CDS1, +} +CDS2 = { + "type": "CDS", + "name": "CDS2", + "start": 1392, + "end": 2595, + "fwd": True, + "opts": opt_CDS2, +} +CDS3 = { + "type": "CDS", + "name": "CDS3", + "start": 3217, + "end": 2770, + "fwd": False, + "opts": opt_CDS3, +} +CDS4 = { + "type": "CDS", + "name": "CDS4", + "start": 4175, + "end": 3374, + "fwd": False, + "opts": opt_CDS4, +} +T1 = { + "type": "Terminator", + "name": "T1", + "start": 2595, + "end": 2643, + "fwd": True, + "opts": {"color": col_map["red"]}, +} # A design is merely a list of parts and their properties design = [P1, RBS1, CDS1, RBS2, CDS2, T1, P2, CDS3, RBS3, P3, CDS4, RBS4, P4] # Loads a sequence file -def load_seq (filename_in): - f_in = open(filename_in, 'rU') - seq = f_in.readline().strip() - f_in.close() - return seq +def load_seq(filename_in): + f_in = open(filename_in, "rU") + seq = f_in.readline().strip() + f_in.close() + return seq + # Calculate the GC% for a moving window def gc_window(seq, window_len): - out = [0]*len(seq) - for idx in range(len(seq)): - start_idx = idx - end_idx = start_idx+window_len - if end_idx > len(seq): - end_idx = len(seq) - gc_count = seq[start_idx:end_idx].count('G') - gc_count += seq[start_idx:end_idx].count('C') - out[idx] = gc_count/float(window_len) - return np.array(out) + out = [0] * len(seq) + for idx in range(len(seq)): + start_idx = idx + end_idx = start_idx + window_len + if end_idx > len(seq): + end_idx = len(seq) + gc_count = seq[start_idx:end_idx].count("G") + gc_count += seq[start_idx:end_idx].count("C") + out[idx] = gc_count / float(window_len) + return np.array(out) + # Loads a file containing trace information -def load_trace (filename_in): - # data[0] is forward strand - # data[1] is reverse strand - data = [[],[]] - trace_reader = csv.reader(open(filename_in, 'rU'), delimiter=',') - data[0] = np.array([float(x) for x in next(trace_reader)]) - data[1] = np.array([float(x) for x in next(trace_reader)]) - return data +def load_trace(filename_in): + # data[0] is forward strand + # data[1] is reverse strand + data = [[], []] + trace_reader = csv.reader(open(filename_in, "rU"), delimiter=",") + data[0] = np.array([float(x) for x in next(trace_reader)]) + data[1] = np.array([float(x) for x in next(trace_reader)]) + return data + # Plot a double trace (e.g, strand-specific data) -def plot_trace_2 (ax_trace, data, col, lab='', hightlight=[0,0]): - # Plot the traces - trace_len = len(data[0]) - ax_trace.fill_between(list(range(trace_len)),data[0],np.zeros(trace_len), color=lighten_color(col,0.5), edgecolor=lighten_color(col,0.5), linewidth=1, zorder=1) - ax_trace.fill_between(list(range(trace_len)),-data[1],np.zeros(trace_len), color=lighten_color(col,0.5), edgecolor=lighten_color(col,0.5), linewidth=1, zorder=1) - # Hightlighted region - r = np.arange(hightlight[0], hightlight[1]) - ax_trace.fill_between(r,data[0][hightlight[0]:hightlight[1]],np.zeros(len(r)), color=col, edgecolor=col, linewidth=1, zorder=1.5) - ax_trace.fill_between(r,-data[1][hightlight[0]:hightlight[1]],np.zeros(len(r)), color=col, edgecolor=col, linewidth=1, zorder=1.5) - # Adjust formatting - ax_trace.plot(list(range(trace_len)), np.zeros(trace_len), color=(0,0,0), linewidth=1, zorder=2) - max_read_depth = max(data[0]) - max_read_depth_1 = max(data[1]) - if max_read_depth_1 > max_read_depth: - max_read_depth = max_read_depth_1 - max_read_depth *= 1.02 - ax_trace.set_ylim([-max_read_depth,max_read_depth]) - ax_trace.spines['right'].set_visible(False) - ax_trace.spines['top'].set_visible(False) - ax_trace.spines['bottom'].set_visible(False) - ax_trace.tick_params(axis='both', direction='out') - ax_trace.set_xticks([]) - ax_trace.get_yaxis().tick_left() - ax_trace.tick_params('both', length=2, width=0.5, which='major') - ax_trace.tick_params(axis='y', which='major', pad=2, labelsize=8) - ax_trace.set_ylabel(lab, fontsize=8, labelpad=6) +def plot_trace_2(ax_trace, data, col, lab="", hightlight=[0, 0]): + # Plot the traces + trace_len = len(data[0]) + ax_trace.fill_between( + list(range(trace_len)), + data[0], + np.zeros(trace_len), + color=lighten_color(col, 0.5), + edgecolor=lighten_color(col, 0.5), + linewidth=1, + zorder=1, + ) + ax_trace.fill_between( + list(range(trace_len)), + -data[1], + np.zeros(trace_len), + color=lighten_color(col, 0.5), + edgecolor=lighten_color(col, 0.5), + linewidth=1, + zorder=1, + ) + # Hightlighted region + r = np.arange(hightlight[0], hightlight[1]) + ax_trace.fill_between( + r, + data[0][hightlight[0] : hightlight[1]], + np.zeros(len(r)), + color=col, + edgecolor=col, + linewidth=1, + zorder=1.5, + ) + ax_trace.fill_between( + r, + -data[1][hightlight[0] : hightlight[1]], + np.zeros(len(r)), + color=col, + edgecolor=col, + linewidth=1, + zorder=1.5, + ) + # Adjust formatting + ax_trace.plot( + list(range(trace_len)), + np.zeros(trace_len), + color=(0, 0, 0), + linewidth=1, + zorder=2, + ) + max_read_depth = max(data[0]) + max_read_depth_1 = max(data[1]) + if max_read_depth_1 > max_read_depth: + max_read_depth = max_read_depth_1 + max_read_depth *= 1.02 + ax_trace.set_ylim([-max_read_depth, max_read_depth]) + ax_trace.spines["right"].set_visible(False) + ax_trace.spines["top"].set_visible(False) + ax_trace.spines["bottom"].set_visible(False) + ax_trace.tick_params(axis="both", direction="out") + ax_trace.set_xticks([]) + ax_trace.get_yaxis().tick_left() + ax_trace.tick_params("both", length=2, width=0.5, which="major") + ax_trace.tick_params(axis="y", which="major", pad=2, labelsize=8) + ax_trace.set_ylabel(lab, fontsize=8, labelpad=6) + # Plot a single trace -def plot_trace_1 (ax_trace, data, col, scale=None, min_y=0, max_y=None, lab='', hightlight=[0,0]): - # Plot the trace - trace_len = len(data) - ax_trace.fill_between(list(range(trace_len)),data,np.zeros(trace_len), color=lighten_color(col,0.5), edgecolor=lighten_color(col,0.5), linewidth=1, zorder=1) - # Hightlight region - r = np.arange(hightlight[0], hightlight[1]) - ax_trace.fill_between(r,data[hightlight[0]:hightlight[1]],np.zeros(len(r)), color=col, edgecolor=col, linewidth=1, zorder=1.5) - # Adjust formatting - ax_trace.plot(list(range(trace_len)), np.zeros(trace_len), color=(0,0,0), linewidth=1, zorder=2) - max_read_depth = max(data) * 1.02 - if max_y == None: - ax_trace.set_ylim([min_y,max_read_depth]) - else: - ax_trace.set_ylim([min_y,max_y]) - ax_trace.spines['right'].set_visible(False) - ax_trace.spines['top'].set_visible(False) - ax_trace.tick_params(axis='both', direction='out') - ax_trace.set_xticks([]) - ax_trace.get_yaxis().tick_left() - ax_trace.tick_params('both', length=2, width=0.5, which='major') - ax_trace.tick_params(axis='y', which='major', pad=2, labelsize=8) - if scale != None: - ax_trace.set_yscale(scale) - ax_trace.set_ylabel(lab, fontsize=8, labelpad=1) +def plot_trace_1( + ax_trace, + data, + col, + scale=None, + min_y=0, + max_y=None, + lab="", + hightlight=[0, 0], +): + # Plot the trace + trace_len = len(data) + ax_trace.fill_between( + list(range(trace_len)), + data, + np.zeros(trace_len), + color=lighten_color(col, 0.5), + edgecolor=lighten_color(col, 0.5), + linewidth=1, + zorder=1, + ) + # Hightlight region + r = np.arange(hightlight[0], hightlight[1]) + ax_trace.fill_between( + r, + data[hightlight[0] : hightlight[1]], + np.zeros(len(r)), + color=col, + edgecolor=col, + linewidth=1, + zorder=1.5, + ) + # Adjust formatting + ax_trace.plot( + list(range(trace_len)), + np.zeros(trace_len), + color=(0, 0, 0), + linewidth=1, + zorder=2, + ) + max_read_depth = max(data) * 1.02 + if max_y == None: + ax_trace.set_ylim([min_y, max_read_depth]) + else: + ax_trace.set_ylim([min_y, max_y]) + ax_trace.spines["right"].set_visible(False) + ax_trace.spines["top"].set_visible(False) + ax_trace.tick_params(axis="both", direction="out") + ax_trace.set_xticks([]) + ax_trace.get_yaxis().tick_left() + ax_trace.tick_params("both", length=2, width=0.5, which="major") + ax_trace.tick_params(axis="y", which="major", pad=2, labelsize=8) + if scale != None: + ax_trace.set_yscale(scale) + ax_trace.set_ylabel(lab, fontsize=8, labelpad=1) + # Create the figure and all axes to draw to -fig = plt.figure(figsize=(3.2,2.7)) -gs = gridspec.GridSpec(4, 1, height_ratios=[0.6,1.5,0.8,0.8]) +fig = plt.figure(figsize=(3.2, 2.7)) +gs = gridspec.GridSpec(4, 1, height_ratios=[0.6, 1.5, 0.8, 0.8]) ax_dna = plt.subplot(gs[0]) ax_trace1 = plt.subplot(gs[1], sharex=ax_dna) -ax_trace1.set_yticklabels(['', '50', '0', '50']) -ax_trace1.text(0.01, 0.86, 'sense', horizontalalignment='left', verticalalignment='center', transform=ax_trace1.transAxes, fontsize=8) -ax_trace1.text(0.01, 0.14, 'anti-sense', horizontalalignment='left', verticalalignment='center', transform=ax_trace1.transAxes, fontsize=8) +ax_trace1.set_yticklabels(["", "50", "0", "50"]) +ax_trace1.text( + 0.01, + 0.86, + "sense", + horizontalalignment="left", + verticalalignment="center", + transform=ax_trace1.transAxes, + fontsize=8, +) +ax_trace1.text( + 0.01, + 0.14, + "anti-sense", + horizontalalignment="left", + verticalalignment="center", + transform=ax_trace1.transAxes, + fontsize=8, +) ax_trace2 = plt.subplot(gs[2], sharex=ax_dna) ax_trace3 = plt.subplot(gs[3], sharex=ax_dna) # Load/calculate the data -data_rnaseq = load_trace('data_rnaseq.csv') -data_rbs = load_trace('data_rbs.csv') -seq = load_seq('data_seq.txt') +data_rnaseq = load_trace("data_rnaseq.csv") +data_rbs = load_trace("data_rbs.csv") +seq = load_seq("data_seq.txt") data_gc = gc_window(seq, 50) # Plot the traces -plot_trace_2(ax_trace1, data_rnaseq, col_map['orange'], lab='Read Depth', hightlight=[RBS2['start'], CDS2['end']]) -plot_trace_1(ax_trace2, data_rbs[0]+data_rbs[1], col_map['blue'], scale='log', min_y=2000, lab='RBS Score', hightlight=[RBS2['start'], CDS2['end']]) -plot_trace_1(ax_trace3, data_gc*100, col_map['purple'], max_y=100, lab='GC %', hightlight=[RBS2['start'], CDS2['end']]) +plot_trace_2( + ax_trace1, + data_rnaseq, + col_map["orange"], + lab="Read Depth", + hightlight=[RBS2["start"], CDS2["end"]], +) +plot_trace_1( + ax_trace2, + data_rbs[0] + data_rbs[1], + col_map["blue"], + scale="log", + min_y=2000, + lab="RBS Score", + hightlight=[RBS2["start"], CDS2["end"]], +) +plot_trace_1( + ax_trace3, + data_gc * 100, + col_map["purple"], + max_y=100, + lab="GC %", + hightlight=[RBS2["start"], CDS2["end"]], +) # Redender the DNA dr = dpl.DNARenderer(scale=4, linewidth=0.9) start, end = dr.renderDNA(ax_dna, design, dr.trace_part_renderers()) # Set bounds and display options for the DNA axis -dna_len = end-start -ax_dna.set_xlim([start-20, end+20]) -ax_dna.set_ylim([-8,8]) -ax_dna.plot([start-20,end+20], [0,0], color=(0,0,0), linewidth=1.0, zorder=1) -ax_dna.axis('off') -plt.subplots_adjust(hspace=.08, left=.12, right=.99, top=0.99, bottom=0.02) +dna_len = end - start +ax_dna.set_xlim([start - 20, end + 20]) +ax_dna.set_ylim([-8, 8]) +ax_dna.plot( + [start - 20, end + 20], [0, 0], color=(0, 0, 0), linewidth=1.0, zorder=1 +) +ax_dna.axis("off") +plt.subplots_adjust(hspace=0.08, left=0.12, right=0.99, top=0.99, bottom=0.02) # Save the figure -fig.savefig('multiple_traces.pdf', transparent=True) -fig.savefig('multiple_traces.png', dpi=300) +fig.savefig("multiple_traces.pdf", transparent=True) +fig.savefig("multiple_traces.png", dpi=300) # Clear the plotting cache -plt.close('all') - +plt.close("all") diff --git a/dnaplotlib/gallery/multiple_traces/multiple_traces.py b/dnaplotlib/gallery/multiple_traces/multiple_traces.py index df2d88d..1567ae9 100755 --- a/dnaplotlib/gallery/multiple_traces/multiple_traces.py +++ b/dnaplotlib/gallery/multiple_traces/multiple_traces.py @@ -9,174 +9,398 @@ import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Calculates a lighter color -def lighten_color (col, fac): - r = col[0] + (fac*(1.0-col[0])) - g = col[1] + (fac*(1.0-col[1])) - b = col[2] + (fac*(1.0-col[2])) - return (r,g,b) +def lighten_color(col, fac): + r = col[0] + (fac * (1.0 - col[0])) + g = col[1] + (fac * (1.0 - col[1])) + b = col[2] + (fac * (1.0 - col[2])) + return (r, g, b) + # Color maps for formatting col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) -col_map['yellow'] = (0.98, 0.97, 0.35) -col_map['grey'] = (0.70, 0.70, 0.70) -col_map['dark_grey'] = (0.60, 0.60, 0.60) -col_map['light_grey'] = (0.9, 0.9, 0.9) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) +col_map["yellow"] = (0.98, 0.97, 0.35) +col_map["grey"] = (0.70, 0.70, 0.70) +col_map["dark_grey"] = (0.60, 0.60, 0.60) +col_map["light_grey"] = (0.9, 0.9, 0.9) # CDS formatting options -opt_CDS1 = {'label':'nifV', 'label_style':'italic', 'label_y_offset':-5, 'color':col_map['light_grey']} -opt_CDS2 = {'label':'nifS', 'label_style':'italic', 'label_y_offset':-5, 'color':col_map['dark_grey']} -opt_CDS3 = {'label':'nifZ', 'label_style':'italic', 'label_y_offset':-5, 'color':col_map['light_grey']} -opt_CDS4 = {'label':'nifM', 'label_style':'italic', 'label_y_offset':-5, 'color':col_map['light_grey']} +opt_CDS1 = { + "label": "nifV", + "label_style": "italic", + "label_y_offset": -5, + "color": col_map["light_grey"], +} +opt_CDS2 = { + "label": "nifS", + "label_style": "italic", + "label_y_offset": -5, + "color": col_map["dark_grey"], +} +opt_CDS3 = { + "label": "nifZ", + "label_style": "italic", + "label_y_offset": -5, + "color": col_map["light_grey"], +} +opt_CDS4 = { + "label": "nifM", + "label_style": "italic", + "label_y_offset": -5, + "color": col_map["light_grey"], +} # Design of the construct -P1 = {'type':'Promoter', 'name':'P1', 'start':0, 'end':23, 'fwd':True, 'opts':{'color':col_map['green']}} -P2 = {'type':'Promoter', 'name':'P2', 'start':2643, 'end':2666, 'fwd':True, 'opts':{'color':col_map['green']}} -P3 = {'type':'Promoter', 'name':'P3', 'start':3320, 'end':3297, 'fwd':False, 'opts':{'color':col_map['green']}} -P4 = {'type':'Promoter', 'name':'P4', 'start':4336, 'end':4313, 'fwd':False, 'opts':{'color':col_map['green']}} -RBS1 = {'type':'RBS', 'name':'RBS1', 'start':72, 'end':106, 'fwd':True, 'opts':{'color':col_map['blue']}} -RBS2 = {'type':'RBS', 'name':'RBS2', 'start':1353, 'end':1392, 'fwd':True, 'opts':{'color':col_map['blue']}} -RBS3 = {'type':'RBS', 'name':'RBS4', 'start':3248, 'end':3217, 'fwd':False, 'opts':{'color':col_map['blue']}} -RBS4 = {'type':'RBS', 'name':'RBS3', 'start':4209, 'end':4175, 'fwd':False, 'opts':{'color':col_map['blue']}} -CDS1 = {'type':'CDS', 'name':'CDS1', 'start':106, 'end':1249, 'fwd':True, 'opts':opt_CDS1} -CDS2 = {'type':'CDS', 'name':'CDS2', 'start':1392, 'end':2595, 'fwd':True, 'opts':opt_CDS2} -CDS3 = {'type':'CDS', 'name':'CDS3', 'start':3217, 'end':2770, 'fwd':False, 'opts':opt_CDS3} -CDS4 = {'type':'CDS', 'name':'CDS4', 'start':4175, 'end':3374, 'fwd':False, 'opts':opt_CDS4} -T1 = {'type':'Terminator', 'name':'T1', 'start':2595, 'end':2643, 'fwd':True, 'opts':{'color':col_map['red']}} +P1 = { + "type": "Promoter", + "name": "P1", + "start": 0, + "end": 23, + "fwd": True, + "opts": {"color": col_map["green"]}, +} +P2 = { + "type": "Promoter", + "name": "P2", + "start": 2643, + "end": 2666, + "fwd": True, + "opts": {"color": col_map["green"]}, +} +P3 = { + "type": "Promoter", + "name": "P3", + "start": 3320, + "end": 3297, + "fwd": False, + "opts": {"color": col_map["green"]}, +} +P4 = { + "type": "Promoter", + "name": "P4", + "start": 4336, + "end": 4313, + "fwd": False, + "opts": {"color": col_map["green"]}, +} +RBS1 = { + "type": "RBS", + "name": "RBS1", + "start": 72, + "end": 106, + "fwd": True, + "opts": {"color": col_map["blue"]}, +} +RBS2 = { + "type": "RBS", + "name": "RBS2", + "start": 1353, + "end": 1392, + "fwd": True, + "opts": {"color": col_map["blue"]}, +} +RBS3 = { + "type": "RBS", + "name": "RBS4", + "start": 3248, + "end": 3217, + "fwd": False, + "opts": {"color": col_map["blue"]}, +} +RBS4 = { + "type": "RBS", + "name": "RBS3", + "start": 4209, + "end": 4175, + "fwd": False, + "opts": {"color": col_map["blue"]}, +} +CDS1 = { + "type": "CDS", + "name": "CDS1", + "start": 106, + "end": 1249, + "fwd": True, + "opts": opt_CDS1, +} +CDS2 = { + "type": "CDS", + "name": "CDS2", + "start": 1392, + "end": 2595, + "fwd": True, + "opts": opt_CDS2, +} +CDS3 = { + "type": "CDS", + "name": "CDS3", + "start": 3217, + "end": 2770, + "fwd": False, + "opts": opt_CDS3, +} +CDS4 = { + "type": "CDS", + "name": "CDS4", + "start": 4175, + "end": 3374, + "fwd": False, + "opts": opt_CDS4, +} +T1 = { + "type": "Terminator", + "name": "T1", + "start": 2595, + "end": 2643, + "fwd": True, + "opts": {"color": col_map["red"]}, +} # A design is merely a list of parts and their properties design = [P1, RBS1, CDS1, RBS2, CDS2, T1, P2, CDS3, RBS3, P3, CDS4, RBS4, P4] # Loads a sequence file -def load_seq (filename_in): - f_in = open(filename_in, 'rU') - seq = f_in.readline().strip() - f_in.close() - return seq +def load_seq(filename_in): + f_in = open(filename_in, "rU") + seq = f_in.readline().strip() + f_in.close() + return seq + # Calculate the GC% for a moving window def gc_window(seq, window_len): - out = [0]*len(seq) - for idx in range(len(seq)): - start_idx = idx - end_idx = start_idx+window_len - if end_idx > len(seq): - end_idx = len(seq) - gc_count = seq[start_idx:end_idx].count('G') - gc_count += seq[start_idx:end_idx].count('C') - out[idx] = gc_count/float(window_len) - return np.array(out) + out = [0] * len(seq) + for idx in range(len(seq)): + start_idx = idx + end_idx = start_idx + window_len + if end_idx > len(seq): + end_idx = len(seq) + gc_count = seq[start_idx:end_idx].count("G") + gc_count += seq[start_idx:end_idx].count("C") + out[idx] = gc_count / float(window_len) + return np.array(out) + # Loads a file containing trace information -def load_trace (filename_in): - # data[0] is forward strand - # data[1] is reverse strand - data = [[],[]] - trace_reader = csv.reader(open(filename_in, 'rU'), delimiter=',') - data[0] = np.array([float(x) for x in next(trace_reader)]) - data[1] = np.array([float(x) for x in next(trace_reader)]) - return data +def load_trace(filename_in): + # data[0] is forward strand + # data[1] is reverse strand + data = [[], []] + trace_reader = csv.reader(open(filename_in, "rU"), delimiter=",") + data[0] = np.array([float(x) for x in next(trace_reader)]) + data[1] = np.array([float(x) for x in next(trace_reader)]) + return data + # Plot a double trace (e.g, strand-specific data) -def plot_trace_2 (ax_trace, data, col, lab='', hightlight=[0,0]): - # Plot the traces - trace_len = len(data[0]) - ax_trace.fill_between(list(range(trace_len)),data[0],np.zeros(trace_len), color=lighten_color(col,0.5), edgecolor=lighten_color(col,0.5), linewidth=1, zorder=1) - ax_trace.fill_between(list(range(trace_len)),-data[1],np.zeros(trace_len), color=lighten_color(col,0.5), edgecolor=lighten_color(col,0.5), linewidth=1, zorder=1) - # Hightlighted region - r = np.arange(hightlight[0], hightlight[1]) - ax_trace.fill_between(r,data[0][hightlight[0]:hightlight[1]],np.zeros(len(r)), color=col, edgecolor=col, linewidth=1, zorder=1.5) - ax_trace.fill_between(r,-data[1][hightlight[0]:hightlight[1]],np.zeros(len(r)), color=col, edgecolor=col, linewidth=1, zorder=1.5) - # Adjust formatting - ax_trace.plot(list(range(trace_len)), np.zeros(trace_len), color=(0,0,0), linewidth=1, zorder=2) - max_read_depth = max(data[0]) - max_read_depth_1 = max(data[1]) - if max_read_depth_1 > max_read_depth: - max_read_depth = max_read_depth_1 - max_read_depth *= 1.02 - ax_trace.set_ylim([-max_read_depth,max_read_depth]) - ax_trace.spines['right'].set_visible(False) - ax_trace.spines['top'].set_visible(False) - ax_trace.spines['bottom'].set_visible(False) - ax_trace.tick_params(axis='both', direction='out') - ax_trace.set_xticks([]) - ax_trace.get_yaxis().tick_left() - ax_trace.tick_params('both', length=2, width=0.5, which='major') - ax_trace.tick_params(axis='y', which='major', pad=2, labelsize=8) - ax_trace.set_ylabel(lab, fontsize=8, labelpad=6) +def plot_trace_2(ax_trace, data, col, lab="", hightlight=[0, 0]): + # Plot the traces + trace_len = len(data[0]) + ax_trace.fill_between( + list(range(trace_len)), + data[0], + np.zeros(trace_len), + color=lighten_color(col, 0.5), + edgecolor=lighten_color(col, 0.5), + linewidth=1, + zorder=1, + ) + ax_trace.fill_between( + list(range(trace_len)), + -data[1], + np.zeros(trace_len), + color=lighten_color(col, 0.5), + edgecolor=lighten_color(col, 0.5), + linewidth=1, + zorder=1, + ) + # Hightlighted region + r = np.arange(hightlight[0], hightlight[1]) + ax_trace.fill_between( + r, + data[0][hightlight[0] : hightlight[1]], + np.zeros(len(r)), + color=col, + edgecolor=col, + linewidth=1, + zorder=1.5, + ) + ax_trace.fill_between( + r, + -data[1][hightlight[0] : hightlight[1]], + np.zeros(len(r)), + color=col, + edgecolor=col, + linewidth=1, + zorder=1.5, + ) + # Adjust formatting + ax_trace.plot( + list(range(trace_len)), + np.zeros(trace_len), + color=(0, 0, 0), + linewidth=1, + zorder=2, + ) + max_read_depth = max(data[0]) + max_read_depth_1 = max(data[1]) + if max_read_depth_1 > max_read_depth: + max_read_depth = max_read_depth_1 + max_read_depth *= 1.02 + ax_trace.set_ylim([-max_read_depth, max_read_depth]) + ax_trace.spines["right"].set_visible(False) + ax_trace.spines["top"].set_visible(False) + ax_trace.spines["bottom"].set_visible(False) + ax_trace.tick_params(axis="both", direction="out") + ax_trace.set_xticks([]) + ax_trace.get_yaxis().tick_left() + ax_trace.tick_params("both", length=2, width=0.5, which="major") + ax_trace.tick_params(axis="y", which="major", pad=2, labelsize=8) + ax_trace.set_ylabel(lab, fontsize=8, labelpad=6) + # Plot a single trace -def plot_trace_1 (ax_trace, data, col, scale=None, min_y=0, max_y=None, lab='', hightlight=[0,0]): - # Plot the trace - trace_len = len(data) - ax_trace.fill_between(list(range(trace_len)),data,np.zeros(trace_len), color=lighten_color(col,0.5), edgecolor=lighten_color(col,0.5), linewidth=1, zorder=1) - # Hightlight region - r = np.arange(hightlight[0], hightlight[1]) - ax_trace.fill_between(r,data[hightlight[0]:hightlight[1]],np.zeros(len(r)), color=col, edgecolor=col, linewidth=1, zorder=1.5) - # Adjust formatting - ax_trace.plot(list(range(trace_len)), np.zeros(trace_len), color=(0,0,0), linewidth=1, zorder=2) - max_read_depth = max(data) * 1.02 - if max_y == None: - ax_trace.set_ylim([min_y,max_read_depth]) - else: - ax_trace.set_ylim([min_y,max_y]) - ax_trace.spines['right'].set_visible(False) - ax_trace.spines['top'].set_visible(False) - ax_trace.tick_params(axis='both', direction='out') - ax_trace.set_xticks([]) - ax_trace.get_yaxis().tick_left() - ax_trace.tick_params('both', length=2, width=0.5, which='major') - ax_trace.tick_params(axis='y', which='major', pad=2, labelsize=8) - if scale != None: - ax_trace.set_yscale(scale) - ax_trace.set_ylabel(lab, fontsize=8, labelpad=1) +def plot_trace_1( + ax_trace, + data, + col, + scale=None, + min_y=0, + max_y=None, + lab="", + hightlight=[0, 0], +): + # Plot the trace + trace_len = len(data) + ax_trace.fill_between( + list(range(trace_len)), + data, + np.zeros(trace_len), + color=lighten_color(col, 0.5), + edgecolor=lighten_color(col, 0.5), + linewidth=1, + zorder=1, + ) + # Hightlight region + r = np.arange(hightlight[0], hightlight[1]) + ax_trace.fill_between( + r, + data[hightlight[0] : hightlight[1]], + np.zeros(len(r)), + color=col, + edgecolor=col, + linewidth=1, + zorder=1.5, + ) + # Adjust formatting + ax_trace.plot( + list(range(trace_len)), + np.zeros(trace_len), + color=(0, 0, 0), + linewidth=1, + zorder=2, + ) + max_read_depth = max(data) * 1.02 + if max_y == None: + ax_trace.set_ylim([min_y, max_read_depth]) + else: + ax_trace.set_ylim([min_y, max_y]) + ax_trace.spines["right"].set_visible(False) + ax_trace.spines["top"].set_visible(False) + ax_trace.tick_params(axis="both", direction="out") + ax_trace.set_xticks([]) + ax_trace.get_yaxis().tick_left() + ax_trace.tick_params("both", length=2, width=0.5, which="major") + ax_trace.tick_params(axis="y", which="major", pad=2, labelsize=8) + if scale != None: + ax_trace.set_yscale(scale) + ax_trace.set_ylabel(lab, fontsize=8, labelpad=1) + # Create the figure and all axes to draw to -fig = plt.figure(figsize=(3.2,2.7)) -gs = gridspec.GridSpec(4, 1, height_ratios=[0.6,1.5,0.8,0.8]) +fig = plt.figure(figsize=(3.2, 2.7)) +gs = gridspec.GridSpec(4, 1, height_ratios=[0.6, 1.5, 0.8, 0.8]) ax_dna = plt.subplot(gs[0]) ax_trace1 = plt.subplot(gs[1], sharex=ax_dna) -ax_trace1.set_yticklabels(['', '50', '0', '50']) -ax_trace1.text(0.01, 0.86, 'sense', horizontalalignment='left', verticalalignment='center', transform=ax_trace1.transAxes, fontsize=8) -ax_trace1.text(0.01, 0.14, 'anti-sense', horizontalalignment='left', verticalalignment='center', transform=ax_trace1.transAxes, fontsize=8) +ax_trace1.set_yticklabels(["", "50", "0", "50"]) +ax_trace1.text( + 0.01, + 0.86, + "sense", + horizontalalignment="left", + verticalalignment="center", + transform=ax_trace1.transAxes, + fontsize=8, +) +ax_trace1.text( + 0.01, + 0.14, + "anti-sense", + horizontalalignment="left", + verticalalignment="center", + transform=ax_trace1.transAxes, + fontsize=8, +) ax_trace2 = plt.subplot(gs[2], sharex=ax_dna) ax_trace3 = plt.subplot(gs[3], sharex=ax_dna) # Load/calculate the data -data_rnaseq = load_trace('data_rnaseq.csv') -data_rbs = load_trace('data_rbs.csv') -seq = load_seq('data_seq.txt') +data_rnaseq = load_trace("data_rnaseq.csv") +data_rbs = load_trace("data_rbs.csv") +seq = load_seq("data_seq.txt") data_gc = gc_window(seq, 50) # Plot the traces -plot_trace_2(ax_trace1, data_rnaseq, col_map['orange'], lab='Read Depth', hightlight=[RBS2['start'], CDS2['end']]) -plot_trace_1(ax_trace2, data_rbs[0]+data_rbs[1], col_map['blue'], scale='log', min_y=2000, lab='RBS Score', hightlight=[RBS2['start'], CDS2['end']]) -plot_trace_1(ax_trace3, data_gc*100, col_map['purple'], max_y=100, lab='GC %', hightlight=[RBS2['start'], CDS2['end']]) +plot_trace_2( + ax_trace1, + data_rnaseq, + col_map["orange"], + lab="Read Depth", + hightlight=[RBS2["start"], CDS2["end"]], +) +plot_trace_1( + ax_trace2, + data_rbs[0] + data_rbs[1], + col_map["blue"], + scale="log", + min_y=2000, + lab="RBS Score", + hightlight=[RBS2["start"], CDS2["end"]], +) +plot_trace_1( + ax_trace3, + data_gc * 100, + col_map["purple"], + max_y=100, + lab="GC %", + hightlight=[RBS2["start"], CDS2["end"]], +) # Redender the DNA dr = dpl.DNARenderer(scale=4, linewidth=0.9) start, end = dr.renderDNA(ax_dna, design, dr.trace_part_renderers()) # Set bounds and display options for the DNA axis -dna_len = end-start -ax_dna.set_xlim([start-20, end+20]) -ax_dna.set_ylim([-8,8]) -ax_dna.plot([start-20,end+20], [0,0], color=(0,0,0), linewidth=1.0, zorder=1) -ax_dna.axis('off') -plt.subplots_adjust(hspace=.08, left=.12, right=.99, top=0.99, bottom=0.02) +dna_len = end - start +ax_dna.set_xlim([start - 20, end + 20]) +ax_dna.set_ylim([-8, 8]) +ax_dna.plot( + [start - 20, end + 20], [0, 0], color=(0, 0, 0), linewidth=1.0, zorder=1 +) +ax_dna.axis("off") +plt.subplots_adjust(hspace=0.08, left=0.12, right=0.99, top=0.99, bottom=0.02) # Save the figure -fig.savefig('multiple_traces.pdf', transparent=True) -fig.savefig('multiple_traces.png', dpi=300) +fig.savefig("multiple_traces.pdf", transparent=True) +fig.savefig("multiple_traces.png", dpi=300) # Clear the plotting cache -plt.close('all') - +plt.close("all") diff --git a/dnaplotlib/gallery/offset_features/offset_features 2.py b/dnaplotlib/gallery/offset_features/offset_features 2.py index b1394ec..feab882 100644 --- a/dnaplotlib/gallery/offset_features/offset_features 2.py +++ b/dnaplotlib/gallery/offset_features/offset_features 2.py @@ -9,43 +9,145 @@ import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Color maps for formatting col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) -col_map['yellow'] = (0.98, 0.97, 0.35) -col_map['grey'] = (0.70, 0.70, 0.70) -col_map['dark_grey'] = (0.60, 0.60, 0.60) -col_map['light_grey'] = (0.9, 0.9, 0.9) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) +col_map["yellow"] = (0.98, 0.97, 0.35) +col_map["grey"] = (0.70, 0.70, 0.70) +col_map["dark_grey"] = (0.60, 0.60, 0.60) +col_map["light_grey"] = (0.9, 0.9, 0.9) # CDS formatting options -opt_CDS1 = {'label':'geneA', 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['blue']} -opt_CDS2 = {'label':'geneB', 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['dark_grey']} -opt_CDS3 = {'label':'geneC', 'label_color': (1,1,1), 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['purple']} -opt_CDS4 = {'label':'geneD', 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['red']} -opt_CDS5 = {'label':'geneE', 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['light_grey']} -opt_UD1 = {'label':'Z', 'label_color': (1,0,0), 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['orange']} +opt_CDS1 = { + "label": "geneA", + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["blue"], +} +opt_CDS2 = { + "label": "geneB", + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["dark_grey"], +} +opt_CDS3 = { + "label": "geneC", + "label_color": (1, 1, 1), + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["purple"], +} +opt_CDS4 = { + "label": "geneD", + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["red"], +} +opt_CDS5 = { + "label": "geneE", + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["light_grey"], +} +opt_UD1 = { + "label": "Z", + "label_color": (1, 0, 0), + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["orange"], +} # Design of the construct for each of the 3 reading frames -P1 = {'type':'Promoter', 'name':'P1', 'start':0, 'end':23, 'fwd':True, 'opts':{'color':col_map['green']}} -RBS1 = {'type':'RBS', 'name':'RBS1', 'start':72, 'end':106, 'fwd':True, 'opts':{'color':col_map['blue']}} -RBS2 = {'type':'RBS', 'name':'RBS2', 'start':1353, 'end':1392, 'fwd':True, 'opts':{'color':col_map['blue']}} -CDS1 = {'type':'CDS', 'name':'CDS1', 'start':106, 'end':1249, 'fwd':True, 'opts':opt_CDS1} -CDS2 = {'type':'CDS', 'name':'CDS2', 'start':1392, 'end':2595, 'fwd':True, 'opts':opt_CDS2} -CDS3 = {'type':'CDS', 'name':'CDS3', 'start':800, 'end':1400, 'fwd':True, 'opts':opt_CDS3} -CDS4 = {'type':'CDS', 'name':'CDS4', 'start':1700, 'end':2200, 'fwd':True, 'opts':opt_CDS4} -Feature3_4 = {'type':'UserDefined', 'name':'UD1', 'start':1450, 'end':1650, 'fwd':True, 'opts':opt_UD1} - -CDS5 = {'type':'CDS', 'name':'CDS5', 'start':1500, 'end':100, 'fwd':False, 'opts':opt_CDS5} -T1 = {'type':'Terminator', 'name':'T1', 'start':2595, 'end':2643, 'fwd':True, 'opts':{'color':col_map['red']}} +P1 = { + "type": "Promoter", + "name": "P1", + "start": 0, + "end": 23, + "fwd": True, + "opts": {"color": col_map["green"]}, +} +RBS1 = { + "type": "RBS", + "name": "RBS1", + "start": 72, + "end": 106, + "fwd": True, + "opts": {"color": col_map["blue"]}, +} +RBS2 = { + "type": "RBS", + "name": "RBS2", + "start": 1353, + "end": 1392, + "fwd": True, + "opts": {"color": col_map["blue"]}, +} +CDS1 = { + "type": "CDS", + "name": "CDS1", + "start": 106, + "end": 1249, + "fwd": True, + "opts": opt_CDS1, +} +CDS2 = { + "type": "CDS", + "name": "CDS2", + "start": 1392, + "end": 2595, + "fwd": True, + "opts": opt_CDS2, +} +CDS3 = { + "type": "CDS", + "name": "CDS3", + "start": 800, + "end": 1400, + "fwd": True, + "opts": opt_CDS3, +} +CDS4 = { + "type": "CDS", + "name": "CDS4", + "start": 1700, + "end": 2200, + "fwd": True, + "opts": opt_CDS4, +} +Feature3_4 = { + "type": "UserDefined", + "name": "UD1", + "start": 1450, + "end": 1650, + "fwd": True, + "opts": opt_UD1, +} + +CDS5 = { + "type": "CDS", + "name": "CDS5", + "start": 1500, + "end": 100, + "fwd": False, + "opts": opt_CDS5, +} +T1 = { + "type": "Terminator", + "name": "T1", + "start": 2595, + "end": 2643, + "fwd": True, + "opts": {"color": col_map["red"]}, +} # A design is merely a list of parts and their properties design_frame1 = [P1, RBS1, CDS1, RBS2, CDS2, T1] @@ -55,90 +157,128 @@ designs = [design_frame1, design_frame2, design_frame3] # Plot the DNA diagrams as three seperate axes -def plot_trace_3_axes (designs, output_prefix): - design_frame1 = designs[0] - design_frame2 = designs[1] - design_frame3 = designs[2] - - # Create the figure and all axes to draw to - fig = plt.figure(figsize=(3.2,1.2)) - gs = gridspec.GridSpec(3, 1, height_ratios=[0.5,0.5,0.75]) - ax_dna_frame1 = plt.subplot(gs[2]) - ax_dna_frame2 = plt.subplot(gs[1], sharex=ax_dna_frame1) - ax_dna_frame3 = plt.subplot(gs[0], sharex=ax_dna_frame1) - - # Redender the DNA - dr = dpl.DNARenderer(scale=5, linewidth=0.9) - start1, end1 = dr.renderDNA(ax_dna_frame1, design_frame1, dr.trace_part_renderers(), plot_backbone=True) - dna_len = end1-start1 - ax_dna_frame1.set_xlim([start1-20, end1+20]) - ax_dna_frame1.set_ylim([-3.5,7]) - # We also plot a manual backbone beyond the extent of the design - ax_dna_frame1.plot([start1-20,end1+20], [0,0], color=(0,0,0), linewidth=1.0, zorder=1) - ax_dna_frame1.axis('off') - - start2, end2 = dr.renderDNA(ax_dna_frame2, design_frame2, dr.trace_part_renderers(), plot_backbone=False) - ax_dna_frame2.set_ylim([-3.5,3.5]) - ax_dna_frame2.axis('off') - - start3, end3 = dr.renderDNA(ax_dna_frame3, design_frame3, dr.trace_part_renderers(), plot_backbone=False) - ax_dna_frame3.set_ylim([-3.5,3.5]) - ax_dna_frame3.axis('off') - - plt.subplots_adjust(hspace=.001, left=.01, right=.99, top=0.99, bottom=0.01) - # Save the figure - fig.savefig(output_prefix+'.pdf', transparent=True) - fig.savefig(output_prefix+'.png', dpi=300) - # Clear the plotting cache - plt.close('all') - -plot_trace_3_axes(designs, 'offset_features_3axes') +def plot_trace_3_axes(designs, output_prefix): + design_frame1 = designs[0] + design_frame2 = designs[1] + design_frame3 = designs[2] + + # Create the figure and all axes to draw to + fig = plt.figure(figsize=(3.2, 1.2)) + gs = gridspec.GridSpec(3, 1, height_ratios=[0.5, 0.5, 0.75]) + ax_dna_frame1 = plt.subplot(gs[2]) + ax_dna_frame2 = plt.subplot(gs[1], sharex=ax_dna_frame1) + ax_dna_frame3 = plt.subplot(gs[0], sharex=ax_dna_frame1) + + # Redender the DNA + dr = dpl.DNARenderer(scale=5, linewidth=0.9) + start1, end1 = dr.renderDNA( + ax_dna_frame1, + design_frame1, + dr.trace_part_renderers(), + plot_backbone=True, + ) + dna_len = end1 - start1 + ax_dna_frame1.set_xlim([start1 - 20, end1 + 20]) + ax_dna_frame1.set_ylim([-3.5, 7]) + # We also plot a manual backbone beyond the extent of the design + ax_dna_frame1.plot( + [start1 - 20, end1 + 20], + [0, 0], + color=(0, 0, 0), + linewidth=1.0, + zorder=1, + ) + ax_dna_frame1.axis("off") + + start2, end2 = dr.renderDNA( + ax_dna_frame2, + design_frame2, + dr.trace_part_renderers(), + plot_backbone=False, + ) + ax_dna_frame2.set_ylim([-3.5, 3.5]) + ax_dna_frame2.axis("off") + + start3, end3 = dr.renderDNA( + ax_dna_frame3, + design_frame3, + dr.trace_part_renderers(), + plot_backbone=False, + ) + ax_dna_frame3.set_ylim([-3.5, 3.5]) + ax_dna_frame3.axis("off") + + plt.subplots_adjust( + hspace=0.001, left=0.01, right=0.99, top=0.99, bottom=0.01 + ) + # Save the figure + fig.savefig(output_prefix + ".pdf", transparent=True) + fig.savefig(output_prefix + ".png", dpi=300) + # Clear the plotting cache + plt.close("all") + + +plot_trace_3_axes(designs, "offset_features_3axes") # Plot the DNA diagrams as single axis with y_offsets for alternative frames -def plot_trace_y_offset (designs, output_prefix): - design_frame1 = designs[0] - design_frame2 = designs[1] - design_frame3 = designs[2] - # Generate the offsets for each design - frame2_offset = 9.0 - for part in design_frame2: - if 'opts' in list(part.keys()): - part['opts']['y_offset'] = frame2_offset - else: - part['opts'] = {'y_offset': frame2_offset} - frame3_offset = 16.0 - for part in design_frame3: - if 'opts' in list(part.keys()): - part['opts']['y_offset'] = frame3_offset - else: - part['opts'] = {'y_offset': frame3_offset} - # We can now combine all into a single design - combined_designs = design_frame1 + design_frame2 + design_frame3 - - # Create the figure and all axes to draw to - fig = plt.figure(figsize=(3.2,1.2)) - gs = gridspec.GridSpec(1, 1) - ax_dna_all_frames = plt.subplot(gs[0]) - - # Redender the DNA - dr = dpl.DNARenderer(scale=5, linewidth=0.9) - start1, end1 = dr.renderDNA(ax_dna_all_frames, combined_designs, dr.trace_part_renderers(), plot_backbone=True) - # We specify the length manually as we know the design constraints - start1 = 0 - end1 = 2640 - dna_len = end1-start1 - ax_dna_all_frames.set_xlim([start1-20, end1+20]) - ax_dna_all_frames.set_ylim([-5,21]) - # We also plot a manual backbone beyond the extent of the design - ax_dna_all_frames.plot([start1-20,end1+20], [0,0], color=(0,0,0), linewidth=1.0, zorder=1) - ax_dna_all_frames.axis('off') - - plt.subplots_adjust(hspace=.001, left=.01, right=.99, top=0.99, bottom=0.01) - # Save the figure - fig.savefig(output_prefix+'.pdf', transparent=True) - fig.savefig(output_prefix+'.png', dpi=300) - # Clear the plotting cache - plt.close('all') +def plot_trace_y_offset(designs, output_prefix): + design_frame1 = designs[0] + design_frame2 = designs[1] + design_frame3 = designs[2] + # Generate the offsets for each design + frame2_offset = 9.0 + for part in design_frame2: + if "opts" in list(part.keys()): + part["opts"]["y_offset"] = frame2_offset + else: + part["opts"] = {"y_offset": frame2_offset} + frame3_offset = 16.0 + for part in design_frame3: + if "opts" in list(part.keys()): + part["opts"]["y_offset"] = frame3_offset + else: + part["opts"] = {"y_offset": frame3_offset} + # We can now combine all into a single design + combined_designs = design_frame1 + design_frame2 + design_frame3 + + # Create the figure and all axes to draw to + fig = plt.figure(figsize=(3.2, 1.2)) + gs = gridspec.GridSpec(1, 1) + ax_dna_all_frames = plt.subplot(gs[0]) + + # Redender the DNA + dr = dpl.DNARenderer(scale=5, linewidth=0.9) + start1, end1 = dr.renderDNA( + ax_dna_all_frames, + combined_designs, + dr.trace_part_renderers(), + plot_backbone=True, + ) + # We specify the length manually as we know the design constraints + start1 = 0 + end1 = 2640 + dna_len = end1 - start1 + ax_dna_all_frames.set_xlim([start1 - 20, end1 + 20]) + ax_dna_all_frames.set_ylim([-5, 21]) + # We also plot a manual backbone beyond the extent of the design + ax_dna_all_frames.plot( + [start1 - 20, end1 + 20], + [0, 0], + color=(0, 0, 0), + linewidth=1.0, + zorder=1, + ) + ax_dna_all_frames.axis("off") + + plt.subplots_adjust( + hspace=0.001, left=0.01, right=0.99, top=0.99, bottom=0.01 + ) + # Save the figure + fig.savefig(output_prefix + ".pdf", transparent=True) + fig.savefig(output_prefix + ".png", dpi=300) + # Clear the plotting cache + plt.close("all") + # This call will update the y_offset of the designs - we don't deep copy -plot_trace_y_offset(designs, 'offset_features_y_offset') +plot_trace_y_offset(designs, "offset_features_y_offset") diff --git a/dnaplotlib/gallery/offset_features/offset_features.py b/dnaplotlib/gallery/offset_features/offset_features.py index b1394ec..feab882 100755 --- a/dnaplotlib/gallery/offset_features/offset_features.py +++ b/dnaplotlib/gallery/offset_features/offset_features.py @@ -9,43 +9,145 @@ import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Color maps for formatting col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) -col_map['yellow'] = (0.98, 0.97, 0.35) -col_map['grey'] = (0.70, 0.70, 0.70) -col_map['dark_grey'] = (0.60, 0.60, 0.60) -col_map['light_grey'] = (0.9, 0.9, 0.9) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) +col_map["yellow"] = (0.98, 0.97, 0.35) +col_map["grey"] = (0.70, 0.70, 0.70) +col_map["dark_grey"] = (0.60, 0.60, 0.60) +col_map["light_grey"] = (0.9, 0.9, 0.9) # CDS formatting options -opt_CDS1 = {'label':'geneA', 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['blue']} -opt_CDS2 = {'label':'geneB', 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['dark_grey']} -opt_CDS3 = {'label':'geneC', 'label_color': (1,1,1), 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['purple']} -opt_CDS4 = {'label':'geneD', 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['red']} -opt_CDS5 = {'label':'geneE', 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['light_grey']} -opt_UD1 = {'label':'Z', 'label_color': (1,0,0), 'label_style':'italic', 'label_y_offset':-0.2, 'color':col_map['orange']} +opt_CDS1 = { + "label": "geneA", + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["blue"], +} +opt_CDS2 = { + "label": "geneB", + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["dark_grey"], +} +opt_CDS3 = { + "label": "geneC", + "label_color": (1, 1, 1), + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["purple"], +} +opt_CDS4 = { + "label": "geneD", + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["red"], +} +opt_CDS5 = { + "label": "geneE", + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["light_grey"], +} +opt_UD1 = { + "label": "Z", + "label_color": (1, 0, 0), + "label_style": "italic", + "label_y_offset": -0.2, + "color": col_map["orange"], +} # Design of the construct for each of the 3 reading frames -P1 = {'type':'Promoter', 'name':'P1', 'start':0, 'end':23, 'fwd':True, 'opts':{'color':col_map['green']}} -RBS1 = {'type':'RBS', 'name':'RBS1', 'start':72, 'end':106, 'fwd':True, 'opts':{'color':col_map['blue']}} -RBS2 = {'type':'RBS', 'name':'RBS2', 'start':1353, 'end':1392, 'fwd':True, 'opts':{'color':col_map['blue']}} -CDS1 = {'type':'CDS', 'name':'CDS1', 'start':106, 'end':1249, 'fwd':True, 'opts':opt_CDS1} -CDS2 = {'type':'CDS', 'name':'CDS2', 'start':1392, 'end':2595, 'fwd':True, 'opts':opt_CDS2} -CDS3 = {'type':'CDS', 'name':'CDS3', 'start':800, 'end':1400, 'fwd':True, 'opts':opt_CDS3} -CDS4 = {'type':'CDS', 'name':'CDS4', 'start':1700, 'end':2200, 'fwd':True, 'opts':opt_CDS4} -Feature3_4 = {'type':'UserDefined', 'name':'UD1', 'start':1450, 'end':1650, 'fwd':True, 'opts':opt_UD1} - -CDS5 = {'type':'CDS', 'name':'CDS5', 'start':1500, 'end':100, 'fwd':False, 'opts':opt_CDS5} -T1 = {'type':'Terminator', 'name':'T1', 'start':2595, 'end':2643, 'fwd':True, 'opts':{'color':col_map['red']}} +P1 = { + "type": "Promoter", + "name": "P1", + "start": 0, + "end": 23, + "fwd": True, + "opts": {"color": col_map["green"]}, +} +RBS1 = { + "type": "RBS", + "name": "RBS1", + "start": 72, + "end": 106, + "fwd": True, + "opts": {"color": col_map["blue"]}, +} +RBS2 = { + "type": "RBS", + "name": "RBS2", + "start": 1353, + "end": 1392, + "fwd": True, + "opts": {"color": col_map["blue"]}, +} +CDS1 = { + "type": "CDS", + "name": "CDS1", + "start": 106, + "end": 1249, + "fwd": True, + "opts": opt_CDS1, +} +CDS2 = { + "type": "CDS", + "name": "CDS2", + "start": 1392, + "end": 2595, + "fwd": True, + "opts": opt_CDS2, +} +CDS3 = { + "type": "CDS", + "name": "CDS3", + "start": 800, + "end": 1400, + "fwd": True, + "opts": opt_CDS3, +} +CDS4 = { + "type": "CDS", + "name": "CDS4", + "start": 1700, + "end": 2200, + "fwd": True, + "opts": opt_CDS4, +} +Feature3_4 = { + "type": "UserDefined", + "name": "UD1", + "start": 1450, + "end": 1650, + "fwd": True, + "opts": opt_UD1, +} + +CDS5 = { + "type": "CDS", + "name": "CDS5", + "start": 1500, + "end": 100, + "fwd": False, + "opts": opt_CDS5, +} +T1 = { + "type": "Terminator", + "name": "T1", + "start": 2595, + "end": 2643, + "fwd": True, + "opts": {"color": col_map["red"]}, +} # A design is merely a list of parts and their properties design_frame1 = [P1, RBS1, CDS1, RBS2, CDS2, T1] @@ -55,90 +157,128 @@ designs = [design_frame1, design_frame2, design_frame3] # Plot the DNA diagrams as three seperate axes -def plot_trace_3_axes (designs, output_prefix): - design_frame1 = designs[0] - design_frame2 = designs[1] - design_frame3 = designs[2] - - # Create the figure and all axes to draw to - fig = plt.figure(figsize=(3.2,1.2)) - gs = gridspec.GridSpec(3, 1, height_ratios=[0.5,0.5,0.75]) - ax_dna_frame1 = plt.subplot(gs[2]) - ax_dna_frame2 = plt.subplot(gs[1], sharex=ax_dna_frame1) - ax_dna_frame3 = plt.subplot(gs[0], sharex=ax_dna_frame1) - - # Redender the DNA - dr = dpl.DNARenderer(scale=5, linewidth=0.9) - start1, end1 = dr.renderDNA(ax_dna_frame1, design_frame1, dr.trace_part_renderers(), plot_backbone=True) - dna_len = end1-start1 - ax_dna_frame1.set_xlim([start1-20, end1+20]) - ax_dna_frame1.set_ylim([-3.5,7]) - # We also plot a manual backbone beyond the extent of the design - ax_dna_frame1.plot([start1-20,end1+20], [0,0], color=(0,0,0), linewidth=1.0, zorder=1) - ax_dna_frame1.axis('off') - - start2, end2 = dr.renderDNA(ax_dna_frame2, design_frame2, dr.trace_part_renderers(), plot_backbone=False) - ax_dna_frame2.set_ylim([-3.5,3.5]) - ax_dna_frame2.axis('off') - - start3, end3 = dr.renderDNA(ax_dna_frame3, design_frame3, dr.trace_part_renderers(), plot_backbone=False) - ax_dna_frame3.set_ylim([-3.5,3.5]) - ax_dna_frame3.axis('off') - - plt.subplots_adjust(hspace=.001, left=.01, right=.99, top=0.99, bottom=0.01) - # Save the figure - fig.savefig(output_prefix+'.pdf', transparent=True) - fig.savefig(output_prefix+'.png', dpi=300) - # Clear the plotting cache - plt.close('all') - -plot_trace_3_axes(designs, 'offset_features_3axes') +def plot_trace_3_axes(designs, output_prefix): + design_frame1 = designs[0] + design_frame2 = designs[1] + design_frame3 = designs[2] + + # Create the figure and all axes to draw to + fig = plt.figure(figsize=(3.2, 1.2)) + gs = gridspec.GridSpec(3, 1, height_ratios=[0.5, 0.5, 0.75]) + ax_dna_frame1 = plt.subplot(gs[2]) + ax_dna_frame2 = plt.subplot(gs[1], sharex=ax_dna_frame1) + ax_dna_frame3 = plt.subplot(gs[0], sharex=ax_dna_frame1) + + # Redender the DNA + dr = dpl.DNARenderer(scale=5, linewidth=0.9) + start1, end1 = dr.renderDNA( + ax_dna_frame1, + design_frame1, + dr.trace_part_renderers(), + plot_backbone=True, + ) + dna_len = end1 - start1 + ax_dna_frame1.set_xlim([start1 - 20, end1 + 20]) + ax_dna_frame1.set_ylim([-3.5, 7]) + # We also plot a manual backbone beyond the extent of the design + ax_dna_frame1.plot( + [start1 - 20, end1 + 20], + [0, 0], + color=(0, 0, 0), + linewidth=1.0, + zorder=1, + ) + ax_dna_frame1.axis("off") + + start2, end2 = dr.renderDNA( + ax_dna_frame2, + design_frame2, + dr.trace_part_renderers(), + plot_backbone=False, + ) + ax_dna_frame2.set_ylim([-3.5, 3.5]) + ax_dna_frame2.axis("off") + + start3, end3 = dr.renderDNA( + ax_dna_frame3, + design_frame3, + dr.trace_part_renderers(), + plot_backbone=False, + ) + ax_dna_frame3.set_ylim([-3.5, 3.5]) + ax_dna_frame3.axis("off") + + plt.subplots_adjust( + hspace=0.001, left=0.01, right=0.99, top=0.99, bottom=0.01 + ) + # Save the figure + fig.savefig(output_prefix + ".pdf", transparent=True) + fig.savefig(output_prefix + ".png", dpi=300) + # Clear the plotting cache + plt.close("all") + + +plot_trace_3_axes(designs, "offset_features_3axes") # Plot the DNA diagrams as single axis with y_offsets for alternative frames -def plot_trace_y_offset (designs, output_prefix): - design_frame1 = designs[0] - design_frame2 = designs[1] - design_frame3 = designs[2] - # Generate the offsets for each design - frame2_offset = 9.0 - for part in design_frame2: - if 'opts' in list(part.keys()): - part['opts']['y_offset'] = frame2_offset - else: - part['opts'] = {'y_offset': frame2_offset} - frame3_offset = 16.0 - for part in design_frame3: - if 'opts' in list(part.keys()): - part['opts']['y_offset'] = frame3_offset - else: - part['opts'] = {'y_offset': frame3_offset} - # We can now combine all into a single design - combined_designs = design_frame1 + design_frame2 + design_frame3 - - # Create the figure and all axes to draw to - fig = plt.figure(figsize=(3.2,1.2)) - gs = gridspec.GridSpec(1, 1) - ax_dna_all_frames = plt.subplot(gs[0]) - - # Redender the DNA - dr = dpl.DNARenderer(scale=5, linewidth=0.9) - start1, end1 = dr.renderDNA(ax_dna_all_frames, combined_designs, dr.trace_part_renderers(), plot_backbone=True) - # We specify the length manually as we know the design constraints - start1 = 0 - end1 = 2640 - dna_len = end1-start1 - ax_dna_all_frames.set_xlim([start1-20, end1+20]) - ax_dna_all_frames.set_ylim([-5,21]) - # We also plot a manual backbone beyond the extent of the design - ax_dna_all_frames.plot([start1-20,end1+20], [0,0], color=(0,0,0), linewidth=1.0, zorder=1) - ax_dna_all_frames.axis('off') - - plt.subplots_adjust(hspace=.001, left=.01, right=.99, top=0.99, bottom=0.01) - # Save the figure - fig.savefig(output_prefix+'.pdf', transparent=True) - fig.savefig(output_prefix+'.png', dpi=300) - # Clear the plotting cache - plt.close('all') +def plot_trace_y_offset(designs, output_prefix): + design_frame1 = designs[0] + design_frame2 = designs[1] + design_frame3 = designs[2] + # Generate the offsets for each design + frame2_offset = 9.0 + for part in design_frame2: + if "opts" in list(part.keys()): + part["opts"]["y_offset"] = frame2_offset + else: + part["opts"] = {"y_offset": frame2_offset} + frame3_offset = 16.0 + for part in design_frame3: + if "opts" in list(part.keys()): + part["opts"]["y_offset"] = frame3_offset + else: + part["opts"] = {"y_offset": frame3_offset} + # We can now combine all into a single design + combined_designs = design_frame1 + design_frame2 + design_frame3 + + # Create the figure and all axes to draw to + fig = plt.figure(figsize=(3.2, 1.2)) + gs = gridspec.GridSpec(1, 1) + ax_dna_all_frames = plt.subplot(gs[0]) + + # Redender the DNA + dr = dpl.DNARenderer(scale=5, linewidth=0.9) + start1, end1 = dr.renderDNA( + ax_dna_all_frames, + combined_designs, + dr.trace_part_renderers(), + plot_backbone=True, + ) + # We specify the length manually as we know the design constraints + start1 = 0 + end1 = 2640 + dna_len = end1 - start1 + ax_dna_all_frames.set_xlim([start1 - 20, end1 + 20]) + ax_dna_all_frames.set_ylim([-5, 21]) + # We also plot a manual backbone beyond the extent of the design + ax_dna_all_frames.plot( + [start1 - 20, end1 + 20], + [0, 0], + color=(0, 0, 0), + linewidth=1.0, + zorder=1, + ) + ax_dna_all_frames.axis("off") + + plt.subplots_adjust( + hspace=0.001, left=0.01, right=0.99, top=0.99, bottom=0.01 + ) + # Save the figure + fig.savefig(output_prefix + ".pdf", transparent=True) + fig.savefig(output_prefix + ".png", dpi=300) + # Clear the plotting cache + plt.close("all") + # This call will update the y_offset of the designs - we don't deep copy -plot_trace_y_offset(designs, 'offset_features_y_offset') +plot_trace_y_offset(designs, "offset_features_y_offset") diff --git a/dnaplotlib/gallery/recombinase_array/recombinase_array.py b/dnaplotlib/gallery/recombinase_array/recombinase_array.py index 5078382..3ff9e5f 100755 --- a/dnaplotlib/gallery/recombinase_array/recombinase_array.py +++ b/dnaplotlib/gallery/recombinase_array/recombinase_array.py @@ -13,244 +13,709 @@ from matplotlib.patheffects import Stroke import matplotlib.patches as patches -__author__ = 'Bryan Der , Voigt Lab, MIT\n\ - Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' - -def sbol_recombinase1 (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ SBOL recombinase site renderer - forward direction - """ - # Default parameters - color = (0,0,0) - color2 = (0,0,0) - start_pad = 0.0 - end_pad = 0.0 - x_extent = 6.0 - y_extent = 6.0 - linestyle = '-' - # Update default parameters if provided - if opts != None: - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'color2' in list(opts.keys()): - color2 = opts['color2'] - # Check direction add start padding - final_end = end - final_start = prev_end - y_lower = -1 * y_extent/2 - y_upper = y_extent/2 - if start > end: - start = prev_end+end_pad+x_extent+linewidth - end = prev_end+end_pad - final_end = start+start_pad - color = color2 - else: - start = prev_end+start_pad+linewidth - end = start+x_extent - final_end = end+end_pad - # Draw the site - p1 = Polygon([(start, y_lower), - (start, y_upper), - (end,0)], - edgecolor=(0,0,0), facecolor=color, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p1) - # Add a label if needed - if opts != None and 'label' in list(opts.keys()): - if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) - else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) - # Return the final start and end positions to the DNA renderer - if final_start > final_end: - return prev_end, final_start - else: - return prev_end, final_end - -def sbol_recombinase2 (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ SBOL recombinase site renderer - reverse direction - """ - # Default parameters - color = (0,0,0) - color2 = (0,0,0) - start_pad = 0.0 - end_pad = 0.0 - x_extent = 6.0 - y_extent = 6.0 - linestyle = '-' - # Update default parameters if provided - if opts != None: - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'color2' in list(opts.keys()): - color2 = opts['color2'] - else: - if 'color' in list(opts.keys()): - r2 = float(color[0]) / 2 - g2 = float(color[1]) / 2 - b2 = float(color[2]) / 2 - color2 = (r2,g2,b2) - # Check direction add start padding - final_end = end - final_start = prev_end - y_lower = -1 * y_extent/2 - y_upper = y_extent/2 - if start > end: - start = prev_end+end_pad+x_extent+linewidth - end = prev_end+end_pad - final_end = start+start_pad - temp = color - color = color2 - color2 = temp - else: - start = prev_end+start_pad+linewidth - end = start+x_extent - final_end = end+end_pad - # Draw the site - p1 = Polygon([(start, y_lower), - (start, y_upper), - (end,0)], - edgecolor=(0,0,0), facecolor=color, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - midpoint = (end + start) / 2 - hypotenuse = math.sqrt( (y_extent/2)**2 + (x_extent)**2 ) - hypotenuse2 = hypotenuse / 2 - cosineA = (y_extent/2) / hypotenuse - f = hypotenuse2 * cosineA - p2 = Polygon([(midpoint, -1*f), - (midpoint, f), - (end,0)], - edgecolor=(0,0,0), facecolor=color2, linewidth=linewidth, zorder=12, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p1) - ax.add_patch(p2) - # Add a label if needed - if opts != None and 'label' in list(opts.keys()): - if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) - else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) - # Return the final start and end positions to the DNA renderer - if final_start > final_end: - return prev_end, final_start - else: - return prev_end, final_end - -def flip_arrow (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Regulation arcs for recombinase sites - """ - # Default parameters - color = (0.0,0.0,0.0) - arcHeightStart = 10 - arcHeightEnd = 10 - # Update default parameters if provided - if opts != None: - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'arc_height_start' in list(opts.keys()): - arcHeightStart = opts['arc_height_start'] - if 'arc_height_end' in list(opts.keys()): - arcHeightEnd = opts['arc_height_end'] - start = (from_part['start'] + from_part['end']) / 2 - end = (to_part['start'] + to_part['end']) / 2 - # Check direction and draw arc - if start > end: - arcHeightStart = -arcHeightStart - arcHeightEnd = -arcHeightEnd - ax.annotate('', (end, arcHeightEnd), (start, arcHeightStart), ha="right", va="center", size=8, arrowprops=dict(arrowstyle='->',connectionstyle="arc3,rad=-.4",lw=linewidth, color=color)) +__author__ = "Bryan Der , Voigt Lab, MIT\n\ + Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" + + +def sbol_recombinase1( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """SBOL recombinase site renderer - forward direction""" + # Default parameters + color = (0, 0, 0) + color2 = (0, 0, 0) + start_pad = 0.0 + end_pad = 0.0 + x_extent = 6.0 + y_extent = 6.0 + linestyle = "-" + # Update default parameters if provided + if opts != None: + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "color" in list(opts.keys()): + color = opts["color"] + if "color2" in list(opts.keys()): + color2 = opts["color2"] + # Check direction add start padding + final_end = end + final_start = prev_end + y_lower = -1 * y_extent / 2 + y_upper = y_extent / 2 + if start > end: + start = prev_end + end_pad + x_extent + linewidth + end = prev_end + end_pad + final_end = start + start_pad + color = color2 + else: + start = prev_end + start_pad + linewidth + end = start + x_extent + final_end = end + end_pad + # Draw the site + p1 = Polygon( + [(start, y_lower), (start, y_upper), (end, 0)], + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p1) + # Add a label if needed + if opts != None and "label" in list(opts.keys()): + if final_start > final_end: + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) + else: + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) + # Return the final start and end positions to the DNA renderer + if final_start > final_end: + return prev_end, final_start + else: + return prev_end, final_end + + +def sbol_recombinase2( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """SBOL recombinase site renderer - reverse direction""" + # Default parameters + color = (0, 0, 0) + color2 = (0, 0, 0) + start_pad = 0.0 + end_pad = 0.0 + x_extent = 6.0 + y_extent = 6.0 + linestyle = "-" + # Update default parameters if provided + if opts != None: + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "color" in list(opts.keys()): + color = opts["color"] + if "color2" in list(opts.keys()): + color2 = opts["color2"] + else: + if "color" in list(opts.keys()): + r2 = float(color[0]) / 2 + g2 = float(color[1]) / 2 + b2 = float(color[2]) / 2 + color2 = (r2, g2, b2) + # Check direction add start padding + final_end = end + final_start = prev_end + y_lower = -1 * y_extent / 2 + y_upper = y_extent / 2 + if start > end: + start = prev_end + end_pad + x_extent + linewidth + end = prev_end + end_pad + final_end = start + start_pad + temp = color + color = color2 + color2 = temp + else: + start = prev_end + start_pad + linewidth + end = start + x_extent + final_end = end + end_pad + # Draw the site + p1 = Polygon( + [(start, y_lower), (start, y_upper), (end, 0)], + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + midpoint = (end + start) / 2 + hypotenuse = math.sqrt((y_extent / 2) ** 2 + (x_extent) ** 2) + hypotenuse2 = hypotenuse / 2 + cosineA = (y_extent / 2) / hypotenuse + f = hypotenuse2 * cosineA + p2 = Polygon( + [(midpoint, -1 * f), (midpoint, f), (end, 0)], + edgecolor=(0, 0, 0), + facecolor=color2, + linewidth=linewidth, + zorder=12, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p1) + ax.add_patch(p2) + # Add a label if needed + if opts != None and "label" in list(opts.keys()): + if final_start > final_end: + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) + else: + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) + # Return the final start and end positions to the DNA renderer + if final_start > final_end: + return prev_end, final_start + else: + return prev_end, final_end + + +def flip_arrow( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Regulation arcs for recombinase sites""" + # Default parameters + color = (0.0, 0.0, 0.0) + arcHeightStart = 10 + arcHeightEnd = 10 + # Update default parameters if provided + if opts != None: + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "color" in list(opts.keys()): + color = opts["color"] + if "arc_height_start" in list(opts.keys()): + arcHeightStart = opts["arc_height_start"] + if "arc_height_end" in list(opts.keys()): + arcHeightEnd = opts["arc_height_end"] + start = (from_part["start"] + from_part["end"]) / 2 + end = (to_part["start"] + to_part["end"]) / 2 + # Check direction and draw arc + if start > end: + arcHeightStart = -arcHeightStart + arcHeightEnd = -arcHeightEnd + ax.annotate( + "", + (end, arcHeightEnd), + (start, arcHeightStart), + ha="right", + va="center", + size=8, + arrowprops=dict( + arrowstyle="->", + connectionstyle="arc3,rad=-.4", + lw=linewidth, + color=color, + ), + ) + # Color maps col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) # Function to darken a colour -def dark (col, fac=2.0): - return (col[0]/fac, col[1]/fac, col[2]/fac) +def dark(col, fac=2.0): + return (col[0] / fac, col[1] / fac, col[2] / fac) + # Create parts for the constructs -sp = {'type':'EmptySpace', 'name':'S1', 'fwd':True} - -a1 = {'type':'RecombinaseSite', 'name':'a1', 'fwd':True, 'opts':{'color':col_map['red'], 'color2':dark(col_map['red']), 'x_extent':16, 'y_extent':12}} -a2 = {'type':'RecombinaseSite', 'name':'a2', 'fwd':False, 'opts':{'color':col_map['red'], 'color2':dark(col_map['red']), 'x_extent':16, 'y_extent':12}} -a1f = {'type':'RecombinaseSite2', 'name':'a1f', 'fwd':True, 'opts':{'color':col_map['red'], 'color2':dark(col_map['red']), 'x_extent':16, 'y_extent':12}} -a2f = {'type':'RecombinaseSite2', 'name':'a2f', 'fwd':False, 'opts':{'color':col_map['red'], 'color2':dark(col_map['red']), 'x_extent':16, 'y_extent':12}} - -b1 = {'type':'RecombinaseSite', 'name':'d1', 'fwd':True, 'opts':{'color':col_map['green'], 'color2':dark(col_map['green']), 'x_extent':16, 'y_extent':12}} -b2 = {'type':'RecombinaseSite', 'name':'d2', 'fwd':False, 'opts':{'color':col_map['green'], 'color2':dark(col_map['green']), 'x_extent':16, 'y_extent':12}} -b1f = {'type':'RecombinaseSite2', 'name':'d1f', 'fwd':True, 'opts':{'color':col_map['green'], 'color2':dark(col_map['green']), 'x_extent':16, 'y_extent':12}} -b2f = {'type':'RecombinaseSite2', 'name':'d2f', 'fwd':False, 'opts':{'color':col_map['green'], 'color2':dark(col_map['green']), 'x_extent':16, 'y_extent':12}} - -c1 = {'type':'RecombinaseSite', 'name':'e1', 'fwd':True, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12}} -c2 = {'type':'RecombinaseSite', 'name':'e2', 'fwd':False, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12}} -c1f = {'type':'RecombinaseSite2', 'name':'e1f', 'fwd':True, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12}} -c2f = {'type':'RecombinaseSite2', 'name':'e2f', 'fwd':False, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12}} - -d1 = {'type':'RecombinaseSite', 'name':'f1', 'fwd':True, 'opts':{'color':col_map['purple'], 'color2':dark(col_map['purple']), 'x_extent':16, 'y_extent':12}} -d2 = {'type':'RecombinaseSite', 'name':'f2', 'fwd':False, 'opts':{'color':col_map['purple'], 'color2':dark(col_map['purple']), 'x_extent':16, 'y_extent':12}} -d1f = {'type':'RecombinaseSite2', 'name':'f1f', 'fwd':True, 'opts':{'color':col_map['purple'], 'color2':dark(col_map['purple']), 'x_extent':16, 'y_extent':12}} -d2f = {'type':'RecombinaseSite2', 'name':'f2f', 'fwd':False, 'opts':{'color':col_map['purple'], 'color2':dark(col_map['purple']), 'color2':dark(col_map['purple']), 'x_extent':16, 'y_extent':12}} - -e1 = {'type':'RecombinaseSite', 'name':'h1', 'fwd':True, 'opts':{'color':col_map['orange'], 'color2':dark(col_map['orange']), 'x_extent':16, 'y_extent':12}} -e2 = {'type':'RecombinaseSite', 'name':'h2', 'fwd':False, 'opts':{'color':col_map['orange'], 'color2':dark(col_map['orange']), 'x_extent':16, 'y_extent':12}} -e1f = {'type':'RecombinaseSite2', 'name':'h1f', 'fwd':True, 'opts':{'color':col_map['orange'], 'color2':dark(col_map['orange']), 'x_extent':16, 'y_extent':12}} -e2f = {'type':'RecombinaseSite2', 'name':'h2f', 'fwd':False, 'opts':{'color':col_map['orange'], 'color2':dark(col_map['orange']), 'x_extent':16, 'y_extent':12}} - -x1 = {'type':'RecombinaseSite', 'name':'x1', 'fwd':True, 'opts':{'color':(0.6,0.6,0.6), 'color2':dark((0.6,0.6,0.6)), 'x_extent':16, 'y_extent':12}} -x2 = {'type':'RecombinaseSite', 'name':'x2', 'fwd':False, 'opts':{'color':(0.6,0.6,0.6), 'color2':dark((0.6,0.6,0.6)), 'x_extent':16, 'y_extent':12}} -x1f = {'type':'RecombinaseSite2', 'name':'x1f', 'fwd':True, 'opts':{'color':(0.6,0.6,0.6), 'color2':dark((0.6,0.6,0.6)), 'x_extent':16, 'y_extent':12}} -x2f = {'type':'RecombinaseSite2', 'name':'x2f', 'fwd':False, 'opts':{'color':(0.6,0.6,0.6), 'color2':dark((0.6,0.6,0.6)), 'x_extent':16, 'y_extent':12}} +sp = {"type": "EmptySpace", "name": "S1", "fwd": True} + +a1 = { + "type": "RecombinaseSite", + "name": "a1", + "fwd": True, + "opts": { + "color": col_map["red"], + "color2": dark(col_map["red"]), + "x_extent": 16, + "y_extent": 12, + }, +} +a2 = { + "type": "RecombinaseSite", + "name": "a2", + "fwd": False, + "opts": { + "color": col_map["red"], + "color2": dark(col_map["red"]), + "x_extent": 16, + "y_extent": 12, + }, +} +a1f = { + "type": "RecombinaseSite2", + "name": "a1f", + "fwd": True, + "opts": { + "color": col_map["red"], + "color2": dark(col_map["red"]), + "x_extent": 16, + "y_extent": 12, + }, +} +a2f = { + "type": "RecombinaseSite2", + "name": "a2f", + "fwd": False, + "opts": { + "color": col_map["red"], + "color2": dark(col_map["red"]), + "x_extent": 16, + "y_extent": 12, + }, +} + +b1 = { + "type": "RecombinaseSite", + "name": "d1", + "fwd": True, + "opts": { + "color": col_map["green"], + "color2": dark(col_map["green"]), + "x_extent": 16, + "y_extent": 12, + }, +} +b2 = { + "type": "RecombinaseSite", + "name": "d2", + "fwd": False, + "opts": { + "color": col_map["green"], + "color2": dark(col_map["green"]), + "x_extent": 16, + "y_extent": 12, + }, +} +b1f = { + "type": "RecombinaseSite2", + "name": "d1f", + "fwd": True, + "opts": { + "color": col_map["green"], + "color2": dark(col_map["green"]), + "x_extent": 16, + "y_extent": 12, + }, +} +b2f = { + "type": "RecombinaseSite2", + "name": "d2f", + "fwd": False, + "opts": { + "color": col_map["green"], + "color2": dark(col_map["green"]), + "x_extent": 16, + "y_extent": 12, + }, +} + +c1 = { + "type": "RecombinaseSite", + "name": "e1", + "fwd": True, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + }, +} +c2 = { + "type": "RecombinaseSite", + "name": "e2", + "fwd": False, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + }, +} +c1f = { + "type": "RecombinaseSite2", + "name": "e1f", + "fwd": True, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + }, +} +c2f = { + "type": "RecombinaseSite2", + "name": "e2f", + "fwd": False, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + }, +} + +d1 = { + "type": "RecombinaseSite", + "name": "f1", + "fwd": True, + "opts": { + "color": col_map["purple"], + "color2": dark(col_map["purple"]), + "x_extent": 16, + "y_extent": 12, + }, +} +d2 = { + "type": "RecombinaseSite", + "name": "f2", + "fwd": False, + "opts": { + "color": col_map["purple"], + "color2": dark(col_map["purple"]), + "x_extent": 16, + "y_extent": 12, + }, +} +d1f = { + "type": "RecombinaseSite2", + "name": "f1f", + "fwd": True, + "opts": { + "color": col_map["purple"], + "color2": dark(col_map["purple"]), + "x_extent": 16, + "y_extent": 12, + }, +} +d2f = { + "type": "RecombinaseSite2", + "name": "f2f", + "fwd": False, + "opts": { + "color": col_map["purple"], + "color2": dark(col_map["purple"]), + "color2": dark(col_map["purple"]), + "x_extent": 16, + "y_extent": 12, + }, +} + +e1 = { + "type": "RecombinaseSite", + "name": "h1", + "fwd": True, + "opts": { + "color": col_map["orange"], + "color2": dark(col_map["orange"]), + "x_extent": 16, + "y_extent": 12, + }, +} +e2 = { + "type": "RecombinaseSite", + "name": "h2", + "fwd": False, + "opts": { + "color": col_map["orange"], + "color2": dark(col_map["orange"]), + "x_extent": 16, + "y_extent": 12, + }, +} +e1f = { + "type": "RecombinaseSite2", + "name": "h1f", + "fwd": True, + "opts": { + "color": col_map["orange"], + "color2": dark(col_map["orange"]), + "x_extent": 16, + "y_extent": 12, + }, +} +e2f = { + "type": "RecombinaseSite2", + "name": "h2f", + "fwd": False, + "opts": { + "color": col_map["orange"], + "color2": dark(col_map["orange"]), + "x_extent": 16, + "y_extent": 12, + }, +} + +x1 = { + "type": "RecombinaseSite", + "name": "x1", + "fwd": True, + "opts": { + "color": (0.6, 0.6, 0.6), + "color2": dark((0.6, 0.6, 0.6)), + "x_extent": 16, + "y_extent": 12, + }, +} +x2 = { + "type": "RecombinaseSite", + "name": "x2", + "fwd": False, + "opts": { + "color": (0.6, 0.6, 0.6), + "color2": dark((0.6, 0.6, 0.6)), + "x_extent": 16, + "y_extent": 12, + }, +} +x1f = { + "type": "RecombinaseSite2", + "name": "x1f", + "fwd": True, + "opts": { + "color": (0.6, 0.6, 0.6), + "color2": dark((0.6, 0.6, 0.6)), + "x_extent": 16, + "y_extent": 12, + }, +} +x2f = { + "type": "RecombinaseSite2", + "name": "x2f", + "fwd": False, + "opts": { + "color": (0.6, 0.6, 0.6), + "color2": dark((0.6, 0.6, 0.6)), + "x_extent": 16, + "y_extent": 12, + }, +} # Define the designs -design1 = [sp, a1,sp,a2, b1,sp,b2, c1,sp,c2, d1,sp,d2, e1,sp,e2, x1,sp,x2, sp] -design2 = [sp, a1f,sp,a2f, b1,sp,b2, c1,sp,c2, d1,sp,d2, e1,sp,e2, x1f,sp,x2f, sp] -design3 = [sp, a1f,sp,a2f, b1,sp,b2, c1f,sp,c2f, d1f,sp,d2f, e1,sp,e2, x1f,sp,x2f, sp] -design4 = [sp, a1f,sp,a2f, b1f,sp,b2f, c1f,sp,c2f, d1f,sp,d2f, e1,sp,e2, x1f,sp,x2f, sp] +design1 = [ + sp, + a1, + sp, + a2, + b1, + sp, + b2, + c1, + sp, + c2, + d1, + sp, + d2, + e1, + sp, + e2, + x1, + sp, + x2, + sp, +] +design2 = [ + sp, + a1f, + sp, + a2f, + b1, + sp, + b2, + c1, + sp, + c2, + d1, + sp, + d2, + e1, + sp, + e2, + x1f, + sp, + x2f, + sp, +] +design3 = [ + sp, + a1f, + sp, + a2f, + b1, + sp, + b2, + c1f, + sp, + c2f, + d1f, + sp, + d2f, + e1, + sp, + e2, + x1f, + sp, + x2f, + sp, +] +design4 = [ + sp, + a1f, + sp, + a2f, + b1f, + sp, + b2f, + c1f, + sp, + c2f, + d1f, + sp, + d2f, + e1, + sp, + e2, + x1f, + sp, + x2f, + sp, +] # Potential regulation arcs that might be present -arc_a = {'type':'Connection', 'from_part':a1, 'to_part':a2, 'opts':{'color':col_map['red'], 'linewidth':1.0, 'arc_height_start':10, 'arc_height_end':10}} -arc_b = {'type':'Connection', 'from_part':b1, 'to_part':b2, 'opts':{'color':col_map['green'], 'linewidth':1.0, 'arc_height_start':10, 'arc_height_end':10}} -arc_c = {'type':'Connection', 'from_part':c1, 'to_part':c2, 'opts':{'color':col_map['blue'], 'linewidth':1.0, 'arc_height_start':10, 'arc_height_end':10}} -arc_d = {'type':'Connection', 'from_part':d1, 'to_part':d2, 'opts':{'color':col_map['purple'], 'linewidth':1.0, 'arc_height_start':10, 'arc_height_end':10}} -arc_e = {'type':'Connection', 'from_part':e1, 'to_part':e2, 'opts':{'color':col_map['orange'], 'linewidth':1.0, 'arc_height_start':10, 'arc_height_end':10}} -arc_x = {'type':'Connection', 'from_part':x1, 'to_part':x2, 'opts':{'color':(0.6,0.6,0.6), 'linewidth':1.0, 'arc_height_start':10, 'arc_height_end':10}} -arc_ar = {'type':'Connection', 'from_part':a2f, 'to_part':a1f, 'opts':{'color':col_map['red'], 'linewidth':1.0, 'arc_height_start':10, 'arc_height_end':10}} -arc_er = {'type':'Connection', 'from_part':e2f, 'to_part':e1f, 'opts':{'color':col_map['orange'], 'linewidth':1.0, 'arc_height_start':10, 'arc_height_end':10}} -arc_xr = {'type':'Connection', 'from_part':x2f, 'to_part':x1f, 'opts':{'color':(0.6,0.6,0.6), 'linewidth':1.0, 'arc_height_start':10, 'arc_height_end':10}} +arc_a = { + "type": "Connection", + "from_part": a1, + "to_part": a2, + "opts": { + "color": col_map["red"], + "linewidth": 1.0, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc_b = { + "type": "Connection", + "from_part": b1, + "to_part": b2, + "opts": { + "color": col_map["green"], + "linewidth": 1.0, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc_c = { + "type": "Connection", + "from_part": c1, + "to_part": c2, + "opts": { + "color": col_map["blue"], + "linewidth": 1.0, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc_d = { + "type": "Connection", + "from_part": d1, + "to_part": d2, + "opts": { + "color": col_map["purple"], + "linewidth": 1.0, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc_e = { + "type": "Connection", + "from_part": e1, + "to_part": e2, + "opts": { + "color": col_map["orange"], + "linewidth": 1.0, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc_x = { + "type": "Connection", + "from_part": x1, + "to_part": x2, + "opts": { + "color": (0.6, 0.6, 0.6), + "linewidth": 1.0, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc_ar = { + "type": "Connection", + "from_part": a2f, + "to_part": a1f, + "opts": { + "color": col_map["red"], + "linewidth": 1.0, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc_er = { + "type": "Connection", + "from_part": e2f, + "to_part": e1f, + "opts": { + "color": col_map["orange"], + "linewidth": 1.0, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc_xr = { + "type": "Connection", + "from_part": x2f, + "to_part": x1f, + "opts": { + "color": (0.6, 0.6, 0.6), + "linewidth": 1.0, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} # Define the regulation at each stage reg1 = [arc_a, arc_x] @@ -258,7 +723,7 @@ def dark (col, fac=2.0): reg3 = [arc_b] # Create the figure and axes -fig = plt.figure(figsize=(2.8,2.0)) +fig = plt.figure(figsize=(2.8, 2.0)) gs = gridspec.GridSpec(4, 1) ax_dna1 = plt.subplot(gs[0]) ax_dna2 = plt.subplot(gs[1]) @@ -271,71 +736,87 @@ def dark (col, fac=2.0): reg_renderers = dr.std_reg_renderers() part_renderers = dr.SBOL_part_renderers() # Append the user defined renderers -reg_renderers['Connection'] = flip_arrow -part_renderers['RecombinaseSite'] = sbol_recombinase1 -part_renderers['RecombinaseSite2'] = sbol_recombinase2 +reg_renderers["Connection"] = flip_arrow +part_renderers["RecombinaseSite"] = sbol_recombinase1 +part_renderers["RecombinaseSite2"] = sbol_recombinase2 # Will go through the design and add label of binary state def label_binary_state(design, ax): - for part in design: - if part['type'] == 'RecombinaseSite' and part['fwd'] == True: - # 0 state - ax.text(part['start']+20, -14.5, '0', fontsize=8, - horizontalalignment='left', verticalalignment='bottom') - elif part['type'] == 'RecombinaseSite2' and part['fwd'] == True: - # 1 state - ax.text(part['start']+20, -14.5, '1', fontsize=8, - horizontalalignment='left', verticalalignment='bottom') + for part in design: + if part["type"] == "RecombinaseSite" and part["fwd"] == True: + # 0 state + ax.text( + part["start"] + 20, + -14.5, + "0", + fontsize=8, + horizontalalignment="left", + verticalalignment="bottom", + ) + elif part["type"] == "RecombinaseSite2" and part["fwd"] == True: + # 1 state + ax.text( + part["start"] + 20, + -14.5, + "1", + fontsize=8, + horizontalalignment="left", + verticalalignment="bottom", + ) + # Render the array -start, end = dr.renderDNA(ax_dna1, design1, part_renderers, - regs=reg1, reg_renderers=reg_renderers) +start, end = dr.renderDNA( + ax_dna1, design1, part_renderers, regs=reg1, reg_renderers=reg_renderers +) label_binary_state(design1, ax_dna1) ax_dna1.set_xlim([start, end]) -ax_dna1.set_ylim([-15,15]) -ax_dna1.set_aspect('equal') +ax_dna1.set_ylim([-15, 15]) +ax_dna1.set_aspect("equal") ax_dna1.set_xticks([]) ax_dna1.set_yticks([]) -ax_dna1.axis('off') +ax_dna1.axis("off") # Render the array -start, end = dr.renderDNA(ax_dna2, design2, part_renderers, - regs=reg2, reg_renderers=reg_renderers) +start, end = dr.renderDNA( + ax_dna2, design2, part_renderers, regs=reg2, reg_renderers=reg_renderers +) label_binary_state(design2, ax_dna2) ax_dna2.set_xlim([start, end]) -ax_dna2.set_ylim([-15,15]) -ax_dna2.set_aspect('equal') +ax_dna2.set_ylim([-15, 15]) +ax_dna2.set_aspect("equal") ax_dna2.set_xticks([]) ax_dna2.set_yticks([]) -ax_dna2.axis('off') +ax_dna2.axis("off") # Render the array -start, end = dr.renderDNA(ax_dna3, design3, part_renderers, - regs=reg3, reg_renderers=reg_renderers) +start, end = dr.renderDNA( + ax_dna3, design3, part_renderers, regs=reg3, reg_renderers=reg_renderers +) label_binary_state(design3, ax_dna3) ax_dna3.set_xlim([start, end]) -ax_dna3.set_ylim([-15,15]) -ax_dna3.set_aspect('equal') +ax_dna3.set_ylim([-15, 15]) +ax_dna3.set_aspect("equal") ax_dna3.set_xticks([]) ax_dna3.set_yticks([]) -ax_dna3.axis('off') +ax_dna3.axis("off") # Render the array (final array has no regulation) start, end = dr.renderDNA(ax_dna4, design4, part_renderers) label_binary_state(design4, ax_dna4) ax_dna4.set_xlim([start, end]) -ax_dna4.set_ylim([-15,15]) -ax_dna4.set_aspect('equal') +ax_dna4.set_ylim([-15, 15]) +ax_dna4.set_aspect("equal") ax_dna4.set_xticks([]) ax_dna4.set_yticks([]) -ax_dna4.axis('off') +ax_dna4.axis("off") # Set bounds and display options for the axes plt.subplots_adjust(hspace=0.01, left=0.05, right=0.95, top=0.99, bottom=0.01) # Save the figure -fig.savefig('recombinase_array.pdf', transparent=True) -fig.savefig('recombinase_array.png', dpi=300) +fig.savefig("recombinase_array.pdf", transparent=True) +fig.savefig("recombinase_array.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/recombinase_not_gate/recombinase_not_gate 2.py b/dnaplotlib/gallery/recombinase_not_gate/recombinase_not_gate 2.py index 492911c..c7dfd9a 100644 --- a/dnaplotlib/gallery/recombinase_not_gate/recombinase_not_gate 2.py +++ b/dnaplotlib/gallery/recombinase_not_gate/recombinase_not_gate 2.py @@ -13,194 +13,244 @@ from matplotlib.patheffects import Stroke import matplotlib.patches as patches -__author__ = 'Bryan Der , Voigt Lab, MIT\n\ - Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Bryan Der , Voigt Lab, MIT\n\ + Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" -def sbol_recombinase1 (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ SBOL recombinase site renderer - forward direction - """ - # Default parameters - color = (0,0,0) - color2 = (0,0,0) - start_pad = 0.0 - end_pad = 0.0 - x_extent = 6.0 - y_extent = 6.0 - linestyle = '-' - # Update default parameters if provided - if opts != None: - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'color2' in list(opts.keys()): - color2 = opts['color2'] - # Check direction add start padding - final_end = end - final_start = prev_end - y_lower = -1 * y_extent/2 - y_upper = y_extent/2 - if start > end: - start = prev_end+end_pad+x_extent+linewidth - end = prev_end+end_pad - final_end = start+start_pad - color = color2 - else: - start = prev_end+start_pad+linewidth - end = start+x_extent - final_end = end+end_pad - # Draw the site - p1 = Polygon([(start, y_lower), - (start, y_upper), - (end,0)], - edgecolor=(0,0,0), facecolor=color, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p1) - # Add a label if needed - if opts != None and 'label' in list(opts.keys()): - if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) - else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) - # Return the final start and end positions to the DNA renderer - if final_start > final_end: - return prev_end, final_start - else: - return prev_end, final_end -def sbol_recombinase2 (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ SBOL recombinase site renderer - reverse direction - """ - # Default parameters - color = (0,0,0) - color2 = (0,0,0) - start_pad = 0.0 - end_pad = 0.0 - x_extent = 6.0 - y_extent = 6.0 - linestyle = '-' - # Update default parameters if provided - if opts != None: - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'color2' in list(opts.keys()): - color2 = opts['color2'] - else: - if 'color' in list(opts.keys()): - r2 = float(color[0]) / 2 - g2 = float(color[1]) / 2 - b2 = float(color[2]) / 2 - color2 = (r2,g2,b2) - # Check direction add start padding - final_end = end - final_start = prev_end - y_lower = -1 * y_extent/2 - y_upper = y_extent/2 - if start > end: - start = prev_end+end_pad+x_extent+linewidth - end = prev_end+end_pad - final_end = start+start_pad - temp = color - color = color2 - color2 = temp - else: - start = prev_end+start_pad+linewidth - end = start+x_extent - final_end = end+end_pad - # Draw the site - p1 = Polygon([(start, y_lower), - (start, y_upper), - (end,0)], - edgecolor=(0,0,0), facecolor=color, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - midpoint = (end + start) / 2 - hypotenuse = math.sqrt( (y_extent/2)**2 + (x_extent)**2 ) - hypotenuse2 = hypotenuse / 2 - cosineA = (y_extent/2) / hypotenuse - f = hypotenuse2 * cosineA - p2 = Polygon([(midpoint, -1*f), - (midpoint, f), - (end,0)], - edgecolor=(0,0,0), facecolor=color2, linewidth=linewidth, zorder=12, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p1) - ax.add_patch(p2) - # Add a label if needed - if opts != None and 'label' in list(opts.keys()): - if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) - else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) - # Return the final start and end positions to the DNA renderer - if final_start > final_end: - return prev_end, final_start - else: - return prev_end, final_end +def sbol_recombinase1( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """SBOL recombinase site renderer - forward direction""" + # Default parameters + color = (0, 0, 0) + color2 = (0, 0, 0) + start_pad = 0.0 + end_pad = 0.0 + x_extent = 6.0 + y_extent = 6.0 + linestyle = "-" + # Update default parameters if provided + if opts != None: + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "color" in list(opts.keys()): + color = opts["color"] + if "color2" in list(opts.keys()): + color2 = opts["color2"] + # Check direction add start padding + final_end = end + final_start = prev_end + y_lower = -1 * y_extent / 2 + y_upper = y_extent / 2 + if start > end: + start = prev_end + end_pad + x_extent + linewidth + end = prev_end + end_pad + final_end = start + start_pad + color = color2 + else: + start = prev_end + start_pad + linewidth + end = start + x_extent + final_end = end + end_pad + # Draw the site + p1 = Polygon( + [(start, y_lower), (start, y_upper), (end, 0)], + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p1) + # Add a label if needed + if opts != None and "label" in list(opts.keys()): + if final_start > final_end: + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) + else: + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) + # Return the final start and end positions to the DNA renderer + if final_start > final_end: + return prev_end, final_start + else: + return prev_end, final_end -def flip_arrow (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Regulation arcs for recombinase sites - """ - # Default parameters - color = (0.0,0.0,0.0) - arcHeightStart = 10 - arcHeightEnd = 10 - # Update default parameters if provided - if opts != None: - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'arc_height_start' in list(opts.keys()): - arcHeightStart = opts['arc_height_start'] - if 'arc_height_end' in list(opts.keys()): - arcHeightEnd = opts['arc_height_end'] - start = (from_part['start'] + from_part['end']) / 2 - end = (to_part['start'] + to_part['end']) / 2 - # Check direction and draw arc - if start > end: - arcHeightStart = -arcHeightStart - arcHeightEnd = -arcHeightEnd - ax.annotate('', (end, arcHeightEnd), (start, arcHeightStart), ha="right", va="center", size=8, arrowprops=dict(arrowstyle='->',connectionstyle="arc3,rad=-.4",lw=linewidth, color=color)) -# Color maps +def sbol_recombinase2( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """SBOL recombinase site renderer - reverse direction""" + # Default parameters + color = (0, 0, 0) + color2 = (0, 0, 0) + start_pad = 0.0 + end_pad = 0.0 + x_extent = 6.0 + y_extent = 6.0 + linestyle = "-" + # Update default parameters if provided + if opts != None: + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "color" in list(opts.keys()): + color = opts["color"] + if "color2" in list(opts.keys()): + color2 = opts["color2"] + else: + if "color" in list(opts.keys()): + r2 = float(color[0]) / 2 + g2 = float(color[1]) / 2 + b2 = float(color[2]) / 2 + color2 = (r2, g2, b2) + # Check direction add start padding + final_end = end + final_start = prev_end + y_lower = -1 * y_extent / 2 + y_upper = y_extent / 2 + if start > end: + start = prev_end + end_pad + x_extent + linewidth + end = prev_end + end_pad + final_end = start + start_pad + temp = color + color = color2 + color2 = temp + else: + start = prev_end + start_pad + linewidth + end = start + x_extent + final_end = end + end_pad + # Draw the site + p1 = Polygon( + [(start, y_lower), (start, y_upper), (end, 0)], + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + midpoint = (end + start) / 2 + hypotenuse = math.sqrt((y_extent / 2) ** 2 + (x_extent) ** 2) + hypotenuse2 = hypotenuse / 2 + cosineA = (y_extent / 2) / hypotenuse + f = hypotenuse2 * cosineA + p2 = Polygon( + [(midpoint, -1 * f), (midpoint, f), (end, 0)], + edgecolor=(0, 0, 0), + facecolor=color2, + linewidth=linewidth, + zorder=12, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p1) + ax.add_patch(p2) + # Add a label if needed + if opts != None and "label" in list(opts.keys()): + if final_start > final_end: + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) + else: + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) + # Return the final start and end positions to the DNA renderer + if final_start > final_end: + return prev_end, final_start + else: + return prev_end, final_end + + +def flip_arrow( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Regulation arcs for recombinase sites""" + # Default parameters + color = (0.0, 0.0, 0.0) + arcHeightStart = 10 + arcHeightEnd = 10 + # Update default parameters if provided + if opts != None: + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "color" in list(opts.keys()): + color = opts["color"] + if "arc_height_start" in list(opts.keys()): + arcHeightStart = opts["arc_height_start"] + if "arc_height_end" in list(opts.keys()): + arcHeightEnd = opts["arc_height_end"] + start = (from_part["start"] + from_part["end"]) / 2 + end = (to_part["start"] + to_part["end"]) / 2 + # Check direction and draw arc + if start > end: + arcHeightStart = -arcHeightStart + arcHeightEnd = -arcHeightEnd + ax.annotate( + "", + (end, arcHeightEnd), + (start, arcHeightStart), + ha="right", + va="center", + size=8, + arrowprops=dict( + arrowstyle="->", + connectionstyle="arc3,rad=-.4", + lw=linewidth, + color=color, + ), + ) + + +# Color maps col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) # Function to calculate darker colour -def dark (col, fac=2.0): - return (col[0]/fac, col[1]/fac, col[2]/fac) +def dark(col, fac=2.0): + return (col[0] / fac, col[1] / fac, col[2] / fac) + # Global line width lw = 1.0 @@ -210,72 +260,177 @@ def dark (col, fac=2.0): # Use default renderers and append our custom ones for recombinases reg_renderers = dr.std_reg_renderers() -reg_renderers['Connection'] = flip_arrow +reg_renderers["Connection"] = flip_arrow part_renderers = dr.SBOL_part_renderers() -part_renderers['RecombinaseSite'] = sbol_recombinase1 -part_renderers['RecombinaseSite2'] = sbol_recombinase2 +part_renderers["RecombinaseSite"] = sbol_recombinase1 +part_renderers["RecombinaseSite2"] = sbol_recombinase2 # Create the construct programmably to plot -sp = {'type':'EmptySpace', 'name':'S1', 'fwd':True, 'opts':{'x_extent':1}} -prom = {'type':'Promoter', 'name':'prom', 'fwd':True} -ins = {'type':'Insulator', 'name':'ins', 'fwd':True} -ribo_r = {'type':'Ribozyme', 'name':'ribo', 'fwd':False} -rbs_r = {'type':'RBS', 'name':'rbs', 'fwd':False, 'opts':{'color':(0.0,0.0,0.0)}} -cds_r = {'type':'CDS', 'name':'cds', 'fwd':False, 'opts':{'color':(0.5,0.5,0.5), 'label':'GFP', 'label_x_offset':2, 'label_y_offset':0.5, 'label_rotation':180, 'label_style':'italic'}} -term = {'type':'Terminator', 'name':'term', 'fwd':True} -rec1f = {'type':'RecombinaseSite', 'name':'a1', 'fwd':True, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12, 'start_pad':3, 'end_pad':3}} -rec1r = {'type':'RecombinaseSite', 'name':'a1', 'fwd':False, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12, 'start_pad':3, 'end_pad':3}} -rec2f = {'type':'RecombinaseSite2', 'name':'a1f', 'fwd':True, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12, 'start_pad':3, 'end_pad':3}} -rec2r = {'type':'RecombinaseSite2', 'name':'a1f', 'fwd':False, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12, 'start_pad':3, 'end_pad':3}} -ribo_f = {'type':'Ribozyme', 'name':'ribo', 'fwd':True} -rbs_f = {'type':'RBS', 'name':'rbs', 'fwd':True, 'opts':{'color':(0.0,0.0,0.0)}} -cds_f = {'type':'CDS', 'name':'cds', 'fwd':True, 'opts':{'color':col_map['green'], 'label':'GFP', 'label_x_offset':-2, 'label_y_offset':-0.5, 'label_style':'italic'}} +sp = {"type": "EmptySpace", "name": "S1", "fwd": True, "opts": {"x_extent": 1}} +prom = {"type": "Promoter", "name": "prom", "fwd": True} +ins = {"type": "Insulator", "name": "ins", "fwd": True} +ribo_r = {"type": "Ribozyme", "name": "ribo", "fwd": False} +rbs_r = { + "type": "RBS", + "name": "rbs", + "fwd": False, + "opts": {"color": (0.0, 0.0, 0.0)}, +} +cds_r = { + "type": "CDS", + "name": "cds", + "fwd": False, + "opts": { + "color": (0.5, 0.5, 0.5), + "label": "GFP", + "label_x_offset": 2, + "label_y_offset": 0.5, + "label_rotation": 180, + "label_style": "italic", + }, +} +term = {"type": "Terminator", "name": "term", "fwd": True} +rec1f = { + "type": "RecombinaseSite", + "name": "a1", + "fwd": True, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + "start_pad": 3, + "end_pad": 3, + }, +} +rec1r = { + "type": "RecombinaseSite", + "name": "a1", + "fwd": False, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + "start_pad": 3, + "end_pad": 3, + }, +} +rec2f = { + "type": "RecombinaseSite2", + "name": "a1f", + "fwd": True, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + "start_pad": 3, + "end_pad": 3, + }, +} +rec2r = { + "type": "RecombinaseSite2", + "name": "a1f", + "fwd": False, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + "start_pad": 3, + "end_pad": 3, + }, +} +ribo_f = {"type": "Ribozyme", "name": "ribo", "fwd": True} +rbs_f = { + "type": "RBS", + "name": "rbs", + "fwd": True, + "opts": {"color": (0.0, 0.0, 0.0)}, +} +cds_f = { + "type": "CDS", + "name": "cds", + "fwd": True, + "opts": { + "color": col_map["green"], + "label": "GFP", + "label_x_offset": -2, + "label_y_offset": -0.5, + "label_style": "italic", + }, +} design1 = [sp, prom, ins, rec1f, cds_r, rbs_r, ribo_r, rec1r, term, sp] design2 = [sp, prom, ins, rec2f, ribo_f, rbs_f, cds_f, rec2r, term, sp] -arc1 = {'type':'Connection', 'from_part':rec1f, 'to_part':rec1r, 'opts':{'color':col_map['blue'], 'linewidth':lw, 'arc_height_start':10, 'arc_height_end':10}} -arc2 = {'type':'Connection', 'from_part':rec2r, 'to_part':rec2f, 'opts':{'color':col_map['blue'], 'linewidth':lw, 'arc_height_start':10, 'arc_height_end':10}} +arc1 = { + "type": "Connection", + "from_part": rec1f, + "to_part": rec1r, + "opts": { + "color": col_map["blue"], + "linewidth": lw, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc2 = { + "type": "Connection", + "from_part": rec2r, + "to_part": rec2f, + "opts": { + "color": col_map["blue"], + "linewidth": lw, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} reg1 = [arc1] reg2 = [arc2] # Create the figure -fig = plt.figure(figsize=(2.2,1.8)) +fig = plt.figure(figsize=(2.2, 1.8)) gs = gridspec.GridSpec(3, 1) ax_dna1 = plt.subplot(gs[0]) ax_dna2 = plt.subplot(gs[1]) ax_dna3 = plt.subplot(gs[2]) # Redender the DNA to axis -start, end = dr.renderDNA(ax_dna1, design1, part_renderers, regs=reg1, reg_renderers=reg_renderers) +start, end = dr.renderDNA( + ax_dna1, design1, part_renderers, regs=reg1, reg_renderers=reg_renderers +) ax_dna1.set_xlim([start, end]) -ax_dna1.set_ylim([-18,18]) -ax_dna1.set_aspect('equal') +ax_dna1.set_ylim([-18, 18]) +ax_dna1.set_aspect("equal") ax_dna1.set_xticks([]) ax_dna1.set_yticks([]) -ax_dna1.axis('off') -start, end = dr.renderDNA(ax_dna2, design2, part_renderers, regs=reg2, reg_renderers=reg_renderers) +ax_dna1.axis("off") +start, end = dr.renderDNA( + ax_dna2, design2, part_renderers, regs=reg2, reg_renderers=reg_renderers +) ax_dna2.set_xlim([start, end]) -ax_dna2.set_ylim([-18,18]) -ax_dna2.set_aspect('equal') +ax_dna2.set_ylim([-18, 18]) +ax_dna2.set_aspect("equal") ax_dna2.set_xticks([]) ax_dna2.set_yticks([]) -ax_dna2.axis('off') +ax_dna2.axis("off") start, end = dr.renderDNA(ax_dna3, design1, part_renderers) ax_dna3.set_xlim([start, end]) -ax_dna3.set_ylim([-18,18]) -ax_dna3.set_aspect('equal') +ax_dna3.set_ylim([-18, 18]) +ax_dna3.set_aspect("equal") ax_dna3.set_xticks([]) ax_dna3.set_yticks([]) -ax_dna3.axis('off') +ax_dna3.axis("off") # Update subplot spacing plt.subplots_adjust(hspace=0.01, left=0.05, right=0.95, top=0.92, bottom=0.01) # Save the figure -fig.savefig('recombinase_not_gate.pdf', transparent=True) -fig.savefig('recombinase_not_gate.png', dpi=300) +fig.savefig("recombinase_not_gate.pdf", transparent=True) +fig.savefig("recombinase_not_gate.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/recombinase_not_gate/recombinase_not_gate.py b/dnaplotlib/gallery/recombinase_not_gate/recombinase_not_gate.py index 492911c..c7dfd9a 100755 --- a/dnaplotlib/gallery/recombinase_not_gate/recombinase_not_gate.py +++ b/dnaplotlib/gallery/recombinase_not_gate/recombinase_not_gate.py @@ -13,194 +13,244 @@ from matplotlib.patheffects import Stroke import matplotlib.patches as patches -__author__ = 'Bryan Der , Voigt Lab, MIT\n\ - Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Bryan Der , Voigt Lab, MIT\n\ + Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" -def sbol_recombinase1 (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ SBOL recombinase site renderer - forward direction - """ - # Default parameters - color = (0,0,0) - color2 = (0,0,0) - start_pad = 0.0 - end_pad = 0.0 - x_extent = 6.0 - y_extent = 6.0 - linestyle = '-' - # Update default parameters if provided - if opts != None: - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'color2' in list(opts.keys()): - color2 = opts['color2'] - # Check direction add start padding - final_end = end - final_start = prev_end - y_lower = -1 * y_extent/2 - y_upper = y_extent/2 - if start > end: - start = prev_end+end_pad+x_extent+linewidth - end = prev_end+end_pad - final_end = start+start_pad - color = color2 - else: - start = prev_end+start_pad+linewidth - end = start+x_extent - final_end = end+end_pad - # Draw the site - p1 = Polygon([(start, y_lower), - (start, y_upper), - (end,0)], - edgecolor=(0,0,0), facecolor=color, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p1) - # Add a label if needed - if opts != None and 'label' in list(opts.keys()): - if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) - else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) - # Return the final start and end positions to the DNA renderer - if final_start > final_end: - return prev_end, final_start - else: - return prev_end, final_end -def sbol_recombinase2 (ax, type, num, start, end, prev_end, scale, linewidth, opts): - """ SBOL recombinase site renderer - reverse direction - """ - # Default parameters - color = (0,0,0) - color2 = (0,0,0) - start_pad = 0.0 - end_pad = 0.0 - x_extent = 6.0 - y_extent = 6.0 - linestyle = '-' - # Update default parameters if provided - if opts != None: - if 'start_pad' in list(opts.keys()): - start_pad = opts['start_pad'] - if 'end_pad' in list(opts.keys()): - end_pad = opts['end_pad'] - if 'x_extent' in list(opts.keys()): - x_extent = opts['x_extent'] - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'linestyle' in list(opts.keys()): - linestyle = opts['linestyle'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'scale' in list(opts.keys()): - scale = opts['scale'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'color2' in list(opts.keys()): - color2 = opts['color2'] - else: - if 'color' in list(opts.keys()): - r2 = float(color[0]) / 2 - g2 = float(color[1]) / 2 - b2 = float(color[2]) / 2 - color2 = (r2,g2,b2) - # Check direction add start padding - final_end = end - final_start = prev_end - y_lower = -1 * y_extent/2 - y_upper = y_extent/2 - if start > end: - start = prev_end+end_pad+x_extent+linewidth - end = prev_end+end_pad - final_end = start+start_pad - temp = color - color = color2 - color2 = temp - else: - start = prev_end+start_pad+linewidth - end = start+x_extent - final_end = end+end_pad - # Draw the site - p1 = Polygon([(start, y_lower), - (start, y_upper), - (end,0)], - edgecolor=(0,0,0), facecolor=color, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - midpoint = (end + start) / 2 - hypotenuse = math.sqrt( (y_extent/2)**2 + (x_extent)**2 ) - hypotenuse2 = hypotenuse / 2 - cosineA = (y_extent/2) / hypotenuse - f = hypotenuse2 * cosineA - p2 = Polygon([(midpoint, -1*f), - (midpoint, f), - (end,0)], - edgecolor=(0,0,0), facecolor=color2, linewidth=linewidth, zorder=12, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p1) - ax.add_patch(p2) - # Add a label if needed - if opts != None and 'label' in list(opts.keys()): - if final_start > final_end: - write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) - else: - write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) - # Return the final start and end positions to the DNA renderer - if final_start > final_end: - return prev_end, final_start - else: - return prev_end, final_end +def sbol_recombinase1( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """SBOL recombinase site renderer - forward direction""" + # Default parameters + color = (0, 0, 0) + color2 = (0, 0, 0) + start_pad = 0.0 + end_pad = 0.0 + x_extent = 6.0 + y_extent = 6.0 + linestyle = "-" + # Update default parameters if provided + if opts != None: + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "color" in list(opts.keys()): + color = opts["color"] + if "color2" in list(opts.keys()): + color2 = opts["color2"] + # Check direction add start padding + final_end = end + final_start = prev_end + y_lower = -1 * y_extent / 2 + y_upper = y_extent / 2 + if start > end: + start = prev_end + end_pad + x_extent + linewidth + end = prev_end + end_pad + final_end = start + start_pad + color = color2 + else: + start = prev_end + start_pad + linewidth + end = start + x_extent + final_end = end + end_pad + # Draw the site + p1 = Polygon( + [(start, y_lower), (start, y_upper), (end, 0)], + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p1) + # Add a label if needed + if opts != None and "label" in list(opts.keys()): + if final_start > final_end: + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) + else: + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) + # Return the final start and end positions to the DNA renderer + if final_start > final_end: + return prev_end, final_start + else: + return prev_end, final_end -def flip_arrow (ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts): - """ Regulation arcs for recombinase sites - """ - # Default parameters - color = (0.0,0.0,0.0) - arcHeightStart = 10 - arcHeightEnd = 10 - # Update default parameters if provided - if opts != None: - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'color' in list(opts.keys()): - color = opts['color'] - if 'arc_height_start' in list(opts.keys()): - arcHeightStart = opts['arc_height_start'] - if 'arc_height_end' in list(opts.keys()): - arcHeightEnd = opts['arc_height_end'] - start = (from_part['start'] + from_part['end']) / 2 - end = (to_part['start'] + to_part['end']) / 2 - # Check direction and draw arc - if start > end: - arcHeightStart = -arcHeightStart - arcHeightEnd = -arcHeightEnd - ax.annotate('', (end, arcHeightEnd), (start, arcHeightStart), ha="right", va="center", size=8, arrowprops=dict(arrowstyle='->',connectionstyle="arc3,rad=-.4",lw=linewidth, color=color)) -# Color maps +def sbol_recombinase2( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + """SBOL recombinase site renderer - reverse direction""" + # Default parameters + color = (0, 0, 0) + color2 = (0, 0, 0) + start_pad = 0.0 + end_pad = 0.0 + x_extent = 6.0 + y_extent = 6.0 + linestyle = "-" + # Update default parameters if provided + if opts != None: + if "start_pad" in list(opts.keys()): + start_pad = opts["start_pad"] + if "end_pad" in list(opts.keys()): + end_pad = opts["end_pad"] + if "x_extent" in list(opts.keys()): + x_extent = opts["x_extent"] + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "linestyle" in list(opts.keys()): + linestyle = opts["linestyle"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "scale" in list(opts.keys()): + scale = opts["scale"] + if "color" in list(opts.keys()): + color = opts["color"] + if "color2" in list(opts.keys()): + color2 = opts["color2"] + else: + if "color" in list(opts.keys()): + r2 = float(color[0]) / 2 + g2 = float(color[1]) / 2 + b2 = float(color[2]) / 2 + color2 = (r2, g2, b2) + # Check direction add start padding + final_end = end + final_start = prev_end + y_lower = -1 * y_extent / 2 + y_upper = y_extent / 2 + if start > end: + start = prev_end + end_pad + x_extent + linewidth + end = prev_end + end_pad + final_end = start + start_pad + temp = color + color = color2 + color2 = temp + else: + start = prev_end + start_pad + linewidth + end = start + x_extent + final_end = end + end_pad + # Draw the site + p1 = Polygon( + [(start, y_lower), (start, y_upper), (end, 0)], + edgecolor=(0, 0, 0), + facecolor=color, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + midpoint = (end + start) / 2 + hypotenuse = math.sqrt((y_extent / 2) ** 2 + (x_extent) ** 2) + hypotenuse2 = hypotenuse / 2 + cosineA = (y_extent / 2) / hypotenuse + f = hypotenuse2 * cosineA + p2 = Polygon( + [(midpoint, -1 * f), (midpoint, f), (end, 0)], + edgecolor=(0, 0, 0), + facecolor=color2, + linewidth=linewidth, + zorder=12, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p1) + ax.add_patch(p2) + # Add a label if needed + if opts != None and "label" in list(opts.keys()): + if final_start > final_end: + write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) + else: + write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) + # Return the final start and end positions to the DNA renderer + if final_start > final_end: + return prev_end, final_start + else: + return prev_end, final_end + + +def flip_arrow( + ax, type, num, from_part, to_part, scale, linewidth, arc_height_index, opts +): + """Regulation arcs for recombinase sites""" + # Default parameters + color = (0.0, 0.0, 0.0) + arcHeightStart = 10 + arcHeightEnd = 10 + # Update default parameters if provided + if opts != None: + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "color" in list(opts.keys()): + color = opts["color"] + if "arc_height_start" in list(opts.keys()): + arcHeightStart = opts["arc_height_start"] + if "arc_height_end" in list(opts.keys()): + arcHeightEnd = opts["arc_height_end"] + start = (from_part["start"] + from_part["end"]) / 2 + end = (to_part["start"] + to_part["end"]) / 2 + # Check direction and draw arc + if start > end: + arcHeightStart = -arcHeightStart + arcHeightEnd = -arcHeightEnd + ax.annotate( + "", + (end, arcHeightEnd), + (start, arcHeightStart), + ha="right", + va="center", + size=8, + arrowprops=dict( + arrowstyle="->", + connectionstyle="arc3,rad=-.4", + lw=linewidth, + color=color, + ), + ) + + +# Color maps col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) # Function to calculate darker colour -def dark (col, fac=2.0): - return (col[0]/fac, col[1]/fac, col[2]/fac) +def dark(col, fac=2.0): + return (col[0] / fac, col[1] / fac, col[2] / fac) + # Global line width lw = 1.0 @@ -210,72 +260,177 @@ def dark (col, fac=2.0): # Use default renderers and append our custom ones for recombinases reg_renderers = dr.std_reg_renderers() -reg_renderers['Connection'] = flip_arrow +reg_renderers["Connection"] = flip_arrow part_renderers = dr.SBOL_part_renderers() -part_renderers['RecombinaseSite'] = sbol_recombinase1 -part_renderers['RecombinaseSite2'] = sbol_recombinase2 +part_renderers["RecombinaseSite"] = sbol_recombinase1 +part_renderers["RecombinaseSite2"] = sbol_recombinase2 # Create the construct programmably to plot -sp = {'type':'EmptySpace', 'name':'S1', 'fwd':True, 'opts':{'x_extent':1}} -prom = {'type':'Promoter', 'name':'prom', 'fwd':True} -ins = {'type':'Insulator', 'name':'ins', 'fwd':True} -ribo_r = {'type':'Ribozyme', 'name':'ribo', 'fwd':False} -rbs_r = {'type':'RBS', 'name':'rbs', 'fwd':False, 'opts':{'color':(0.0,0.0,0.0)}} -cds_r = {'type':'CDS', 'name':'cds', 'fwd':False, 'opts':{'color':(0.5,0.5,0.5), 'label':'GFP', 'label_x_offset':2, 'label_y_offset':0.5, 'label_rotation':180, 'label_style':'italic'}} -term = {'type':'Terminator', 'name':'term', 'fwd':True} -rec1f = {'type':'RecombinaseSite', 'name':'a1', 'fwd':True, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12, 'start_pad':3, 'end_pad':3}} -rec1r = {'type':'RecombinaseSite', 'name':'a1', 'fwd':False, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12, 'start_pad':3, 'end_pad':3}} -rec2f = {'type':'RecombinaseSite2', 'name':'a1f', 'fwd':True, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12, 'start_pad':3, 'end_pad':3}} -rec2r = {'type':'RecombinaseSite2', 'name':'a1f', 'fwd':False, 'opts':{'color':col_map['blue'], 'color2':dark(col_map['blue']), 'x_extent':16, 'y_extent':12, 'start_pad':3, 'end_pad':3}} -ribo_f = {'type':'Ribozyme', 'name':'ribo', 'fwd':True} -rbs_f = {'type':'RBS', 'name':'rbs', 'fwd':True, 'opts':{'color':(0.0,0.0,0.0)}} -cds_f = {'type':'CDS', 'name':'cds', 'fwd':True, 'opts':{'color':col_map['green'], 'label':'GFP', 'label_x_offset':-2, 'label_y_offset':-0.5, 'label_style':'italic'}} +sp = {"type": "EmptySpace", "name": "S1", "fwd": True, "opts": {"x_extent": 1}} +prom = {"type": "Promoter", "name": "prom", "fwd": True} +ins = {"type": "Insulator", "name": "ins", "fwd": True} +ribo_r = {"type": "Ribozyme", "name": "ribo", "fwd": False} +rbs_r = { + "type": "RBS", + "name": "rbs", + "fwd": False, + "opts": {"color": (0.0, 0.0, 0.0)}, +} +cds_r = { + "type": "CDS", + "name": "cds", + "fwd": False, + "opts": { + "color": (0.5, 0.5, 0.5), + "label": "GFP", + "label_x_offset": 2, + "label_y_offset": 0.5, + "label_rotation": 180, + "label_style": "italic", + }, +} +term = {"type": "Terminator", "name": "term", "fwd": True} +rec1f = { + "type": "RecombinaseSite", + "name": "a1", + "fwd": True, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + "start_pad": 3, + "end_pad": 3, + }, +} +rec1r = { + "type": "RecombinaseSite", + "name": "a1", + "fwd": False, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + "start_pad": 3, + "end_pad": 3, + }, +} +rec2f = { + "type": "RecombinaseSite2", + "name": "a1f", + "fwd": True, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + "start_pad": 3, + "end_pad": 3, + }, +} +rec2r = { + "type": "RecombinaseSite2", + "name": "a1f", + "fwd": False, + "opts": { + "color": col_map["blue"], + "color2": dark(col_map["blue"]), + "x_extent": 16, + "y_extent": 12, + "start_pad": 3, + "end_pad": 3, + }, +} +ribo_f = {"type": "Ribozyme", "name": "ribo", "fwd": True} +rbs_f = { + "type": "RBS", + "name": "rbs", + "fwd": True, + "opts": {"color": (0.0, 0.0, 0.0)}, +} +cds_f = { + "type": "CDS", + "name": "cds", + "fwd": True, + "opts": { + "color": col_map["green"], + "label": "GFP", + "label_x_offset": -2, + "label_y_offset": -0.5, + "label_style": "italic", + }, +} design1 = [sp, prom, ins, rec1f, cds_r, rbs_r, ribo_r, rec1r, term, sp] design2 = [sp, prom, ins, rec2f, ribo_f, rbs_f, cds_f, rec2r, term, sp] -arc1 = {'type':'Connection', 'from_part':rec1f, 'to_part':rec1r, 'opts':{'color':col_map['blue'], 'linewidth':lw, 'arc_height_start':10, 'arc_height_end':10}} -arc2 = {'type':'Connection', 'from_part':rec2r, 'to_part':rec2f, 'opts':{'color':col_map['blue'], 'linewidth':lw, 'arc_height_start':10, 'arc_height_end':10}} +arc1 = { + "type": "Connection", + "from_part": rec1f, + "to_part": rec1r, + "opts": { + "color": col_map["blue"], + "linewidth": lw, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} +arc2 = { + "type": "Connection", + "from_part": rec2r, + "to_part": rec2f, + "opts": { + "color": col_map["blue"], + "linewidth": lw, + "arc_height_start": 10, + "arc_height_end": 10, + }, +} reg1 = [arc1] reg2 = [arc2] # Create the figure -fig = plt.figure(figsize=(2.2,1.8)) +fig = plt.figure(figsize=(2.2, 1.8)) gs = gridspec.GridSpec(3, 1) ax_dna1 = plt.subplot(gs[0]) ax_dna2 = plt.subplot(gs[1]) ax_dna3 = plt.subplot(gs[2]) # Redender the DNA to axis -start, end = dr.renderDNA(ax_dna1, design1, part_renderers, regs=reg1, reg_renderers=reg_renderers) +start, end = dr.renderDNA( + ax_dna1, design1, part_renderers, regs=reg1, reg_renderers=reg_renderers +) ax_dna1.set_xlim([start, end]) -ax_dna1.set_ylim([-18,18]) -ax_dna1.set_aspect('equal') +ax_dna1.set_ylim([-18, 18]) +ax_dna1.set_aspect("equal") ax_dna1.set_xticks([]) ax_dna1.set_yticks([]) -ax_dna1.axis('off') -start, end = dr.renderDNA(ax_dna2, design2, part_renderers, regs=reg2, reg_renderers=reg_renderers) +ax_dna1.axis("off") +start, end = dr.renderDNA( + ax_dna2, design2, part_renderers, regs=reg2, reg_renderers=reg_renderers +) ax_dna2.set_xlim([start, end]) -ax_dna2.set_ylim([-18,18]) -ax_dna2.set_aspect('equal') +ax_dna2.set_ylim([-18, 18]) +ax_dna2.set_aspect("equal") ax_dna2.set_xticks([]) ax_dna2.set_yticks([]) -ax_dna2.axis('off') +ax_dna2.axis("off") start, end = dr.renderDNA(ax_dna3, design1, part_renderers) ax_dna3.set_xlim([start, end]) -ax_dna3.set_ylim([-18,18]) -ax_dna3.set_aspect('equal') +ax_dna3.set_ylim([-18, 18]) +ax_dna3.set_aspect("equal") ax_dna3.set_xticks([]) ax_dna3.set_yticks([]) -ax_dna3.axis('off') +ax_dna3.axis("off") # Update subplot spacing plt.subplots_adjust(hspace=0.01, left=0.05, right=0.95, top=0.92, bottom=0.01) # Save the figure -fig.savefig('recombinase_not_gate.pdf', transparent=True) -fig.savefig('recombinase_not_gate.png', dpi=300) +fig.savefig("recombinase_not_gate.pdf", transparent=True) +fig.savefig("recombinase_not_gate.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/repressilator_animate/repressilator_animate 2.py b/dnaplotlib/gallery/repressilator_animate/repressilator_animate 2.py index d0895cb..dcb7503 100644 --- a/dnaplotlib/gallery/repressilator_animate/repressilator_animate 2.py +++ b/dnaplotlib/gallery/repressilator_animate/repressilator_animate 2.py @@ -9,9 +9,9 @@ import matplotlib.pyplot as plt from matplotlib import gridspec -__author__ = 'Emerson Glassey , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Emerson Glassey , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Initialize Simulation # Initial concentration of mRNA and Protein for each repressor @@ -29,126 +29,269 @@ # tetr is orange [1.00, 0.75, 0.17] # lacI is green [0.38, 0.82, 0.32] # gamma is blue [0.38, 0.65, 0.87] -plac = {'name':'P_lac', 'start':1, 'end':10, 'type':'Promoter', 'opts': {'color':[0.38, 0.82, 0.32]}} -rbs1 = {'name':'RBS', 'start':11, 'end':20, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -tetr = {'name':'tetR', 'start':21, 'end':40, 'type':'CDS', 'opts':{'label': '', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -2, 'label_style':'italic', 'color':[1.00, 0.75, 0.17]}} -term1 = {'name':'Term', 'start':41, 'end':55, 'type':'Terminator'} -pgamma = {'name':'P_gamma', 'start':56, 'end':65, 'type':'Promoter', 'opts': {'color':[0.38, 0.65, 0.87]}} -rbs2 = {'name':'RBS', 'start':66, 'end':75, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -laci = {'name':'lacI', 'start':76, 'end':95, 'type':'CDS', 'opts':{'label': '', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -2, 'label_style':'italic', 'color':[0.38, 0.82, 0.32]}} -term2 = {'name':'Term', 'start':96, 'end':110, 'type':'Terminator'} -ptet = {'name':'P_tet', 'start':111, 'end':120, 'type':'Promoter', 'opts': {'color':[1.00, 0.75, 0.17]}} -rbs3 = {'name':'RBS', 'start':121, 'end':130, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -gamma = {'name':'gamma', 'start':131, 'end':150, 'type':'CDS', 'opts':{'label': '', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -1, 'label_style':'italic', 'color':[0.38, 0.65, 0.87]}} -term3 = {'name':'Term', 'start':151, 'end':165, 'type':'Terminator'} - -lac_repress = {'from_part':laci, 'to_part':plac, 'type':'Repression', 'opts':{'linewidth':1, 'color':[0.38, 0.82, 0.32]}} -gamma_repress = {'from_part':gamma, 'to_part':pgamma, 'type':'Repression', 'opts':{'linewidth':1, 'color':[0.38, 0.65, 0.87]}} -tet_repress = {'from_part':tetr, 'to_part':ptet, 'type':'Repression', 'opts':{'linewidth':1, 'color':[1.00, 0.75, 0.17]}} +plac = { + "name": "P_lac", + "start": 1, + "end": 10, + "type": "Promoter", + "opts": {"color": [0.38, 0.82, 0.32]}, +} +rbs1 = { + "name": "RBS", + "start": 11, + "end": 20, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +tetr = { + "name": "tetR", + "start": 21, + "end": 40, + "type": "CDS", + "opts": { + "label": "", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -2, + "label_style": "italic", + "color": [1.00, 0.75, 0.17], + }, +} +term1 = {"name": "Term", "start": 41, "end": 55, "type": "Terminator"} +pgamma = { + "name": "P_gamma", + "start": 56, + "end": 65, + "type": "Promoter", + "opts": {"color": [0.38, 0.65, 0.87]}, +} +rbs2 = { + "name": "RBS", + "start": 66, + "end": 75, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +laci = { + "name": "lacI", + "start": 76, + "end": 95, + "type": "CDS", + "opts": { + "label": "", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -2, + "label_style": "italic", + "color": [0.38, 0.82, 0.32], + }, +} +term2 = {"name": "Term", "start": 96, "end": 110, "type": "Terminator"} +ptet = { + "name": "P_tet", + "start": 111, + "end": 120, + "type": "Promoter", + "opts": {"color": [1.00, 0.75, 0.17]}, +} +rbs3 = { + "name": "RBS", + "start": 121, + "end": 130, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +gamma = { + "name": "gamma", + "start": 131, + "end": 150, + "type": "CDS", + "opts": { + "label": "", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -1, + "label_style": "italic", + "color": [0.38, 0.65, 0.87], + }, +} +term3 = {"name": "Term", "start": 151, "end": 165, "type": "Terminator"} + +lac_repress = { + "from_part": laci, + "to_part": plac, + "type": "Repression", + "opts": {"linewidth": 1, "color": [0.38, 0.82, 0.32]}, +} +gamma_repress = { + "from_part": gamma, + "to_part": pgamma, + "type": "Repression", + "opts": {"linewidth": 1, "color": [0.38, 0.65, 0.87]}, +} +tet_repress = { + "from_part": tetr, + "to_part": ptet, + "type": "Repression", + "opts": {"linewidth": 1, "color": [1.00, 0.75, 0.17]}, +} + def repressilator(y, t): mtet, mlac, mgamma, tet, lac, gamma = y - - dmtet = -mtet + (alpha / (1 + lac**n)) + leak + + dmtet = -mtet + (alpha / (1 + lac ** n)) + leak dtet = -beta * (tet - mtet) - - dmlac = -mlac + (alpha / (1 + gamma**n)) + leak + + dmlac = -mlac + (alpha / (1 + gamma ** n)) + leak dlac = -beta * (lac - mlac) - - dmgamma = -mgamma + (alpha / (1 + tet**n)) + leak + + dmgamma = -mgamma + (alpha / (1 + tet ** n)) + leak dgamma = -beta * (gamma - mgamma) return [dmtet, dmlac, dmgamma, dtet, dlac, dgamma] + def repression(val, Kd, power): """Function takes a value and Kd. Function fits the value to a hill function with n=power and Kd and returns the fraction bound.""" - new_val = val**power / (Kd**power + val** power) + new_val = val ** power / (Kd ** power + val ** power) return new_val - + + def expression(val, lims): """function takes a value between two limits (as a tuple) and returns the value normalized by the limits to be between 0 and 1""" new_val = (val - lims[0]) / (lims[1] - lims[0]) return new_val + def rescale(val, lims): """function takes a value between 0 and 1 and normalizes it between the limits in lims""" - new_val = (val*(lims[1]-lims[0])) + lims[0] + new_val = (val * (lims[1] - lims[0])) + lims[0] return new_val - + + def plot_construct(ax, t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma): - tind = int(t*10) - exp_lims = (1.0, 4.0) - # Set color for each of the CDSs - tetr['opts']['color'] = [rescale(1 - expression(ymtet[tind], exp_lims), (1.0, 1.0)), - rescale(1 - expression(ymtet[tind], exp_lims), (0.75, 1.0)), - rescale(1 - expression(ymtet[tind], exp_lims), (0.17, 1.0))] - laci['opts']['color'] = [rescale(1 - expression(ymlac[tind], exp_lims), (0.38, 1.0)), - rescale(1 - expression(ymlac[tind], exp_lims), (0.82, 1.0)), - rescale(1 - expression(ymlac[tind], exp_lims), (0.32, 1.0))] - gamma['opts']['color'] = [rescale(1 - expression(ymgamma[tind], exp_lims), (0.38, 1.0)), - rescale(1 - expression(ymgamma[tind], exp_lims), (0.65, 1.0)), - rescale(1 - expression(ymgamma[tind], exp_lims), (0.87, 1.0))] - # Set transparency for each of the regulatory lines - lac_repress['opts']['color'] = [0.38, 0.82, 0.32, - rescale(repression(ylac[tind], 2.0, 8), (0.2, 1.0))] - gamma_repress['opts']['color'] = [0.38, 0.65, 0.87, - rescale(repression(ygamma[tind], 2.0, 8), (0.2, 1.0))] - tet_repress['opts']['color'] = [1.00, 0.75, 0.17, - rescale(repression(ytet[tind], 2.0, 8), (0.2, 1.0))] - # Set width for each of the regulatory lines - lac_repress['opts']['linewidth'] = rescale(repression(ylac[tind], 2.0, 8), (0.5, 2.0)) - gamma_repress['opts']['linewidth'] = rescale(repression(ygamma[tind], 2.0, 8), (0.5, 2.0)) - tet_repress['opts']['linewidth'] = rescale(repression(ytet[tind], 2.0, 8), (0.5, 2.0)) - dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], - [[lac_repress, gamma_repress, tet_repress]]) - ax.set_ylim([-11, 31]) - + tind = int(t * 10) + exp_lims = (1.0, 4.0) + # Set color for each of the CDSs + tetr["opts"]["color"] = [ + rescale(1 - expression(ymtet[tind], exp_lims), (1.0, 1.0)), + rescale(1 - expression(ymtet[tind], exp_lims), (0.75, 1.0)), + rescale(1 - expression(ymtet[tind], exp_lims), (0.17, 1.0)), + ] + laci["opts"]["color"] = [ + rescale(1 - expression(ymlac[tind], exp_lims), (0.38, 1.0)), + rescale(1 - expression(ymlac[tind], exp_lims), (0.82, 1.0)), + rescale(1 - expression(ymlac[tind], exp_lims), (0.32, 1.0)), + ] + gamma["opts"]["color"] = [ + rescale(1 - expression(ymgamma[tind], exp_lims), (0.38, 1.0)), + rescale(1 - expression(ymgamma[tind], exp_lims), (0.65, 1.0)), + rescale(1 - expression(ymgamma[tind], exp_lims), (0.87, 1.0)), + ] + # Set transparency for each of the regulatory lines + lac_repress["opts"]["color"] = [ + 0.38, + 0.82, + 0.32, + rescale(repression(ylac[tind], 2.0, 8), (0.2, 1.0)), + ] + gamma_repress["opts"]["color"] = [ + 0.38, + 0.65, + 0.87, + rescale(repression(ygamma[tind], 2.0, 8), (0.2, 1.0)), + ] + tet_repress["opts"]["color"] = [ + 1.00, + 0.75, + 0.17, + rescale(repression(ytet[tind], 2.0, 8), (0.2, 1.0)), + ] + # Set width for each of the regulatory lines + lac_repress["opts"]["linewidth"] = rescale( + repression(ylac[tind], 2.0, 8), (0.5, 2.0) + ) + gamma_repress["opts"]["linewidth"] = rescale( + repression(ygamma[tind], 2.0, 8), (0.5, 2.0) + ) + tet_repress["opts"]["linewidth"] = rescale( + repression(ytet[tind], 2.0, 8), (0.5, 2.0) + ) + dnaplotlib.plot_sbol_designs( + [ax], + [ + [ + plac, + rbs1, + tetr, + term1, + pgamma, + rbs2, + laci, + term2, + ptet, + rbs3, + gamma, + term3, + ] + ], + [[lac_repress, gamma_repress, tet_repress]], + ) + ax.set_ylim([-11, 31]) + + def main(): - t = np.arange(0, 30.1, 0.1) - ymtet, ymlac, ymgamma, ytet, ylac, ygamma = list(zip(*odeint(repressilator, initial, t))) - plt.close() - plt.figure(figsize=(3.7, 1.5)) - gs = gridspec.GridSpec(3, 2, height_ratios=[1, 1, 1], width_ratios=[2.6, 3]) - - # Plot of repressilator circuit - #ax = plt.subplot(gs[0], rowspan=3) - #dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], - # [[lac_repress, gamma_repress, tet_repress]]) - #ax.set_ylim([-10, 31]) - - # Plot of repressilator dynamics - ax = plt.subplot(gs[0:,0]) - plt.plot(t, ytet, color=[1.00, 0.75, 0.17]) - plt.plot(t, ylac, color=[0.38, 0.82, 0.32]) - plt.plot(t, ygamma, color=[0.38, 0.65, 0.87]) - plt.axvline(x=1, color='k', linewidth=0.7) - plt.axvline(x=12, color='k', linewidth=0.7) - plt.axvline(x=25.3, color='k', linewidth=0.7) - plt.axvline(x=27.3, color='k', linewidth=0.7) - plt.axvline(x=29.4, color='k', linewidth=0.7) - plt.ylim([1,4]) - ax.tick_params(axis='both', labelsize=8, width=0.8, length=3) - ax.yaxis.tick_left() - ax.xaxis.tick_bottom() - ax.set_xlabel('Time', fontsize=8, labelpad=1) - ax.set_ylabel('Protein Concentration', fontsize=8, labelpad=2) - #plt.legend(['tetR', 'lacI', 'gamma'], frameon=False, fontsize=8, labelspacing=0.15, loc=(0.06,0.65)) - - # Plot of each timepoint - ax = plt.subplot(gs[1]) - plot_construct(ax, 25.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[3]) - plot_construct(ax, 27.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[5]) - plot_construct(ax, 29.4, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - - # Update subplot spacing - plt.subplots_adjust(hspace=0.1, wspace=0.05, left=0.01, right=0.99, top=0.99, bottom=0.01) - - # Save the figure - plt.savefig('repressilator_fig.pdf', transparent=True) - plt.savefig('repressilator_fig.png', dpi=300) - -if __name__ == '__main__': - main() + t = np.arange(0, 30.1, 0.1) + ymtet, ymlac, ymgamma, ytet, ylac, ygamma = list( + zip(*odeint(repressilator, initial, t)) + ) + plt.close() + plt.figure(figsize=(3.7, 1.5)) + gs = gridspec.GridSpec(3, 2, height_ratios=[1, 1, 1], width_ratios=[2.6, 3]) + + # Plot of repressilator circuit + # ax = plt.subplot(gs[0], rowspan=3) + # dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], + # [[lac_repress, gamma_repress, tet_repress]]) + # ax.set_ylim([-10, 31]) + + # Plot of repressilator dynamics + ax = plt.subplot(gs[0:, 0]) + plt.plot(t, ytet, color=[1.00, 0.75, 0.17]) + plt.plot(t, ylac, color=[0.38, 0.82, 0.32]) + plt.plot(t, ygamma, color=[0.38, 0.65, 0.87]) + plt.axvline(x=1, color="k", linewidth=0.7) + plt.axvline(x=12, color="k", linewidth=0.7) + plt.axvline(x=25.3, color="k", linewidth=0.7) + plt.axvline(x=27.3, color="k", linewidth=0.7) + plt.axvline(x=29.4, color="k", linewidth=0.7) + plt.ylim([1, 4]) + ax.tick_params(axis="both", labelsize=8, width=0.8, length=3) + ax.yaxis.tick_left() + ax.xaxis.tick_bottom() + ax.set_xlabel("Time", fontsize=8, labelpad=1) + ax.set_ylabel("Protein Concentration", fontsize=8, labelpad=2) + # plt.legend(['tetR', 'lacI', 'gamma'], frameon=False, fontsize=8, labelspacing=0.15, loc=(0.06,0.65)) + + # Plot of each timepoint + ax = plt.subplot(gs[1]) + plot_construct(ax, 25.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[3]) + plot_construct(ax, 27.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[5]) + plot_construct(ax, 29.4, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + + # Update subplot spacing + plt.subplots_adjust( + hspace=0.1, wspace=0.05, left=0.01, right=0.99, top=0.99, bottom=0.01 + ) + + # Save the figure + plt.savefig("repressilator_fig.pdf", transparent=True) + plt.savefig("repressilator_fig.png", dpi=300) + + +if __name__ == "__main__": + main() diff --git a/dnaplotlib/gallery/repressilator_animate/repressilator_animate.py b/dnaplotlib/gallery/repressilator_animate/repressilator_animate.py index d0895cb..dcb7503 100644 --- a/dnaplotlib/gallery/repressilator_animate/repressilator_animate.py +++ b/dnaplotlib/gallery/repressilator_animate/repressilator_animate.py @@ -9,9 +9,9 @@ import matplotlib.pyplot as plt from matplotlib import gridspec -__author__ = 'Emerson Glassey , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Emerson Glassey , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Initialize Simulation # Initial concentration of mRNA and Protein for each repressor @@ -29,126 +29,269 @@ # tetr is orange [1.00, 0.75, 0.17] # lacI is green [0.38, 0.82, 0.32] # gamma is blue [0.38, 0.65, 0.87] -plac = {'name':'P_lac', 'start':1, 'end':10, 'type':'Promoter', 'opts': {'color':[0.38, 0.82, 0.32]}} -rbs1 = {'name':'RBS', 'start':11, 'end':20, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -tetr = {'name':'tetR', 'start':21, 'end':40, 'type':'CDS', 'opts':{'label': '', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -2, 'label_style':'italic', 'color':[1.00, 0.75, 0.17]}} -term1 = {'name':'Term', 'start':41, 'end':55, 'type':'Terminator'} -pgamma = {'name':'P_gamma', 'start':56, 'end':65, 'type':'Promoter', 'opts': {'color':[0.38, 0.65, 0.87]}} -rbs2 = {'name':'RBS', 'start':66, 'end':75, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -laci = {'name':'lacI', 'start':76, 'end':95, 'type':'CDS', 'opts':{'label': '', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -2, 'label_style':'italic', 'color':[0.38, 0.82, 0.32]}} -term2 = {'name':'Term', 'start':96, 'end':110, 'type':'Terminator'} -ptet = {'name':'P_tet', 'start':111, 'end':120, 'type':'Promoter', 'opts': {'color':[1.00, 0.75, 0.17]}} -rbs3 = {'name':'RBS', 'start':121, 'end':130, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -gamma = {'name':'gamma', 'start':131, 'end':150, 'type':'CDS', 'opts':{'label': '', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -1, 'label_style':'italic', 'color':[0.38, 0.65, 0.87]}} -term3 = {'name':'Term', 'start':151, 'end':165, 'type':'Terminator'} - -lac_repress = {'from_part':laci, 'to_part':plac, 'type':'Repression', 'opts':{'linewidth':1, 'color':[0.38, 0.82, 0.32]}} -gamma_repress = {'from_part':gamma, 'to_part':pgamma, 'type':'Repression', 'opts':{'linewidth':1, 'color':[0.38, 0.65, 0.87]}} -tet_repress = {'from_part':tetr, 'to_part':ptet, 'type':'Repression', 'opts':{'linewidth':1, 'color':[1.00, 0.75, 0.17]}} +plac = { + "name": "P_lac", + "start": 1, + "end": 10, + "type": "Promoter", + "opts": {"color": [0.38, 0.82, 0.32]}, +} +rbs1 = { + "name": "RBS", + "start": 11, + "end": 20, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +tetr = { + "name": "tetR", + "start": 21, + "end": 40, + "type": "CDS", + "opts": { + "label": "", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -2, + "label_style": "italic", + "color": [1.00, 0.75, 0.17], + }, +} +term1 = {"name": "Term", "start": 41, "end": 55, "type": "Terminator"} +pgamma = { + "name": "P_gamma", + "start": 56, + "end": 65, + "type": "Promoter", + "opts": {"color": [0.38, 0.65, 0.87]}, +} +rbs2 = { + "name": "RBS", + "start": 66, + "end": 75, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +laci = { + "name": "lacI", + "start": 76, + "end": 95, + "type": "CDS", + "opts": { + "label": "", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -2, + "label_style": "italic", + "color": [0.38, 0.82, 0.32], + }, +} +term2 = {"name": "Term", "start": 96, "end": 110, "type": "Terminator"} +ptet = { + "name": "P_tet", + "start": 111, + "end": 120, + "type": "Promoter", + "opts": {"color": [1.00, 0.75, 0.17]}, +} +rbs3 = { + "name": "RBS", + "start": 121, + "end": 130, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +gamma = { + "name": "gamma", + "start": 131, + "end": 150, + "type": "CDS", + "opts": { + "label": "", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -1, + "label_style": "italic", + "color": [0.38, 0.65, 0.87], + }, +} +term3 = {"name": "Term", "start": 151, "end": 165, "type": "Terminator"} + +lac_repress = { + "from_part": laci, + "to_part": plac, + "type": "Repression", + "opts": {"linewidth": 1, "color": [0.38, 0.82, 0.32]}, +} +gamma_repress = { + "from_part": gamma, + "to_part": pgamma, + "type": "Repression", + "opts": {"linewidth": 1, "color": [0.38, 0.65, 0.87]}, +} +tet_repress = { + "from_part": tetr, + "to_part": ptet, + "type": "Repression", + "opts": {"linewidth": 1, "color": [1.00, 0.75, 0.17]}, +} + def repressilator(y, t): mtet, mlac, mgamma, tet, lac, gamma = y - - dmtet = -mtet + (alpha / (1 + lac**n)) + leak + + dmtet = -mtet + (alpha / (1 + lac ** n)) + leak dtet = -beta * (tet - mtet) - - dmlac = -mlac + (alpha / (1 + gamma**n)) + leak + + dmlac = -mlac + (alpha / (1 + gamma ** n)) + leak dlac = -beta * (lac - mlac) - - dmgamma = -mgamma + (alpha / (1 + tet**n)) + leak + + dmgamma = -mgamma + (alpha / (1 + tet ** n)) + leak dgamma = -beta * (gamma - mgamma) return [dmtet, dmlac, dmgamma, dtet, dlac, dgamma] + def repression(val, Kd, power): """Function takes a value and Kd. Function fits the value to a hill function with n=power and Kd and returns the fraction bound.""" - new_val = val**power / (Kd**power + val** power) + new_val = val ** power / (Kd ** power + val ** power) return new_val - + + def expression(val, lims): """function takes a value between two limits (as a tuple) and returns the value normalized by the limits to be between 0 and 1""" new_val = (val - lims[0]) / (lims[1] - lims[0]) return new_val + def rescale(val, lims): """function takes a value between 0 and 1 and normalizes it between the limits in lims""" - new_val = (val*(lims[1]-lims[0])) + lims[0] + new_val = (val * (lims[1] - lims[0])) + lims[0] return new_val - + + def plot_construct(ax, t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma): - tind = int(t*10) - exp_lims = (1.0, 4.0) - # Set color for each of the CDSs - tetr['opts']['color'] = [rescale(1 - expression(ymtet[tind], exp_lims), (1.0, 1.0)), - rescale(1 - expression(ymtet[tind], exp_lims), (0.75, 1.0)), - rescale(1 - expression(ymtet[tind], exp_lims), (0.17, 1.0))] - laci['opts']['color'] = [rescale(1 - expression(ymlac[tind], exp_lims), (0.38, 1.0)), - rescale(1 - expression(ymlac[tind], exp_lims), (0.82, 1.0)), - rescale(1 - expression(ymlac[tind], exp_lims), (0.32, 1.0))] - gamma['opts']['color'] = [rescale(1 - expression(ymgamma[tind], exp_lims), (0.38, 1.0)), - rescale(1 - expression(ymgamma[tind], exp_lims), (0.65, 1.0)), - rescale(1 - expression(ymgamma[tind], exp_lims), (0.87, 1.0))] - # Set transparency for each of the regulatory lines - lac_repress['opts']['color'] = [0.38, 0.82, 0.32, - rescale(repression(ylac[tind], 2.0, 8), (0.2, 1.0))] - gamma_repress['opts']['color'] = [0.38, 0.65, 0.87, - rescale(repression(ygamma[tind], 2.0, 8), (0.2, 1.0))] - tet_repress['opts']['color'] = [1.00, 0.75, 0.17, - rescale(repression(ytet[tind], 2.0, 8), (0.2, 1.0))] - # Set width for each of the regulatory lines - lac_repress['opts']['linewidth'] = rescale(repression(ylac[tind], 2.0, 8), (0.5, 2.0)) - gamma_repress['opts']['linewidth'] = rescale(repression(ygamma[tind], 2.0, 8), (0.5, 2.0)) - tet_repress['opts']['linewidth'] = rescale(repression(ytet[tind], 2.0, 8), (0.5, 2.0)) - dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], - [[lac_repress, gamma_repress, tet_repress]]) - ax.set_ylim([-11, 31]) - + tind = int(t * 10) + exp_lims = (1.0, 4.0) + # Set color for each of the CDSs + tetr["opts"]["color"] = [ + rescale(1 - expression(ymtet[tind], exp_lims), (1.0, 1.0)), + rescale(1 - expression(ymtet[tind], exp_lims), (0.75, 1.0)), + rescale(1 - expression(ymtet[tind], exp_lims), (0.17, 1.0)), + ] + laci["opts"]["color"] = [ + rescale(1 - expression(ymlac[tind], exp_lims), (0.38, 1.0)), + rescale(1 - expression(ymlac[tind], exp_lims), (0.82, 1.0)), + rescale(1 - expression(ymlac[tind], exp_lims), (0.32, 1.0)), + ] + gamma["opts"]["color"] = [ + rescale(1 - expression(ymgamma[tind], exp_lims), (0.38, 1.0)), + rescale(1 - expression(ymgamma[tind], exp_lims), (0.65, 1.0)), + rescale(1 - expression(ymgamma[tind], exp_lims), (0.87, 1.0)), + ] + # Set transparency for each of the regulatory lines + lac_repress["opts"]["color"] = [ + 0.38, + 0.82, + 0.32, + rescale(repression(ylac[tind], 2.0, 8), (0.2, 1.0)), + ] + gamma_repress["opts"]["color"] = [ + 0.38, + 0.65, + 0.87, + rescale(repression(ygamma[tind], 2.0, 8), (0.2, 1.0)), + ] + tet_repress["opts"]["color"] = [ + 1.00, + 0.75, + 0.17, + rescale(repression(ytet[tind], 2.0, 8), (0.2, 1.0)), + ] + # Set width for each of the regulatory lines + lac_repress["opts"]["linewidth"] = rescale( + repression(ylac[tind], 2.0, 8), (0.5, 2.0) + ) + gamma_repress["opts"]["linewidth"] = rescale( + repression(ygamma[tind], 2.0, 8), (0.5, 2.0) + ) + tet_repress["opts"]["linewidth"] = rescale( + repression(ytet[tind], 2.0, 8), (0.5, 2.0) + ) + dnaplotlib.plot_sbol_designs( + [ax], + [ + [ + plac, + rbs1, + tetr, + term1, + pgamma, + rbs2, + laci, + term2, + ptet, + rbs3, + gamma, + term3, + ] + ], + [[lac_repress, gamma_repress, tet_repress]], + ) + ax.set_ylim([-11, 31]) + + def main(): - t = np.arange(0, 30.1, 0.1) - ymtet, ymlac, ymgamma, ytet, ylac, ygamma = list(zip(*odeint(repressilator, initial, t))) - plt.close() - plt.figure(figsize=(3.7, 1.5)) - gs = gridspec.GridSpec(3, 2, height_ratios=[1, 1, 1], width_ratios=[2.6, 3]) - - # Plot of repressilator circuit - #ax = plt.subplot(gs[0], rowspan=3) - #dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], - # [[lac_repress, gamma_repress, tet_repress]]) - #ax.set_ylim([-10, 31]) - - # Plot of repressilator dynamics - ax = plt.subplot(gs[0:,0]) - plt.plot(t, ytet, color=[1.00, 0.75, 0.17]) - plt.plot(t, ylac, color=[0.38, 0.82, 0.32]) - plt.plot(t, ygamma, color=[0.38, 0.65, 0.87]) - plt.axvline(x=1, color='k', linewidth=0.7) - plt.axvline(x=12, color='k', linewidth=0.7) - plt.axvline(x=25.3, color='k', linewidth=0.7) - plt.axvline(x=27.3, color='k', linewidth=0.7) - plt.axvline(x=29.4, color='k', linewidth=0.7) - plt.ylim([1,4]) - ax.tick_params(axis='both', labelsize=8, width=0.8, length=3) - ax.yaxis.tick_left() - ax.xaxis.tick_bottom() - ax.set_xlabel('Time', fontsize=8, labelpad=1) - ax.set_ylabel('Protein Concentration', fontsize=8, labelpad=2) - #plt.legend(['tetR', 'lacI', 'gamma'], frameon=False, fontsize=8, labelspacing=0.15, loc=(0.06,0.65)) - - # Plot of each timepoint - ax = plt.subplot(gs[1]) - plot_construct(ax, 25.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[3]) - plot_construct(ax, 27.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[5]) - plot_construct(ax, 29.4, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - - # Update subplot spacing - plt.subplots_adjust(hspace=0.1, wspace=0.05, left=0.01, right=0.99, top=0.99, bottom=0.01) - - # Save the figure - plt.savefig('repressilator_fig.pdf', transparent=True) - plt.savefig('repressilator_fig.png', dpi=300) - -if __name__ == '__main__': - main() + t = np.arange(0, 30.1, 0.1) + ymtet, ymlac, ymgamma, ytet, ylac, ygamma = list( + zip(*odeint(repressilator, initial, t)) + ) + plt.close() + plt.figure(figsize=(3.7, 1.5)) + gs = gridspec.GridSpec(3, 2, height_ratios=[1, 1, 1], width_ratios=[2.6, 3]) + + # Plot of repressilator circuit + # ax = plt.subplot(gs[0], rowspan=3) + # dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], + # [[lac_repress, gamma_repress, tet_repress]]) + # ax.set_ylim([-10, 31]) + + # Plot of repressilator dynamics + ax = plt.subplot(gs[0:, 0]) + plt.plot(t, ytet, color=[1.00, 0.75, 0.17]) + plt.plot(t, ylac, color=[0.38, 0.82, 0.32]) + plt.plot(t, ygamma, color=[0.38, 0.65, 0.87]) + plt.axvline(x=1, color="k", linewidth=0.7) + plt.axvline(x=12, color="k", linewidth=0.7) + plt.axvline(x=25.3, color="k", linewidth=0.7) + plt.axvline(x=27.3, color="k", linewidth=0.7) + plt.axvline(x=29.4, color="k", linewidth=0.7) + plt.ylim([1, 4]) + ax.tick_params(axis="both", labelsize=8, width=0.8, length=3) + ax.yaxis.tick_left() + ax.xaxis.tick_bottom() + ax.set_xlabel("Time", fontsize=8, labelpad=1) + ax.set_ylabel("Protein Concentration", fontsize=8, labelpad=2) + # plt.legend(['tetR', 'lacI', 'gamma'], frameon=False, fontsize=8, labelspacing=0.15, loc=(0.06,0.65)) + + # Plot of each timepoint + ax = plt.subplot(gs[1]) + plot_construct(ax, 25.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[3]) + plot_construct(ax, 27.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[5]) + plot_construct(ax, 29.4, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + + # Update subplot spacing + plt.subplots_adjust( + hspace=0.1, wspace=0.05, left=0.01, right=0.99, top=0.99, bottom=0.01 + ) + + # Save the figure + plt.savefig("repressilator_fig.pdf", transparent=True) + plt.savefig("repressilator_fig.png", dpi=300) + + +if __name__ == "__main__": + main() diff --git a/dnaplotlib/gallery/repressilator_animate/repressilator_figure 2.py b/dnaplotlib/gallery/repressilator_animate/repressilator_figure 2.py index 979ee7e..c88bec1 100644 --- a/dnaplotlib/gallery/repressilator_animate/repressilator_figure 2.py +++ b/dnaplotlib/gallery/repressilator_animate/repressilator_figure 2.py @@ -9,9 +9,9 @@ import matplotlib.pyplot as plt from matplotlib import gridspec -__author__ = 'Emerson Glassey , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Emerson Glassey , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Initialize Simulation # Initial concentration of mRNA and Protein for each repressor @@ -29,159 +29,363 @@ # tetr is orange [1.00, 0.75, 0.17] # lacI is green [0.38, 0.82, 0.32] # gamma is blue [0.38, 0.65, 0.87] -plac = {'name':'P_lac', 'start':1, 'end':10, 'type':'Promoter', 'opts': {'color':[0.38, 0.82, 0.32]}} -rbs1 = {'name':'RBS', 'start':11, 'end':20, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -tetr = {'name':'tetR', 'start':21, 'end':40, 'type':'CDS', 'opts':{'label': 'tetR', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -2, 'label_style':'italic', 'color':[1.00, 0.75, 0.17]}} -term1 = {'name':'Term', 'start':41, 'end':55, 'type':'Terminator'} -pgamma = {'name':'P_gamma', 'start':56, 'end':65, 'type':'Promoter', 'opts': {'color':[0.38, 0.65, 0.87]}} -rbs2 = {'name':'RBS', 'start':66, 'end':75, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -laci = {'name':'lacI', 'start':76, 'end':95, 'type':'CDS', 'opts':{'label': 'lacI', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -2, 'label_style':'italic', 'color':[0.38, 0.82, 0.32]}} -term2 = {'name':'Term', 'start':96, 'end':110, 'type':'Terminator'} -ptet = {'name':'P_tet', 'start':111, 'end':120, 'type':'Promoter', 'opts': {'color':[1.00, 0.75, 0.17]}} -rbs3 = {'name':'RBS', 'start':121, 'end':130, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -gamma = {'name':'gamma', 'start':131, 'end':150, 'type':'CDS', 'opts':{'label': 'gamma', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -1, 'label_style':'italic', 'color':[0.38, 0.65, 0.87]}} -term3 = {'name':'Term', 'start':151, 'end':165, 'type':'Terminator'} - -lac_repress = {'from_part':laci, 'to_part':plac, 'type':'Repression', 'opts':{'linewidth':1, 'color':[0.38, 0.82, 0.32]}} -gamma_repress = {'from_part':gamma, 'to_part':pgamma, 'type':'Repression', 'opts':{'linewidth':1, 'color':[0.38, 0.65, 0.87]}} -tet_repress = {'from_part':tetr, 'to_part':ptet, 'type':'Repression', 'opts':{'linewidth':1, 'color':[1.00, 0.75, 0.17]}} +plac = { + "name": "P_lac", + "start": 1, + "end": 10, + "type": "Promoter", + "opts": {"color": [0.38, 0.82, 0.32]}, +} +rbs1 = { + "name": "RBS", + "start": 11, + "end": 20, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +tetr = { + "name": "tetR", + "start": 21, + "end": 40, + "type": "CDS", + "opts": { + "label": "tetR", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -2, + "label_style": "italic", + "color": [1.00, 0.75, 0.17], + }, +} +term1 = {"name": "Term", "start": 41, "end": 55, "type": "Terminator"} +pgamma = { + "name": "P_gamma", + "start": 56, + "end": 65, + "type": "Promoter", + "opts": {"color": [0.38, 0.65, 0.87]}, +} +rbs2 = { + "name": "RBS", + "start": 66, + "end": 75, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +laci = { + "name": "lacI", + "start": 76, + "end": 95, + "type": "CDS", + "opts": { + "label": "lacI", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -2, + "label_style": "italic", + "color": [0.38, 0.82, 0.32], + }, +} +term2 = {"name": "Term", "start": 96, "end": 110, "type": "Terminator"} +ptet = { + "name": "P_tet", + "start": 111, + "end": 120, + "type": "Promoter", + "opts": {"color": [1.00, 0.75, 0.17]}, +} +rbs3 = { + "name": "RBS", + "start": 121, + "end": 130, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +gamma = { + "name": "gamma", + "start": 131, + "end": 150, + "type": "CDS", + "opts": { + "label": "gamma", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -1, + "label_style": "italic", + "color": [0.38, 0.65, 0.87], + }, +} +term3 = {"name": "Term", "start": 151, "end": 165, "type": "Terminator"} + +lac_repress = { + "from_part": laci, + "to_part": plac, + "type": "Repression", + "opts": {"linewidth": 1, "color": [0.38, 0.82, 0.32]}, +} +gamma_repress = { + "from_part": gamma, + "to_part": pgamma, + "type": "Repression", + "opts": {"linewidth": 1, "color": [0.38, 0.65, 0.87]}, +} +tet_repress = { + "from_part": tetr, + "to_part": ptet, + "type": "Repression", + "opts": {"linewidth": 1, "color": [1.00, 0.75, 0.17]}, +} + def repressilator(y, t): mtet, mlac, mgamma, tet, lac, gamma = y - - dmtet = -mtet + (alpha / (1 + lac**n)) + leak + + dmtet = -mtet + (alpha / (1 + lac ** n)) + leak dtet = -beta * (tet - mtet) - - dmlac = -mlac + (alpha / (1 + gamma**n)) + leak + + dmlac = -mlac + (alpha / (1 + gamma ** n)) + leak dlac = -beta * (lac - mlac) - - dmgamma = -mgamma + (alpha / (1 + tet**n)) + leak + + dmgamma = -mgamma + (alpha / (1 + tet ** n)) + leak dgamma = -beta * (gamma - mgamma) return [dmtet, dmlac, dmgamma, dtet, dlac, dgamma] + def repression(val, Kd, power): """Function takes a value and Kd. Function fits the value to a hill function with n=power and Kd and returns the fraction bound.""" - new_val = val**power / (Kd**power + val** power) + new_val = val ** power / (Kd ** power + val ** power) return new_val - + + def expression(val, lims): """function takes a value between two limits (as a tuple) and returns the value normalized by the limits to be between 0 and 1""" new_val = (val - lims[0]) / (lims[1] - lims[0]) return new_val + def rescale(val, lims): """function takes a value between 0 and 1 and normalizes it between the limits in lims""" - new_val = (val*(lims[1]-lims[0])) + lims[0] + new_val = (val * (lims[1] - lims[0])) + lims[0] return new_val - + + def plot_construct(ax, t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma): - tind = int(t*10) - exp_lims = (1.0, 4.0) - ax.set_title('t = {}'.format(t), fontsize=8) - # Set color for each of the CDSs - tetr['opts']['color'] = [rescale(1 - expression(ymtet[tind], exp_lims), (1.0, 1.0)), - rescale(1 - expression(ymtet[tind], exp_lims), (0.75, 1.0)), - rescale(1 - expression(ymtet[tind], exp_lims), (0.17, 1.0))] - laci['opts']['color'] = [rescale(1 - expression(ymlac[tind], exp_lims), (0.38, 1.0)), - rescale(1 - expression(ymlac[tind], exp_lims), (0.82, 1.0)), - rescale(1 - expression(ymlac[tind], exp_lims), (0.32, 1.0))] - gamma['opts']['color'] = [rescale(1 - expression(ymgamma[tind], exp_lims), (0.38, 1.0)), - rescale(1 - expression(ymgamma[tind], exp_lims), (0.65, 1.0)), - rescale(1 - expression(ymgamma[tind], exp_lims), (0.87, 1.0))] - # Set transparency for each of the regulatory lines - lac_repress['opts']['color'] = [0.38, 0.82, 0.32, - rescale(repression(ylac[tind], 2.0, 8), (0.2, 1.0))] - gamma_repress['opts']['color'] = [0.38, 0.65, 0.87, - rescale(repression(ygamma[tind], 2.0, 8), (0.2, 1.0))] - tet_repress['opts']['color'] = [1.00, 0.75, 0.17, - rescale(repression(ytet[tind], 2.0, 8), (0.2, 1.0))] - # Set width for each of the regulatory lines - lac_repress['opts']['linewidth'] = rescale(repression(ylac[tind], 2.0, 8), (0.5, 2.0)) - gamma_repress['opts']['linewidth'] = rescale(repression(ygamma[tind], 2.0, 8), (0.5, 2.0)) - tet_repress['opts']['linewidth'] = rescale(repression(ytet[tind], 2.0, 8), (0.5, 2.0)) - dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], - [[lac_repress, gamma_repress, tet_repress]]) - ax.set_ylim([-10, 31]) - + tind = int(t * 10) + exp_lims = (1.0, 4.0) + ax.set_title("t = {}".format(t), fontsize=8) + # Set color for each of the CDSs + tetr["opts"]["color"] = [ + rescale(1 - expression(ymtet[tind], exp_lims), (1.0, 1.0)), + rescale(1 - expression(ymtet[tind], exp_lims), (0.75, 1.0)), + rescale(1 - expression(ymtet[tind], exp_lims), (0.17, 1.0)), + ] + laci["opts"]["color"] = [ + rescale(1 - expression(ymlac[tind], exp_lims), (0.38, 1.0)), + rescale(1 - expression(ymlac[tind], exp_lims), (0.82, 1.0)), + rescale(1 - expression(ymlac[tind], exp_lims), (0.32, 1.0)), + ] + gamma["opts"]["color"] = [ + rescale(1 - expression(ymgamma[tind], exp_lims), (0.38, 1.0)), + rescale(1 - expression(ymgamma[tind], exp_lims), (0.65, 1.0)), + rescale(1 - expression(ymgamma[tind], exp_lims), (0.87, 1.0)), + ] + # Set transparency for each of the regulatory lines + lac_repress["opts"]["color"] = [ + 0.38, + 0.82, + 0.32, + rescale(repression(ylac[tind], 2.0, 8), (0.2, 1.0)), + ] + gamma_repress["opts"]["color"] = [ + 0.38, + 0.65, + 0.87, + rescale(repression(ygamma[tind], 2.0, 8), (0.2, 1.0)), + ] + tet_repress["opts"]["color"] = [ + 1.00, + 0.75, + 0.17, + rescale(repression(ytet[tind], 2.0, 8), (0.2, 1.0)), + ] + # Set width for each of the regulatory lines + lac_repress["opts"]["linewidth"] = rescale( + repression(ylac[tind], 2.0, 8), (0.5, 2.0) + ) + gamma_repress["opts"]["linewidth"] = rescale( + repression(ygamma[tind], 2.0, 8), (0.5, 2.0) + ) + tet_repress["opts"]["linewidth"] = rescale( + repression(ytet[tind], 2.0, 8), (0.5, 2.0) + ) + dnaplotlib.plot_sbol_designs( + [ax], + [ + [ + plac, + rbs1, + tetr, + term1, + pgamma, + rbs2, + laci, + term2, + ptet, + rbs3, + gamma, + term3, + ] + ], + [[lac_repress, gamma_repress, tet_repress]], + ) + ax.set_ylim([-10, 31]) + + def movie(ts, ymtet, ymlac, ymgamma, ytet, ylac, ygamma): - for t in ts: - plt.close() - plt.figure(figsize=(4, 3.5)) - gs = gridspec.GridSpec(3, 1, height_ratios=[2, 0.5, 1]) - - ax = plt.subplot(gs[0]) - plt.plot(ts[:int(t*10)+1], ytet[:int(t*10)+1], color=[1.00, 0.75, 0.17]) - plt.plot(ts[:int(t*10)+1], ylac[:int(t*10)+1], color=[0.38, 0.82, 0.32]) - plt.plot(ts[:int(t*10)+1], ygamma[:int(t*10)+1], color=[0.38, 0.65, 0.87]) - plt.xlim([0, 30]) - plt.ylim([1,4]) - ax.tick_params(axis='both', labelsize=8, width=0.8, length=3) - ax.yaxis.tick_left() - ax.xaxis.tick_bottom() - ax.set_xlabel('Time', fontsize=8, labelpad=3) - ax.set_ylabel('Protein Concentration', fontsize=8, labelpad=4) - plt.legend(['tetR', 'lacI', 'gamma'], frameon=False, fontsize=8, labelspacing=0.15, loc=(0.03,0.65)) - plt.plot(ts[int(t*10)], ytet[int(t*10)], '.', color=[1.00, 0.75, 0.17], markersize=6.0) - plt.plot(ts[int(t*10)], ylac[int(t*10)], '.', color=[0.38, 0.82, 0.32], markersize=6.0) - plt.plot(ts[int(t*10)], ygamma[int(t*10)], '.', color=[0.38, 0.65, 0.87], markersize=6.0) - ax = plt.subplot(gs[2]) - plot_construct(ax, t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - plt.savefig("movie/repressilator_t{}.jpg".format(t), dpi=300) - + for t in ts: + plt.close() + plt.figure(figsize=(4, 3.5)) + gs = gridspec.GridSpec(3, 1, height_ratios=[2, 0.5, 1]) + + ax = plt.subplot(gs[0]) + plt.plot( + ts[: int(t * 10) + 1], + ytet[: int(t * 10) + 1], + color=[1.00, 0.75, 0.17], + ) + plt.plot( + ts[: int(t * 10) + 1], + ylac[: int(t * 10) + 1], + color=[0.38, 0.82, 0.32], + ) + plt.plot( + ts[: int(t * 10) + 1], + ygamma[: int(t * 10) + 1], + color=[0.38, 0.65, 0.87], + ) + plt.xlim([0, 30]) + plt.ylim([1, 4]) + ax.tick_params(axis="both", labelsize=8, width=0.8, length=3) + ax.yaxis.tick_left() + ax.xaxis.tick_bottom() + ax.set_xlabel("Time", fontsize=8, labelpad=3) + ax.set_ylabel("Protein Concentration", fontsize=8, labelpad=4) + plt.legend( + ["tetR", "lacI", "gamma"], + frameon=False, + fontsize=8, + labelspacing=0.15, + loc=(0.03, 0.65), + ) + plt.plot( + ts[int(t * 10)], + ytet[int(t * 10)], + ".", + color=[1.00, 0.75, 0.17], + markersize=6.0, + ) + plt.plot( + ts[int(t * 10)], + ylac[int(t * 10)], + ".", + color=[0.38, 0.82, 0.32], + markersize=6.0, + ) + plt.plot( + ts[int(t * 10)], + ygamma[int(t * 10)], + ".", + color=[0.38, 0.65, 0.87], + markersize=6.0, + ) + ax = plt.subplot(gs[2]) + plot_construct(ax, t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + plt.savefig("movie/repressilator_t{}.jpg".format(t), dpi=300) + + def main(): - t = np.arange(0, 30.1, 0.1) - ymtet, ymlac, ymgamma, ytet, ylac, ygamma = list(zip(*odeint(repressilator, initial, t))) - plt.close() - plt.figure(figsize=(3.5, 6.5)) - gs = gridspec.GridSpec(8, 1, height_ratios=[1, 2.5, 0.1, 1, 1, 1, 1, 1]) - - # Plot of repressilator circuit - ax = plt.subplot(gs[0]) - dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], - [[lac_repress, gamma_repress, tet_repress]]) - ax.set_ylim([-10, 31]) - - # Plot of repressilator dynamics - ax = plt.subplot(gs[1]) - plt.plot(t, ytet, color=[1.00, 0.75, 0.17]) - plt.plot(t, ylac, color=[0.38, 0.82, 0.32]) - plt.plot(t, ygamma, color=[0.38, 0.65, 0.87]) - plt.axvline(x=1, color='k', linewidth=0.7) - plt.axvline(x=12, color='k', linewidth=0.7) - plt.axvline(x=25.3, color='k', linewidth=0.7) - plt.axvline(x=27.3, color='k', linewidth=0.7) - plt.axvline(x=29.4, color='k', linewidth=0.7) - plt.ylim([1,4]) - ax.tick_params(axis='both', labelsize=8, width=0.8, length=3) - ax.yaxis.tick_left() - ax.xaxis.tick_bottom() - ax.set_xlabel('Time', fontsize=8, labelpad=1) - ax.set_ylabel('Protein Concentration', fontsize=8, labelpad=2) - plt.legend(['tetR', 'lacI', 'gamma'], frameon=False, fontsize=8, labelspacing=0.15, loc=(0.06,0.65)) - - # Plot of each timepoint - ax = plt.subplot(gs[3]) - plot_construct(ax, 1, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[4]) - plot_construct(ax, 12, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[5]) - plot_construct(ax, 25.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[6]) - plot_construct(ax, 27.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[7]) - plot_construct(ax, 29.4, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - - # Update subplot spacing - plt.subplots_adjust(hspace=0.4, left=0.12, right=0.95, top=0.99, bottom=0.01) - - # Save the figure - plt.savefig('repressilator_animate.pdf', transparent=True) - plt.savefig('repressilator_animate.png', dpi=300) - - # Generate the movie frames - movie(t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - -if __name__ == '__main__': - main() + t = np.arange(0, 30.1, 0.1) + ymtet, ymlac, ymgamma, ytet, ylac, ygamma = list( + zip(*odeint(repressilator, initial, t)) + ) + plt.close() + plt.figure(figsize=(3.5, 6.5)) + gs = gridspec.GridSpec(8, 1, height_ratios=[1, 2.5, 0.1, 1, 1, 1, 1, 1]) + + # Plot of repressilator circuit + ax = plt.subplot(gs[0]) + dnaplotlib.plot_sbol_designs( + [ax], + [ + [ + plac, + rbs1, + tetr, + term1, + pgamma, + rbs2, + laci, + term2, + ptet, + rbs3, + gamma, + term3, + ] + ], + [[lac_repress, gamma_repress, tet_repress]], + ) + ax.set_ylim([-10, 31]) + + # Plot of repressilator dynamics + ax = plt.subplot(gs[1]) + plt.plot(t, ytet, color=[1.00, 0.75, 0.17]) + plt.plot(t, ylac, color=[0.38, 0.82, 0.32]) + plt.plot(t, ygamma, color=[0.38, 0.65, 0.87]) + plt.axvline(x=1, color="k", linewidth=0.7) + plt.axvline(x=12, color="k", linewidth=0.7) + plt.axvline(x=25.3, color="k", linewidth=0.7) + plt.axvline(x=27.3, color="k", linewidth=0.7) + plt.axvline(x=29.4, color="k", linewidth=0.7) + plt.ylim([1, 4]) + ax.tick_params(axis="both", labelsize=8, width=0.8, length=3) + ax.yaxis.tick_left() + ax.xaxis.tick_bottom() + ax.set_xlabel("Time", fontsize=8, labelpad=1) + ax.set_ylabel("Protein Concentration", fontsize=8, labelpad=2) + plt.legend( + ["tetR", "lacI", "gamma"], + frameon=False, + fontsize=8, + labelspacing=0.15, + loc=(0.06, 0.65), + ) + + # Plot of each timepoint + ax = plt.subplot(gs[3]) + plot_construct(ax, 1, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[4]) + plot_construct(ax, 12, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[5]) + plot_construct(ax, 25.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[6]) + plot_construct(ax, 27.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[7]) + plot_construct(ax, 29.4, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + + # Update subplot spacing + plt.subplots_adjust( + hspace=0.4, left=0.12, right=0.95, top=0.99, bottom=0.01 + ) + + # Save the figure + plt.savefig("repressilator_animate.pdf", transparent=True) + plt.savefig("repressilator_animate.png", dpi=300) + + # Generate the movie frames + movie(t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + + +if __name__ == "__main__": + main() diff --git a/dnaplotlib/gallery/repressilator_animate/repressilator_figure.py b/dnaplotlib/gallery/repressilator_animate/repressilator_figure.py index 979ee7e..c88bec1 100644 --- a/dnaplotlib/gallery/repressilator_animate/repressilator_figure.py +++ b/dnaplotlib/gallery/repressilator_animate/repressilator_figure.py @@ -9,9 +9,9 @@ import matplotlib.pyplot as plt from matplotlib import gridspec -__author__ = 'Emerson Glassey , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Emerson Glassey , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Initialize Simulation # Initial concentration of mRNA and Protein for each repressor @@ -29,159 +29,363 @@ # tetr is orange [1.00, 0.75, 0.17] # lacI is green [0.38, 0.82, 0.32] # gamma is blue [0.38, 0.65, 0.87] -plac = {'name':'P_lac', 'start':1, 'end':10, 'type':'Promoter', 'opts': {'color':[0.38, 0.82, 0.32]}} -rbs1 = {'name':'RBS', 'start':11, 'end':20, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -tetr = {'name':'tetR', 'start':21, 'end':40, 'type':'CDS', 'opts':{'label': 'tetR', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -2, 'label_style':'italic', 'color':[1.00, 0.75, 0.17]}} -term1 = {'name':'Term', 'start':41, 'end':55, 'type':'Terminator'} -pgamma = {'name':'P_gamma', 'start':56, 'end':65, 'type':'Promoter', 'opts': {'color':[0.38, 0.65, 0.87]}} -rbs2 = {'name':'RBS', 'start':66, 'end':75, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -laci = {'name':'lacI', 'start':76, 'end':95, 'type':'CDS', 'opts':{'label': 'lacI', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -2, 'label_style':'italic', 'color':[0.38, 0.82, 0.32]}} -term2 = {'name':'Term', 'start':96, 'end':110, 'type':'Terminator'} -ptet = {'name':'P_tet', 'start':111, 'end':120, 'type':'Promoter', 'opts': {'color':[1.00, 0.75, 0.17]}} -rbs3 = {'name':'RBS', 'start':121, 'end':130, 'type':'RBS', 'opts':{'linewidth': 0, 'color':[0.0, 0.0, 0.0]}} -gamma = {'name':'gamma', 'start':131, 'end':150, 'type':'CDS', 'opts':{'label': 'gamma', 'fontsize': 8, 'label_y_offset': 0, 'label_x_offset': -1, 'label_style':'italic', 'color':[0.38, 0.65, 0.87]}} -term3 = {'name':'Term', 'start':151, 'end':165, 'type':'Terminator'} - -lac_repress = {'from_part':laci, 'to_part':plac, 'type':'Repression', 'opts':{'linewidth':1, 'color':[0.38, 0.82, 0.32]}} -gamma_repress = {'from_part':gamma, 'to_part':pgamma, 'type':'Repression', 'opts':{'linewidth':1, 'color':[0.38, 0.65, 0.87]}} -tet_repress = {'from_part':tetr, 'to_part':ptet, 'type':'Repression', 'opts':{'linewidth':1, 'color':[1.00, 0.75, 0.17]}} +plac = { + "name": "P_lac", + "start": 1, + "end": 10, + "type": "Promoter", + "opts": {"color": [0.38, 0.82, 0.32]}, +} +rbs1 = { + "name": "RBS", + "start": 11, + "end": 20, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +tetr = { + "name": "tetR", + "start": 21, + "end": 40, + "type": "CDS", + "opts": { + "label": "tetR", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -2, + "label_style": "italic", + "color": [1.00, 0.75, 0.17], + }, +} +term1 = {"name": "Term", "start": 41, "end": 55, "type": "Terminator"} +pgamma = { + "name": "P_gamma", + "start": 56, + "end": 65, + "type": "Promoter", + "opts": {"color": [0.38, 0.65, 0.87]}, +} +rbs2 = { + "name": "RBS", + "start": 66, + "end": 75, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +laci = { + "name": "lacI", + "start": 76, + "end": 95, + "type": "CDS", + "opts": { + "label": "lacI", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -2, + "label_style": "italic", + "color": [0.38, 0.82, 0.32], + }, +} +term2 = {"name": "Term", "start": 96, "end": 110, "type": "Terminator"} +ptet = { + "name": "P_tet", + "start": 111, + "end": 120, + "type": "Promoter", + "opts": {"color": [1.00, 0.75, 0.17]}, +} +rbs3 = { + "name": "RBS", + "start": 121, + "end": 130, + "type": "RBS", + "opts": {"linewidth": 0, "color": [0.0, 0.0, 0.0]}, +} +gamma = { + "name": "gamma", + "start": 131, + "end": 150, + "type": "CDS", + "opts": { + "label": "gamma", + "fontsize": 8, + "label_y_offset": 0, + "label_x_offset": -1, + "label_style": "italic", + "color": [0.38, 0.65, 0.87], + }, +} +term3 = {"name": "Term", "start": 151, "end": 165, "type": "Terminator"} + +lac_repress = { + "from_part": laci, + "to_part": plac, + "type": "Repression", + "opts": {"linewidth": 1, "color": [0.38, 0.82, 0.32]}, +} +gamma_repress = { + "from_part": gamma, + "to_part": pgamma, + "type": "Repression", + "opts": {"linewidth": 1, "color": [0.38, 0.65, 0.87]}, +} +tet_repress = { + "from_part": tetr, + "to_part": ptet, + "type": "Repression", + "opts": {"linewidth": 1, "color": [1.00, 0.75, 0.17]}, +} + def repressilator(y, t): mtet, mlac, mgamma, tet, lac, gamma = y - - dmtet = -mtet + (alpha / (1 + lac**n)) + leak + + dmtet = -mtet + (alpha / (1 + lac ** n)) + leak dtet = -beta * (tet - mtet) - - dmlac = -mlac + (alpha / (1 + gamma**n)) + leak + + dmlac = -mlac + (alpha / (1 + gamma ** n)) + leak dlac = -beta * (lac - mlac) - - dmgamma = -mgamma + (alpha / (1 + tet**n)) + leak + + dmgamma = -mgamma + (alpha / (1 + tet ** n)) + leak dgamma = -beta * (gamma - mgamma) return [dmtet, dmlac, dmgamma, dtet, dlac, dgamma] + def repression(val, Kd, power): """Function takes a value and Kd. Function fits the value to a hill function with n=power and Kd and returns the fraction bound.""" - new_val = val**power / (Kd**power + val** power) + new_val = val ** power / (Kd ** power + val ** power) return new_val - + + def expression(val, lims): """function takes a value between two limits (as a tuple) and returns the value normalized by the limits to be between 0 and 1""" new_val = (val - lims[0]) / (lims[1] - lims[0]) return new_val + def rescale(val, lims): """function takes a value between 0 and 1 and normalizes it between the limits in lims""" - new_val = (val*(lims[1]-lims[0])) + lims[0] + new_val = (val * (lims[1] - lims[0])) + lims[0] return new_val - + + def plot_construct(ax, t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma): - tind = int(t*10) - exp_lims = (1.0, 4.0) - ax.set_title('t = {}'.format(t), fontsize=8) - # Set color for each of the CDSs - tetr['opts']['color'] = [rescale(1 - expression(ymtet[tind], exp_lims), (1.0, 1.0)), - rescale(1 - expression(ymtet[tind], exp_lims), (0.75, 1.0)), - rescale(1 - expression(ymtet[tind], exp_lims), (0.17, 1.0))] - laci['opts']['color'] = [rescale(1 - expression(ymlac[tind], exp_lims), (0.38, 1.0)), - rescale(1 - expression(ymlac[tind], exp_lims), (0.82, 1.0)), - rescale(1 - expression(ymlac[tind], exp_lims), (0.32, 1.0))] - gamma['opts']['color'] = [rescale(1 - expression(ymgamma[tind], exp_lims), (0.38, 1.0)), - rescale(1 - expression(ymgamma[tind], exp_lims), (0.65, 1.0)), - rescale(1 - expression(ymgamma[tind], exp_lims), (0.87, 1.0))] - # Set transparency for each of the regulatory lines - lac_repress['opts']['color'] = [0.38, 0.82, 0.32, - rescale(repression(ylac[tind], 2.0, 8), (0.2, 1.0))] - gamma_repress['opts']['color'] = [0.38, 0.65, 0.87, - rescale(repression(ygamma[tind], 2.0, 8), (0.2, 1.0))] - tet_repress['opts']['color'] = [1.00, 0.75, 0.17, - rescale(repression(ytet[tind], 2.0, 8), (0.2, 1.0))] - # Set width for each of the regulatory lines - lac_repress['opts']['linewidth'] = rescale(repression(ylac[tind], 2.0, 8), (0.5, 2.0)) - gamma_repress['opts']['linewidth'] = rescale(repression(ygamma[tind], 2.0, 8), (0.5, 2.0)) - tet_repress['opts']['linewidth'] = rescale(repression(ytet[tind], 2.0, 8), (0.5, 2.0)) - dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], - [[lac_repress, gamma_repress, tet_repress]]) - ax.set_ylim([-10, 31]) - + tind = int(t * 10) + exp_lims = (1.0, 4.0) + ax.set_title("t = {}".format(t), fontsize=8) + # Set color for each of the CDSs + tetr["opts"]["color"] = [ + rescale(1 - expression(ymtet[tind], exp_lims), (1.0, 1.0)), + rescale(1 - expression(ymtet[tind], exp_lims), (0.75, 1.0)), + rescale(1 - expression(ymtet[tind], exp_lims), (0.17, 1.0)), + ] + laci["opts"]["color"] = [ + rescale(1 - expression(ymlac[tind], exp_lims), (0.38, 1.0)), + rescale(1 - expression(ymlac[tind], exp_lims), (0.82, 1.0)), + rescale(1 - expression(ymlac[tind], exp_lims), (0.32, 1.0)), + ] + gamma["opts"]["color"] = [ + rescale(1 - expression(ymgamma[tind], exp_lims), (0.38, 1.0)), + rescale(1 - expression(ymgamma[tind], exp_lims), (0.65, 1.0)), + rescale(1 - expression(ymgamma[tind], exp_lims), (0.87, 1.0)), + ] + # Set transparency for each of the regulatory lines + lac_repress["opts"]["color"] = [ + 0.38, + 0.82, + 0.32, + rescale(repression(ylac[tind], 2.0, 8), (0.2, 1.0)), + ] + gamma_repress["opts"]["color"] = [ + 0.38, + 0.65, + 0.87, + rescale(repression(ygamma[tind], 2.0, 8), (0.2, 1.0)), + ] + tet_repress["opts"]["color"] = [ + 1.00, + 0.75, + 0.17, + rescale(repression(ytet[tind], 2.0, 8), (0.2, 1.0)), + ] + # Set width for each of the regulatory lines + lac_repress["opts"]["linewidth"] = rescale( + repression(ylac[tind], 2.0, 8), (0.5, 2.0) + ) + gamma_repress["opts"]["linewidth"] = rescale( + repression(ygamma[tind], 2.0, 8), (0.5, 2.0) + ) + tet_repress["opts"]["linewidth"] = rescale( + repression(ytet[tind], 2.0, 8), (0.5, 2.0) + ) + dnaplotlib.plot_sbol_designs( + [ax], + [ + [ + plac, + rbs1, + tetr, + term1, + pgamma, + rbs2, + laci, + term2, + ptet, + rbs3, + gamma, + term3, + ] + ], + [[lac_repress, gamma_repress, tet_repress]], + ) + ax.set_ylim([-10, 31]) + + def movie(ts, ymtet, ymlac, ymgamma, ytet, ylac, ygamma): - for t in ts: - plt.close() - plt.figure(figsize=(4, 3.5)) - gs = gridspec.GridSpec(3, 1, height_ratios=[2, 0.5, 1]) - - ax = plt.subplot(gs[0]) - plt.plot(ts[:int(t*10)+1], ytet[:int(t*10)+1], color=[1.00, 0.75, 0.17]) - plt.plot(ts[:int(t*10)+1], ylac[:int(t*10)+1], color=[0.38, 0.82, 0.32]) - plt.plot(ts[:int(t*10)+1], ygamma[:int(t*10)+1], color=[0.38, 0.65, 0.87]) - plt.xlim([0, 30]) - plt.ylim([1,4]) - ax.tick_params(axis='both', labelsize=8, width=0.8, length=3) - ax.yaxis.tick_left() - ax.xaxis.tick_bottom() - ax.set_xlabel('Time', fontsize=8, labelpad=3) - ax.set_ylabel('Protein Concentration', fontsize=8, labelpad=4) - plt.legend(['tetR', 'lacI', 'gamma'], frameon=False, fontsize=8, labelspacing=0.15, loc=(0.03,0.65)) - plt.plot(ts[int(t*10)], ytet[int(t*10)], '.', color=[1.00, 0.75, 0.17], markersize=6.0) - plt.plot(ts[int(t*10)], ylac[int(t*10)], '.', color=[0.38, 0.82, 0.32], markersize=6.0) - plt.plot(ts[int(t*10)], ygamma[int(t*10)], '.', color=[0.38, 0.65, 0.87], markersize=6.0) - ax = plt.subplot(gs[2]) - plot_construct(ax, t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - plt.savefig("movie/repressilator_t{}.jpg".format(t), dpi=300) - + for t in ts: + plt.close() + plt.figure(figsize=(4, 3.5)) + gs = gridspec.GridSpec(3, 1, height_ratios=[2, 0.5, 1]) + + ax = plt.subplot(gs[0]) + plt.plot( + ts[: int(t * 10) + 1], + ytet[: int(t * 10) + 1], + color=[1.00, 0.75, 0.17], + ) + plt.plot( + ts[: int(t * 10) + 1], + ylac[: int(t * 10) + 1], + color=[0.38, 0.82, 0.32], + ) + plt.plot( + ts[: int(t * 10) + 1], + ygamma[: int(t * 10) + 1], + color=[0.38, 0.65, 0.87], + ) + plt.xlim([0, 30]) + plt.ylim([1, 4]) + ax.tick_params(axis="both", labelsize=8, width=0.8, length=3) + ax.yaxis.tick_left() + ax.xaxis.tick_bottom() + ax.set_xlabel("Time", fontsize=8, labelpad=3) + ax.set_ylabel("Protein Concentration", fontsize=8, labelpad=4) + plt.legend( + ["tetR", "lacI", "gamma"], + frameon=False, + fontsize=8, + labelspacing=0.15, + loc=(0.03, 0.65), + ) + plt.plot( + ts[int(t * 10)], + ytet[int(t * 10)], + ".", + color=[1.00, 0.75, 0.17], + markersize=6.0, + ) + plt.plot( + ts[int(t * 10)], + ylac[int(t * 10)], + ".", + color=[0.38, 0.82, 0.32], + markersize=6.0, + ) + plt.plot( + ts[int(t * 10)], + ygamma[int(t * 10)], + ".", + color=[0.38, 0.65, 0.87], + markersize=6.0, + ) + ax = plt.subplot(gs[2]) + plot_construct(ax, t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + plt.savefig("movie/repressilator_t{}.jpg".format(t), dpi=300) + + def main(): - t = np.arange(0, 30.1, 0.1) - ymtet, ymlac, ymgamma, ytet, ylac, ygamma = list(zip(*odeint(repressilator, initial, t))) - plt.close() - plt.figure(figsize=(3.5, 6.5)) - gs = gridspec.GridSpec(8, 1, height_ratios=[1, 2.5, 0.1, 1, 1, 1, 1, 1]) - - # Plot of repressilator circuit - ax = plt.subplot(gs[0]) - dnaplotlib.plot_sbol_designs([ax], [[plac, rbs1, tetr, term1, pgamma, rbs2, laci, term2, ptet, rbs3, gamma, term3]], - [[lac_repress, gamma_repress, tet_repress]]) - ax.set_ylim([-10, 31]) - - # Plot of repressilator dynamics - ax = plt.subplot(gs[1]) - plt.plot(t, ytet, color=[1.00, 0.75, 0.17]) - plt.plot(t, ylac, color=[0.38, 0.82, 0.32]) - plt.plot(t, ygamma, color=[0.38, 0.65, 0.87]) - plt.axvline(x=1, color='k', linewidth=0.7) - plt.axvline(x=12, color='k', linewidth=0.7) - plt.axvline(x=25.3, color='k', linewidth=0.7) - plt.axvline(x=27.3, color='k', linewidth=0.7) - plt.axvline(x=29.4, color='k', linewidth=0.7) - plt.ylim([1,4]) - ax.tick_params(axis='both', labelsize=8, width=0.8, length=3) - ax.yaxis.tick_left() - ax.xaxis.tick_bottom() - ax.set_xlabel('Time', fontsize=8, labelpad=1) - ax.set_ylabel('Protein Concentration', fontsize=8, labelpad=2) - plt.legend(['tetR', 'lacI', 'gamma'], frameon=False, fontsize=8, labelspacing=0.15, loc=(0.06,0.65)) - - # Plot of each timepoint - ax = plt.subplot(gs[3]) - plot_construct(ax, 1, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[4]) - plot_construct(ax, 12, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[5]) - plot_construct(ax, 25.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[6]) - plot_construct(ax, 27.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - ax = plt.subplot(gs[7]) - plot_construct(ax, 29.4, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - - # Update subplot spacing - plt.subplots_adjust(hspace=0.4, left=0.12, right=0.95, top=0.99, bottom=0.01) - - # Save the figure - plt.savefig('repressilator_animate.pdf', transparent=True) - plt.savefig('repressilator_animate.png', dpi=300) - - # Generate the movie frames - movie(t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) - -if __name__ == '__main__': - main() + t = np.arange(0, 30.1, 0.1) + ymtet, ymlac, ymgamma, ytet, ylac, ygamma = list( + zip(*odeint(repressilator, initial, t)) + ) + plt.close() + plt.figure(figsize=(3.5, 6.5)) + gs = gridspec.GridSpec(8, 1, height_ratios=[1, 2.5, 0.1, 1, 1, 1, 1, 1]) + + # Plot of repressilator circuit + ax = plt.subplot(gs[0]) + dnaplotlib.plot_sbol_designs( + [ax], + [ + [ + plac, + rbs1, + tetr, + term1, + pgamma, + rbs2, + laci, + term2, + ptet, + rbs3, + gamma, + term3, + ] + ], + [[lac_repress, gamma_repress, tet_repress]], + ) + ax.set_ylim([-10, 31]) + + # Plot of repressilator dynamics + ax = plt.subplot(gs[1]) + plt.plot(t, ytet, color=[1.00, 0.75, 0.17]) + plt.plot(t, ylac, color=[0.38, 0.82, 0.32]) + plt.plot(t, ygamma, color=[0.38, 0.65, 0.87]) + plt.axvline(x=1, color="k", linewidth=0.7) + plt.axvline(x=12, color="k", linewidth=0.7) + plt.axvline(x=25.3, color="k", linewidth=0.7) + plt.axvline(x=27.3, color="k", linewidth=0.7) + plt.axvline(x=29.4, color="k", linewidth=0.7) + plt.ylim([1, 4]) + ax.tick_params(axis="both", labelsize=8, width=0.8, length=3) + ax.yaxis.tick_left() + ax.xaxis.tick_bottom() + ax.set_xlabel("Time", fontsize=8, labelpad=1) + ax.set_ylabel("Protein Concentration", fontsize=8, labelpad=2) + plt.legend( + ["tetR", "lacI", "gamma"], + frameon=False, + fontsize=8, + labelspacing=0.15, + loc=(0.06, 0.65), + ) + + # Plot of each timepoint + ax = plt.subplot(gs[3]) + plot_construct(ax, 1, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[4]) + plot_construct(ax, 12, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[5]) + plot_construct(ax, 25.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[6]) + plot_construct(ax, 27.3, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + ax = plt.subplot(gs[7]) + plot_construct(ax, 29.4, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + + # Update subplot spacing + plt.subplots_adjust( + hspace=0.4, left=0.12, right=0.95, top=0.99, bottom=0.01 + ) + + # Save the figure + plt.savefig("repressilator_animate.pdf", transparent=True) + plt.savefig("repressilator_animate.png", dpi=300) + + # Generate the movie frames + movie(t, ymtet, ymlac, ymgamma, ytet, ylac, ygamma) + + +if __name__ == "__main__": + main() diff --git a/dnaplotlib/gallery/rotated_design/rotated_design 2.py b/dnaplotlib/gallery/rotated_design/rotated_design 2.py index 5ddf1f1..087ded5 100644 --- a/dnaplotlib/gallery/rotated_design/rotated_design 2.py +++ b/dnaplotlib/gallery/rotated_design/rotated_design 2.py @@ -14,113 +14,226 @@ from matplotlib.transforms import Affine2D import mpl_toolkits.axisartist.floating_axes as floating_axes import mpl_toolkits.axisartist.grid_helper_curvelinear as gh -from mpl_toolkits.axes_grid.parasite_axes import SubplotHost, ParasiteAxesAuxTrans +from mpl_toolkits.axes_grid.parasite_axes import ( + SubplotHost, + ParasiteAxesAuxTrans, +) from matplotlib import colors -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Color maps (we use these throughout) col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) -col_map['yellow'] = (0.98, 0.97, 0.35) -col_map['grey'] = (0.80, 0.80, 0.80) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) +col_map["yellow"] = (0.98, 0.97, 0.35) +col_map["grey"] = (0.80, 0.80, 0.80) # Options dictionary map (makes it easier to apply same styling) opt_map = {} -opt_map['Promoter'] = {'color':col_map['green']} -opt_map['UserDefined'] = {'color':col_map['grey']} -opt_map['Terminator'] = {'color':col_map['red']} -opt_map['pTet'] = {'color':[0,0,0], 'label':'pTet', 'label_y_offset':-4, 'x_extent':50} -opt_map['pTac'] = {'color':[0,0,0], 'label':'pTac', 'label_y_offset':-4, 'x_extent':50} -opt_map['pA1'] = {'color':col_map['green'], 'label':'pA1', 'label_y_offset':-4, 'label_color':col_map['green'], 'x_extent':50} -opt_map['pA3'] = {'color':col_map['blue'], 'label':'pA3', 'label_y_offset':-4, 'label_color':col_map['blue'], 'x_extent':50} -opt_map['pA5'] = {'color':col_map['orange'], 'label':'pA5', 'label_y_offset':-4, 'label_color':col_map['orange'], 'x_extent':50} -opt_map['g1'] = {'color':col_map['green'], 'label':'g1', 'label_style':'italic', 'label_y_offset':4, 'label_color':col_map['green']} -opt_map['g2'] = {'color':(1,1,1), 'label':'g2', 'label_style':'italic', 'label_y_offset':4, 'label_color':(0,0,0)} -opt_map['g3'] = {'color':col_map['blue'], 'label':'g3', 'label_style':'italic', 'label_y_offset':4, 'label_color':col_map['blue']} -opt_map['g5'] = {'color':col_map['orange'], 'label':'g5', 'label_style':'italic', 'label_y_offset':4, 'label_color':col_map['orange']} +opt_map["Promoter"] = {"color": col_map["green"]} +opt_map["UserDefined"] = {"color": col_map["grey"]} +opt_map["Terminator"] = {"color": col_map["red"]} +opt_map["pTet"] = { + "color": [0, 0, 0], + "label": "pTet", + "label_y_offset": -4, + "x_extent": 50, +} +opt_map["pTac"] = { + "color": [0, 0, 0], + "label": "pTac", + "label_y_offset": -4, + "x_extent": 50, +} +opt_map["pA1"] = { + "color": col_map["green"], + "label": "pA1", + "label_y_offset": -4, + "label_color": col_map["green"], + "x_extent": 50, +} +opt_map["pA3"] = { + "color": col_map["blue"], + "label": "pA3", + "label_y_offset": -4, + "label_color": col_map["blue"], + "x_extent": 50, +} +opt_map["pA5"] = { + "color": col_map["orange"], + "label": "pA5", + "label_y_offset": -4, + "label_color": col_map["orange"], + "x_extent": 50, +} +opt_map["g1"] = { + "color": col_map["green"], + "label": "g1", + "label_style": "italic", + "label_y_offset": 4, + "label_color": col_map["green"], +} +opt_map["g2"] = { + "color": (1, 1, 1), + "label": "g2", + "label_style": "italic", + "label_y_offset": 4, + "label_color": (0, 0, 0), +} +opt_map["g3"] = { + "color": col_map["blue"], + "label": "g3", + "label_style": "italic", + "label_y_offset": 4, + "label_color": col_map["blue"], +} +opt_map["g5"] = { + "color": col_map["orange"], + "label": "g5", + "label_style": "italic", + "label_y_offset": 4, + "label_color": col_map["orange"], +} # Function to load the design of the circuit from a text file -def load_design (filename, opt_map): - design = [] - parts = {} - seq = '' - cur_bp = 0 - reader = csv.reader(open(filename, 'rU'), delimiter=' ') - for row in reader: - if len(row) == 3: - p_type = row[0] - p_name = row[1] - p_seq = row[2] - p_opts = {} - if p_name in list(opt_map.keys()): - p_opts = opt_map[p_name] - elif p_type in list(opt_map.keys()): - p_opts = opt_map[p_type] - new_part = {'type':p_type, - 'name':p_name, - 'start':cur_bp, - 'end':cur_bp+len(p_seq), - 'fwd':True, - 'opts':p_opts} - # Return all the parts by name - if p_name not in list(parts.keys()): - parts[p_name] = [new_part] - else: - parts[p_name].append(new_part) - design.append(new_part) - seq += p_seq.upper() - cur_bp = cur_bp+len(p_seq) - return design, seq, parts +def load_design(filename, opt_map): + design = [] + parts = {} + seq = "" + cur_bp = 0 + reader = csv.reader(open(filename, "rU"), delimiter=" ") + for row in reader: + if len(row) == 3: + p_type = row[0] + p_name = row[1] + p_seq = row[2] + p_opts = {} + if p_name in list(opt_map.keys()): + p_opts = opt_map[p_name] + elif p_type in list(opt_map.keys()): + p_opts = opt_map[p_type] + new_part = { + "type": p_type, + "name": p_name, + "start": cur_bp, + "end": cur_bp + len(p_seq), + "fwd": True, + "opts": p_opts, + } + # Return all the parts by name + if p_name not in list(parts.keys()): + parts[p_name] = [new_part] + else: + parts[p_name].append(new_part) + design.append(new_part) + seq += p_seq.upper() + cur_bp = cur_bp + len(p_seq) + return design, seq, parts + # Function to calculate the reverse complement of a sequence def revcomp(seq, trans=string.maketrans("ACGT", "TGCA")): - return "".join(reversed(seq.translate(trans))) + return "".join(reversed(seq.translate(trans))) + # Function to calculate number of shared bases between two sequences def homology(seq1, seq2): - same_count = 0 - for idx in range(len(seq1)): - if idx < len(seq2): - if seq1[idx] == seq2[idx]: - same_count += 1 - return same_count + same_count = 0 + for idx in range(len(seq1)): + if idx < len(seq2): + if seq1[idx] == seq2[idx]: + same_count += 1 + return same_count + # Generate a homology matrix for a given sequence and window length # (Homology is calculated against itself) def homology_matrix2(seq, window_len=20): - h_matrix = np.zeros((len(seq), len(seq))) - for idx1 in range(len(seq)-window_len): - # Extract the first seqeunce - start_bp1 = idx1 - end_bp1 = idx1+window_len - cur_seq1 = seq[start_bp1:end_bp1] - - for idx2 in range(len(seq)-window_len): - # Extract the second sequence - start_bp2 = idx2 - end_bp2 = idx2+window_len - cur_seq2 = seq[start_bp2:end_bp2] - - # Calculate homology (include reverse complement) - if cur_seq1 == cur_seq2 or cur_seq1 == revcomp(cur_seq2): - h_matrix[start_bp1:end_bp1,start_bp2:end_bp2] = 1 - return h_matrix + h_matrix = np.zeros((len(seq), len(seq))) + for idx1 in range(len(seq) - window_len): + # Extract the first seqeunce + start_bp1 = idx1 + end_bp1 = idx1 + window_len + cur_seq1 = seq[start_bp1:end_bp1] + + for idx2 in range(len(seq) - window_len): + # Extract the second sequence + start_bp2 = idx2 + end_bp2 = idx2 + window_len + cur_seq2 = seq[start_bp2:end_bp2] + + # Calculate homology (include reverse complement) + if cur_seq1 == cur_seq2 or cur_seq1 == revcomp(cur_seq2): + h_matrix[start_bp1:end_bp1, start_bp2:end_bp2] = 1 + return h_matrix + # Load the design -design, seq, parts = load_design('data_design.txt', opt_map) +design, seq, parts = load_design("data_design.txt", opt_map) # Create regulation -arc1 = {'type':'Repression', 'from_part':parts['g5'][0], 'to_part':parts['pA5'][0], 'opts':{'color':col_map['orange'], 'linewidth':1.0, 'arrowhead_length':8, 'arc_height_start':8, 'arc_height_const':9, 'arc_height_spacing':1.1, 'arc_height_end':7.5}} -arc2 = {'type':'Repression', 'from_part':parts['g1'][0], 'to_part':parts['pA1'][0], 'opts':{'color':col_map['green'], 'linewidth':1.0, 'arrowhead_length':8, 'arc_height_start':8, 'arc_height_const':9, 'arc_height_spacing':1.1, 'arc_height_end':7.5}} -arc3 = {'type':'Repression', 'from_part':parts['g3'][0], 'to_part':parts['pA3'][0], 'opts':{'color':col_map['blue'], 'linewidth':1.0, 'arrowhead_length':8, 'arc_height_start':8, 'arc_height_const':9, 'arc_height_spacing':1.1, 'arc_height_end':7.5}} -arc4 = {'type':'Repression', 'from_part':parts['g3'][1], 'to_part':parts['pA3'][0], 'opts':{'color':col_map['blue'], 'linewidth':1.0, 'arrowhead_length':8, 'arc_height_start':8, 'arc_height_const':9, 'arc_height_spacing':1.1, 'arc_height_end':7.5}} +arc1 = { + "type": "Repression", + "from_part": parts["g5"][0], + "to_part": parts["pA5"][0], + "opts": { + "color": col_map["orange"], + "linewidth": 1.0, + "arrowhead_length": 8, + "arc_height_start": 8, + "arc_height_const": 9, + "arc_height_spacing": 1.1, + "arc_height_end": 7.5, + }, +} +arc2 = { + "type": "Repression", + "from_part": parts["g1"][0], + "to_part": parts["pA1"][0], + "opts": { + "color": col_map["green"], + "linewidth": 1.0, + "arrowhead_length": 8, + "arc_height_start": 8, + "arc_height_const": 9, + "arc_height_spacing": 1.1, + "arc_height_end": 7.5, + }, +} +arc3 = { + "type": "Repression", + "from_part": parts["g3"][0], + "to_part": parts["pA3"][0], + "opts": { + "color": col_map["blue"], + "linewidth": 1.0, + "arrowhead_length": 8, + "arc_height_start": 8, + "arc_height_const": 9, + "arc_height_spacing": 1.1, + "arc_height_end": 7.5, + }, +} +arc4 = { + "type": "Repression", + "from_part": parts["g3"][1], + "to_part": parts["pA3"][0], + "opts": { + "color": col_map["blue"], + "linewidth": 1.0, + "arrowhead_length": 8, + "arc_height_start": 8, + "arc_height_const": 9, + "arc_height_spacing": 1.1, + "arc_height_end": 7.5, + }, +} regs = [arc1, arc2, arc3, arc4] @@ -132,52 +245,60 @@ def homology_matrix2(seq, window_len=20): # Collate homology results so that different levels of homology are coloured differently h_matrix = np.zeros((len(seq), len(seq))) for idx1 in range(len(seq)): - for idx2 in range(len(seq)): - if h_matrix_60[idx1,idx2] == 1: - h_matrix[idx1,idx2] = 60 - elif h_matrix_30[idx1,idx2] == 1: - h_matrix[idx1,idx2] = 25 - elif h_matrix_15[idx1,idx2] == 1: - h_matrix[idx1,idx2] = 10 + for idx2 in range(len(seq)): + if h_matrix_60[idx1, idx2] == 1: + h_matrix[idx1, idx2] = 60 + elif h_matrix_30[idx1, idx2] == 1: + h_matrix[idx1, idx2] = 25 + elif h_matrix_15[idx1, idx2] == 1: + h_matrix[idx1, idx2] = 10 # Create the figure and all axes to draw to -fig = plt.figure(figsize=(3.2,3.4)) -gs = gridspec.GridSpec(2, 2, width_ratios=[1,9], height_ratios=[1.6,9]) +fig = plt.figure(figsize=(3.2, 3.4)) +gs = gridspec.GridSpec(2, 2, width_ratios=[1, 9], height_ratios=[1.6, 9]) ax_dna_x = plt.subplot(gs[1]) # Redender the DNA dr = dpl.DNARenderer(scale=1, linewidth=0.9) -start, end = dr.renderDNA(ax_dna_x, design, dr.trace_part_renderers(), - regs=regs, reg_renderers=dr.std_reg_renderers()) +start, end = dr.renderDNA( + ax_dna_x, + design, + dr.trace_part_renderers(), + regs=regs, + reg_renderers=dr.std_reg_renderers(), +) # Set bounds and display options for the DNA axis -dna_len = end-start +dna_len = end - start ax_dna_x.set_xlim([start, end]) -ax_dna_x.set_ylim([-6,13]) -ax_dna_x.plot([start-20,end+20], [0,0], color=(0,0,0), linewidth=1.0, zorder=1) -ax_dna_x.axis('off') +ax_dna_x.set_ylim([-6, 13]) +ax_dna_x.plot( + [start - 20, end + 20], [0, 0], color=(0, 0, 0), linewidth=1.0, zorder=1 +) +ax_dna_x.axis("off") # Setup the rotated axis def setup_rot_axes(fig, rect): - tr = Affine2D().rotate_deg(90.0) - grid_helper = gh.GridHelperCurveLinear(tr) - ax1 = SubplotHost(fig, rect, grid_helper=grid_helper) - fig.add_subplot(ax1) - ax2 = ParasiteAxesAuxTrans(ax1, tr, "equal") - ax1.set_ylim([end, start]) - ax1.set_xlim([-8, 4]) - ax2 = ax1.get_aux_axes(tr) - ax1.set_aspect('auto') - ax1.axis['top', 'right', 'left', 'bottom'].set_visible(False) - return ax1, ax2 + tr = Affine2D().rotate_deg(90.0) + grid_helper = gh.GridHelperCurveLinear(tr) + ax1 = SubplotHost(fig, rect, grid_helper=grid_helper) + fig.add_subplot(ax1) + ax2 = ParasiteAxesAuxTrans(ax1, tr, "equal") + ax1.set_ylim([end, start]) + ax1.set_xlim([-8, 4]) + ax2 = ax1.get_aux_axes(tr) + ax1.set_aspect("auto") + ax1.axis["top", "right", "left", "bottom"].set_visible(False) + return ax1, ax2 + # Generate the rotated axis. ax_dna_y_main, ax_dna_y = setup_rot_axes(fig, gs[2]) # Before rendering rotated circuit remove all labels (simplify plot) for el in design: - if 'label' in list(el['opts'].keys()): - el['opts']['label'] = '' + if "label" in list(el["opts"].keys()): + el["opts"]["label"] = "" # Render the rotated design normally (rotation done by matplotlib) start, end = dr.renderDNA(ax_dna_y, design, dr.trace_part_renderers()) @@ -185,18 +306,20 @@ def setup_rot_axes(fig, rect): # Plot the homology matrix (make sure aspect the same) ax_data = plt.subplot(gs[3], sharex=ax_dna_x) ax_data.matshow(h_matrix, cmap=pylab.cm.gray_r) -ax_data.set_aspect('auto') +ax_data.set_aspect("auto") ax_data.set_xticks([]) ax_data.set_yticks([]) ax_data.set_ylim([end, start]) ax_data.set_xlim([start, end]) # Sort out subplot spacing -plt.subplots_adjust(hspace=.04, wspace=.04, left=.01, right=.99, top=0.99, bottom=0.01) +plt.subplots_adjust( + hspace=0.04, wspace=0.04, left=0.01, right=0.99, top=0.99, bottom=0.01 +) # Save the figure -fig.savefig('rotated_design.pdf', transparent=True) -fig.savefig('rotated_design.png', dpi=300) +fig.savefig("rotated_design.pdf", transparent=True) +fig.savefig("rotated_design.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/rotated_design/rotated_design.py b/dnaplotlib/gallery/rotated_design/rotated_design.py index 5ddf1f1..087ded5 100755 --- a/dnaplotlib/gallery/rotated_design/rotated_design.py +++ b/dnaplotlib/gallery/rotated_design/rotated_design.py @@ -14,113 +14,226 @@ from matplotlib.transforms import Affine2D import mpl_toolkits.axisartist.floating_axes as floating_axes import mpl_toolkits.axisartist.grid_helper_curvelinear as gh -from mpl_toolkits.axes_grid.parasite_axes import SubplotHost, ParasiteAxesAuxTrans +from mpl_toolkits.axes_grid.parasite_axes import ( + SubplotHost, + ParasiteAxesAuxTrans, +) from matplotlib import colors -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Color maps (we use these throughout) col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) -col_map['yellow'] = (0.98, 0.97, 0.35) -col_map['grey'] = (0.80, 0.80, 0.80) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) +col_map["yellow"] = (0.98, 0.97, 0.35) +col_map["grey"] = (0.80, 0.80, 0.80) # Options dictionary map (makes it easier to apply same styling) opt_map = {} -opt_map['Promoter'] = {'color':col_map['green']} -opt_map['UserDefined'] = {'color':col_map['grey']} -opt_map['Terminator'] = {'color':col_map['red']} -opt_map['pTet'] = {'color':[0,0,0], 'label':'pTet', 'label_y_offset':-4, 'x_extent':50} -opt_map['pTac'] = {'color':[0,0,0], 'label':'pTac', 'label_y_offset':-4, 'x_extent':50} -opt_map['pA1'] = {'color':col_map['green'], 'label':'pA1', 'label_y_offset':-4, 'label_color':col_map['green'], 'x_extent':50} -opt_map['pA3'] = {'color':col_map['blue'], 'label':'pA3', 'label_y_offset':-4, 'label_color':col_map['blue'], 'x_extent':50} -opt_map['pA5'] = {'color':col_map['orange'], 'label':'pA5', 'label_y_offset':-4, 'label_color':col_map['orange'], 'x_extent':50} -opt_map['g1'] = {'color':col_map['green'], 'label':'g1', 'label_style':'italic', 'label_y_offset':4, 'label_color':col_map['green']} -opt_map['g2'] = {'color':(1,1,1), 'label':'g2', 'label_style':'italic', 'label_y_offset':4, 'label_color':(0,0,0)} -opt_map['g3'] = {'color':col_map['blue'], 'label':'g3', 'label_style':'italic', 'label_y_offset':4, 'label_color':col_map['blue']} -opt_map['g5'] = {'color':col_map['orange'], 'label':'g5', 'label_style':'italic', 'label_y_offset':4, 'label_color':col_map['orange']} +opt_map["Promoter"] = {"color": col_map["green"]} +opt_map["UserDefined"] = {"color": col_map["grey"]} +opt_map["Terminator"] = {"color": col_map["red"]} +opt_map["pTet"] = { + "color": [0, 0, 0], + "label": "pTet", + "label_y_offset": -4, + "x_extent": 50, +} +opt_map["pTac"] = { + "color": [0, 0, 0], + "label": "pTac", + "label_y_offset": -4, + "x_extent": 50, +} +opt_map["pA1"] = { + "color": col_map["green"], + "label": "pA1", + "label_y_offset": -4, + "label_color": col_map["green"], + "x_extent": 50, +} +opt_map["pA3"] = { + "color": col_map["blue"], + "label": "pA3", + "label_y_offset": -4, + "label_color": col_map["blue"], + "x_extent": 50, +} +opt_map["pA5"] = { + "color": col_map["orange"], + "label": "pA5", + "label_y_offset": -4, + "label_color": col_map["orange"], + "x_extent": 50, +} +opt_map["g1"] = { + "color": col_map["green"], + "label": "g1", + "label_style": "italic", + "label_y_offset": 4, + "label_color": col_map["green"], +} +opt_map["g2"] = { + "color": (1, 1, 1), + "label": "g2", + "label_style": "italic", + "label_y_offset": 4, + "label_color": (0, 0, 0), +} +opt_map["g3"] = { + "color": col_map["blue"], + "label": "g3", + "label_style": "italic", + "label_y_offset": 4, + "label_color": col_map["blue"], +} +opt_map["g5"] = { + "color": col_map["orange"], + "label": "g5", + "label_style": "italic", + "label_y_offset": 4, + "label_color": col_map["orange"], +} # Function to load the design of the circuit from a text file -def load_design (filename, opt_map): - design = [] - parts = {} - seq = '' - cur_bp = 0 - reader = csv.reader(open(filename, 'rU'), delimiter=' ') - for row in reader: - if len(row) == 3: - p_type = row[0] - p_name = row[1] - p_seq = row[2] - p_opts = {} - if p_name in list(opt_map.keys()): - p_opts = opt_map[p_name] - elif p_type in list(opt_map.keys()): - p_opts = opt_map[p_type] - new_part = {'type':p_type, - 'name':p_name, - 'start':cur_bp, - 'end':cur_bp+len(p_seq), - 'fwd':True, - 'opts':p_opts} - # Return all the parts by name - if p_name not in list(parts.keys()): - parts[p_name] = [new_part] - else: - parts[p_name].append(new_part) - design.append(new_part) - seq += p_seq.upper() - cur_bp = cur_bp+len(p_seq) - return design, seq, parts +def load_design(filename, opt_map): + design = [] + parts = {} + seq = "" + cur_bp = 0 + reader = csv.reader(open(filename, "rU"), delimiter=" ") + for row in reader: + if len(row) == 3: + p_type = row[0] + p_name = row[1] + p_seq = row[2] + p_opts = {} + if p_name in list(opt_map.keys()): + p_opts = opt_map[p_name] + elif p_type in list(opt_map.keys()): + p_opts = opt_map[p_type] + new_part = { + "type": p_type, + "name": p_name, + "start": cur_bp, + "end": cur_bp + len(p_seq), + "fwd": True, + "opts": p_opts, + } + # Return all the parts by name + if p_name not in list(parts.keys()): + parts[p_name] = [new_part] + else: + parts[p_name].append(new_part) + design.append(new_part) + seq += p_seq.upper() + cur_bp = cur_bp + len(p_seq) + return design, seq, parts + # Function to calculate the reverse complement of a sequence def revcomp(seq, trans=string.maketrans("ACGT", "TGCA")): - return "".join(reversed(seq.translate(trans))) + return "".join(reversed(seq.translate(trans))) + # Function to calculate number of shared bases between two sequences def homology(seq1, seq2): - same_count = 0 - for idx in range(len(seq1)): - if idx < len(seq2): - if seq1[idx] == seq2[idx]: - same_count += 1 - return same_count + same_count = 0 + for idx in range(len(seq1)): + if idx < len(seq2): + if seq1[idx] == seq2[idx]: + same_count += 1 + return same_count + # Generate a homology matrix for a given sequence and window length # (Homology is calculated against itself) def homology_matrix2(seq, window_len=20): - h_matrix = np.zeros((len(seq), len(seq))) - for idx1 in range(len(seq)-window_len): - # Extract the first seqeunce - start_bp1 = idx1 - end_bp1 = idx1+window_len - cur_seq1 = seq[start_bp1:end_bp1] - - for idx2 in range(len(seq)-window_len): - # Extract the second sequence - start_bp2 = idx2 - end_bp2 = idx2+window_len - cur_seq2 = seq[start_bp2:end_bp2] - - # Calculate homology (include reverse complement) - if cur_seq1 == cur_seq2 or cur_seq1 == revcomp(cur_seq2): - h_matrix[start_bp1:end_bp1,start_bp2:end_bp2] = 1 - return h_matrix + h_matrix = np.zeros((len(seq), len(seq))) + for idx1 in range(len(seq) - window_len): + # Extract the first seqeunce + start_bp1 = idx1 + end_bp1 = idx1 + window_len + cur_seq1 = seq[start_bp1:end_bp1] + + for idx2 in range(len(seq) - window_len): + # Extract the second sequence + start_bp2 = idx2 + end_bp2 = idx2 + window_len + cur_seq2 = seq[start_bp2:end_bp2] + + # Calculate homology (include reverse complement) + if cur_seq1 == cur_seq2 or cur_seq1 == revcomp(cur_seq2): + h_matrix[start_bp1:end_bp1, start_bp2:end_bp2] = 1 + return h_matrix + # Load the design -design, seq, parts = load_design('data_design.txt', opt_map) +design, seq, parts = load_design("data_design.txt", opt_map) # Create regulation -arc1 = {'type':'Repression', 'from_part':parts['g5'][0], 'to_part':parts['pA5'][0], 'opts':{'color':col_map['orange'], 'linewidth':1.0, 'arrowhead_length':8, 'arc_height_start':8, 'arc_height_const':9, 'arc_height_spacing':1.1, 'arc_height_end':7.5}} -arc2 = {'type':'Repression', 'from_part':parts['g1'][0], 'to_part':parts['pA1'][0], 'opts':{'color':col_map['green'], 'linewidth':1.0, 'arrowhead_length':8, 'arc_height_start':8, 'arc_height_const':9, 'arc_height_spacing':1.1, 'arc_height_end':7.5}} -arc3 = {'type':'Repression', 'from_part':parts['g3'][0], 'to_part':parts['pA3'][0], 'opts':{'color':col_map['blue'], 'linewidth':1.0, 'arrowhead_length':8, 'arc_height_start':8, 'arc_height_const':9, 'arc_height_spacing':1.1, 'arc_height_end':7.5}} -arc4 = {'type':'Repression', 'from_part':parts['g3'][1], 'to_part':parts['pA3'][0], 'opts':{'color':col_map['blue'], 'linewidth':1.0, 'arrowhead_length':8, 'arc_height_start':8, 'arc_height_const':9, 'arc_height_spacing':1.1, 'arc_height_end':7.5}} +arc1 = { + "type": "Repression", + "from_part": parts["g5"][0], + "to_part": parts["pA5"][0], + "opts": { + "color": col_map["orange"], + "linewidth": 1.0, + "arrowhead_length": 8, + "arc_height_start": 8, + "arc_height_const": 9, + "arc_height_spacing": 1.1, + "arc_height_end": 7.5, + }, +} +arc2 = { + "type": "Repression", + "from_part": parts["g1"][0], + "to_part": parts["pA1"][0], + "opts": { + "color": col_map["green"], + "linewidth": 1.0, + "arrowhead_length": 8, + "arc_height_start": 8, + "arc_height_const": 9, + "arc_height_spacing": 1.1, + "arc_height_end": 7.5, + }, +} +arc3 = { + "type": "Repression", + "from_part": parts["g3"][0], + "to_part": parts["pA3"][0], + "opts": { + "color": col_map["blue"], + "linewidth": 1.0, + "arrowhead_length": 8, + "arc_height_start": 8, + "arc_height_const": 9, + "arc_height_spacing": 1.1, + "arc_height_end": 7.5, + }, +} +arc4 = { + "type": "Repression", + "from_part": parts["g3"][1], + "to_part": parts["pA3"][0], + "opts": { + "color": col_map["blue"], + "linewidth": 1.0, + "arrowhead_length": 8, + "arc_height_start": 8, + "arc_height_const": 9, + "arc_height_spacing": 1.1, + "arc_height_end": 7.5, + }, +} regs = [arc1, arc2, arc3, arc4] @@ -132,52 +245,60 @@ def homology_matrix2(seq, window_len=20): # Collate homology results so that different levels of homology are coloured differently h_matrix = np.zeros((len(seq), len(seq))) for idx1 in range(len(seq)): - for idx2 in range(len(seq)): - if h_matrix_60[idx1,idx2] == 1: - h_matrix[idx1,idx2] = 60 - elif h_matrix_30[idx1,idx2] == 1: - h_matrix[idx1,idx2] = 25 - elif h_matrix_15[idx1,idx2] == 1: - h_matrix[idx1,idx2] = 10 + for idx2 in range(len(seq)): + if h_matrix_60[idx1, idx2] == 1: + h_matrix[idx1, idx2] = 60 + elif h_matrix_30[idx1, idx2] == 1: + h_matrix[idx1, idx2] = 25 + elif h_matrix_15[idx1, idx2] == 1: + h_matrix[idx1, idx2] = 10 # Create the figure and all axes to draw to -fig = plt.figure(figsize=(3.2,3.4)) -gs = gridspec.GridSpec(2, 2, width_ratios=[1,9], height_ratios=[1.6,9]) +fig = plt.figure(figsize=(3.2, 3.4)) +gs = gridspec.GridSpec(2, 2, width_ratios=[1, 9], height_ratios=[1.6, 9]) ax_dna_x = plt.subplot(gs[1]) # Redender the DNA dr = dpl.DNARenderer(scale=1, linewidth=0.9) -start, end = dr.renderDNA(ax_dna_x, design, dr.trace_part_renderers(), - regs=regs, reg_renderers=dr.std_reg_renderers()) +start, end = dr.renderDNA( + ax_dna_x, + design, + dr.trace_part_renderers(), + regs=regs, + reg_renderers=dr.std_reg_renderers(), +) # Set bounds and display options for the DNA axis -dna_len = end-start +dna_len = end - start ax_dna_x.set_xlim([start, end]) -ax_dna_x.set_ylim([-6,13]) -ax_dna_x.plot([start-20,end+20], [0,0], color=(0,0,0), linewidth=1.0, zorder=1) -ax_dna_x.axis('off') +ax_dna_x.set_ylim([-6, 13]) +ax_dna_x.plot( + [start - 20, end + 20], [0, 0], color=(0, 0, 0), linewidth=1.0, zorder=1 +) +ax_dna_x.axis("off") # Setup the rotated axis def setup_rot_axes(fig, rect): - tr = Affine2D().rotate_deg(90.0) - grid_helper = gh.GridHelperCurveLinear(tr) - ax1 = SubplotHost(fig, rect, grid_helper=grid_helper) - fig.add_subplot(ax1) - ax2 = ParasiteAxesAuxTrans(ax1, tr, "equal") - ax1.set_ylim([end, start]) - ax1.set_xlim([-8, 4]) - ax2 = ax1.get_aux_axes(tr) - ax1.set_aspect('auto') - ax1.axis['top', 'right', 'left', 'bottom'].set_visible(False) - return ax1, ax2 + tr = Affine2D().rotate_deg(90.0) + grid_helper = gh.GridHelperCurveLinear(tr) + ax1 = SubplotHost(fig, rect, grid_helper=grid_helper) + fig.add_subplot(ax1) + ax2 = ParasiteAxesAuxTrans(ax1, tr, "equal") + ax1.set_ylim([end, start]) + ax1.set_xlim([-8, 4]) + ax2 = ax1.get_aux_axes(tr) + ax1.set_aspect("auto") + ax1.axis["top", "right", "left", "bottom"].set_visible(False) + return ax1, ax2 + # Generate the rotated axis. ax_dna_y_main, ax_dna_y = setup_rot_axes(fig, gs[2]) # Before rendering rotated circuit remove all labels (simplify plot) for el in design: - if 'label' in list(el['opts'].keys()): - el['opts']['label'] = '' + if "label" in list(el["opts"].keys()): + el["opts"]["label"] = "" # Render the rotated design normally (rotation done by matplotlib) start, end = dr.renderDNA(ax_dna_y, design, dr.trace_part_renderers()) @@ -185,18 +306,20 @@ def setup_rot_axes(fig, rect): # Plot the homology matrix (make sure aspect the same) ax_data = plt.subplot(gs[3], sharex=ax_dna_x) ax_data.matshow(h_matrix, cmap=pylab.cm.gray_r) -ax_data.set_aspect('auto') +ax_data.set_aspect("auto") ax_data.set_xticks([]) ax_data.set_yticks([]) ax_data.set_ylim([end, start]) ax_data.set_xlim([start, end]) # Sort out subplot spacing -plt.subplots_adjust(hspace=.04, wspace=.04, left=.01, right=.99, top=0.99, bottom=0.01) +plt.subplots_adjust( + hspace=0.04, wspace=0.04, left=0.01, right=0.99, top=0.99, bottom=0.01 +) # Save the figure -fig.savefig('rotated_design.pdf', transparent=True) -fig.savefig('rotated_design.png', dpi=300) +fig.savefig("rotated_design.pdf", transparent=True) +fig.savefig("rotated_design.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/sbol_interactive/assembly 2.py b/dnaplotlib/gallery/sbol_interactive/assembly 2.py index 95fe395..1fa14be 100644 --- a/dnaplotlib/gallery/sbol_interactive/assembly 2.py +++ b/dnaplotlib/gallery/sbol_interactive/assembly 2.py @@ -4,13 +4,19 @@ # Add SBOL module directory to PYTHONPATH import os, sys -lib_path = os.path.abspath('..') + +lib_path = os.path.abspath("..") sys.path.append(lib_path) import random # For random sequence generation import sbol -#from sbol import libsbol -from subprocess import Popen, PIPE, STDOUT # For calling command line tools Clustal Omega and EMBOSS + +# from sbol import libsbol +from subprocess import ( + Popen, + PIPE, + STDOUT, +) # For calling command line tools Clustal Omega and EMBOSS # Command line tools for sequence verification CLUSTAL_DIR = "C:/Program Files (x86)/clustal-omega-1.2.0-win32" @@ -33,23 +39,29 @@ SO_NUCLEOTIDE_MATCH = "http://purl.obolibrary.org/obo/SO_0000347" col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) random.seed() + def populate_subcomponents(parent_component): for ann in parent_component.annotations: i_start = ann.start - 1 i_end = ann.end - sub_seq_nucleotides = parent_component.sequence.nucleotides[i_start:i_end] - #ann.subComponent = sbol.DNAComponent(doc, '%s//subComponent' %ann.uri) - ann.subcomponent.sequence = sbol.DNASequence(doc, '%s//Sequence' %ann.subcomponent.uri ) + sub_seq_nucleotides = parent_component.sequence.nucleotides[ + i_start:i_end + ] + # ann.subComponent = sbol.DNAComponent(doc, '%s//subComponent' %ann.uri) + ann.subcomponent.sequence = sbol.DNASequence( + doc, "%s//Sequence" % ann.subcomponent.uri + ) ann.subcomponent.sequence.nucleotides = sub_seq_nucleotides + def find_sequence_homologs(target_seq): result_handle = NCBIWWW.qblast("blastn", "nt", target_seq) blast_records = list(NCBIXML.parseAndGenerateImage(result_handle)) @@ -61,17 +73,20 @@ def find_sequence_homologs(target_seq): variant_urls = [] for alignment in rec.alignments: hsp = alignment.hsps[0] # high-scoring pairs - variant_acc_nos.append( str(alignment.accession) ) - variant_nucleotides.append( str(hsp.sbjct) ) - #cds_variant_urls.append(alignment.accession) + variant_acc_nos.append(str(alignment.accession)) + variant_nucleotides.append(str(hsp.sbjct)) + # cds_variant_urls.append(alignment.accession) return variant_acc_nos, variant_nucleotides, variant_urls + def remove_annotation(parent_component, deleted_ann): - """ An annotation is removed. The precedes relationship, start and end indexes of other annotations - are updated accordingly """ + """An annotation is removed. The precedes relationship, start and end indexes of other annotations + are updated accordingly""" - downstream_ann = deleted_ann.precedes[0] # Find annotation downstream of the one to be removed + downstream_ann = deleted_ann.precedes[ + 0 + ] # Find annotation downstream of the one to be removed # Finds the upstream annotation that precedes the annotation to be removed for ann in parent_component.annotations: @@ -84,7 +99,7 @@ def remove_annotation(parent_component, deleted_ann): # Update all start and end indices for annotations downstream from insertion deletion_size = deleted_ann.end - deleted_ann.start + 1 - while (len(upstream_ann.precedes) > 0): + while len(upstream_ann.precedes) > 0: downstream_ann = upstream_ann.precedes[0] old_start = downstream_ann.start old_end = downstream_ann.end @@ -94,14 +109,14 @@ def remove_annotation(parent_component, deleted_ann): downstream_ann.end = new_end upstream_ann = downstream_ann - #doc.sequences.remove(deleted_ann.subcomponent.sequence) - #doc.components.remove(deleted_ann.subcomponent) - #doc.annotations.remove(deleted_ann) + # doc.sequences.remove(deleted_ann.subcomponent.sequence) + # doc.components.remove(deleted_ann.subcomponent) + # doc.annotations.remove(deleted_ann) parent_component.annotations.remove(deleted_ann) def insert_annotation_downstream(parent_component, upstream_ann, insert_ann): - """ A new annotation is inserted after an upstream annotation. + """A new annotation is inserted after an upstream annotation. The precedes relationship, start and end indexes are update accordingly. The annotation is expected to have a subComponent and Sequence object attached""" parent_component.annotations.append(insert_ann) @@ -114,7 +129,9 @@ def insert_annotation_downstream(parent_component, upstream_ann, insert_ann): # Update precedes relationship of annotations # If inserting annotation between two existing annotations if upstream_ann.precedes: - downstream_ann = upstream_ann.precedes[0] # Assumes annotations only have one precedes relationship + downstream_ann = upstream_ann.precedes[ + 0 + ] # Assumes annotations only have one precedes relationship upstream_ann.precedes.remove(upstream_ann.precedes[0]) upstream_ann.precedes.append(insert_ann) insert_ann.precedes.append(downstream_ann) @@ -123,7 +140,7 @@ def insert_annotation_downstream(parent_component, upstream_ann, insert_ann): # Update all start and end indices for annotations downstream from insertion upstream_ann = insert_ann - while (len(upstream_ann.precedes) > 0): + while len(upstream_ann.precedes) > 0: downstream_ann = upstream_ann.precedes[0] old_start = downstream_ann.start old_end = downstream_ann.end @@ -133,123 +150,148 @@ def insert_annotation_downstream(parent_component, upstream_ann, insert_ann): downstream_ann.end = new_end upstream_ann = downstream_ann + def insert_annotation_upstream(parent_component, insert_ann, downstream_ann): - """ A new annotation (upstream) is inserted before the downstream annotation - The precedes relationship, start and end indexes are update accordingly """ - #print downstream_ann.uri - #print + """A new annotation (upstream) is inserted before the downstream annotation + The precedes relationship, start and end indexes are update accordingly""" + # print downstream_ann.uri + # print for i_ann, ann in enumerate(parent_component.annotations): - #print i_ann, ann.uri + # print i_ann, ann.uri if downstream_ann in ann.precedes: - upstream_uri = ann.uri # finds the annotation upstream, because it owns the precedes - print('Upstream uri: %s' %upstream_uri) + upstream_uri = ( + ann.uri + ) # finds the annotation upstream, because it owns the precedes + print("Upstream uri: %s" % upstream_uri) upstream_ann = parent_component.annotations[upstream_uri] insert_annotation_downstream(parent_component, upstream_ann, insert_ann) + def assemble_subcomponents(parent_component): parent_seq_len = 0 for ann in parent_component.annotations: - parent_seq_len = parent_seq_len + len(ann.subcomponent.sequence.nucleotides) - assembled_seq = 'n' * parent_seq_len + parent_seq_len = parent_seq_len + len( + ann.subcomponent.sequence.nucleotides + ) + assembled_seq = "n" * parent_seq_len for ann in parent_component.annotations: - #assembled_seq[ann.start:ann.end] = ann.subcomponent.sequence.nucleotides - assembled_seq = assembled_seq[:ann.start - 1] + \ - ann.subcomponent.sequence.nucleotides + \ - assembled_seq[ann.end:] + # assembled_seq[ann.start:ann.end] = ann.subcomponent.sequence.nucleotides + assembled_seq = ( + assembled_seq[: ann.start - 1] + + ann.subcomponent.sequence.nucleotides + + assembled_seq[ann.end :] + ) parent_component.sequence.nucleotides = assembled_seq + def print_downstream_Annotations(ann): reader_head = ann - print(reader_head.uri, end=' ') + print(reader_head.uri, end=" ") while reader_head.precedes: reader_head = reader_head.precedes[0] - print('->', reader_head.uri, end=' ') + print("->", reader_head.uri, end=" ") print() -#def write_to_fasta(seq_name, nucleotides, col_length = 20) : -def write_to_fasta(entries, col_length = 20) : + +# def write_to_fasta(seq_name, nucleotides, col_length = 20) : +def write_to_fasta(entries, col_length=20): formatted_entries = [] for seq_name, nts in entries: - nts = [ nts[i:i + col_length] for i in range(0, len(nts), col_length)] - nts = '\n'.join(nts) - formatted_entries.append( '>%s\n%s' %(seq_name, nts) ) - return '\r\n'.join(formatted_entries) - + nts = [nts[i : i + col_length] for i in range(0, len(nts), col_length)] + nts = "\n".join(nts) + formatted_entries.append(">%s\n%s" % (seq_name, nts)) + return "\r\n".join(formatted_entries) def parse_fasta(fasta_str): - entries = fasta_str.split('>') + entries = fasta_str.split(">") entries = [entry.strip() for entry in entries] - entries = [entry.encode('ascii','ignore') for entry in entries] - entries = entries[1:] # Sequence has empty entry '' at the beginning of the list - if len(entries) < 1 : - print('Invalid FASTA format') + entries = [entry.encode("ascii", "ignore") for entry in entries] + entries = entries[ + 1: + ] # Sequence has empty entry '' at the beginning of the list + if len(entries) < 1: + print("Invalid FASTA format") return - else : + else: parsed_entries = [] - for entry in entries : + for entry in entries: try: entry = entry.strip() - tokens = entry.split('\n') + tokens = entry.split("\n") seq_name = tokens[0] - #nucleotides = '\r\n'.join(tokens[1:]) - nucleotides = ''.join(tokens[1:]) - nucleotides = nucleotides.replace('\r', '') + # nucleotides = '\r\n'.join(tokens[1:]) + nucleotides = "".join(tokens[1:]) + nucleotides = nucleotides.replace("\r", "") parsed_entries.append((seq_name, nucleotides)) except: - print(('Invalid entry: %s' %entry)) + print(("Invalid entry: %s" % entry)) return parsed_entries -def getSequenceAnnotationsAtBaseNo(parent_component, base_no, annotations_found = None): + +def getSequenceAnnotationsAtBaseNo( + parent_component, base_no, annotations_found=None +): # Assumes parent_component is an SBOL data structure of the general form DNAComponent(->SequenceAnnotation->DNAComponent)n # where n+1 is an integer describing how many hierarchical levels are in the SBOL structure - if not annotations_found : + if not annotations_found: annotations_found = [] # print "Searching for base no %d" %base_no # Look at each of this component's annotations, is the target base there? - for ann in parent_component.annotations : + for ann in parent_component.annotations: # print ann.uri, ann.start, ann.end # If target base is found ... - if base_no >= ann.start and base_no <= ann.end : - #print "Annotation FOUND" + if base_no >= ann.start and base_no <= ann.end: + # print "Annotation FOUND" annotations_found.append(ann) # Is this the lowest level of the hierarchy, or are there subcomponents? if ann.subcomponent and len(ann.subcomponent.annotations) > 0: - #print "Descending one level" - annotations_found = annotations_found[:-1] # Remove parent annotation, continue search for leaf annotations - sub_annotations_found = getSequenceAnnotationsAtBaseNo(ann.subcomponent, base_no, annotations_found) - if len(sub_annotations_found) == len(annotations_found): # If no leaf annotations were found at the lower level, replace the higher level annotation - #print "No sub annotations found" + # print "Descending one level" + annotations_found = annotations_found[ + :-1 + ] # Remove parent annotation, continue search for leaf annotations + sub_annotations_found = getSequenceAnnotationsAtBaseNo( + ann.subcomponent, base_no, annotations_found + ) + if len(sub_annotations_found) == len( + annotations_found + ): # If no leaf annotations were found at the lower level, replace the higher level annotation + # print "No sub annotations found" annotations_found.append(ann) return annotations_found else: - #print "Sub annotations found" + # print "Sub annotations found" return sub_annotations_found else: - #print "No sub annotations found" + # print "No sub annotations found" return annotations_found - #print "Completing search at this level" + # print "Completing search at this level" return annotations_found - # return annotations_found - # else : - # print base_no, ann.start, ann.end - # annotations_found.append(ann) - # return annotations_found - -def verify_base(ref_base, query_base) : - if ref_base.upper() == query_base.upper() : + # return annotations_found + # else : + # print base_no, ann.start, ann.end + # annotations_found.append(ann) + # return annotations_found + + +def verify_base(ref_base, query_base): + if ref_base.upper() == query_base.upper(): return SO_NUCLEOTIDE_MATCH - elif ref_base == '-' and query_base.upper() == 'N': + elif ref_base == "-" and query_base.upper() == "N": return SO_POSSIBLE_ASSEMBLY_ERROR - elif ref_base == '-' and query_base.upper() in ['A', 'C', 'T', 'G'] : + elif ref_base == "-" and query_base.upper() in ["A", "C", "T", "G"]: return SO_INSERTION - elif ref_base.upper() in ['A', 'C', 'T', 'G'] and query_base.upper() == 'N' : + elif ref_base.upper() in ["A", "C", "T", "G"] and query_base.upper() == "N": return SO_POSSIBLE_ASSEMBLY_ERROR - elif ref_base.upper() in ['A', 'C', 'T', 'G'] and query_base == '-' : + elif ref_base.upper() in ["A", "C", "T", "G"] and query_base == "-": return SO_DELETION - elif not ref_base.upper() == query_base.upper() : + elif not ref_base.upper() == query_base.upper(): return SO_SUBSTITUTION - raise sbol.SBOLError('Alignment contains unrecognized character %s or %s' %(ref_base,query_base)) + raise sbol.SBOLError( + "Alignment contains unrecognized character %s or %s" + % (ref_base, query_base) + ) + # def classify_mutation(ref_base, query_base) : # if ref_base.upper() == query_base.upper() : @@ -266,7 +308,8 @@ def verify_base(ref_base, query_base) : # return SO_SUBSTITUTION # return None -def is_mutation(dna_component) : + +def is_mutation(dna_component): if dna_component.part_type in [ SO_INSERTION, SO_DELETION, @@ -276,18 +319,21 @@ def is_mutation(dna_component) : else: return False -def is_ambiguity(dna_component) : + +def is_ambiguity(dna_component): if dna_component.part_type == SO_POSSIBLE_ASSEMBLY_ERROR: return True else: return False -def is_match(dna_component) : + +def is_match(dna_component): if dna_component.part_type == SO_NUCLEOTIDE_MATCH: return True else: return False + # def calculate_identity(dna_component) : # reference_seq = dna_component.sequence.nucleotides # mutations = [] @@ -299,15 +345,19 @@ def is_match(dna_component) : # identity = (1. - float(len(mutations))/float(len(reference_seq))) * 100. # return identity + def flatten_subtree(dc, children_annotations=[]): for ann in dc.annotations: if ann.subcomponent: - children_annotations = flatten_subtree(ann.subcomponent, children_annotations) + children_annotations = flatten_subtree( + ann.subcomponent, children_annotations + ) children_annotations.extend(dc.annotations) children_annotations = list(set(children_annotations)) return children_annotations -def calculate_identity(dna_component) : + +def calculate_identity(dna_component): matched_regions = [] reference_seq = dna_component.sequence.nucleotides for ann in flatten_subtree(dna_component): @@ -316,11 +366,12 @@ def calculate_identity(dna_component) : print(ann.start, ann.end, region_length) matched_regions.append(region_length) total_matched = sum(matched_regions) - identity = float(total_matched)/float(len(reference_seq)) * 100. + identity = float(total_matched) / float(len(reference_seq)) * 100.0 print("Identity", total_matched, len(reference_seq)) return identity -def calculate_error(dna_component) : + +def calculate_error(dna_component): mismatched_regions = [] reference_seq = dna_component.sequence.nucleotides for ann in flatten_subtree(dna_component): @@ -330,11 +381,14 @@ def calculate_error(dna_component) : mismatched_regions.append(region_length) total_mismatched = sum(mismatched_regions) - percent_mismatched = float(total_mismatched)/float(len(reference_seq)) * 100. + percent_mismatched = ( + float(total_mismatched) / float(len(reference_seq)) * 100.0 + ) print("Error", total_mismatched, len(reference_seq)) return percent_mismatched -def calculate_ambiguity(dna_component) : + +def calculate_ambiguity(dna_component): ambiguous_regions = [] reference_seq = dna_component.sequence.nucleotides for ann in flatten_subtree(dna_component): @@ -344,67 +398,80 @@ def calculate_ambiguity(dna_component) : ambiguous_regions.append(region_length) total_ambiguous_region = sum(ambiguous_regions) - percent_ambiguity = float(total_ambiguous_region)/float(len(reference_seq)) * 100. + percent_ambiguity = ( + float(total_ambiguous_region) / float(len(reference_seq)) * 100.0 + ) print("Ambiguity", total_ambiguous_region, len(reference_seq)) return percent_ambiguity -def calculate_coverage(dna_component) : + +def calculate_coverage(dna_component): covered_regions = [] reference_seq = dna_component.sequence.nucleotides for ann in flatten_subtree(dna_component): - if is_match(ann.subcomponent) or is_mutation(ann.subcomponent) or is_ambiguity(ann.subcomponent): + if ( + is_match(ann.subcomponent) + or is_mutation(ann.subcomponent) + or is_ambiguity(ann.subcomponent) + ): region_length = ann.end - ann.start + 1 print(ann.start, ann.end, region_length) covered_regions.append(region_length) total_covered_region = sum(covered_regions) - percent_coverage = float(total_covered_region)/float(len(reference_seq)) * 100. + percent_coverage = ( + float(total_covered_region) / float(len(reference_seq)) * 100.0 + ) print("Coverage:", total_covered_region, len(reference_seq)) return percent_coverage -parts_length_dist = { - PROMOTER : 50, - RBS : 15, - CDS : 1000, - TERMINATOR : 100 -} +parts_length_dist = {PROMOTER: 50, RBS: 15, CDS: 1000, TERMINATOR: 100} + def n(): r = random.random() - if r <= 0.25 : - return 'a' - elif r <= 0.5 : - return 't' - elif r <= 0.75 : - return 'c' - elif r <= 1 : - return 'g' + if r <= 0.25: + return "a" + elif r <= 0.5: + return "t" + elif r <= 0.75: + return "c" + elif r <= 1: + return "g" + def nnn(seq_length): - seq = '' - for i in range(0, seq_length) : - seq = seq + n() + seq = "" + for i in range(0, seq_length): + seq = seq + n() return seq + def random_part_length(part_type): mu_length = parts_length_dist[part_type] sigma_length = 0.2 * parts_length_dist[part_type] - return int ( random.gauss( mu_length, sigma_length )) + return int(random.gauss(mu_length, sigma_length)) + def qc(design, data=None, infile=None): if infile: - with open (infile, "r") as f: + with open(infile, "r") as f: data = f.read() if data: - if len(parse_fasta(data)) > 1 : + if len(parse_fasta(data)) > 1: multialignment = align(data) clone = find_consensus(multialignment) else: clone = data - target_design = write_to_fasta( [(design.uri, design.sequence.nucleotides)] ) - alignment_qc = align(target_design + '\r\n' + clone, outfile='%s.align' %design.display_id) + target_design = write_to_fasta( + [(design.uri, design.sequence.nucleotides)] + ) + alignment_qc = align( + target_design + "\r\n" + clone, + outfile="%s.align" % design.display_id, + ) # Scan alignment and classify mutations design_seq = design.sequence.nucleotides @@ -414,11 +481,13 @@ def qc(design, data=None, infile=None): # Translate alignment coordinates into coordinates of the reference and query sequences l_alignment = len(reference_seq) # Determine length of alignment - l_ref = len(reference_seq.replace('-', '')) - l_que = len(query_seq.replace('-', '')) + l_ref = len(reference_seq.replace("-", "")) + l_que = len(query_seq.replace("-", "")) # The following dictionaries are used like lists indexed from one - ref_map = {} # Maps nucleotide coordinates of reference sequence to alignment coordinates + ref_map = ( + {} + ) # Maps nucleotide coordinates of reference sequence to alignment coordinates i_ref = 0 # If the design sequence is not fully covered by sequencing data, there may be '---' padding the end of @@ -427,26 +496,32 @@ def qc(design, data=None, infile=None): # ref actggtca # qry --tggt-- # - i_left = query_seq.index(next(token for token in query_seq if not token == '-')) - i_right = len(query_seq)- query_seq[::-1].index(next(token for token in reversed(query_seq) if not token == '-')) + i_left = query_seq.index( + next(token for token in query_seq if not token == "-") + ) + i_right = len(query_seq) - query_seq[::-1].index( + next(token for token in reversed(query_seq) if not token == "-") + ) for i_alignment in range(l_alignment): ref_base = reference_seq[i_alignment] que_base = query_seq[i_alignment] - if not ref_base == '-': + if not ref_base == "-": i_ref += 1 # Do not map the design coordinates to alignment coordinates if they aren't covered if i_alignment >= i_left and i_alignment <= i_right: ref_map[i_ref] = i_alignment # Should be a unit test - #for i in range(0, l_ref): + # for i in range(0, l_ref): # assert design_sequence[i] == reference_seq[ref_map[i+1]], "%d %s does not match %s"%(i,design_sequence[i], reference_seq[ref_map[i+1]]) # Only leaf annotations at the bottom of the hierarchy are annotated... leaf_annotations = [] for i_design in range(len(design_seq)): - target_annotations = getSequenceAnnotationsAtBaseNo(design, i_design) + target_annotations = getSequenceAnnotationsAtBaseNo( + design, i_design + ) for ann in target_annotations: if not ann in leaf_annotations: leaf_annotations.append(ann) @@ -455,23 +530,48 @@ def qc(design, data=None, infile=None): # then determine the covered bases in the annotation. All, part, or several discontiguous parts of an annotation # may be covered for i_ann, ann in enumerate(leaf_annotations): - covered_coordinates = list(ref_map.keys()) # List of all base coordinates for this design / reference sequence that are covered + covered_coordinates = list( + ref_map.keys() + ) # List of all base coordinates for this design / reference sequence that are covered # Now narrow down to find just the bases in this annotation - covered_coordinates = [ x for x in covered_coordinates if x >= ann.start and x <= ann.end ] + covered_coordinates = [ + x + for x in covered_coordinates + if x >= ann.start and x <= ann.end + ] # Now translate into alignment coordinates - alignment_coordinates = [ ref_map[x] for x in covered_coordinates ] + alignment_coordinates = [ref_map[x] for x in covered_coordinates] if len(alignment_coordinates) > 0: alignment_start = min(alignment_coordinates) alignment_end = max(alignment_coordinates) # Scan alignment - print("Verifying %s from %d to %d" %(ann.subcomponent.display_id, ann.start, ann.end)) - print(''.join([ nt for nt in reference_seq[alignment_start:alignment_end]])) - print(''.join([ nt for nt in query_seq[alignment_start:alignment_end]])) + print( + "Verifying %s from %d to %d" + % (ann.subcomponent.display_id, ann.start, ann.end) + ) + print( + "".join( + [ + nt + for nt in reference_seq[ + alignment_start:alignment_end + ] + ] + ) + ) + print( + "".join( + [nt for nt in query_seq[alignment_start:alignment_end]] + ) + ) # Classification of alignment - base_comparisons = [ verify_base(reference_seq[x], query_seq[x]) for x in alignment_coordinates ] + base_comparisons = [ + verify_base(reference_seq[x], query_seq[x]) + for x in alignment_coordinates + ] for x in alignment_coordinates: comparison = verify_base(reference_seq[x], query_seq[x]) if comparison == None: @@ -487,12 +587,21 @@ def qc(design, data=None, infile=None): reg_start = 0 reg_end = 0 previous_term = None - elif i_alignment > 0 and i_alignment < (len(base_comparisons) - 1): + elif i_alignment > 0 and i_alignment < ( + len(base_comparisons) - 1 + ): # Mark end of an old region of interest and beginning of a new region if not current_term == previous_term: - ref_start = covered_coordinates[reg_start] # Translate from alignment to design / reference coordinates - ref_end = covered_coordinates[reg_end] # Translate from alignment to design / reference coordinates - region_of_interest = ((ref_start, ref_end), previous_term) + ref_start = covered_coordinates[ + reg_start + ] # Translate from alignment to design / reference coordinates + ref_end = covered_coordinates[ + reg_end + ] # Translate from alignment to design / reference coordinates + region_of_interest = ( + (ref_start, ref_end), + previous_term, + ) regions.append(region_of_interest) reg_start = i_alignment reg_end = i_alignment @@ -503,17 +612,31 @@ def qc(design, data=None, infile=None): if not current_term == previous_term: reg_start = i_alignment reg_end = i_alignment - ref_start = covered_coordinates[reg_start] # Translate from alignment to design / reference coordinates - ref_end = covered_coordinates[reg_end] # Translate from alignment to design / reference coordinates - region_of_interest = ((ref_start, ref_end), previous_term) + ref_start = covered_coordinates[ + reg_start + ] # Translate from alignment to design / reference coordinates + ref_end = covered_coordinates[ + reg_end + ] # Translate from alignment to design / reference coordinates + region_of_interest = ( + (ref_start, ref_end), + previous_term, + ) regions.append(region_of_interest) elif current_term == previous_term: reg_end = i_alignment - ref_start = covered_coordinates[reg_start] # Translate from alignment to design / reference coordinates - ref_end = covered_coordinates[reg_end] # Translate from alignment to design / reference coordinates - region_of_interest = ((ref_start, ref_end), previous_term) + ref_start = covered_coordinates[ + reg_start + ] # Translate from alignment to design / reference coordinates + ref_end = covered_coordinates[ + reg_end + ] # Translate from alignment to design / reference coordinates + region_of_interest = ( + (ref_start, ref_end), + previous_term, + ) regions.append(region_of_interest) - #print i_alignment, current_term, reg_start, reg_end, covered_coordinates[reg_start], covered_coordinates[reg_end] + # print i_alignment, current_term, reg_start, reg_end, covered_coordinates[reg_start], covered_coordinates[reg_end] previous_term = current_term i_alignment += 1 @@ -534,74 +657,142 @@ def qc(design, data=None, infile=None): qc_classification = region[1] n_components = len(doc.components) n_annotations = len(doc.annotations) - if qc_classification : - if qc_classification == SO_NUCLEOTIDE_MATCH: # The reference sequence matches the query sequence - annotated_region = sbol.SequenceAnnotation(doc, "%s/MatchedSequence/SA%d" %(design.uri, n_annotations)) + if qc_classification: + if ( + qc_classification == SO_NUCLEOTIDE_MATCH + ): # The reference sequence matches the query sequence + annotated_region = sbol.SequenceAnnotation( + doc, + "%s/MatchedSequence/SA%d" + % (design.uri, n_annotations), + ) annotated_region.start = qc_start annotated_region.end = qc_end - annotated_region.subcomponent = sbol.DNAComponent(doc,"%s/MatchedSequence/SA%d/DC%d" %(design.uri, n_annotations, n_components) ) + annotated_region.subcomponent = sbol.DNAComponent( + doc, + "%s/MatchedSequence/SA%d/DC%d" + % (design.uri, n_annotations, n_components), + ) annotated_region.subcomponent.display_id = "" - annotated_region.subcomponent.part_type = qc_classification + annotated_region.subcomponent.part_type = ( + qc_classification + ) else: # A mismatch was identified - annotated_region = sbol.SequenceAnnotation(doc, "%s/AssemblyErrors/SA%d" %(design.uri, n_annotations)) + annotated_region = sbol.SequenceAnnotation( + doc, + "%s/AssemblyErrors/SA%d" + % (design.uri, n_annotations), + ) annotated_region.start = qc_start annotated_region.end = qc_end - annotated_region.subcomponent = sbol.DNAComponent(doc,"%s/AssemblyErrors/SA%d/DC%d" %(design.uri, n_annotations, n_components) ) + annotated_region.subcomponent = sbol.DNAComponent( + doc, + "%s/AssemblyErrors/SA%d/DC%d" + % (design.uri, n_annotations, n_components), + ) annotated_region.subcomponent.display_id = "" - annotated_region.subcomponent.part_type = qc_classification - print("Adding %s to %s from %d to %d" %(annotated_region.uri, ann.subcomponent.display_id, annotated_region.start, annotated_region.end)) + annotated_region.subcomponent.part_type = ( + qc_classification + ) + print( + "Adding %s to %s from %d to %d" + % ( + annotated_region.uri, + ann.subcomponent.display_id, + annotated_region.start, + annotated_region.end, + ) + ) ann.subcomponent.annotations.append(annotated_region) -def align(sequencing_data, outfile = None): + +def align(sequencing_data, outfile=None): """ Sequencing data is a string in FASTA format """ - if outfile != None : - print ("Aligning") + if outfile != None: + print("Aligning") # align_sequences = Popen(['%s\clustalo.exe' % CLUSTAL_DIR, '-i', '-'], stdin=PIPE, stdout=PIPE, stderr=STDOUT, cwd=DATA_DIR) - align_sequences = Popen(['%s\clustalo.exe' % CLUSTAL_DIR, '-i', '-', '-o', '%s'%outfile, '--outfmt', 'msf'], stdin=PIPE, stdout=PIPE, stderr=STDOUT) + align_sequences = Popen( + [ + "%s\clustalo.exe" % CLUSTAL_DIR, + "-i", + "-", + "-o", + "%s" % outfile, + "--outfmt", + "msf", + ], + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + ) alignment = align_sequences.communicate(sequencing_data)[0].decode() align_sequences.terminate() - align_sequences = Popen(['%s\clustalo.exe' % CLUSTAL_DIR, '-i', '-'], stdin=PIPE, stdout=PIPE, stderr=STDOUT) + align_sequences = Popen( + ["%s\clustalo.exe" % CLUSTAL_DIR, "-i", "-"], + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + ) alignment = align_sequences.communicate(sequencing_data)[0].decode() align_sequences.terminate() return alignment + def find_consensus(alignment): - find_consensus = Popen(['%s\cons.exe' % EMBOSS_DIR, '-filter', '-identity', '2'], stdin=PIPE, stdout=PIPE, stderr=STDOUT) + find_consensus = Popen( + ["%s\cons.exe" % EMBOSS_DIR, "-filter", "-identity", "2"], + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + ) consensus = find_consensus.communicate(input=alignment)[0].decode() find_consensus.terminate() return consensus + def initialize_design(doc): - n_designs = len([part for part in doc.components if part.part_type and part.part_type == DESIGN]) - root = sbol.DNAComponent(doc, '%s/Design_%d' %(BASE_URI, n_designs + 1)) + n_designs = len( + [ + part + for part in doc.components + if part.part_type and part.part_type == DESIGN + ] + ) + root = sbol.DNAComponent(doc, "%s/Design_%d" % (BASE_URI, n_designs + 1)) root.part_type = DESIGN - root.display_id = 'Design %d' %(n_designs + 1) - root.name = 'Design %d' %(n_designs + 1) - root.sequence = sbol.DNASequence(doc, '%s/Design_%d/Seq_%d' %(BASE_URI, n_designs + 1, n_designs + 1)) - root.sequence.nucleotides = 'n' + root.display_id = "Design %d" % (n_designs + 1) + root.name = "Design %d" % (n_designs + 1) + root.sequence = sbol.DNASequence( + doc, "%s/Design_%d/Seq_%d" % (BASE_URI, n_designs + 1, n_designs + 1) + ) + root.sequence.nucleotides = "n" return root + def construct_design(doc, root, target_design): # target_design is a list of part uris n_components = len(doc.components) n_annotations = len(doc.annotations) n_sequences = len(doc.sequences) - sbol_parts = [] for uri in target_design: - #uri = uris[part_name] + # uri = uris[part_name] part = doc.components[uri] - SA = sbol.SequenceAnnotation(doc, '%s/SA_%d' %(root.uri, n_annotations + 1)) + SA = sbol.SequenceAnnotation( + doc, "%s/SA_%d" % (root.uri, n_annotations + 1) + ) n_annotations += 1 if not part.sequence: - part.sequence = sbol.DNASequence(doc, '%s/Seq_%d' %(part.uri, n_sequences + 1)) - part.sequence.nucleotides = 'n' + part.sequence = sbol.DNASequence( + doc, "%s/Seq_%d" % (part.uri, n_sequences + 1) + ) + part.sequence.nucleotides = "n" SA.start = 1 SA.end = len(part.sequence.nucleotides) - SA.orientation = '+' + SA.orientation = "+" sbol_parts.append(SA) SA.subcomponent = part @@ -609,22 +800,23 @@ def construct_design(doc, root, target_design): for i_part in range(1, len(sbol_parts)): upstream_ann = sbol_parts[i_part - 1] downstream_ann = sbol_parts[i_part] - insert_annotation_downstream( root, upstream_ann, downstream_ann ) + insert_annotation_downstream(root, upstream_ann, downstream_ann) assemble_subcomponents(root) - #for part in sbol_parts: + # for part in sbol_parts: # print part.start, part.end, part.subcomponent.name, part.subcomponent.type, part.subcomponent.uri return root -def scrape_parts(doc, part_files, parts_list, TARGET_DIR = '.'): + +def scrape_parts(doc, part_files, parts_list, TARGET_DIR="."): # Scrape parts from files # doc is the Document to which the scraped parts will be added # part_files should be a list of file names without .xml extension for pf in part_files: print(pf) sbol_in = sbol.Document() - sbol_in.read(TARGET_DIR + '/' + pf + '.xml') + sbol_in.read(TARGET_DIR + "/" + pf + ".xml") print("Components in infile", len(sbol_in.components)) for i_dc, dc in enumerate(sbol_in.components): @@ -632,6 +824,6 @@ def scrape_parts(doc, part_files, parts_list, TARGET_DIR = '.'): if dc.uri in parts_list: dc.move(doc) except: - print('error in ', i_dc) + print("error in ", i_dc) libsbol.deleteDocument(sbol_in.ptr) return doc diff --git a/dnaplotlib/gallery/sbol_interactive/assembly.py b/dnaplotlib/gallery/sbol_interactive/assembly.py index 95fe395..1fa14be 100755 --- a/dnaplotlib/gallery/sbol_interactive/assembly.py +++ b/dnaplotlib/gallery/sbol_interactive/assembly.py @@ -4,13 +4,19 @@ # Add SBOL module directory to PYTHONPATH import os, sys -lib_path = os.path.abspath('..') + +lib_path = os.path.abspath("..") sys.path.append(lib_path) import random # For random sequence generation import sbol -#from sbol import libsbol -from subprocess import Popen, PIPE, STDOUT # For calling command line tools Clustal Omega and EMBOSS + +# from sbol import libsbol +from subprocess import ( + Popen, + PIPE, + STDOUT, +) # For calling command line tools Clustal Omega and EMBOSS # Command line tools for sequence verification CLUSTAL_DIR = "C:/Program Files (x86)/clustal-omega-1.2.0-win32" @@ -33,23 +39,29 @@ SO_NUCLEOTIDE_MATCH = "http://purl.obolibrary.org/obo/SO_0000347" col_map = {} -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) random.seed() + def populate_subcomponents(parent_component): for ann in parent_component.annotations: i_start = ann.start - 1 i_end = ann.end - sub_seq_nucleotides = parent_component.sequence.nucleotides[i_start:i_end] - #ann.subComponent = sbol.DNAComponent(doc, '%s//subComponent' %ann.uri) - ann.subcomponent.sequence = sbol.DNASequence(doc, '%s//Sequence' %ann.subcomponent.uri ) + sub_seq_nucleotides = parent_component.sequence.nucleotides[ + i_start:i_end + ] + # ann.subComponent = sbol.DNAComponent(doc, '%s//subComponent' %ann.uri) + ann.subcomponent.sequence = sbol.DNASequence( + doc, "%s//Sequence" % ann.subcomponent.uri + ) ann.subcomponent.sequence.nucleotides = sub_seq_nucleotides + def find_sequence_homologs(target_seq): result_handle = NCBIWWW.qblast("blastn", "nt", target_seq) blast_records = list(NCBIXML.parseAndGenerateImage(result_handle)) @@ -61,17 +73,20 @@ def find_sequence_homologs(target_seq): variant_urls = [] for alignment in rec.alignments: hsp = alignment.hsps[0] # high-scoring pairs - variant_acc_nos.append( str(alignment.accession) ) - variant_nucleotides.append( str(hsp.sbjct) ) - #cds_variant_urls.append(alignment.accession) + variant_acc_nos.append(str(alignment.accession)) + variant_nucleotides.append(str(hsp.sbjct)) + # cds_variant_urls.append(alignment.accession) return variant_acc_nos, variant_nucleotides, variant_urls + def remove_annotation(parent_component, deleted_ann): - """ An annotation is removed. The precedes relationship, start and end indexes of other annotations - are updated accordingly """ + """An annotation is removed. The precedes relationship, start and end indexes of other annotations + are updated accordingly""" - downstream_ann = deleted_ann.precedes[0] # Find annotation downstream of the one to be removed + downstream_ann = deleted_ann.precedes[ + 0 + ] # Find annotation downstream of the one to be removed # Finds the upstream annotation that precedes the annotation to be removed for ann in parent_component.annotations: @@ -84,7 +99,7 @@ def remove_annotation(parent_component, deleted_ann): # Update all start and end indices for annotations downstream from insertion deletion_size = deleted_ann.end - deleted_ann.start + 1 - while (len(upstream_ann.precedes) > 0): + while len(upstream_ann.precedes) > 0: downstream_ann = upstream_ann.precedes[0] old_start = downstream_ann.start old_end = downstream_ann.end @@ -94,14 +109,14 @@ def remove_annotation(parent_component, deleted_ann): downstream_ann.end = new_end upstream_ann = downstream_ann - #doc.sequences.remove(deleted_ann.subcomponent.sequence) - #doc.components.remove(deleted_ann.subcomponent) - #doc.annotations.remove(deleted_ann) + # doc.sequences.remove(deleted_ann.subcomponent.sequence) + # doc.components.remove(deleted_ann.subcomponent) + # doc.annotations.remove(deleted_ann) parent_component.annotations.remove(deleted_ann) def insert_annotation_downstream(parent_component, upstream_ann, insert_ann): - """ A new annotation is inserted after an upstream annotation. + """A new annotation is inserted after an upstream annotation. The precedes relationship, start and end indexes are update accordingly. The annotation is expected to have a subComponent and Sequence object attached""" parent_component.annotations.append(insert_ann) @@ -114,7 +129,9 @@ def insert_annotation_downstream(parent_component, upstream_ann, insert_ann): # Update precedes relationship of annotations # If inserting annotation between two existing annotations if upstream_ann.precedes: - downstream_ann = upstream_ann.precedes[0] # Assumes annotations only have one precedes relationship + downstream_ann = upstream_ann.precedes[ + 0 + ] # Assumes annotations only have one precedes relationship upstream_ann.precedes.remove(upstream_ann.precedes[0]) upstream_ann.precedes.append(insert_ann) insert_ann.precedes.append(downstream_ann) @@ -123,7 +140,7 @@ def insert_annotation_downstream(parent_component, upstream_ann, insert_ann): # Update all start and end indices for annotations downstream from insertion upstream_ann = insert_ann - while (len(upstream_ann.precedes) > 0): + while len(upstream_ann.precedes) > 0: downstream_ann = upstream_ann.precedes[0] old_start = downstream_ann.start old_end = downstream_ann.end @@ -133,123 +150,148 @@ def insert_annotation_downstream(parent_component, upstream_ann, insert_ann): downstream_ann.end = new_end upstream_ann = downstream_ann + def insert_annotation_upstream(parent_component, insert_ann, downstream_ann): - """ A new annotation (upstream) is inserted before the downstream annotation - The precedes relationship, start and end indexes are update accordingly """ - #print downstream_ann.uri - #print + """A new annotation (upstream) is inserted before the downstream annotation + The precedes relationship, start and end indexes are update accordingly""" + # print downstream_ann.uri + # print for i_ann, ann in enumerate(parent_component.annotations): - #print i_ann, ann.uri + # print i_ann, ann.uri if downstream_ann in ann.precedes: - upstream_uri = ann.uri # finds the annotation upstream, because it owns the precedes - print('Upstream uri: %s' %upstream_uri) + upstream_uri = ( + ann.uri + ) # finds the annotation upstream, because it owns the precedes + print("Upstream uri: %s" % upstream_uri) upstream_ann = parent_component.annotations[upstream_uri] insert_annotation_downstream(parent_component, upstream_ann, insert_ann) + def assemble_subcomponents(parent_component): parent_seq_len = 0 for ann in parent_component.annotations: - parent_seq_len = parent_seq_len + len(ann.subcomponent.sequence.nucleotides) - assembled_seq = 'n' * parent_seq_len + parent_seq_len = parent_seq_len + len( + ann.subcomponent.sequence.nucleotides + ) + assembled_seq = "n" * parent_seq_len for ann in parent_component.annotations: - #assembled_seq[ann.start:ann.end] = ann.subcomponent.sequence.nucleotides - assembled_seq = assembled_seq[:ann.start - 1] + \ - ann.subcomponent.sequence.nucleotides + \ - assembled_seq[ann.end:] + # assembled_seq[ann.start:ann.end] = ann.subcomponent.sequence.nucleotides + assembled_seq = ( + assembled_seq[: ann.start - 1] + + ann.subcomponent.sequence.nucleotides + + assembled_seq[ann.end :] + ) parent_component.sequence.nucleotides = assembled_seq + def print_downstream_Annotations(ann): reader_head = ann - print(reader_head.uri, end=' ') + print(reader_head.uri, end=" ") while reader_head.precedes: reader_head = reader_head.precedes[0] - print('->', reader_head.uri, end=' ') + print("->", reader_head.uri, end=" ") print() -#def write_to_fasta(seq_name, nucleotides, col_length = 20) : -def write_to_fasta(entries, col_length = 20) : + +# def write_to_fasta(seq_name, nucleotides, col_length = 20) : +def write_to_fasta(entries, col_length=20): formatted_entries = [] for seq_name, nts in entries: - nts = [ nts[i:i + col_length] for i in range(0, len(nts), col_length)] - nts = '\n'.join(nts) - formatted_entries.append( '>%s\n%s' %(seq_name, nts) ) - return '\r\n'.join(formatted_entries) - + nts = [nts[i : i + col_length] for i in range(0, len(nts), col_length)] + nts = "\n".join(nts) + formatted_entries.append(">%s\n%s" % (seq_name, nts)) + return "\r\n".join(formatted_entries) def parse_fasta(fasta_str): - entries = fasta_str.split('>') + entries = fasta_str.split(">") entries = [entry.strip() for entry in entries] - entries = [entry.encode('ascii','ignore') for entry in entries] - entries = entries[1:] # Sequence has empty entry '' at the beginning of the list - if len(entries) < 1 : - print('Invalid FASTA format') + entries = [entry.encode("ascii", "ignore") for entry in entries] + entries = entries[ + 1: + ] # Sequence has empty entry '' at the beginning of the list + if len(entries) < 1: + print("Invalid FASTA format") return - else : + else: parsed_entries = [] - for entry in entries : + for entry in entries: try: entry = entry.strip() - tokens = entry.split('\n') + tokens = entry.split("\n") seq_name = tokens[0] - #nucleotides = '\r\n'.join(tokens[1:]) - nucleotides = ''.join(tokens[1:]) - nucleotides = nucleotides.replace('\r', '') + # nucleotides = '\r\n'.join(tokens[1:]) + nucleotides = "".join(tokens[1:]) + nucleotides = nucleotides.replace("\r", "") parsed_entries.append((seq_name, nucleotides)) except: - print(('Invalid entry: %s' %entry)) + print(("Invalid entry: %s" % entry)) return parsed_entries -def getSequenceAnnotationsAtBaseNo(parent_component, base_no, annotations_found = None): + +def getSequenceAnnotationsAtBaseNo( + parent_component, base_no, annotations_found=None +): # Assumes parent_component is an SBOL data structure of the general form DNAComponent(->SequenceAnnotation->DNAComponent)n # where n+1 is an integer describing how many hierarchical levels are in the SBOL structure - if not annotations_found : + if not annotations_found: annotations_found = [] # print "Searching for base no %d" %base_no # Look at each of this component's annotations, is the target base there? - for ann in parent_component.annotations : + for ann in parent_component.annotations: # print ann.uri, ann.start, ann.end # If target base is found ... - if base_no >= ann.start and base_no <= ann.end : - #print "Annotation FOUND" + if base_no >= ann.start and base_no <= ann.end: + # print "Annotation FOUND" annotations_found.append(ann) # Is this the lowest level of the hierarchy, or are there subcomponents? if ann.subcomponent and len(ann.subcomponent.annotations) > 0: - #print "Descending one level" - annotations_found = annotations_found[:-1] # Remove parent annotation, continue search for leaf annotations - sub_annotations_found = getSequenceAnnotationsAtBaseNo(ann.subcomponent, base_no, annotations_found) - if len(sub_annotations_found) == len(annotations_found): # If no leaf annotations were found at the lower level, replace the higher level annotation - #print "No sub annotations found" + # print "Descending one level" + annotations_found = annotations_found[ + :-1 + ] # Remove parent annotation, continue search for leaf annotations + sub_annotations_found = getSequenceAnnotationsAtBaseNo( + ann.subcomponent, base_no, annotations_found + ) + if len(sub_annotations_found) == len( + annotations_found + ): # If no leaf annotations were found at the lower level, replace the higher level annotation + # print "No sub annotations found" annotations_found.append(ann) return annotations_found else: - #print "Sub annotations found" + # print "Sub annotations found" return sub_annotations_found else: - #print "No sub annotations found" + # print "No sub annotations found" return annotations_found - #print "Completing search at this level" + # print "Completing search at this level" return annotations_found - # return annotations_found - # else : - # print base_no, ann.start, ann.end - # annotations_found.append(ann) - # return annotations_found - -def verify_base(ref_base, query_base) : - if ref_base.upper() == query_base.upper() : + # return annotations_found + # else : + # print base_no, ann.start, ann.end + # annotations_found.append(ann) + # return annotations_found + + +def verify_base(ref_base, query_base): + if ref_base.upper() == query_base.upper(): return SO_NUCLEOTIDE_MATCH - elif ref_base == '-' and query_base.upper() == 'N': + elif ref_base == "-" and query_base.upper() == "N": return SO_POSSIBLE_ASSEMBLY_ERROR - elif ref_base == '-' and query_base.upper() in ['A', 'C', 'T', 'G'] : + elif ref_base == "-" and query_base.upper() in ["A", "C", "T", "G"]: return SO_INSERTION - elif ref_base.upper() in ['A', 'C', 'T', 'G'] and query_base.upper() == 'N' : + elif ref_base.upper() in ["A", "C", "T", "G"] and query_base.upper() == "N": return SO_POSSIBLE_ASSEMBLY_ERROR - elif ref_base.upper() in ['A', 'C', 'T', 'G'] and query_base == '-' : + elif ref_base.upper() in ["A", "C", "T", "G"] and query_base == "-": return SO_DELETION - elif not ref_base.upper() == query_base.upper() : + elif not ref_base.upper() == query_base.upper(): return SO_SUBSTITUTION - raise sbol.SBOLError('Alignment contains unrecognized character %s or %s' %(ref_base,query_base)) + raise sbol.SBOLError( + "Alignment contains unrecognized character %s or %s" + % (ref_base, query_base) + ) + # def classify_mutation(ref_base, query_base) : # if ref_base.upper() == query_base.upper() : @@ -266,7 +308,8 @@ def verify_base(ref_base, query_base) : # return SO_SUBSTITUTION # return None -def is_mutation(dna_component) : + +def is_mutation(dna_component): if dna_component.part_type in [ SO_INSERTION, SO_DELETION, @@ -276,18 +319,21 @@ def is_mutation(dna_component) : else: return False -def is_ambiguity(dna_component) : + +def is_ambiguity(dna_component): if dna_component.part_type == SO_POSSIBLE_ASSEMBLY_ERROR: return True else: return False -def is_match(dna_component) : + +def is_match(dna_component): if dna_component.part_type == SO_NUCLEOTIDE_MATCH: return True else: return False + # def calculate_identity(dna_component) : # reference_seq = dna_component.sequence.nucleotides # mutations = [] @@ -299,15 +345,19 @@ def is_match(dna_component) : # identity = (1. - float(len(mutations))/float(len(reference_seq))) * 100. # return identity + def flatten_subtree(dc, children_annotations=[]): for ann in dc.annotations: if ann.subcomponent: - children_annotations = flatten_subtree(ann.subcomponent, children_annotations) + children_annotations = flatten_subtree( + ann.subcomponent, children_annotations + ) children_annotations.extend(dc.annotations) children_annotations = list(set(children_annotations)) return children_annotations -def calculate_identity(dna_component) : + +def calculate_identity(dna_component): matched_regions = [] reference_seq = dna_component.sequence.nucleotides for ann in flatten_subtree(dna_component): @@ -316,11 +366,12 @@ def calculate_identity(dna_component) : print(ann.start, ann.end, region_length) matched_regions.append(region_length) total_matched = sum(matched_regions) - identity = float(total_matched)/float(len(reference_seq)) * 100. + identity = float(total_matched) / float(len(reference_seq)) * 100.0 print("Identity", total_matched, len(reference_seq)) return identity -def calculate_error(dna_component) : + +def calculate_error(dna_component): mismatched_regions = [] reference_seq = dna_component.sequence.nucleotides for ann in flatten_subtree(dna_component): @@ -330,11 +381,14 @@ def calculate_error(dna_component) : mismatched_regions.append(region_length) total_mismatched = sum(mismatched_regions) - percent_mismatched = float(total_mismatched)/float(len(reference_seq)) * 100. + percent_mismatched = ( + float(total_mismatched) / float(len(reference_seq)) * 100.0 + ) print("Error", total_mismatched, len(reference_seq)) return percent_mismatched -def calculate_ambiguity(dna_component) : + +def calculate_ambiguity(dna_component): ambiguous_regions = [] reference_seq = dna_component.sequence.nucleotides for ann in flatten_subtree(dna_component): @@ -344,67 +398,80 @@ def calculate_ambiguity(dna_component) : ambiguous_regions.append(region_length) total_ambiguous_region = sum(ambiguous_regions) - percent_ambiguity = float(total_ambiguous_region)/float(len(reference_seq)) * 100. + percent_ambiguity = ( + float(total_ambiguous_region) / float(len(reference_seq)) * 100.0 + ) print("Ambiguity", total_ambiguous_region, len(reference_seq)) return percent_ambiguity -def calculate_coverage(dna_component) : + +def calculate_coverage(dna_component): covered_regions = [] reference_seq = dna_component.sequence.nucleotides for ann in flatten_subtree(dna_component): - if is_match(ann.subcomponent) or is_mutation(ann.subcomponent) or is_ambiguity(ann.subcomponent): + if ( + is_match(ann.subcomponent) + or is_mutation(ann.subcomponent) + or is_ambiguity(ann.subcomponent) + ): region_length = ann.end - ann.start + 1 print(ann.start, ann.end, region_length) covered_regions.append(region_length) total_covered_region = sum(covered_regions) - percent_coverage = float(total_covered_region)/float(len(reference_seq)) * 100. + percent_coverage = ( + float(total_covered_region) / float(len(reference_seq)) * 100.0 + ) print("Coverage:", total_covered_region, len(reference_seq)) return percent_coverage -parts_length_dist = { - PROMOTER : 50, - RBS : 15, - CDS : 1000, - TERMINATOR : 100 -} +parts_length_dist = {PROMOTER: 50, RBS: 15, CDS: 1000, TERMINATOR: 100} + def n(): r = random.random() - if r <= 0.25 : - return 'a' - elif r <= 0.5 : - return 't' - elif r <= 0.75 : - return 'c' - elif r <= 1 : - return 'g' + if r <= 0.25: + return "a" + elif r <= 0.5: + return "t" + elif r <= 0.75: + return "c" + elif r <= 1: + return "g" + def nnn(seq_length): - seq = '' - for i in range(0, seq_length) : - seq = seq + n() + seq = "" + for i in range(0, seq_length): + seq = seq + n() return seq + def random_part_length(part_type): mu_length = parts_length_dist[part_type] sigma_length = 0.2 * parts_length_dist[part_type] - return int ( random.gauss( mu_length, sigma_length )) + return int(random.gauss(mu_length, sigma_length)) + def qc(design, data=None, infile=None): if infile: - with open (infile, "r") as f: + with open(infile, "r") as f: data = f.read() if data: - if len(parse_fasta(data)) > 1 : + if len(parse_fasta(data)) > 1: multialignment = align(data) clone = find_consensus(multialignment) else: clone = data - target_design = write_to_fasta( [(design.uri, design.sequence.nucleotides)] ) - alignment_qc = align(target_design + '\r\n' + clone, outfile='%s.align' %design.display_id) + target_design = write_to_fasta( + [(design.uri, design.sequence.nucleotides)] + ) + alignment_qc = align( + target_design + "\r\n" + clone, + outfile="%s.align" % design.display_id, + ) # Scan alignment and classify mutations design_seq = design.sequence.nucleotides @@ -414,11 +481,13 @@ def qc(design, data=None, infile=None): # Translate alignment coordinates into coordinates of the reference and query sequences l_alignment = len(reference_seq) # Determine length of alignment - l_ref = len(reference_seq.replace('-', '')) - l_que = len(query_seq.replace('-', '')) + l_ref = len(reference_seq.replace("-", "")) + l_que = len(query_seq.replace("-", "")) # The following dictionaries are used like lists indexed from one - ref_map = {} # Maps nucleotide coordinates of reference sequence to alignment coordinates + ref_map = ( + {} + ) # Maps nucleotide coordinates of reference sequence to alignment coordinates i_ref = 0 # If the design sequence is not fully covered by sequencing data, there may be '---' padding the end of @@ -427,26 +496,32 @@ def qc(design, data=None, infile=None): # ref actggtca # qry --tggt-- # - i_left = query_seq.index(next(token for token in query_seq if not token == '-')) - i_right = len(query_seq)- query_seq[::-1].index(next(token for token in reversed(query_seq) if not token == '-')) + i_left = query_seq.index( + next(token for token in query_seq if not token == "-") + ) + i_right = len(query_seq) - query_seq[::-1].index( + next(token for token in reversed(query_seq) if not token == "-") + ) for i_alignment in range(l_alignment): ref_base = reference_seq[i_alignment] que_base = query_seq[i_alignment] - if not ref_base == '-': + if not ref_base == "-": i_ref += 1 # Do not map the design coordinates to alignment coordinates if they aren't covered if i_alignment >= i_left and i_alignment <= i_right: ref_map[i_ref] = i_alignment # Should be a unit test - #for i in range(0, l_ref): + # for i in range(0, l_ref): # assert design_sequence[i] == reference_seq[ref_map[i+1]], "%d %s does not match %s"%(i,design_sequence[i], reference_seq[ref_map[i+1]]) # Only leaf annotations at the bottom of the hierarchy are annotated... leaf_annotations = [] for i_design in range(len(design_seq)): - target_annotations = getSequenceAnnotationsAtBaseNo(design, i_design) + target_annotations = getSequenceAnnotationsAtBaseNo( + design, i_design + ) for ann in target_annotations: if not ann in leaf_annotations: leaf_annotations.append(ann) @@ -455,23 +530,48 @@ def qc(design, data=None, infile=None): # then determine the covered bases in the annotation. All, part, or several discontiguous parts of an annotation # may be covered for i_ann, ann in enumerate(leaf_annotations): - covered_coordinates = list(ref_map.keys()) # List of all base coordinates for this design / reference sequence that are covered + covered_coordinates = list( + ref_map.keys() + ) # List of all base coordinates for this design / reference sequence that are covered # Now narrow down to find just the bases in this annotation - covered_coordinates = [ x for x in covered_coordinates if x >= ann.start and x <= ann.end ] + covered_coordinates = [ + x + for x in covered_coordinates + if x >= ann.start and x <= ann.end + ] # Now translate into alignment coordinates - alignment_coordinates = [ ref_map[x] for x in covered_coordinates ] + alignment_coordinates = [ref_map[x] for x in covered_coordinates] if len(alignment_coordinates) > 0: alignment_start = min(alignment_coordinates) alignment_end = max(alignment_coordinates) # Scan alignment - print("Verifying %s from %d to %d" %(ann.subcomponent.display_id, ann.start, ann.end)) - print(''.join([ nt for nt in reference_seq[alignment_start:alignment_end]])) - print(''.join([ nt for nt in query_seq[alignment_start:alignment_end]])) + print( + "Verifying %s from %d to %d" + % (ann.subcomponent.display_id, ann.start, ann.end) + ) + print( + "".join( + [ + nt + for nt in reference_seq[ + alignment_start:alignment_end + ] + ] + ) + ) + print( + "".join( + [nt for nt in query_seq[alignment_start:alignment_end]] + ) + ) # Classification of alignment - base_comparisons = [ verify_base(reference_seq[x], query_seq[x]) for x in alignment_coordinates ] + base_comparisons = [ + verify_base(reference_seq[x], query_seq[x]) + for x in alignment_coordinates + ] for x in alignment_coordinates: comparison = verify_base(reference_seq[x], query_seq[x]) if comparison == None: @@ -487,12 +587,21 @@ def qc(design, data=None, infile=None): reg_start = 0 reg_end = 0 previous_term = None - elif i_alignment > 0 and i_alignment < (len(base_comparisons) - 1): + elif i_alignment > 0 and i_alignment < ( + len(base_comparisons) - 1 + ): # Mark end of an old region of interest and beginning of a new region if not current_term == previous_term: - ref_start = covered_coordinates[reg_start] # Translate from alignment to design / reference coordinates - ref_end = covered_coordinates[reg_end] # Translate from alignment to design / reference coordinates - region_of_interest = ((ref_start, ref_end), previous_term) + ref_start = covered_coordinates[ + reg_start + ] # Translate from alignment to design / reference coordinates + ref_end = covered_coordinates[ + reg_end + ] # Translate from alignment to design / reference coordinates + region_of_interest = ( + (ref_start, ref_end), + previous_term, + ) regions.append(region_of_interest) reg_start = i_alignment reg_end = i_alignment @@ -503,17 +612,31 @@ def qc(design, data=None, infile=None): if not current_term == previous_term: reg_start = i_alignment reg_end = i_alignment - ref_start = covered_coordinates[reg_start] # Translate from alignment to design / reference coordinates - ref_end = covered_coordinates[reg_end] # Translate from alignment to design / reference coordinates - region_of_interest = ((ref_start, ref_end), previous_term) + ref_start = covered_coordinates[ + reg_start + ] # Translate from alignment to design / reference coordinates + ref_end = covered_coordinates[ + reg_end + ] # Translate from alignment to design / reference coordinates + region_of_interest = ( + (ref_start, ref_end), + previous_term, + ) regions.append(region_of_interest) elif current_term == previous_term: reg_end = i_alignment - ref_start = covered_coordinates[reg_start] # Translate from alignment to design / reference coordinates - ref_end = covered_coordinates[reg_end] # Translate from alignment to design / reference coordinates - region_of_interest = ((ref_start, ref_end), previous_term) + ref_start = covered_coordinates[ + reg_start + ] # Translate from alignment to design / reference coordinates + ref_end = covered_coordinates[ + reg_end + ] # Translate from alignment to design / reference coordinates + region_of_interest = ( + (ref_start, ref_end), + previous_term, + ) regions.append(region_of_interest) - #print i_alignment, current_term, reg_start, reg_end, covered_coordinates[reg_start], covered_coordinates[reg_end] + # print i_alignment, current_term, reg_start, reg_end, covered_coordinates[reg_start], covered_coordinates[reg_end] previous_term = current_term i_alignment += 1 @@ -534,74 +657,142 @@ def qc(design, data=None, infile=None): qc_classification = region[1] n_components = len(doc.components) n_annotations = len(doc.annotations) - if qc_classification : - if qc_classification == SO_NUCLEOTIDE_MATCH: # The reference sequence matches the query sequence - annotated_region = sbol.SequenceAnnotation(doc, "%s/MatchedSequence/SA%d" %(design.uri, n_annotations)) + if qc_classification: + if ( + qc_classification == SO_NUCLEOTIDE_MATCH + ): # The reference sequence matches the query sequence + annotated_region = sbol.SequenceAnnotation( + doc, + "%s/MatchedSequence/SA%d" + % (design.uri, n_annotations), + ) annotated_region.start = qc_start annotated_region.end = qc_end - annotated_region.subcomponent = sbol.DNAComponent(doc,"%s/MatchedSequence/SA%d/DC%d" %(design.uri, n_annotations, n_components) ) + annotated_region.subcomponent = sbol.DNAComponent( + doc, + "%s/MatchedSequence/SA%d/DC%d" + % (design.uri, n_annotations, n_components), + ) annotated_region.subcomponent.display_id = "" - annotated_region.subcomponent.part_type = qc_classification + annotated_region.subcomponent.part_type = ( + qc_classification + ) else: # A mismatch was identified - annotated_region = sbol.SequenceAnnotation(doc, "%s/AssemblyErrors/SA%d" %(design.uri, n_annotations)) + annotated_region = sbol.SequenceAnnotation( + doc, + "%s/AssemblyErrors/SA%d" + % (design.uri, n_annotations), + ) annotated_region.start = qc_start annotated_region.end = qc_end - annotated_region.subcomponent = sbol.DNAComponent(doc,"%s/AssemblyErrors/SA%d/DC%d" %(design.uri, n_annotations, n_components) ) + annotated_region.subcomponent = sbol.DNAComponent( + doc, + "%s/AssemblyErrors/SA%d/DC%d" + % (design.uri, n_annotations, n_components), + ) annotated_region.subcomponent.display_id = "" - annotated_region.subcomponent.part_type = qc_classification - print("Adding %s to %s from %d to %d" %(annotated_region.uri, ann.subcomponent.display_id, annotated_region.start, annotated_region.end)) + annotated_region.subcomponent.part_type = ( + qc_classification + ) + print( + "Adding %s to %s from %d to %d" + % ( + annotated_region.uri, + ann.subcomponent.display_id, + annotated_region.start, + annotated_region.end, + ) + ) ann.subcomponent.annotations.append(annotated_region) -def align(sequencing_data, outfile = None): + +def align(sequencing_data, outfile=None): """ Sequencing data is a string in FASTA format """ - if outfile != None : - print ("Aligning") + if outfile != None: + print("Aligning") # align_sequences = Popen(['%s\clustalo.exe' % CLUSTAL_DIR, '-i', '-'], stdin=PIPE, stdout=PIPE, stderr=STDOUT, cwd=DATA_DIR) - align_sequences = Popen(['%s\clustalo.exe' % CLUSTAL_DIR, '-i', '-', '-o', '%s'%outfile, '--outfmt', 'msf'], stdin=PIPE, stdout=PIPE, stderr=STDOUT) + align_sequences = Popen( + [ + "%s\clustalo.exe" % CLUSTAL_DIR, + "-i", + "-", + "-o", + "%s" % outfile, + "--outfmt", + "msf", + ], + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + ) alignment = align_sequences.communicate(sequencing_data)[0].decode() align_sequences.terminate() - align_sequences = Popen(['%s\clustalo.exe' % CLUSTAL_DIR, '-i', '-'], stdin=PIPE, stdout=PIPE, stderr=STDOUT) + align_sequences = Popen( + ["%s\clustalo.exe" % CLUSTAL_DIR, "-i", "-"], + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + ) alignment = align_sequences.communicate(sequencing_data)[0].decode() align_sequences.terminate() return alignment + def find_consensus(alignment): - find_consensus = Popen(['%s\cons.exe' % EMBOSS_DIR, '-filter', '-identity', '2'], stdin=PIPE, stdout=PIPE, stderr=STDOUT) + find_consensus = Popen( + ["%s\cons.exe" % EMBOSS_DIR, "-filter", "-identity", "2"], + stdin=PIPE, + stdout=PIPE, + stderr=STDOUT, + ) consensus = find_consensus.communicate(input=alignment)[0].decode() find_consensus.terminate() return consensus + def initialize_design(doc): - n_designs = len([part for part in doc.components if part.part_type and part.part_type == DESIGN]) - root = sbol.DNAComponent(doc, '%s/Design_%d' %(BASE_URI, n_designs + 1)) + n_designs = len( + [ + part + for part in doc.components + if part.part_type and part.part_type == DESIGN + ] + ) + root = sbol.DNAComponent(doc, "%s/Design_%d" % (BASE_URI, n_designs + 1)) root.part_type = DESIGN - root.display_id = 'Design %d' %(n_designs + 1) - root.name = 'Design %d' %(n_designs + 1) - root.sequence = sbol.DNASequence(doc, '%s/Design_%d/Seq_%d' %(BASE_URI, n_designs + 1, n_designs + 1)) - root.sequence.nucleotides = 'n' + root.display_id = "Design %d" % (n_designs + 1) + root.name = "Design %d" % (n_designs + 1) + root.sequence = sbol.DNASequence( + doc, "%s/Design_%d/Seq_%d" % (BASE_URI, n_designs + 1, n_designs + 1) + ) + root.sequence.nucleotides = "n" return root + def construct_design(doc, root, target_design): # target_design is a list of part uris n_components = len(doc.components) n_annotations = len(doc.annotations) n_sequences = len(doc.sequences) - sbol_parts = [] for uri in target_design: - #uri = uris[part_name] + # uri = uris[part_name] part = doc.components[uri] - SA = sbol.SequenceAnnotation(doc, '%s/SA_%d' %(root.uri, n_annotations + 1)) + SA = sbol.SequenceAnnotation( + doc, "%s/SA_%d" % (root.uri, n_annotations + 1) + ) n_annotations += 1 if not part.sequence: - part.sequence = sbol.DNASequence(doc, '%s/Seq_%d' %(part.uri, n_sequences + 1)) - part.sequence.nucleotides = 'n' + part.sequence = sbol.DNASequence( + doc, "%s/Seq_%d" % (part.uri, n_sequences + 1) + ) + part.sequence.nucleotides = "n" SA.start = 1 SA.end = len(part.sequence.nucleotides) - SA.orientation = '+' + SA.orientation = "+" sbol_parts.append(SA) SA.subcomponent = part @@ -609,22 +800,23 @@ def construct_design(doc, root, target_design): for i_part in range(1, len(sbol_parts)): upstream_ann = sbol_parts[i_part - 1] downstream_ann = sbol_parts[i_part] - insert_annotation_downstream( root, upstream_ann, downstream_ann ) + insert_annotation_downstream(root, upstream_ann, downstream_ann) assemble_subcomponents(root) - #for part in sbol_parts: + # for part in sbol_parts: # print part.start, part.end, part.subcomponent.name, part.subcomponent.type, part.subcomponent.uri return root -def scrape_parts(doc, part_files, parts_list, TARGET_DIR = '.'): + +def scrape_parts(doc, part_files, parts_list, TARGET_DIR="."): # Scrape parts from files # doc is the Document to which the scraped parts will be added # part_files should be a list of file names without .xml extension for pf in part_files: print(pf) sbol_in = sbol.Document() - sbol_in.read(TARGET_DIR + '/' + pf + '.xml') + sbol_in.read(TARGET_DIR + "/" + pf + ".xml") print("Components in infile", len(sbol_in.components)) for i_dc, dc in enumerate(sbol_in.components): @@ -632,6 +824,6 @@ def scrape_parts(doc, part_files, parts_list, TARGET_DIR = '.'): if dc.uri in parts_list: dc.move(doc) except: - print('error in ', i_dc) + print("error in ", i_dc) libsbol.deleteDocument(sbol_in.ptr) return doc diff --git a/dnaplotlib/gallery/sbol_interactive/sbol_viewer 2.py b/dnaplotlib/gallery/sbol_interactive/sbol_viewer 2.py index baed0b6..f124ca2 100644 --- a/dnaplotlib/gallery/sbol_interactive/sbol_viewer 2.py +++ b/dnaplotlib/gallery/sbol_interactive/sbol_viewer 2.py @@ -22,31 +22,31 @@ from matplotlib.patheffects import Stroke import matplotlib.patches as patches -__author__ = 'Bryan Der , Voigt Lab, MIT\n\ - Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Bryan Der , Voigt Lab, MIT\n\ + Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Test pySBOL interface doc = sbol.Document() -doc.read('ExampleAlignment.xml') -target = doc.components['http://sys-bio.org/Design'] -module = [ None ] * 3 -module[0] = doc.components['http://sys-bio.org/DC1'] -module[1] = doc.components['http://sys-bio.org/DC2'] -module[2] = doc.components['http://sys-bio.org/DC3'] +doc.read("ExampleAlignment.xml") +target = doc.components["http://sys-bio.org/Design"] +module = [None] * 3 +module[0] = doc.components["http://sys-bio.org/DC1"] +module[1] = doc.components["http://sys-bio.org/DC2"] +module[2] = doc.components["http://sys-bio.org/DC3"] # Create the DNAplotlib renderer dr = dpl_sbol.SBOLRenderer() design = [] for dc in module: - SO_term = dc.type.split('/')[-1] + SO_term = dc.type.split("/")[-1] part = {} if SO_term in list(dr.SO_terms().keys()): - part['type'] = dr.SO_terms()[SO_term] - part['name'] = dc.name - part['fwd'] = True + part["type"] = dr.SO_terms()[SO_term] + part["name"] = dc.name + part["fwd"] = True design.append(part) # Instantiate rendered @@ -64,27 +64,28 @@ # dpl.write_label(ax, "%.2f" %identity, (start+end)/2, { 'label_size' : 18, 'label_y_offset': 12 }) # #ax.text(center, -10, "%.2f" %identity, horizontalalignment = 'center', fontsize = 12) from matplotlib.patches import Rectangle + ax.set_xlim([start, end]) -ax.set_ylim([-18,18]) -ax.set_aspect('equal') +ax.set_ylim([-18, 18]) +ax.set_aspect("equal") ax.set_xticks([]) ax.set_yticks([]) -ax.axis('off') -#plt.ion() -#ax.add_patch(Rectangle((start, .5), 1, 1, facecolor="grey")) -#plt.show() +ax.axis("off") +# plt.ion() +# ax.add_patch(Rectangle((start, .5), 1, 1, facecolor="grey")) +# plt.show() design = [] subcomponents = [] for ann in module[0].annotations: dc = ann.subcomponent subcomponents.append(dc) - SO_term = dc.part_type.split('/')[-1] + SO_term = dc.part_type.split("/")[-1] part = {} if SO_term in list(dr.SO_terms().keys()): - part['type'] = dr.SO_terms()[SO_term] - part['name'] = dc.display_id - part['fwd'] = True + part["type"] = dr.SO_terms()[SO_term] + part["name"] = dc.display_id + part["fwd"] = True design.append(part) """ @@ -114,4 +115,4 @@ plt.show() # Clear the plotting cache -#plt.close('all') +# plt.close('all') diff --git a/dnaplotlib/gallery/sbol_interactive/sbol_viewer.py b/dnaplotlib/gallery/sbol_interactive/sbol_viewer.py index baed0b6..f124ca2 100644 --- a/dnaplotlib/gallery/sbol_interactive/sbol_viewer.py +++ b/dnaplotlib/gallery/sbol_interactive/sbol_viewer.py @@ -22,31 +22,31 @@ from matplotlib.patheffects import Stroke import matplotlib.patches as patches -__author__ = 'Bryan Der , Voigt Lab, MIT\n\ - Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Bryan Der , Voigt Lab, MIT\n\ + Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Test pySBOL interface doc = sbol.Document() -doc.read('ExampleAlignment.xml') -target = doc.components['http://sys-bio.org/Design'] -module = [ None ] * 3 -module[0] = doc.components['http://sys-bio.org/DC1'] -module[1] = doc.components['http://sys-bio.org/DC2'] -module[2] = doc.components['http://sys-bio.org/DC3'] +doc.read("ExampleAlignment.xml") +target = doc.components["http://sys-bio.org/Design"] +module = [None] * 3 +module[0] = doc.components["http://sys-bio.org/DC1"] +module[1] = doc.components["http://sys-bio.org/DC2"] +module[2] = doc.components["http://sys-bio.org/DC3"] # Create the DNAplotlib renderer dr = dpl_sbol.SBOLRenderer() design = [] for dc in module: - SO_term = dc.type.split('/')[-1] + SO_term = dc.type.split("/")[-1] part = {} if SO_term in list(dr.SO_terms().keys()): - part['type'] = dr.SO_terms()[SO_term] - part['name'] = dc.name - part['fwd'] = True + part["type"] = dr.SO_terms()[SO_term] + part["name"] = dc.name + part["fwd"] = True design.append(part) # Instantiate rendered @@ -64,27 +64,28 @@ # dpl.write_label(ax, "%.2f" %identity, (start+end)/2, { 'label_size' : 18, 'label_y_offset': 12 }) # #ax.text(center, -10, "%.2f" %identity, horizontalalignment = 'center', fontsize = 12) from matplotlib.patches import Rectangle + ax.set_xlim([start, end]) -ax.set_ylim([-18,18]) -ax.set_aspect('equal') +ax.set_ylim([-18, 18]) +ax.set_aspect("equal") ax.set_xticks([]) ax.set_yticks([]) -ax.axis('off') -#plt.ion() -#ax.add_patch(Rectangle((start, .5), 1, 1, facecolor="grey")) -#plt.show() +ax.axis("off") +# plt.ion() +# ax.add_patch(Rectangle((start, .5), 1, 1, facecolor="grey")) +# plt.show() design = [] subcomponents = [] for ann in module[0].annotations: dc = ann.subcomponent subcomponents.append(dc) - SO_term = dc.part_type.split('/')[-1] + SO_term = dc.part_type.split("/")[-1] part = {} if SO_term in list(dr.SO_terms().keys()): - part['type'] = dr.SO_terms()[SO_term] - part['name'] = dc.display_id - part['fwd'] = True + part["type"] = dr.SO_terms()[SO_term] + part["name"] = dc.display_id + part["fwd"] = True design.append(part) """ @@ -114,4 +115,4 @@ plt.show() # Clear the plotting cache -#plt.close('all') +# plt.close('all') diff --git a/dnaplotlib/gallery/sbol_visual/sbol_visual 2.py b/dnaplotlib/gallery/sbol_visual/sbol_visual 2.py index 3ad71ae..4b6ec43 100644 --- a/dnaplotlib/gallery/sbol_visual/sbol_visual 2.py +++ b/dnaplotlib/gallery/sbol_visual/sbol_visual 2.py @@ -1,4 +1,4 @@ -__author__ = 'user' +__author__ = "user" import dnaplotlib as dpl import dnaplotlib.sbol as dpl_sbol @@ -7,10 +7,10 @@ # Import the SBOL design file doc = sbol.Document() -doc.read('gene_cassette.sbol') +doc.read("gene_cassette.sbol") # In this case, we know ahead of time the URI of the design. In some cases, you may have to explore the doc's components to find the design you are looking for -design = doc.components['http://sbolstandard.org/examples/Design'] +design = doc.components["http://sbolstandard.org/examples/Design"] print(design.display_id) print(design) @@ -23,23 +23,30 @@ # Create the figure fig = plt.figure() ax = plt.gca() -start, end = dr.renderSBOL(ax, design, part_renderers) # Render SBOL. This function has parallel structure to renderDNA +start, end = dr.renderSBOL( + ax, design, part_renderers +) # Render SBOL. This function has parallel structure to renderDNA # Give the figure a title -dpl.write_label(ax, design.display_id, (start+end)/2, { 'label_size' : 18, 'label_y_offset': 12 }) +dpl.write_label( + ax, + design.display_id, + (start + end) / 2, + {"label_size": 18, "label_y_offset": 12}, +) # Configure plot ax.set_xlim([start, end]) -ax.set_ylim([-18,18]) -ax.set_aspect('equal') +ax.set_ylim([-18, 18]) +ax.set_aspect("equal") ax.set_xticks([]) ax.set_yticks([]) -ax.axis('off') +ax.axis("off") # Save the figure -fig.savefig('sbol_visual.pdf', transparent=True) -fig.savefig('sbol_visual.png', dpi=300) +fig.savefig("sbol_visual.pdf", transparent=True) +fig.savefig("sbol_visual.png", dpi=300) # Clear the plotting cache -#plt.close('all') +# plt.close('all') plt.show() diff --git a/dnaplotlib/gallery/sbol_visual/sbol_visual.py b/dnaplotlib/gallery/sbol_visual/sbol_visual.py index 3ad71ae..4b6ec43 100644 --- a/dnaplotlib/gallery/sbol_visual/sbol_visual.py +++ b/dnaplotlib/gallery/sbol_visual/sbol_visual.py @@ -1,4 +1,4 @@ -__author__ = 'user' +__author__ = "user" import dnaplotlib as dpl import dnaplotlib.sbol as dpl_sbol @@ -7,10 +7,10 @@ # Import the SBOL design file doc = sbol.Document() -doc.read('gene_cassette.sbol') +doc.read("gene_cassette.sbol") # In this case, we know ahead of time the URI of the design. In some cases, you may have to explore the doc's components to find the design you are looking for -design = doc.components['http://sbolstandard.org/examples/Design'] +design = doc.components["http://sbolstandard.org/examples/Design"] print(design.display_id) print(design) @@ -23,23 +23,30 @@ # Create the figure fig = plt.figure() ax = plt.gca() -start, end = dr.renderSBOL(ax, design, part_renderers) # Render SBOL. This function has parallel structure to renderDNA +start, end = dr.renderSBOL( + ax, design, part_renderers +) # Render SBOL. This function has parallel structure to renderDNA # Give the figure a title -dpl.write_label(ax, design.display_id, (start+end)/2, { 'label_size' : 18, 'label_y_offset': 12 }) +dpl.write_label( + ax, + design.display_id, + (start + end) / 2, + {"label_size": 18, "label_y_offset": 12}, +) # Configure plot ax.set_xlim([start, end]) -ax.set_ylim([-18,18]) -ax.set_aspect('equal') +ax.set_ylim([-18, 18]) +ax.set_aspect("equal") ax.set_xticks([]) ax.set_yticks([]) -ax.axis('off') +ax.axis("off") # Save the figure -fig.savefig('sbol_visual.pdf', transparent=True) -fig.savefig('sbol_visual.png', dpi=300) +fig.savefig("sbol_visual.pdf", transparent=True) +fig.savefig("sbol_visual.png", dpi=300) # Clear the plotting cache -#plt.close('all') +# plt.close('all') plt.show() diff --git a/dnaplotlib/gallery/scatter_annotate/scatter_annotate 2.py b/dnaplotlib/gallery/scatter_annotate/scatter_annotate 2.py index 8cfd406..026c5ae 100644 --- a/dnaplotlib/gallery/scatter_annotate/scatter_annotate 2.py +++ b/dnaplotlib/gallery/scatter_annotate/scatter_annotate 2.py @@ -8,106 +8,326 @@ import dnaplotlib as dpl import csv -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Read some data points for the scatter plot -filename_in ='data_points.txt' -data_reader = csv.reader(open(filename_in, 'rU'), delimiter=' ') +filename_in = "data_points.txt" +data_reader = csv.reader(open(filename_in, "rU"), delimiter=" ") x = [] y = [] for row in data_reader: - y.append( float(row[1]) ) - x.append( float(row[2]) ) + y.append(float(row[1])) + x.append(float(row[2])) # Generate the scatter plot -fig = plt.figure(figsize=(2.8,2.32)) +fig = plt.figure(figsize=(2.8, 2.32)) ax = plt.subplot(1, 1, 1) -ax.set_yscale('log') -ax.set_xlim([0.85,1.05]) -ax.set_ylim([1,500]) +ax.set_yscale("log") +ax.set_xlim([0.85, 1.05]) +ax.set_ylim([1, 500]) ax.set_xticks([0.85, 0.9, 0.95, 1.0, 1.05]) -ax.tick_params(axis='y', labelsize=8) -ax.tick_params(axis='x', labelsize=8) -ax.spines['right'].set_visible(False) -ax.spines['top'].set_visible(False) -ax.yaxis.set_ticks_position('left') -ax.xaxis.set_ticks_position('bottom') -plt.xlabel('Parameter 1', fontsize=8, labelpad=0) -plt.ylabel('Parameter 2', fontsize=8, labelpad=0) -ax.tick_params(axis='y', which='major', pad=1) -plt.scatter(x, y, c='none', s=6, edgecolor=(0.5,0.5,0.5), lw = 0.8) #(0.38, 0.65, 0.87) +ax.tick_params(axis="y", labelsize=8) +ax.tick_params(axis="x", labelsize=8) +ax.spines["right"].set_visible(False) +ax.spines["top"].set_visible(False) +ax.yaxis.set_ticks_position("left") +ax.xaxis.set_ticks_position("bottom") +plt.xlabel("Parameter 1", fontsize=8, labelpad=0) +plt.ylabel("Parameter 2", fontsize=8, labelpad=0) +ax.tick_params(axis="y", which="major", pad=1) +plt.scatter( + x, y, c="none", s=6, edgecolor=(0.5, 0.5, 0.5), lw=0.8 +) # (0.38, 0.65, 0.87) # Add arrows to the constructs plt.annotate( - '', - xy = (0.8785, 323.5), xytext = (25, 5), - textcoords = 'offset points', ha = 'right', va = 'bottom', - bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), - arrowprops = dict(arrowstyle = '->', linewidth=1.0, connectionstyle = 'arc3,rad=0')) + "", + xy=(0.8785, 323.5), + xytext=(25, 5), + textcoords="offset points", + ha="right", + va="bottom", + bbox=dict(boxstyle="round,pad=0.5", fc="yellow", alpha=0.5), + arrowprops=dict( + arrowstyle="->", linewidth=1.0, connectionstyle="arc3,rad=0" + ), +) plt.annotate( - '', - xy = (0.977, 34), xytext = (20, 14), - textcoords = 'offset points', ha = 'right', va = 'bottom', - bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), - arrowprops = dict(arrowstyle = '->', linewidth=1.0, connectionstyle = 'arc3,rad=0')) + "", + xy=(0.977, 34), + xytext=(20, 14), + textcoords="offset points", + ha="right", + va="bottom", + bbox=dict(boxstyle="round,pad=0.5", fc="yellow", alpha=0.5), + arrowprops=dict( + arrowstyle="->", linewidth=1.0, connectionstyle="arc3,rad=0" + ), +) plt.annotate( - '', - xy = (0.982, 3.3), xytext = (22, 10), - textcoords = 'offset points', ha = 'right', va = 'bottom', - bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), - arrowprops = dict(arrowstyle = '->', linewidth=1.0, connectionstyle = 'arc3,rad=0')) + "", + xy=(0.982, 3.3), + xytext=(22, 10), + textcoords="offset points", + ha="right", + va="bottom", + bbox=dict(boxstyle="round,pad=0.5", fc="yellow", alpha=0.5), + arrowprops=dict( + arrowstyle="->", linewidth=1.0, connectionstyle="arc3,rad=0" + ), +) # Color maps (let's make sure we use similar colors) col_map = {} -col_map['black'] = (0.00, 0.00, 0.00) -col_map['white'] = (1.00, 1.00, 1.00) -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) -col_map['yellow'] = (0.98, 0.97, 0.35) +col_map["black"] = (0.00, 0.00, 0.00) +col_map["white"] = (1.00, 1.00, 1.00) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) +col_map["yellow"] = (0.98, 0.97, 0.35) # Global line width lw = 1.0 # Define design 1 -p1_1 = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black']}} -rbs_1_1 = {'type':'RBS', 'name':'rbs_f', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -gA_1 = {'type':'CDS', 'name':'gA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['red'], 'edgecolor':col_map['red'], 'x_extent':24, 'label':'A', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -rbs_1_2 = {'type':'RBS', 'name':'rbs_r', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':2, 'x_extent':6}} -gB_1 = {'type':'CDS', 'name':'gB', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['blue'], 'edgecolor':col_map['blue'], 'x_extent':24, 'label':'B', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -t1_1 = {'type':'Terminator', 'name':'t0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} +p1_1 = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} +rbs_1_1 = { + "type": "RBS", + "name": "rbs_f", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +gA_1 = { + "type": "CDS", + "name": "gA", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["red"], + "edgecolor": col_map["red"], + "x_extent": 24, + "label": "A", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +rbs_1_2 = { + "type": "RBS", + "name": "rbs_r", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": 2, + "x_extent": 6, + }, +} +gB_1 = { + "type": "CDS", + "name": "gB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["blue"], + "edgecolor": col_map["blue"], + "x_extent": 24, + "label": "B", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +t1_1 = { + "type": "Terminator", + "name": "t0", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} design1 = [p1_1, rbs_1_1, gA_1, rbs_1_2, gB_1, t1_1] # Define design 2 -t1_2 = {'type':'Terminator', 'name':'t0', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -gA_2 = {'type':'CDS', 'name':'gA', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['red'], 'edgecolor':col_map['red'], 'x_extent':24, 'label':'A', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':2, 'label_y_offset':-1}} -rbs_1_2 = {'type':'RBS', 'name':'rbs_f', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -p1_2 = {'type':'Promoter', 'name':'pA', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black']}} -p2_2 = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black']}} -rbs_2_2 = {'type':'RBS', 'name':'rbs_r', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -gB_2 = {'type':'CDS', 'name':'gB', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['blue'], 'edgecolor':col_map['blue'], 'x_extent':24, 'label':'B', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -t2_2 = {'type':'Terminator', 'name':'t0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} +t1_2 = { + "type": "Terminator", + "name": "t0", + "fwd": False, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +gA_2 = { + "type": "CDS", + "name": "gA", + "fwd": False, + "opts": { + "linewidth": lw, + "color": col_map["red"], + "edgecolor": col_map["red"], + "x_extent": 24, + "label": "A", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": 2, + "label_y_offset": -1, + }, +} +rbs_1_2 = { + "type": "RBS", + "name": "rbs_f", + "fwd": False, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +p1_2 = { + "type": "Promoter", + "name": "pA", + "fwd": False, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} +p2_2 = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} +rbs_2_2 = { + "type": "RBS", + "name": "rbs_r", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +gB_2 = { + "type": "CDS", + "name": "gB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["blue"], + "edgecolor": col_map["blue"], + "x_extent": 24, + "label": "B", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +t2_2 = { + "type": "Terminator", + "name": "t0", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} design2 = [t1_2, gA_2, rbs_1_2, p1_2, p2_2, rbs_2_2, gB_2, t2_2] # Define design 3 -p1_3 = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black']}} -rbs_1_3 = {'type':'RBS', 'name':'rbs_r', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -gA_3 = {'type':'CDS', 'name':'gB', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['red'], 'edgecolor':col_map['red'], 'x_extent':24, 'label':'A', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -t1_3 = {'type':'Terminator', 'name':'t0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t2_3 = {'type':'Terminator', 'name':'t0', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -gB_3 = {'type':'CDS', 'name':'gA', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['blue'], 'edgecolor':col_map['blue'], 'x_extent':24, 'label':'B', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':0, 'label_y_offset':-1}} -rbs_2_3 = {'type':'RBS', 'name':'rbs_f', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -p2_3 = {'type':'Promoter', 'name':'pA', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black']}} +p1_3 = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} +rbs_1_3 = { + "type": "RBS", + "name": "rbs_r", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +gA_3 = { + "type": "CDS", + "name": "gB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["red"], + "edgecolor": col_map["red"], + "x_extent": 24, + "label": "A", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +t1_3 = { + "type": "Terminator", + "name": "t0", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t2_3 = { + "type": "Terminator", + "name": "t0", + "fwd": False, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +gB_3 = { + "type": "CDS", + "name": "gA", + "fwd": False, + "opts": { + "linewidth": lw, + "color": col_map["blue"], + "edgecolor": col_map["blue"], + "x_extent": 24, + "label": "B", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": 0, + "label_y_offset": -1, + }, +} +rbs_2_3 = { + "type": "RBS", + "name": "rbs_f", + "fwd": False, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +p2_3 = { + "type": "Promoter", + "name": "pA", + "fwd": False, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} design3 = [p1_3, rbs_1_3, gA_3, t1_3, t2_3, gB_3, rbs_2_3, p2_3] # Set up the axes for the genetic constructs ax_dna1 = plt.axes([0.35, 0.83, 0.35, 0.12]) ax_dna2 = plt.axes([0.61, 0.65, 0.4, 0.12]) -ax_dna3 = plt.axes([0.58, 0.32, 0.4, 0.12]) +ax_dna3 = plt.axes([0.58, 0.32, 0.4, 0.12]) # Create the DNAplotlib renderer dr = dpl.DNARenderer() @@ -115,33 +335,32 @@ # Redender the DNA to axis start, end = dr.renderDNA(ax_dna1, design1, dr.SBOL_part_renderers()) ax_dna1.set_xlim([start, end]) -ax_dna1.set_ylim([-15,15]) -ax_dna1.set_aspect('equal') +ax_dna1.set_ylim([-15, 15]) +ax_dna1.set_aspect("equal") ax_dna1.set_xticks([]) ax_dna1.set_yticks([]) -ax_dna1.axis('off') +ax_dna1.axis("off") start, end = dr.renderDNA(ax_dna2, design2, dr.SBOL_part_renderers()) ax_dna2.set_xlim([start, end]) -ax_dna2.set_ylim([-15,15]) -ax_dna2.set_aspect('equal') +ax_dna2.set_ylim([-15, 15]) +ax_dna2.set_aspect("equal") ax_dna2.set_xticks([]) ax_dna2.set_yticks([]) -ax_dna2.axis('off') +ax_dna2.axis("off") start, end = dr.renderDNA(ax_dna3, design3, dr.SBOL_part_renderers()) ax_dna3.set_xlim([start, end]) -ax_dna3.set_ylim([-15,15]) -ax_dna3.set_aspect('equal') +ax_dna3.set_ylim([-15, 15]) +ax_dna3.set_aspect("equal") ax_dna3.set_xticks([]) ax_dna3.set_yticks([]) -ax_dna3.axis('off') +ax_dna3.axis("off") # Sort out subplot spacing plt.subplots_adjust(hspace=0.01, left=0.13, right=0.95, top=0.93, bottom=0.13) # Save the figure -fig.savefig('scatter_annotate.pdf', transparent=True) -fig.savefig('scatter_annotate.png', dpi=300) +fig.savefig("scatter_annotate.pdf", transparent=True) +fig.savefig("scatter_annotate.png", dpi=300) # Clear the plotting cache -plt.close('all') - +plt.close("all") diff --git a/dnaplotlib/gallery/scatter_annotate/scatter_annotate.py b/dnaplotlib/gallery/scatter_annotate/scatter_annotate.py index 8cfd406..026c5ae 100644 --- a/dnaplotlib/gallery/scatter_annotate/scatter_annotate.py +++ b/dnaplotlib/gallery/scatter_annotate/scatter_annotate.py @@ -8,106 +8,326 @@ import dnaplotlib as dpl import csv -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Read some data points for the scatter plot -filename_in ='data_points.txt' -data_reader = csv.reader(open(filename_in, 'rU'), delimiter=' ') +filename_in = "data_points.txt" +data_reader = csv.reader(open(filename_in, "rU"), delimiter=" ") x = [] y = [] for row in data_reader: - y.append( float(row[1]) ) - x.append( float(row[2]) ) + y.append(float(row[1])) + x.append(float(row[2])) # Generate the scatter plot -fig = plt.figure(figsize=(2.8,2.32)) +fig = plt.figure(figsize=(2.8, 2.32)) ax = plt.subplot(1, 1, 1) -ax.set_yscale('log') -ax.set_xlim([0.85,1.05]) -ax.set_ylim([1,500]) +ax.set_yscale("log") +ax.set_xlim([0.85, 1.05]) +ax.set_ylim([1, 500]) ax.set_xticks([0.85, 0.9, 0.95, 1.0, 1.05]) -ax.tick_params(axis='y', labelsize=8) -ax.tick_params(axis='x', labelsize=8) -ax.spines['right'].set_visible(False) -ax.spines['top'].set_visible(False) -ax.yaxis.set_ticks_position('left') -ax.xaxis.set_ticks_position('bottom') -plt.xlabel('Parameter 1', fontsize=8, labelpad=0) -plt.ylabel('Parameter 2', fontsize=8, labelpad=0) -ax.tick_params(axis='y', which='major', pad=1) -plt.scatter(x, y, c='none', s=6, edgecolor=(0.5,0.5,0.5), lw = 0.8) #(0.38, 0.65, 0.87) +ax.tick_params(axis="y", labelsize=8) +ax.tick_params(axis="x", labelsize=8) +ax.spines["right"].set_visible(False) +ax.spines["top"].set_visible(False) +ax.yaxis.set_ticks_position("left") +ax.xaxis.set_ticks_position("bottom") +plt.xlabel("Parameter 1", fontsize=8, labelpad=0) +plt.ylabel("Parameter 2", fontsize=8, labelpad=0) +ax.tick_params(axis="y", which="major", pad=1) +plt.scatter( + x, y, c="none", s=6, edgecolor=(0.5, 0.5, 0.5), lw=0.8 +) # (0.38, 0.65, 0.87) # Add arrows to the constructs plt.annotate( - '', - xy = (0.8785, 323.5), xytext = (25, 5), - textcoords = 'offset points', ha = 'right', va = 'bottom', - bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), - arrowprops = dict(arrowstyle = '->', linewidth=1.0, connectionstyle = 'arc3,rad=0')) + "", + xy=(0.8785, 323.5), + xytext=(25, 5), + textcoords="offset points", + ha="right", + va="bottom", + bbox=dict(boxstyle="round,pad=0.5", fc="yellow", alpha=0.5), + arrowprops=dict( + arrowstyle="->", linewidth=1.0, connectionstyle="arc3,rad=0" + ), +) plt.annotate( - '', - xy = (0.977, 34), xytext = (20, 14), - textcoords = 'offset points', ha = 'right', va = 'bottom', - bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), - arrowprops = dict(arrowstyle = '->', linewidth=1.0, connectionstyle = 'arc3,rad=0')) + "", + xy=(0.977, 34), + xytext=(20, 14), + textcoords="offset points", + ha="right", + va="bottom", + bbox=dict(boxstyle="round,pad=0.5", fc="yellow", alpha=0.5), + arrowprops=dict( + arrowstyle="->", linewidth=1.0, connectionstyle="arc3,rad=0" + ), +) plt.annotate( - '', - xy = (0.982, 3.3), xytext = (22, 10), - textcoords = 'offset points', ha = 'right', va = 'bottom', - bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), - arrowprops = dict(arrowstyle = '->', linewidth=1.0, connectionstyle = 'arc3,rad=0')) + "", + xy=(0.982, 3.3), + xytext=(22, 10), + textcoords="offset points", + ha="right", + va="bottom", + bbox=dict(boxstyle="round,pad=0.5", fc="yellow", alpha=0.5), + arrowprops=dict( + arrowstyle="->", linewidth=1.0, connectionstyle="arc3,rad=0" + ), +) # Color maps (let's make sure we use similar colors) col_map = {} -col_map['black'] = (0.00, 0.00, 0.00) -col_map['white'] = (1.00, 1.00, 1.00) -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) -col_map['purple'] = (0.55, 0.35, 0.64) -col_map['yellow'] = (0.98, 0.97, 0.35) +col_map["black"] = (0.00, 0.00, 0.00) +col_map["white"] = (1.00, 1.00, 1.00) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) +col_map["purple"] = (0.55, 0.35, 0.64) +col_map["yellow"] = (0.98, 0.97, 0.35) # Global line width lw = 1.0 # Define design 1 -p1_1 = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black']}} -rbs_1_1 = {'type':'RBS', 'name':'rbs_f', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -gA_1 = {'type':'CDS', 'name':'gA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['red'], 'edgecolor':col_map['red'], 'x_extent':24, 'label':'A', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -rbs_1_2 = {'type':'RBS', 'name':'rbs_r', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':2, 'x_extent':6}} -gB_1 = {'type':'CDS', 'name':'gB', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['blue'], 'edgecolor':col_map['blue'], 'x_extent':24, 'label':'B', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -t1_1 = {'type':'Terminator', 'name':'t0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} +p1_1 = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} +rbs_1_1 = { + "type": "RBS", + "name": "rbs_f", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +gA_1 = { + "type": "CDS", + "name": "gA", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["red"], + "edgecolor": col_map["red"], + "x_extent": 24, + "label": "A", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +rbs_1_2 = { + "type": "RBS", + "name": "rbs_r", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": 2, + "x_extent": 6, + }, +} +gB_1 = { + "type": "CDS", + "name": "gB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["blue"], + "edgecolor": col_map["blue"], + "x_extent": 24, + "label": "B", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +t1_1 = { + "type": "Terminator", + "name": "t0", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} design1 = [p1_1, rbs_1_1, gA_1, rbs_1_2, gB_1, t1_1] # Define design 2 -t1_2 = {'type':'Terminator', 'name':'t0', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -gA_2 = {'type':'CDS', 'name':'gA', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['red'], 'edgecolor':col_map['red'], 'x_extent':24, 'label':'A', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':2, 'label_y_offset':-1}} -rbs_1_2 = {'type':'RBS', 'name':'rbs_f', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -p1_2 = {'type':'Promoter', 'name':'pA', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black']}} -p2_2 = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black']}} -rbs_2_2 = {'type':'RBS', 'name':'rbs_r', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -gB_2 = {'type':'CDS', 'name':'gB', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['blue'], 'edgecolor':col_map['blue'], 'x_extent':24, 'label':'B', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -t2_2 = {'type':'Terminator', 'name':'t0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} +t1_2 = { + "type": "Terminator", + "name": "t0", + "fwd": False, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +gA_2 = { + "type": "CDS", + "name": "gA", + "fwd": False, + "opts": { + "linewidth": lw, + "color": col_map["red"], + "edgecolor": col_map["red"], + "x_extent": 24, + "label": "A", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": 2, + "label_y_offset": -1, + }, +} +rbs_1_2 = { + "type": "RBS", + "name": "rbs_f", + "fwd": False, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +p1_2 = { + "type": "Promoter", + "name": "pA", + "fwd": False, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} +p2_2 = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} +rbs_2_2 = { + "type": "RBS", + "name": "rbs_r", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +gB_2 = { + "type": "CDS", + "name": "gB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["blue"], + "edgecolor": col_map["blue"], + "x_extent": 24, + "label": "B", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +t2_2 = { + "type": "Terminator", + "name": "t0", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} design2 = [t1_2, gA_2, rbs_1_2, p1_2, p2_2, rbs_2_2, gB_2, t2_2] # Define design 3 -p1_3 = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black']}} -rbs_1_3 = {'type':'RBS', 'name':'rbs_r', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -gA_3 = {'type':'CDS', 'name':'gB', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['red'], 'edgecolor':col_map['red'], 'x_extent':24, 'label':'A', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -t1_3 = {'type':'Terminator', 'name':'t0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t2_3 = {'type':'Terminator', 'name':'t0', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -gB_3 = {'type':'CDS', 'name':'gA', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['blue'], 'edgecolor':col_map['blue'], 'x_extent':24, 'label':'B', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':0, 'label_y_offset':-1}} -rbs_2_3 = {'type':'RBS', 'name':'rbs_f', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -p2_3 = {'type':'Promoter', 'name':'pA', 'fwd':False, 'opts':{'linewidth':lw, 'color':col_map['black']}} +p1_3 = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} +rbs_1_3 = { + "type": "RBS", + "name": "rbs_r", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +gA_3 = { + "type": "CDS", + "name": "gB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["red"], + "edgecolor": col_map["red"], + "x_extent": 24, + "label": "A", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +t1_3 = { + "type": "Terminator", + "name": "t0", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t2_3 = { + "type": "Terminator", + "name": "t0", + "fwd": False, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +gB_3 = { + "type": "CDS", + "name": "gA", + "fwd": False, + "opts": { + "linewidth": lw, + "color": col_map["blue"], + "edgecolor": col_map["blue"], + "x_extent": 24, + "label": "B", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": 0, + "label_y_offset": -1, + }, +} +rbs_2_3 = { + "type": "RBS", + "name": "rbs_f", + "fwd": False, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +p2_3 = { + "type": "Promoter", + "name": "pA", + "fwd": False, + "opts": {"linewidth": lw, "color": col_map["black"]}, +} design3 = [p1_3, rbs_1_3, gA_3, t1_3, t2_3, gB_3, rbs_2_3, p2_3] # Set up the axes for the genetic constructs ax_dna1 = plt.axes([0.35, 0.83, 0.35, 0.12]) ax_dna2 = plt.axes([0.61, 0.65, 0.4, 0.12]) -ax_dna3 = plt.axes([0.58, 0.32, 0.4, 0.12]) +ax_dna3 = plt.axes([0.58, 0.32, 0.4, 0.12]) # Create the DNAplotlib renderer dr = dpl.DNARenderer() @@ -115,33 +335,32 @@ # Redender the DNA to axis start, end = dr.renderDNA(ax_dna1, design1, dr.SBOL_part_renderers()) ax_dna1.set_xlim([start, end]) -ax_dna1.set_ylim([-15,15]) -ax_dna1.set_aspect('equal') +ax_dna1.set_ylim([-15, 15]) +ax_dna1.set_aspect("equal") ax_dna1.set_xticks([]) ax_dna1.set_yticks([]) -ax_dna1.axis('off') +ax_dna1.axis("off") start, end = dr.renderDNA(ax_dna2, design2, dr.SBOL_part_renderers()) ax_dna2.set_xlim([start, end]) -ax_dna2.set_ylim([-15,15]) -ax_dna2.set_aspect('equal') +ax_dna2.set_ylim([-15, 15]) +ax_dna2.set_aspect("equal") ax_dna2.set_xticks([]) ax_dna2.set_yticks([]) -ax_dna2.axis('off') +ax_dna2.axis("off") start, end = dr.renderDNA(ax_dna3, design3, dr.SBOL_part_renderers()) ax_dna3.set_xlim([start, end]) -ax_dna3.set_ylim([-15,15]) -ax_dna3.set_aspect('equal') +ax_dna3.set_ylim([-15, 15]) +ax_dna3.set_aspect("equal") ax_dna3.set_xticks([]) ax_dna3.set_yticks([]) -ax_dna3.axis('off') +ax_dna3.axis("off") # Sort out subplot spacing plt.subplots_adjust(hspace=0.01, left=0.13, right=0.95, top=0.93, bottom=0.13) # Save the figure -fig.savefig('scatter_annotate.pdf', transparent=True) -fig.savefig('scatter_annotate.png', dpi=300) +fig.savefig("scatter_annotate.pdf", transparent=True) +fig.savefig("scatter_annotate.png", dpi=300) # Clear the plotting cache -plt.close('all') - +plt.close("all") diff --git a/dnaplotlib/gallery/sequence_features/sequence_features 2.py b/dnaplotlib/gallery/sequence_features/sequence_features 2.py index 2b4f66c..1970715 100644 --- a/dnaplotlib/gallery/sequence_features/sequence_features 2.py +++ b/dnaplotlib/gallery/sequence_features/sequence_features 2.py @@ -13,9 +13,9 @@ from matplotlib.patheffects import Stroke import matplotlib.patches as patches -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" ############################################################################## # HELPER FUNCTIONS @@ -27,101 +27,170 @@ ############################################################################## # Function for writing a sequence to axis -def draw_sequence (ax, start_pos, y_offset, seq): - # For each letter position in center of range - for c_idx, c in enumerate(seq): - ax.annotate(c,(start_pos+c_idx+0.5, y_offset), ha='center', va='bottom', fontsize=8) +def draw_sequence(ax, start_pos, y_offset, seq): + # For each letter position in center of range + for c_idx, c in enumerate(seq): + ax.annotate( + c, + (start_pos + c_idx + 0.5, y_offset), + ha="center", + va="bottom", + fontsize=8, + ) + # Custom renderer for promoter -35 to -10 site (this is used by DNAplotlib to render the sites in a design) -def promoter_region (ax, type, num, start, end, prev_end, scale, linewidth, opts): - # Default parameters - these can be added to, but we usually use this style (probably should simplify in future) - y_offset = 0.0 - color_35 = (0.5,0.5,0.5) - color_10 = (0.5,0.5,0.5) - color_connector = (0,0,0) - linewidth_connector = 2.0 - len_35 = 4 - len_10 = 2 - y_extent = 4.0 - # Update default parameters if provided - if opts != None: - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'color_35' in list(opts.keys()): - color_35 = opts['color_35'] - if 'color_10' in list(opts.keys()): - color_10 = opts['color_10'] - if 'color_connector' in list(opts.keys()): - color_connector = opts['color_connector'] - if 'linewidth_connector' in list(opts.keys()): - linewidth_connector = opts['linewidth_connector'] - if 'len_35' in list(opts.keys()): - len_35 = opts['len_35'] - if 'len_10' in list(opts.keys()): - len_10 = opts['len_10'] - # Check direction (we don't use at moment) - fwd = True - if start > end: - fwd = False - # Draw the -35 site (from start to start + length of -35 site) - p35 = Polygon([(start, y_offset), - (start, y_offset+y_extent), - (start+len_35,y_offset+y_extent), - (start+len_35,y_offset)], - edgecolor=(0,0,0), facecolor=color_35, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p35) - # Draw the -10 site (from end-length of -10 site to end) - p10 = Polygon([(end-len_10, y_offset), - (end-len_10, y_offset+y_extent), - (end,y_offset+y_extent), - (end,y_offset)], - edgecolor=(0,0,0), facecolor=color_10, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p10) - l1 = Line2D([start+len_35, end-len_10], - [y_offset+(y_extent/2.0), y_offset+(y_extent/2.0)], linewidth=linewidth_connector, - color=color_connector, zorder=10) - ax.add_line(l1) - - # Add a label if needed - if opts != None and 'label' in list(opts.keys()): - if final_start > final_end: - dpl.write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) - else: - dpl.write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) - # Return the final start and end positions to the DNA renderer - return start, end +def promoter_region( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + # Default parameters - these can be added to, but we usually use this style (probably should simplify in future) + y_offset = 0.0 + color_35 = (0.5, 0.5, 0.5) + color_10 = (0.5, 0.5, 0.5) + color_connector = (0, 0, 0) + linewidth_connector = 2.0 + len_35 = 4 + len_10 = 2 + y_extent = 4.0 + # Update default parameters if provided + if opts != None: + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "color_35" in list(opts.keys()): + color_35 = opts["color_35"] + if "color_10" in list(opts.keys()): + color_10 = opts["color_10"] + if "color_connector" in list(opts.keys()): + color_connector = opts["color_connector"] + if "linewidth_connector" in list(opts.keys()): + linewidth_connector = opts["linewidth_connector"] + if "len_35" in list(opts.keys()): + len_35 = opts["len_35"] + if "len_10" in list(opts.keys()): + len_10 = opts["len_10"] + # Check direction (we don't use at moment) + fwd = True + if start > end: + fwd = False + # Draw the -35 site (from start to start + length of -35 site) + p35 = Polygon( + [ + (start, y_offset), + (start, y_offset + y_extent), + (start + len_35, y_offset + y_extent), + (start + len_35, y_offset), + ], + edgecolor=(0, 0, 0), + facecolor=color_35, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p35) + # Draw the -10 site (from end-length of -10 site to end) + p10 = Polygon( + [ + (end - len_10, y_offset), + (end - len_10, y_offset + y_extent), + (end, y_offset + y_extent), + (end, y_offset), + ], + edgecolor=(0, 0, 0), + facecolor=color_10, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p10) + l1 = Line2D( + [start + len_35, end - len_10], + [y_offset + (y_extent / 2.0), y_offset + (y_extent / 2.0)], + linewidth=linewidth_connector, + color=color_connector, + zorder=10, + ) + ax.add_line(l1) + + # Add a label if needed + if opts != None and "label" in list(opts.keys()): + if final_start > final_end: + dpl.write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) + else: + dpl.write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) + # Return the final start and end positions to the DNA renderer + return start, end + ############################################################################## # CREATES THE FIGURE ############################################################################## # Create the figure -fig = plt.figure(figsize=(3.0,1.5)) +fig = plt.figure(figsize=(3.0, 1.5)) gs = gridspec.GridSpec(1, 1) ax_dna = plt.subplot(gs[0]) # This is the main sequence -seq1 = 'AATTCCGAGCGCGAGCTTTGCGAGTGA' +seq1 = "AATTCCGAGCGCGAGCTTTGCGAGTGA" draw_sequence(ax_dna, 0, 0, seq1) # Another sequence to show you can overlay them if needed with an offset -seq2 = 'TTGCGAGTGA' +seq2 = "TTGCGAGTGA" draw_sequence(ax_dna, 8, 5, seq2) # Create the DNAplotlib renderer and map of part types to renderering functions dr = dpl.DNARenderer() -part_renderers = {'PromoterRegion': promoter_region} +part_renderers = {"PromoterRegion": promoter_region} # Create the sites to draw -r1 = {'type':'PromoterRegion', 'name':'region1', 'start': 2, 'end': 13, 'fwd':True, 'opts':{'y_offset':10, 'len_35':1, 'len_10':1, 'color_35':(0,0.5,0.2), 'color_10':(0.9,0.2,0.7)}} -r2 = {'type':'PromoterRegion', 'name':'region2', 'start': 15, 'end': 22, 'fwd':True, 'opts':{'y_offset':20, 'color_connector':(1,0,0), 'linewidth_connector':4.0}} -r3 = {'type':'PromoterRegion', 'name':'region3', 'start': 5, 'end': 24, 'fwd':True, 'opts':{'y_offset':30}} +r1 = { + "type": "PromoterRegion", + "name": "region1", + "start": 2, + "end": 13, + "fwd": True, + "opts": { + "y_offset": 10, + "len_35": 1, + "len_10": 1, + "color_35": (0, 0.5, 0.2), + "color_10": (0.9, 0.2, 0.7), + }, +} +r2 = { + "type": "PromoterRegion", + "name": "region2", + "start": 15, + "end": 22, + "fwd": True, + "opts": { + "y_offset": 20, + "color_connector": (1, 0, 0), + "linewidth_connector": 4.0, + }, +} +r3 = { + "type": "PromoterRegion", + "name": "region3", + "start": 5, + "end": 24, + "fwd": True, + "opts": {"y_offset": 30}, +} # We don't use a design, so just annotate an axis dr.annotate(ax_dna, part_renderers, r1) @@ -129,18 +198,18 @@ def promoter_region (ax, type, num, start, end, prev_end, scale, linewidth, opts dr.annotate(ax_dna, part_renderers, r3) # Set up bounds of the axis -ax_dna.set_xlim([-0.5, len(seq1)+0.5]) -ax_dna.set_ylim([0,40]) +ax_dna.set_xlim([-0.5, len(seq1) + 0.5]) +ax_dna.set_ylim([0, 40]) ax_dna.set_xticks([]) ax_dna.set_yticks([]) -ax_dna.axis('off') +ax_dna.axis("off") # Update subplot spacing plt.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01) # Save the figure -fig.savefig('sequence_features.pdf', transparent=True) -fig.savefig('sequence_features.png', dpi=300) +fig.savefig("sequence_features.pdf", transparent=True) +fig.savefig("sequence_features.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/sequence_features/sequence_features.py b/dnaplotlib/gallery/sequence_features/sequence_features.py index 2b4f66c..1970715 100755 --- a/dnaplotlib/gallery/sequence_features/sequence_features.py +++ b/dnaplotlib/gallery/sequence_features/sequence_features.py @@ -13,9 +13,9 @@ from matplotlib.patheffects import Stroke import matplotlib.patches as patches -__author__ = 'Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" ############################################################################## # HELPER FUNCTIONS @@ -27,101 +27,170 @@ ############################################################################## # Function for writing a sequence to axis -def draw_sequence (ax, start_pos, y_offset, seq): - # For each letter position in center of range - for c_idx, c in enumerate(seq): - ax.annotate(c,(start_pos+c_idx+0.5, y_offset), ha='center', va='bottom', fontsize=8) +def draw_sequence(ax, start_pos, y_offset, seq): + # For each letter position in center of range + for c_idx, c in enumerate(seq): + ax.annotate( + c, + (start_pos + c_idx + 0.5, y_offset), + ha="center", + va="bottom", + fontsize=8, + ) + # Custom renderer for promoter -35 to -10 site (this is used by DNAplotlib to render the sites in a design) -def promoter_region (ax, type, num, start, end, prev_end, scale, linewidth, opts): - # Default parameters - these can be added to, but we usually use this style (probably should simplify in future) - y_offset = 0.0 - color_35 = (0.5,0.5,0.5) - color_10 = (0.5,0.5,0.5) - color_connector = (0,0,0) - linewidth_connector = 2.0 - len_35 = 4 - len_10 = 2 - y_extent = 4.0 - # Update default parameters if provided - if opts != None: - if 'y_extent' in list(opts.keys()): - y_extent = opts['y_extent'] - if 'y_offset' in list(opts.keys()): - y_offset = opts['y_offset'] - if 'linewidth' in list(opts.keys()): - linewidth = opts['linewidth'] - if 'color_35' in list(opts.keys()): - color_35 = opts['color_35'] - if 'color_10' in list(opts.keys()): - color_10 = opts['color_10'] - if 'color_connector' in list(opts.keys()): - color_connector = opts['color_connector'] - if 'linewidth_connector' in list(opts.keys()): - linewidth_connector = opts['linewidth_connector'] - if 'len_35' in list(opts.keys()): - len_35 = opts['len_35'] - if 'len_10' in list(opts.keys()): - len_10 = opts['len_10'] - # Check direction (we don't use at moment) - fwd = True - if start > end: - fwd = False - # Draw the -35 site (from start to start + length of -35 site) - p35 = Polygon([(start, y_offset), - (start, y_offset+y_extent), - (start+len_35,y_offset+y_extent), - (start+len_35,y_offset)], - edgecolor=(0,0,0), facecolor=color_35, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p35) - # Draw the -10 site (from end-length of -10 site to end) - p10 = Polygon([(end-len_10, y_offset), - (end-len_10, y_offset+y_extent), - (end,y_offset+y_extent), - (end,y_offset)], - edgecolor=(0,0,0), facecolor=color_10, linewidth=linewidth, zorder=11, - path_effects=[Stroke(joinstyle="miter")]) - ax.add_patch(p10) - l1 = Line2D([start+len_35, end-len_10], - [y_offset+(y_extent/2.0), y_offset+(y_extent/2.0)], linewidth=linewidth_connector, - color=color_connector, zorder=10) - ax.add_line(l1) - - # Add a label if needed - if opts != None and 'label' in list(opts.keys()): - if final_start > final_end: - dpl.write_label(ax, opts['label'], final_end+((final_start-final_end)/2.0), opts=opts) - else: - dpl.write_label(ax, opts['label'], final_start+((final_end-final_start)/2.0), opts=opts) - # Return the final start and end positions to the DNA renderer - return start, end +def promoter_region( + ax, type, num, start, end, prev_end, scale, linewidth, opts +): + # Default parameters - these can be added to, but we usually use this style (probably should simplify in future) + y_offset = 0.0 + color_35 = (0.5, 0.5, 0.5) + color_10 = (0.5, 0.5, 0.5) + color_connector = (0, 0, 0) + linewidth_connector = 2.0 + len_35 = 4 + len_10 = 2 + y_extent = 4.0 + # Update default parameters if provided + if opts != None: + if "y_extent" in list(opts.keys()): + y_extent = opts["y_extent"] + if "y_offset" in list(opts.keys()): + y_offset = opts["y_offset"] + if "linewidth" in list(opts.keys()): + linewidth = opts["linewidth"] + if "color_35" in list(opts.keys()): + color_35 = opts["color_35"] + if "color_10" in list(opts.keys()): + color_10 = opts["color_10"] + if "color_connector" in list(opts.keys()): + color_connector = opts["color_connector"] + if "linewidth_connector" in list(opts.keys()): + linewidth_connector = opts["linewidth_connector"] + if "len_35" in list(opts.keys()): + len_35 = opts["len_35"] + if "len_10" in list(opts.keys()): + len_10 = opts["len_10"] + # Check direction (we don't use at moment) + fwd = True + if start > end: + fwd = False + # Draw the -35 site (from start to start + length of -35 site) + p35 = Polygon( + [ + (start, y_offset), + (start, y_offset + y_extent), + (start + len_35, y_offset + y_extent), + (start + len_35, y_offset), + ], + edgecolor=(0, 0, 0), + facecolor=color_35, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p35) + # Draw the -10 site (from end-length of -10 site to end) + p10 = Polygon( + [ + (end - len_10, y_offset), + (end - len_10, y_offset + y_extent), + (end, y_offset + y_extent), + (end, y_offset), + ], + edgecolor=(0, 0, 0), + facecolor=color_10, + linewidth=linewidth, + zorder=11, + path_effects=[Stroke(joinstyle="miter")], + ) + ax.add_patch(p10) + l1 = Line2D( + [start + len_35, end - len_10], + [y_offset + (y_extent / 2.0), y_offset + (y_extent / 2.0)], + linewidth=linewidth_connector, + color=color_connector, + zorder=10, + ) + ax.add_line(l1) + + # Add a label if needed + if opts != None and "label" in list(opts.keys()): + if final_start > final_end: + dpl.write_label( + ax, + opts["label"], + final_end + ((final_start - final_end) / 2.0), + opts=opts, + ) + else: + dpl.write_label( + ax, + opts["label"], + final_start + ((final_end - final_start) / 2.0), + opts=opts, + ) + # Return the final start and end positions to the DNA renderer + return start, end + ############################################################################## # CREATES THE FIGURE ############################################################################## # Create the figure -fig = plt.figure(figsize=(3.0,1.5)) +fig = plt.figure(figsize=(3.0, 1.5)) gs = gridspec.GridSpec(1, 1) ax_dna = plt.subplot(gs[0]) # This is the main sequence -seq1 = 'AATTCCGAGCGCGAGCTTTGCGAGTGA' +seq1 = "AATTCCGAGCGCGAGCTTTGCGAGTGA" draw_sequence(ax_dna, 0, 0, seq1) # Another sequence to show you can overlay them if needed with an offset -seq2 = 'TTGCGAGTGA' +seq2 = "TTGCGAGTGA" draw_sequence(ax_dna, 8, 5, seq2) # Create the DNAplotlib renderer and map of part types to renderering functions dr = dpl.DNARenderer() -part_renderers = {'PromoterRegion': promoter_region} +part_renderers = {"PromoterRegion": promoter_region} # Create the sites to draw -r1 = {'type':'PromoterRegion', 'name':'region1', 'start': 2, 'end': 13, 'fwd':True, 'opts':{'y_offset':10, 'len_35':1, 'len_10':1, 'color_35':(0,0.5,0.2), 'color_10':(0.9,0.2,0.7)}} -r2 = {'type':'PromoterRegion', 'name':'region2', 'start': 15, 'end': 22, 'fwd':True, 'opts':{'y_offset':20, 'color_connector':(1,0,0), 'linewidth_connector':4.0}} -r3 = {'type':'PromoterRegion', 'name':'region3', 'start': 5, 'end': 24, 'fwd':True, 'opts':{'y_offset':30}} +r1 = { + "type": "PromoterRegion", + "name": "region1", + "start": 2, + "end": 13, + "fwd": True, + "opts": { + "y_offset": 10, + "len_35": 1, + "len_10": 1, + "color_35": (0, 0.5, 0.2), + "color_10": (0.9, 0.2, 0.7), + }, +} +r2 = { + "type": "PromoterRegion", + "name": "region2", + "start": 15, + "end": 22, + "fwd": True, + "opts": { + "y_offset": 20, + "color_connector": (1, 0, 0), + "linewidth_connector": 4.0, + }, +} +r3 = { + "type": "PromoterRegion", + "name": "region3", + "start": 5, + "end": 24, + "fwd": True, + "opts": {"y_offset": 30}, +} # We don't use a design, so just annotate an axis dr.annotate(ax_dna, part_renderers, r1) @@ -129,18 +198,18 @@ def promoter_region (ax, type, num, start, end, prev_end, scale, linewidth, opts dr.annotate(ax_dna, part_renderers, r3) # Set up bounds of the axis -ax_dna.set_xlim([-0.5, len(seq1)+0.5]) -ax_dna.set_ylim([0,40]) +ax_dna.set_xlim([-0.5, len(seq1) + 0.5]) +ax_dna.set_ylim([0, 40]) ax_dna.set_xticks([]) ax_dna.set_yticks([]) -ax_dna.axis('off') +ax_dna.axis("off") # Update subplot spacing plt.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01) # Save the figure -fig.savefig('sequence_features.pdf', transparent=True) -fig.savefig('sequence_features.png', dpi=300) +fig.savefig("sequence_features.pdf", transparent=True) +fig.savefig("sequence_features.png", dpi=300) # Clear the plotting cache -plt.close('all') +plt.close("all") diff --git a/dnaplotlib/gallery/variants_library/variants_library 2.py b/dnaplotlib/gallery/variants_library/variants_library 2.py index feae4fa..245fb74 100644 --- a/dnaplotlib/gallery/variants_library/variants_library 2.py +++ b/dnaplotlib/gallery/variants_library/variants_library 2.py @@ -15,220 +15,278 @@ import matplotlib.gridspec as gridspec import numpy as np -__author__ = 'Thomas E. Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas E. Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Function that converts string to float (if possible) -def make_float_if_needed (s): - try: - float(s) - return float(s) - except ValueError: - return s +def make_float_if_needed(s): + try: + float(s) + return float(s) + except ValueError: + return s + # Function to load the parameters data file -def load_plot_parameters (filename): - plot_params = {} - param_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(param_reader) - # Process all parameters - for row in param_reader: - if len(row) >= 2: - if row[1] != '': - plot_params[row[0]] = make_float_if_needed(row[1]) - return plot_params +def load_plot_parameters(filename): + plot_params = {} + param_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(param_reader) + # Process all parameters + for row in param_reader: + if len(row) >= 2: + if row[1] != "": + plot_params[row[0]] = make_float_if_needed(row[1]) + return plot_params + # Function to load the part information data file -def load_part_information (filename): - part_info = {} - parts_reader = csv.reader(open(filename, 'rU'), delimiter=',') - header = next(parts_reader) - header_map = {} - for i in range(len(header)): - header_map[header[i]] = i - attrib_keys = [k for k in list(header_map.keys()) if k not in ['part_name', 'type']] - for row in parts_reader: - # Make the attributes map - part_attribs_map = {} - for k in attrib_keys: - if row[header_map[k]] != '': - if k == 'color' or k == 'label_color': - part_attribs_map[k] = [float(x) for x in row[header_map[k]].split(';')] - else: - part_attribs_map[k] = make_float_if_needed(row[header_map[k]]) - part_name = row[header_map['part_name']] - part_type = row[header_map['type']] - part_info[part_name] = [part_name, part_type, part_attribs_map] - return part_info +def load_part_information(filename): + part_info = {} + parts_reader = csv.reader(open(filename, "rU"), delimiter=",") + header = next(parts_reader) + header_map = {} + for i in range(len(header)): + header_map[header[i]] = i + attrib_keys = [ + k for k in list(header_map.keys()) if k not in ["part_name", "type"] + ] + for row in parts_reader: + # Make the attributes map + part_attribs_map = {} + for k in attrib_keys: + if row[header_map[k]] != "": + if k == "color" or k == "label_color": + part_attribs_map[k] = [ + float(x) for x in row[header_map[k]].split(";") + ] + else: + part_attribs_map[k] = make_float_if_needed( + row[header_map[k]] + ) + part_name = row[header_map["part_name"]] + part_type = row[header_map["type"]] + part_info[part_name] = [part_name, part_type, part_attribs_map] + return part_info + # Function to load the performance data file -def load_perf_information (filename): - perf_info = {} - perf_reader = csv.reader(open(filename, 'rU'), delimiter=',') - header = next(perf_reader) - header_map = {} - for i in range(len(header)): - header_map[header[i]] = i - attrib_keys = [k for k in list(header_map.keys()) if k != 'Variant'] - for row in perf_reader: - # Make the attributes map - perf_attribs_map = {} - for k in attrib_keys: - if row[header_map[k]] != '': - perf_attribs_map[k] = make_float_if_needed(row[header_map[k]]) - variant = row[header_map['Variant']] - perf_info[variant] = perf_attribs_map - return perf_info +def load_perf_information(filename): + perf_info = {} + perf_reader = csv.reader(open(filename, "rU"), delimiter=",") + header = next(perf_reader) + header_map = {} + for i in range(len(header)): + header_map[header[i]] = i + attrib_keys = [k for k in list(header_map.keys()) if k != "Variant"] + for row in perf_reader: + # Make the attributes map + perf_attribs_map = {} + for k in attrib_keys: + if row[header_map[k]] != "": + perf_attribs_map[k] = make_float_if_needed(row[header_map[k]]) + variant = row[header_map["Variant"]] + perf_info[variant] = perf_attribs_map + return perf_info + # Function to load the DNA designs data file -def load_dna_designs (filename, part_info): - dna_design_order = [] - dna_designs = {} - design_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(design_reader) - # Process all parameters - for row in design_reader: - if len(row[0]) != '': - part_list = [] - for i in range(1,len(row)): - # Handle reverse parts - fwd = True - part_name = row[i] - if len(part_name) != 0: - if part_name[0] == 'r': - part_name = part_name[1:] - fwd = False - # Store the design - part_design = {} - cur_part_info = part_info[part_name] - part_design['type'] = cur_part_info[1] - part_design['name'] = part_name - part_design['fwd'] = fwd - if fwd == True: - part_design['start'] = i - part_design['end'] = i+1 - else: - part_design['end'] = i - part_design['start'] = i+1 - part_design['opts'] = cur_part_info[2] - part_list.append(part_design) - dna_designs[row[0]] = part_list - dna_design_order.append(row[0]) - return dna_designs, dna_design_order +def load_dna_designs(filename, part_info): + dna_design_order = [] + dna_designs = {} + design_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(design_reader) + # Process all parameters + for row in design_reader: + if len(row[0]) != "": + part_list = [] + for i in range(1, len(row)): + # Handle reverse parts + fwd = True + part_name = row[i] + if len(part_name) != 0: + if part_name[0] == "r": + part_name = part_name[1:] + fwd = False + # Store the design + part_design = {} + cur_part_info = part_info[part_name] + part_design["type"] = cur_part_info[1] + part_design["name"] = part_name + part_design["fwd"] = fwd + if fwd == True: + part_design["start"] = i + part_design["end"] = i + 1 + else: + part_design["end"] = i + part_design["start"] = i + 1 + part_design["opts"] = cur_part_info[2] + part_list.append(part_design) + dna_designs[row[0]] = part_list + dna_design_order.append(row[0]) + return dna_designs, dna_design_order + # Function to all of the values for a given attribute from a dictionary -def extract_dict_attribs (d, dict_keys, attrib_key): - out = [] - for d_key in dict_keys: - out.append(d[d_key][attrib_key]) - return out +def extract_dict_attribs(d, dict_keys, attrib_key): + out = [] + for d_key in dict_keys: + out.append(d[d_key][attrib_key]) + return out + # Function to plot the designs and performance information -def plot_dna (dna_designs, dna_design_order, out_filename, plot_params, perf_data): - # Default parameters for the plotting - if 'axis_y' not in list(plot_params.keys()): - plot_params['axis_y'] = 35 - left_pad = 0.0 - right_pad = 0.0 - scale = 1.0 - linewidth = 1.0 - fig_y = 5.0 - fig_x = 5.0 - # Update parameters if needed - if 'backbone_pad_left' in list(plot_params.keys()): - left_pad = plot_params['backbone_pad_left'] - if 'backbone_pad_right' in list(plot_params.keys()): - right_pad = plot_params['backbone_pad_right'] - if 'scale' in list(plot_params.keys()): - scale = plot_params['scale'] - if 'linewidth' in list(plot_params.keys()): - linewidth = plot_params['linewidth'] - if 'fig_y' in list(plot_params.keys()): - fig_y = plot_params['fig_y'] - if 'fig_x' in list(plot_params.keys()): - fig_x = plot_params['fig_x'] - dr = dpl.DNARenderer(scale=scale, linewidth=linewidth, - backbone_pad_left=left_pad, - backbone_pad_right=right_pad) - - # We default to the SBOL part renderers - part_renderers = dr.SBOL_part_renderers() +def plot_dna( + dna_designs, dna_design_order, out_filename, plot_params, perf_data +): + # Default parameters for the plotting + if "axis_y" not in list(plot_params.keys()): + plot_params["axis_y"] = 35 + left_pad = 0.0 + right_pad = 0.0 + scale = 1.0 + linewidth = 1.0 + fig_y = 5.0 + fig_x = 5.0 + # Update parameters if needed + if "backbone_pad_left" in list(plot_params.keys()): + left_pad = plot_params["backbone_pad_left"] + if "backbone_pad_right" in list(plot_params.keys()): + right_pad = plot_params["backbone_pad_right"] + if "scale" in list(plot_params.keys()): + scale = plot_params["scale"] + if "linewidth" in list(plot_params.keys()): + linewidth = plot_params["linewidth"] + if "fig_y" in list(plot_params.keys()): + fig_y = plot_params["fig_y"] + if "fig_x" in list(plot_params.keys()): + fig_x = plot_params["fig_x"] + dr = dpl.DNARenderer( + scale=scale, + linewidth=linewidth, + backbone_pad_left=left_pad, + backbone_pad_right=right_pad, + ) + + # We default to the SBOL part renderers + part_renderers = dr.SBOL_part_renderers() # Create the figure - fig = plt.figure(figsize=(3.6,6.2)) - - # Cycle through the designs an plot on individual axes - design_list = sorted(dna_designs.keys()) - num_of_designs = len(design_list) - ax_list = [] - max_dna_len = 0.0 - gs = gridspec.GridSpec(num_of_designs,2, width_ratios=[1,12]) - - # Plot the genetic designs - for i in range(len(dna_design_order)): - # Create axis for the design and plot - design = dna_designs[dna_design_order[i]] - ax = plt.subplot(gs[i, 1]) - if 'show_title' in list(plot_params.keys()) and plot_params['show_title'] == 'Y': - ax.set_title(design_list[i], fontsize=8) - start, end = dr.renderDNA(ax, design, part_renderers) - dna_len = end-start - if max_dna_len < dna_len: - max_dna_len = dna_len - ax_list.append(ax) - for ax in ax_list: - ax.set_xticks([]) - ax.set_yticks([]) - # Set bounds - ax.set_xlim([(-0.01*max_dna_len)-left_pad, - max_dna_len+(0.01*max_dna_len)+right_pad]) - ax.set_ylim([-14,14]) - ax.set_aspect('equal') - ax.set_axis_off() - - # Plot the performance data (bar charts) - perf_vals = extract_dict_attribs(perf_data, dna_design_order, 'Activity') - perf_sd_vals = extract_dict_attribs(perf_data, dna_design_order, 'Activity_SD') - ax_perf = plt.subplot(gs[:, 0]) - bar_height = 0.3 - ax_perf.plot([1],[1]) - ax_perf.spines['top'].set_visible(False) - ax_perf.spines['bottom'].set_visible(False) - ax_perf.spines['right'].set_visible(False) - ax_perf.invert_yaxis() - ax_perf.set_xticks([]) - ax_perf.yaxis.tick_left() - ax_perf.yaxis.set_ticks_position('left') - ax_perf.tick_params(axis='y', direction='out') - ax_perf.tick_params('y', length=3, width=0.8, which='major', pad=2, labelsize=8) - pos1 = np.arange(len(perf_vals)) - ax_perf.barh(pos1, perf_vals, height=bar_height, color=(0.6,0.6,0.6), edgecolor=(0.6,0.6,0.6)) - ax_perf.errorbar(perf_vals, pos1+(bar_height/2.0), fmt='none', xerr=perf_sd_vals, ecolor=(0,0,0), capthick=1) - ax_perf.set_yticks(pos1+(bar_height/2.0)) - ax_perf.set_yticklabels(dna_design_order) - ax_perf.set_ylim([max(pos1)+0.65, -0.35]) - ax_perf.set_xlim([0, 1062606*1.05]) - - # Save the figure - plt.subplots_adjust(hspace=0.001, wspace=0.05, top=0.99, bottom=0.01, left=0.06, right=0.99) - fig.savefig(out_filename, transparent=True, dpi=300) - - # Clear the plotting cache - plt.close('all') - -def main(): - # Load the data - plot_params = load_plot_parameters('plot_parameters.csv') - part_info = load_part_information('part_information.csv') - dna_designs, dna_design_order = load_dna_designs ('dna_designs.csv', part_info) - perf_data =load_perf_information('performance.csv') - # Plot the libraries - plot_dna(dna_designs, dna_design_order, 'variants_library.pdf', plot_params, perf_data) - plot_dna(dna_designs, dna_design_order, 'variants_library.png', plot_params, perf_data) + fig = plt.figure(figsize=(3.6, 6.2)) + + # Cycle through the designs an plot on individual axes + design_list = sorted(dna_designs.keys()) + num_of_designs = len(design_list) + ax_list = [] + max_dna_len = 0.0 + gs = gridspec.GridSpec(num_of_designs, 2, width_ratios=[1, 12]) + + # Plot the genetic designs + for i in range(len(dna_design_order)): + # Create axis for the design and plot + design = dna_designs[dna_design_order[i]] + ax = plt.subplot(gs[i, 1]) + if ( + "show_title" in list(plot_params.keys()) + and plot_params["show_title"] == "Y" + ): + ax.set_title(design_list[i], fontsize=8) + start, end = dr.renderDNA(ax, design, part_renderers) + dna_len = end - start + if max_dna_len < dna_len: + max_dna_len = dna_len + ax_list.append(ax) + for ax in ax_list: + ax.set_xticks([]) + ax.set_yticks([]) + # Set bounds + ax.set_xlim( + [ + (-0.01 * max_dna_len) - left_pad, + max_dna_len + (0.01 * max_dna_len) + right_pad, + ] + ) + ax.set_ylim([-14, 14]) + ax.set_aspect("equal") + ax.set_axis_off() + + # Plot the performance data (bar charts) + perf_vals = extract_dict_attribs(perf_data, dna_design_order, "Activity") + perf_sd_vals = extract_dict_attribs( + perf_data, dna_design_order, "Activity_SD" + ) + ax_perf = plt.subplot(gs[:, 0]) + bar_height = 0.3 + ax_perf.plot([1], [1]) + ax_perf.spines["top"].set_visible(False) + ax_perf.spines["bottom"].set_visible(False) + ax_perf.spines["right"].set_visible(False) + ax_perf.invert_yaxis() + ax_perf.set_xticks([]) + ax_perf.yaxis.tick_left() + ax_perf.yaxis.set_ticks_position("left") + ax_perf.tick_params(axis="y", direction="out") + ax_perf.tick_params( + "y", length=3, width=0.8, which="major", pad=2, labelsize=8 + ) + pos1 = np.arange(len(perf_vals)) + ax_perf.barh( + pos1, + perf_vals, + height=bar_height, + color=(0.6, 0.6, 0.6), + edgecolor=(0.6, 0.6, 0.6), + ) + ax_perf.errorbar( + perf_vals, + pos1 + (bar_height / 2.0), + fmt="none", + xerr=perf_sd_vals, + ecolor=(0, 0, 0), + capthick=1, + ) + ax_perf.set_yticks(pos1 + (bar_height / 2.0)) + ax_perf.set_yticklabels(dna_design_order) + ax_perf.set_ylim([max(pos1) + 0.65, -0.35]) + ax_perf.set_xlim([0, 1062606 * 1.05]) + + # Save the figure + plt.subplots_adjust( + hspace=0.001, wspace=0.05, top=0.99, bottom=0.01, left=0.06, right=0.99 + ) + fig.savefig(out_filename, transparent=True, dpi=300) + + # Clear the plotting cache + plt.close("all") + + +def main(): + # Load the data + plot_params = load_plot_parameters("plot_parameters.csv") + part_info = load_part_information("part_information.csv") + dna_designs, dna_design_order = load_dna_designs( + "dna_designs.csv", part_info + ) + perf_data = load_perf_information("performance.csv") + # Plot the libraries + plot_dna( + dna_designs, + dna_design_order, + "variants_library.pdf", + plot_params, + perf_data, + ) + plot_dna( + dna_designs, + dna_design_order, + "variants_library.png", + plot_params, + perf_data, + ) + if __name__ == "__main__": - main() - + main() diff --git a/dnaplotlib/gallery/variants_library/variants_library.py b/dnaplotlib/gallery/variants_library/variants_library.py index feae4fa..245fb74 100755 --- a/dnaplotlib/gallery/variants_library/variants_library.py +++ b/dnaplotlib/gallery/variants_library/variants_library.py @@ -15,220 +15,278 @@ import matplotlib.gridspec as gridspec import numpy as np -__author__ = 'Thomas E. Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Thomas E. Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Function that converts string to float (if possible) -def make_float_if_needed (s): - try: - float(s) - return float(s) - except ValueError: - return s +def make_float_if_needed(s): + try: + float(s) + return float(s) + except ValueError: + return s + # Function to load the parameters data file -def load_plot_parameters (filename): - plot_params = {} - param_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(param_reader) - # Process all parameters - for row in param_reader: - if len(row) >= 2: - if row[1] != '': - plot_params[row[0]] = make_float_if_needed(row[1]) - return plot_params +def load_plot_parameters(filename): + plot_params = {} + param_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(param_reader) + # Process all parameters + for row in param_reader: + if len(row) >= 2: + if row[1] != "": + plot_params[row[0]] = make_float_if_needed(row[1]) + return plot_params + # Function to load the part information data file -def load_part_information (filename): - part_info = {} - parts_reader = csv.reader(open(filename, 'rU'), delimiter=',') - header = next(parts_reader) - header_map = {} - for i in range(len(header)): - header_map[header[i]] = i - attrib_keys = [k for k in list(header_map.keys()) if k not in ['part_name', 'type']] - for row in parts_reader: - # Make the attributes map - part_attribs_map = {} - for k in attrib_keys: - if row[header_map[k]] != '': - if k == 'color' or k == 'label_color': - part_attribs_map[k] = [float(x) for x in row[header_map[k]].split(';')] - else: - part_attribs_map[k] = make_float_if_needed(row[header_map[k]]) - part_name = row[header_map['part_name']] - part_type = row[header_map['type']] - part_info[part_name] = [part_name, part_type, part_attribs_map] - return part_info +def load_part_information(filename): + part_info = {} + parts_reader = csv.reader(open(filename, "rU"), delimiter=",") + header = next(parts_reader) + header_map = {} + for i in range(len(header)): + header_map[header[i]] = i + attrib_keys = [ + k for k in list(header_map.keys()) if k not in ["part_name", "type"] + ] + for row in parts_reader: + # Make the attributes map + part_attribs_map = {} + for k in attrib_keys: + if row[header_map[k]] != "": + if k == "color" or k == "label_color": + part_attribs_map[k] = [ + float(x) for x in row[header_map[k]].split(";") + ] + else: + part_attribs_map[k] = make_float_if_needed( + row[header_map[k]] + ) + part_name = row[header_map["part_name"]] + part_type = row[header_map["type"]] + part_info[part_name] = [part_name, part_type, part_attribs_map] + return part_info + # Function to load the performance data file -def load_perf_information (filename): - perf_info = {} - perf_reader = csv.reader(open(filename, 'rU'), delimiter=',') - header = next(perf_reader) - header_map = {} - for i in range(len(header)): - header_map[header[i]] = i - attrib_keys = [k for k in list(header_map.keys()) if k != 'Variant'] - for row in perf_reader: - # Make the attributes map - perf_attribs_map = {} - for k in attrib_keys: - if row[header_map[k]] != '': - perf_attribs_map[k] = make_float_if_needed(row[header_map[k]]) - variant = row[header_map['Variant']] - perf_info[variant] = perf_attribs_map - return perf_info +def load_perf_information(filename): + perf_info = {} + perf_reader = csv.reader(open(filename, "rU"), delimiter=",") + header = next(perf_reader) + header_map = {} + for i in range(len(header)): + header_map[header[i]] = i + attrib_keys = [k for k in list(header_map.keys()) if k != "Variant"] + for row in perf_reader: + # Make the attributes map + perf_attribs_map = {} + for k in attrib_keys: + if row[header_map[k]] != "": + perf_attribs_map[k] = make_float_if_needed(row[header_map[k]]) + variant = row[header_map["Variant"]] + perf_info[variant] = perf_attribs_map + return perf_info + # Function to load the DNA designs data file -def load_dna_designs (filename, part_info): - dna_design_order = [] - dna_designs = {} - design_reader = csv.reader(open(filename, 'rU'), delimiter=',') - # Ignore header - header = next(design_reader) - # Process all parameters - for row in design_reader: - if len(row[0]) != '': - part_list = [] - for i in range(1,len(row)): - # Handle reverse parts - fwd = True - part_name = row[i] - if len(part_name) != 0: - if part_name[0] == 'r': - part_name = part_name[1:] - fwd = False - # Store the design - part_design = {} - cur_part_info = part_info[part_name] - part_design['type'] = cur_part_info[1] - part_design['name'] = part_name - part_design['fwd'] = fwd - if fwd == True: - part_design['start'] = i - part_design['end'] = i+1 - else: - part_design['end'] = i - part_design['start'] = i+1 - part_design['opts'] = cur_part_info[2] - part_list.append(part_design) - dna_designs[row[0]] = part_list - dna_design_order.append(row[0]) - return dna_designs, dna_design_order +def load_dna_designs(filename, part_info): + dna_design_order = [] + dna_designs = {} + design_reader = csv.reader(open(filename, "rU"), delimiter=",") + # Ignore header + header = next(design_reader) + # Process all parameters + for row in design_reader: + if len(row[0]) != "": + part_list = [] + for i in range(1, len(row)): + # Handle reverse parts + fwd = True + part_name = row[i] + if len(part_name) != 0: + if part_name[0] == "r": + part_name = part_name[1:] + fwd = False + # Store the design + part_design = {} + cur_part_info = part_info[part_name] + part_design["type"] = cur_part_info[1] + part_design["name"] = part_name + part_design["fwd"] = fwd + if fwd == True: + part_design["start"] = i + part_design["end"] = i + 1 + else: + part_design["end"] = i + part_design["start"] = i + 1 + part_design["opts"] = cur_part_info[2] + part_list.append(part_design) + dna_designs[row[0]] = part_list + dna_design_order.append(row[0]) + return dna_designs, dna_design_order + # Function to all of the values for a given attribute from a dictionary -def extract_dict_attribs (d, dict_keys, attrib_key): - out = [] - for d_key in dict_keys: - out.append(d[d_key][attrib_key]) - return out +def extract_dict_attribs(d, dict_keys, attrib_key): + out = [] + for d_key in dict_keys: + out.append(d[d_key][attrib_key]) + return out + # Function to plot the designs and performance information -def plot_dna (dna_designs, dna_design_order, out_filename, plot_params, perf_data): - # Default parameters for the plotting - if 'axis_y' not in list(plot_params.keys()): - plot_params['axis_y'] = 35 - left_pad = 0.0 - right_pad = 0.0 - scale = 1.0 - linewidth = 1.0 - fig_y = 5.0 - fig_x = 5.0 - # Update parameters if needed - if 'backbone_pad_left' in list(plot_params.keys()): - left_pad = plot_params['backbone_pad_left'] - if 'backbone_pad_right' in list(plot_params.keys()): - right_pad = plot_params['backbone_pad_right'] - if 'scale' in list(plot_params.keys()): - scale = plot_params['scale'] - if 'linewidth' in list(plot_params.keys()): - linewidth = plot_params['linewidth'] - if 'fig_y' in list(plot_params.keys()): - fig_y = plot_params['fig_y'] - if 'fig_x' in list(plot_params.keys()): - fig_x = plot_params['fig_x'] - dr = dpl.DNARenderer(scale=scale, linewidth=linewidth, - backbone_pad_left=left_pad, - backbone_pad_right=right_pad) - - # We default to the SBOL part renderers - part_renderers = dr.SBOL_part_renderers() +def plot_dna( + dna_designs, dna_design_order, out_filename, plot_params, perf_data +): + # Default parameters for the plotting + if "axis_y" not in list(plot_params.keys()): + plot_params["axis_y"] = 35 + left_pad = 0.0 + right_pad = 0.0 + scale = 1.0 + linewidth = 1.0 + fig_y = 5.0 + fig_x = 5.0 + # Update parameters if needed + if "backbone_pad_left" in list(plot_params.keys()): + left_pad = plot_params["backbone_pad_left"] + if "backbone_pad_right" in list(plot_params.keys()): + right_pad = plot_params["backbone_pad_right"] + if "scale" in list(plot_params.keys()): + scale = plot_params["scale"] + if "linewidth" in list(plot_params.keys()): + linewidth = plot_params["linewidth"] + if "fig_y" in list(plot_params.keys()): + fig_y = plot_params["fig_y"] + if "fig_x" in list(plot_params.keys()): + fig_x = plot_params["fig_x"] + dr = dpl.DNARenderer( + scale=scale, + linewidth=linewidth, + backbone_pad_left=left_pad, + backbone_pad_right=right_pad, + ) + + # We default to the SBOL part renderers + part_renderers = dr.SBOL_part_renderers() # Create the figure - fig = plt.figure(figsize=(3.6,6.2)) - - # Cycle through the designs an plot on individual axes - design_list = sorted(dna_designs.keys()) - num_of_designs = len(design_list) - ax_list = [] - max_dna_len = 0.0 - gs = gridspec.GridSpec(num_of_designs,2, width_ratios=[1,12]) - - # Plot the genetic designs - for i in range(len(dna_design_order)): - # Create axis for the design and plot - design = dna_designs[dna_design_order[i]] - ax = plt.subplot(gs[i, 1]) - if 'show_title' in list(plot_params.keys()) and plot_params['show_title'] == 'Y': - ax.set_title(design_list[i], fontsize=8) - start, end = dr.renderDNA(ax, design, part_renderers) - dna_len = end-start - if max_dna_len < dna_len: - max_dna_len = dna_len - ax_list.append(ax) - for ax in ax_list: - ax.set_xticks([]) - ax.set_yticks([]) - # Set bounds - ax.set_xlim([(-0.01*max_dna_len)-left_pad, - max_dna_len+(0.01*max_dna_len)+right_pad]) - ax.set_ylim([-14,14]) - ax.set_aspect('equal') - ax.set_axis_off() - - # Plot the performance data (bar charts) - perf_vals = extract_dict_attribs(perf_data, dna_design_order, 'Activity') - perf_sd_vals = extract_dict_attribs(perf_data, dna_design_order, 'Activity_SD') - ax_perf = plt.subplot(gs[:, 0]) - bar_height = 0.3 - ax_perf.plot([1],[1]) - ax_perf.spines['top'].set_visible(False) - ax_perf.spines['bottom'].set_visible(False) - ax_perf.spines['right'].set_visible(False) - ax_perf.invert_yaxis() - ax_perf.set_xticks([]) - ax_perf.yaxis.tick_left() - ax_perf.yaxis.set_ticks_position('left') - ax_perf.tick_params(axis='y', direction='out') - ax_perf.tick_params('y', length=3, width=0.8, which='major', pad=2, labelsize=8) - pos1 = np.arange(len(perf_vals)) - ax_perf.barh(pos1, perf_vals, height=bar_height, color=(0.6,0.6,0.6), edgecolor=(0.6,0.6,0.6)) - ax_perf.errorbar(perf_vals, pos1+(bar_height/2.0), fmt='none', xerr=perf_sd_vals, ecolor=(0,0,0), capthick=1) - ax_perf.set_yticks(pos1+(bar_height/2.0)) - ax_perf.set_yticklabels(dna_design_order) - ax_perf.set_ylim([max(pos1)+0.65, -0.35]) - ax_perf.set_xlim([0, 1062606*1.05]) - - # Save the figure - plt.subplots_adjust(hspace=0.001, wspace=0.05, top=0.99, bottom=0.01, left=0.06, right=0.99) - fig.savefig(out_filename, transparent=True, dpi=300) - - # Clear the plotting cache - plt.close('all') - -def main(): - # Load the data - plot_params = load_plot_parameters('plot_parameters.csv') - part_info = load_part_information('part_information.csv') - dna_designs, dna_design_order = load_dna_designs ('dna_designs.csv', part_info) - perf_data =load_perf_information('performance.csv') - # Plot the libraries - plot_dna(dna_designs, dna_design_order, 'variants_library.pdf', plot_params, perf_data) - plot_dna(dna_designs, dna_design_order, 'variants_library.png', plot_params, perf_data) + fig = plt.figure(figsize=(3.6, 6.2)) + + # Cycle through the designs an plot on individual axes + design_list = sorted(dna_designs.keys()) + num_of_designs = len(design_list) + ax_list = [] + max_dna_len = 0.0 + gs = gridspec.GridSpec(num_of_designs, 2, width_ratios=[1, 12]) + + # Plot the genetic designs + for i in range(len(dna_design_order)): + # Create axis for the design and plot + design = dna_designs[dna_design_order[i]] + ax = plt.subplot(gs[i, 1]) + if ( + "show_title" in list(plot_params.keys()) + and plot_params["show_title"] == "Y" + ): + ax.set_title(design_list[i], fontsize=8) + start, end = dr.renderDNA(ax, design, part_renderers) + dna_len = end - start + if max_dna_len < dna_len: + max_dna_len = dna_len + ax_list.append(ax) + for ax in ax_list: + ax.set_xticks([]) + ax.set_yticks([]) + # Set bounds + ax.set_xlim( + [ + (-0.01 * max_dna_len) - left_pad, + max_dna_len + (0.01 * max_dna_len) + right_pad, + ] + ) + ax.set_ylim([-14, 14]) + ax.set_aspect("equal") + ax.set_axis_off() + + # Plot the performance data (bar charts) + perf_vals = extract_dict_attribs(perf_data, dna_design_order, "Activity") + perf_sd_vals = extract_dict_attribs( + perf_data, dna_design_order, "Activity_SD" + ) + ax_perf = plt.subplot(gs[:, 0]) + bar_height = 0.3 + ax_perf.plot([1], [1]) + ax_perf.spines["top"].set_visible(False) + ax_perf.spines["bottom"].set_visible(False) + ax_perf.spines["right"].set_visible(False) + ax_perf.invert_yaxis() + ax_perf.set_xticks([]) + ax_perf.yaxis.tick_left() + ax_perf.yaxis.set_ticks_position("left") + ax_perf.tick_params(axis="y", direction="out") + ax_perf.tick_params( + "y", length=3, width=0.8, which="major", pad=2, labelsize=8 + ) + pos1 = np.arange(len(perf_vals)) + ax_perf.barh( + pos1, + perf_vals, + height=bar_height, + color=(0.6, 0.6, 0.6), + edgecolor=(0.6, 0.6, 0.6), + ) + ax_perf.errorbar( + perf_vals, + pos1 + (bar_height / 2.0), + fmt="none", + xerr=perf_sd_vals, + ecolor=(0, 0, 0), + capthick=1, + ) + ax_perf.set_yticks(pos1 + (bar_height / 2.0)) + ax_perf.set_yticklabels(dna_design_order) + ax_perf.set_ylim([max(pos1) + 0.65, -0.35]) + ax_perf.set_xlim([0, 1062606 * 1.05]) + + # Save the figure + plt.subplots_adjust( + hspace=0.001, wspace=0.05, top=0.99, bottom=0.01, left=0.06, right=0.99 + ) + fig.savefig(out_filename, transparent=True, dpi=300) + + # Clear the plotting cache + plt.close("all") + + +def main(): + # Load the data + plot_params = load_plot_parameters("plot_parameters.csv") + part_info = load_part_information("part_information.csv") + dna_designs, dna_design_order = load_dna_designs( + "dna_designs.csv", part_info + ) + perf_data = load_perf_information("performance.csv") + # Plot the libraries + plot_dna( + dna_designs, + dna_design_order, + "variants_library.pdf", + plot_params, + perf_data, + ) + plot_dna( + dna_designs, + dna_design_order, + "variants_library.png", + plot_params, + perf_data, + ) + if __name__ == "__main__": - main() - + main() diff --git a/dnaplotlib/gallery/xnor_truthtable/xnor_truthtable 2.py b/dnaplotlib/gallery/xnor_truthtable/xnor_truthtable 2.py index 26daef5..02d298e 100644 --- a/dnaplotlib/gallery/xnor_truthtable/xnor_truthtable 2.py +++ b/dnaplotlib/gallery/xnor_truthtable/xnor_truthtable 2.py @@ -8,116 +8,437 @@ import matplotlib.pyplot as plt -__author__ = 'Bryan Der , Voigt Lab, MIT\n\ - Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Bryan Der , Voigt Lab, MIT\n\ + Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Function to generate a ligher colour -def lighten_color (col, fac): - r = col[0] + (fac*(1.0-col[0])) - g = col[1] + (fac*(1.0-col[1])) - b = col[2] + (fac*(1.0-col[2])) - return (r,g,b) +def lighten_color(col, fac): + r = col[0] + (fac * (1.0 - col[0])) + g = col[1] + (fac * (1.0 - col[1])) + b = col[2] + (fac * (1.0 - col[2])) + return (r, g, b) + # Plot bar chart -fig = plt.figure(figsize=(3.7,2.32)) +fig = plt.figure(figsize=(3.7, 2.32)) ax = plt.axes([0.08, 0.14, 0.21, 0.80]) -ax.set_xscale('log') -ax.tick_params(axis='y', labelsize=8) -ax.tick_params(axis='x', labelsize=8) -ax.tick_params(axis='y', which='major', pad=3) -reu_to_rpu = 1.0/4.2 +ax.set_xscale("log") +ax.tick_params(axis="y", labelsize=8) +ax.tick_params(axis="x", labelsize=8) +ax.tick_params(axis="y", which="major", pad=3) +reu_to_rpu = 1.0 / 4.2 val = [2.5, 0.008, 0.012, 2.5] -val = [x*reu_to_rpu for x in val] -pos = arange(4)+.5 -barlist=ax.barh(pos,val,0.3, align='center', log=True) -barlist[0].set_color('black') -barlist[0].set_facecolor('black') -barlist[1].set_color('black') -barlist[1].set_facecolor('white') -barlist[2].set_color('black') -barlist[2].set_facecolor('white') -barlist[3].set_color('black') -barlist[3].set_facecolor('black') -ax.spines['top'].set_visible(False) -ax.spines['right'].set_visible(False) +val = [x * reu_to_rpu for x in val] +pos = arange(4) + 0.5 +barlist = ax.barh(pos, val, 0.3, align="center", log=True) +barlist[0].set_color("black") +barlist[0].set_facecolor("black") +barlist[1].set_color("black") +barlist[1].set_facecolor("white") +barlist[2].set_color("black") +barlist[2].set_facecolor("white") +barlist[3].set_color("black") +barlist[3].set_facecolor("black") +ax.spines["top"].set_visible(False) +ax.spines["right"].set_visible(False) ax.yaxis.tick_left() ax.xaxis.tick_bottom() -ax.set_xlim([0.005/4.2,10/4.2]) -ax.set_ylim([-0.1,3.9]) -plt.yticks(pos, ('+/+', '-/+', '+/-', '-/-')) -plt.xlabel('Output (RPU)', fontsize=8, labelpad=0) -plt.ylabel('Input', fontsize=8, labelpad=-1) +ax.set_xlim([0.005 / 4.2, 10 / 4.2]) +ax.set_ylim([-0.1, 3.9]) +plt.yticks(pos, ("+/+", "-/+", "+/-", "-/-")) +plt.xlabel("Output (RPU)", fontsize=8, labelpad=0) +plt.ylabel("Input", fontsize=8, labelpad=-1) plt.grid(False) # Colour map col_map = {} -col_map['black'] = (0.00, 0.00, 0.00) -col_map['white'] = (1.00, 1.00, 1.00) -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) +col_map["black"] = (0.00, 0.00, 0.00) +col_map["white"] = (1.00, 1.00, 1.00) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) # Global line width lw = 1.0 # Define the parts -g0_OFF = {'type':'CDS', 'name':'g0_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['black'], 'x_extent':24}} #output -g0_ON = {'type':'CDS', 'name':'g0_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'edge_color':col_map['black'], 'x_extent':24, 'label':'Out', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -g1_OFF = {'type':'CDS', 'name':'g1_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['red'], 'x_extent':24}} -g1_ON = {'type':'CDS', 'name':'g1_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['red'], 'edge_color':col_map['red'], 'x_extent':24, 'label':'D', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -g2_OFF = {'type':'CDS', 'name':'g2_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['blue'], 'x_extent':24}} -g2_ON = {'type':'CDS', 'name':'g2_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['blue'], 'edge_color':col_map['blue'], 'x_extent':24, 'label':'C', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -g3_OFF = {'type':'CDS', 'name':'g3_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['green'], 'x_extent':24}} -g3_ON = {'type':'CDS', 'name':'g3_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['green'], 'edge_color':col_map['green'], 'x_extent':24, 'label':'B', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -g4_OFF = {'type':'CDS', 'name':'g4_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['orange'], 'x_extent':24}} -g4_ON = {'type':'CDS', 'name':'g4_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['orange'], 'edge_color':col_map['orange'], 'x_extent':24, 'label':'A', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} - -pA = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'label':'p1', 'label_y_offset':-8}} -pB = {'type':'Promoter', 'name':'pB', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'label':'p2', 'label_y_offset':-8}} -p1 = {'type':'Promoter', 'name':'p3', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['red']}} -p2 = {'type':'Promoter', 'name':'p4', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['blue']}} -p3 = {'type':'Promoter', 'name':'p5', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['green']}} -p4_1 = {'type':'Promoter', 'name':'p6', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['orange']}} -p4_2 = {'type':'Promoter', 'name':'p6', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['orange']}} +g0_OFF = { + "type": "CDS", + "name": "g0_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["black"], + "x_extent": 24, + }, +} # output +g0_ON = { + "type": "CDS", + "name": "g0_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "edge_color": col_map["black"], + "x_extent": 24, + "label": "Out", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +g1_OFF = { + "type": "CDS", + "name": "g1_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["red"], + "x_extent": 24, + }, +} +g1_ON = { + "type": "CDS", + "name": "g1_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["red"], + "edge_color": col_map["red"], + "x_extent": 24, + "label": "D", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +g2_OFF = { + "type": "CDS", + "name": "g2_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["blue"], + "x_extent": 24, + }, +} +g2_ON = { + "type": "CDS", + "name": "g2_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["blue"], + "edge_color": col_map["blue"], + "x_extent": 24, + "label": "C", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +g3_OFF = { + "type": "CDS", + "name": "g3_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["green"], + "x_extent": 24, + }, +} +g3_ON = { + "type": "CDS", + "name": "g3_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["green"], + "edge_color": col_map["green"], + "x_extent": 24, + "label": "B", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +g4_OFF = { + "type": "CDS", + "name": "g4_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["orange"], + "x_extent": 24, + }, +} +g4_ON = { + "type": "CDS", + "name": "g4_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["orange"], + "edge_color": col_map["orange"], + "x_extent": 24, + "label": "A", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} + +pA = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "label": "p1", + "label_y_offset": -8, + }, +} +pB = { + "type": "Promoter", + "name": "pB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "label": "p2", + "label_y_offset": -8, + }, +} +p1 = { + "type": "Promoter", + "name": "p3", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["red"]}, +} +p2 = { + "type": "Promoter", + "name": "p4", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["blue"]}, +} +p3 = { + "type": "Promoter", + "name": "p5", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["green"]}, +} +p4_1 = { + "type": "Promoter", + "name": "p6", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["orange"]}, +} +p4_2 = { + "type": "Promoter", + "name": "p6", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["orange"]}, +} # How much to lighten OFF components off_fac = 0.7 -print('black', lighten_color(col_map['black'],off_fac)) -print('red', lighten_color(col_map['red'],off_fac)) -print('green', lighten_color(col_map['green'],off_fac)) -print('blue', lighten_color(col_map['blue'],off_fac)) -print('orange', lighten_color(col_map['orange'],off_fac)) - -pA_OFF = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['black'],off_fac)}} -pB_OFF = {'type':'Promoter', 'name':'pB', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['black'],off_fac)}} -p1_OFF = {'type':'Promoter', 'name':'p3', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['red'],off_fac)}} -p2_OFF = {'type':'Promoter', 'name':'p4', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['blue'],off_fac)}} -p3_OFF = {'type':'Promoter', 'name':'p5', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['green'],off_fac)}} -p4_1_OFF = {'type':'Promoter', 'name':'p6', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['orange'],off_fac)}} -p4_2_OFF = {'type':'Promoter', 'name':'p6', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['orange'],off_fac)}} - -t0 = {'type':'Terminator', 'name':'t0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t1 = {'type':'Terminator', 'name':'t1', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t2 = {'type':'Terminator', 'name':'t2', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t3 = {'type':'Terminator', 'name':'t3', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t4 = {'type':'Terminator', 'name':'t4', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} - -u0 = {'type':'RBS', 'name':'u0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -u1 = {'type':'RBS', 'name':'u1', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -u2 = {'type':'RBS', 'name':'u2', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -u3 = {'type':'RBS', 'name':'u3', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -u4 = {'type':'RBS', 'name':'u4', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} +print("black", lighten_color(col_map["black"], off_fac)) +print("red", lighten_color(col_map["red"], off_fac)) +print("green", lighten_color(col_map["green"], off_fac)) +print("blue", lighten_color(col_map["blue"], off_fac)) +print("orange", lighten_color(col_map["orange"], off_fac)) + +pA_OFF = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["black"], off_fac), + }, +} +pB_OFF = { + "type": "Promoter", + "name": "pB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["black"], off_fac), + }, +} +p1_OFF = { + "type": "Promoter", + "name": "p3", + "fwd": True, + "opts": {"linewidth": lw, "color": lighten_color(col_map["red"], off_fac)}, +} +p2_OFF = { + "type": "Promoter", + "name": "p4", + "fwd": True, + "opts": {"linewidth": lw, "color": lighten_color(col_map["blue"], off_fac)}, +} +p3_OFF = { + "type": "Promoter", + "name": "p5", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["green"], off_fac), + }, +} +p4_1_OFF = { + "type": "Promoter", + "name": "p6", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["orange"], off_fac), + }, +} +p4_2_OFF = { + "type": "Promoter", + "name": "p6", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["orange"], off_fac), + }, +} + +t0 = { + "type": "Terminator", + "name": "t0", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t1 = { + "type": "Terminator", + "name": "t1", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t2 = { + "type": "Terminator", + "name": "t2", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t3 = { + "type": "Terminator", + "name": "t3", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t4 = { + "type": "Terminator", + "name": "t4", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} + +u0 = { + "type": "RBS", + "name": "u0", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +u1 = { + "type": "RBS", + "name": "u1", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +u2 = { + "type": "RBS", + "name": "u2", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +u3 = { + "type": "RBS", + "name": "u3", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +u4 = { + "type": "RBS", + "name": "u4", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} # Define the regulation -arc1 = {'type':'Repression', 'from_part':g1_ON, 'to_part':p1_OFF, 'opts':{'color':col_map['red'], 'linewidth':lw}} -arc2 = {'type':'Repression', 'from_part':g2_ON, 'to_part':p2_OFF, 'opts':{'color':col_map['blue'], 'linewidth':lw}} -arc3 = {'type':'Repression', 'from_part':g3_ON, 'to_part':p3_OFF, 'opts':{'color':col_map['green'], 'linewidth':lw, 'arc_height':25}} -arc4 = {'type':'Repression', 'from_part':g4_ON, 'to_part':p4_1_OFF, 'opts':{'color':col_map['orange'], 'linewidth':lw, 'arc_height':20}} -arc5 = {'type':'Repression', 'from_part':g4_ON, 'to_part':p4_2_OFF, 'opts':{'color':col_map['orange'], 'linewidth':lw, 'arc_height':20}} +arc1 = { + "type": "Repression", + "from_part": g1_ON, + "to_part": p1_OFF, + "opts": {"color": col_map["red"], "linewidth": lw}, +} +arc2 = { + "type": "Repression", + "from_part": g2_ON, + "to_part": p2_OFF, + "opts": {"color": col_map["blue"], "linewidth": lw}, +} +arc3 = { + "type": "Repression", + "from_part": g3_ON, + "to_part": p3_OFF, + "opts": {"color": col_map["green"], "linewidth": lw, "arc_height": 25}, +} +arc4 = { + "type": "Repression", + "from_part": g4_ON, + "to_part": p4_1_OFF, + "opts": {"color": col_map["orange"], "linewidth": lw, "arc_height": 20}, +} +arc5 = { + "type": "Repression", + "from_part": g4_ON, + "to_part": p4_2_OFF, + "opts": {"color": col_map["orange"], "linewidth": lw, "arc_height": 20}, +} reg1 = [arc2, arc3] reg2 = [arc1, arc2, arc4, arc5] @@ -125,10 +446,110 @@ def lighten_color (col, fac): reg4 = [arc2, arc3, arc4, arc5] # A design is merely a list of parts and their properties -design1 = [pA_OFF, pB_OFF, u4, g4_OFF, t4, pB_OFF, p4_1, u3, g3_ON, t3, pA_OFF, p4_2, u2, g2_ON, t2, p3_OFF, p2_OFF, u1, g1_OFF, t1, p1, u0, g0_ON, t0] -design2 = [pA, pB_OFF, u4, g4_ON, t4, pB_OFF, p4_1_OFF, u3, g3_OFF, t3, pA, p4_2_OFF, u2, g2_ON, t2, p3, p2_OFF, u1, g1_ON, t1, p1_OFF, u0, g0_OFF, t0] -design3 = [pA_OFF, pB, u4, g4_ON, t4, pB, p4_1_OFF, u3, g3_ON, t3, pA_OFF, p4_2_OFF, u2, g2_OFF, t2, p3_OFF, p2, u1, g1_ON, t1, p1_OFF, u0, g0_OFF, t0] -design4 = [pA, pB, u4, g4_ON, t4, pB, p4_1_OFF, u3, g3_ON, t3, pA, p4_2_OFF, u2, g2_ON, t2, p3_OFF, p2_OFF, u1, g1_OFF, t1, p1, u0, g0_ON, t0] +design1 = [ + pA_OFF, + pB_OFF, + u4, + g4_OFF, + t4, + pB_OFF, + p4_1, + u3, + g3_ON, + t3, + pA_OFF, + p4_2, + u2, + g2_ON, + t2, + p3_OFF, + p2_OFF, + u1, + g1_OFF, + t1, + p1, + u0, + g0_ON, + t0, +] +design2 = [ + pA, + pB_OFF, + u4, + g4_ON, + t4, + pB_OFF, + p4_1_OFF, + u3, + g3_OFF, + t3, + pA, + p4_2_OFF, + u2, + g2_ON, + t2, + p3, + p2_OFF, + u1, + g1_ON, + t1, + p1_OFF, + u0, + g0_OFF, + t0, +] +design3 = [ + pA_OFF, + pB, + u4, + g4_ON, + t4, + pB, + p4_1_OFF, + u3, + g3_ON, + t3, + pA_OFF, + p4_2_OFF, + u2, + g2_OFF, + t2, + p3_OFF, + p2, + u1, + g1_ON, + t1, + p1_OFF, + u0, + g0_OFF, + t0, +] +design4 = [ + pA, + pB, + u4, + g4_ON, + t4, + pB, + p4_1_OFF, + u3, + g3_ON, + t3, + pA, + p4_2_OFF, + u2, + g2_ON, + t2, + p3_OFF, + p2_OFF, + u1, + g1_OFF, + t1, + p1, + u0, + g0_ON, + t0, +] # Set up the axes for the genetic constructs ax_dna1 = plt.axes([0.135, 0.75, 1, 0.2]) @@ -140,43 +561,62 @@ def lighten_color (col, fac): dr = dpl.DNARenderer() # Redender the DNA to axis -start, end = dr.renderDNA(ax_dna1, design1, dr.SBOL_part_renderers(), - regs=reg1, reg_renderers=dr.std_reg_renderers()) +start, end = dr.renderDNA( + ax_dna1, + design1, + dr.SBOL_part_renderers(), + regs=reg1, + reg_renderers=dr.std_reg_renderers(), +) ax_dna1.set_xlim([start, end]) -ax_dna1.set_ylim([-27,27]) -ax_dna1.set_aspect('equal') +ax_dna1.set_ylim([-27, 27]) +ax_dna1.set_aspect("equal") ax_dna1.set_xticks([]) ax_dna1.set_yticks([]) -ax_dna1.axis('off') -start, end = dr.renderDNA(ax_dna2, design2, dr.SBOL_part_renderers(), - regs=reg2, reg_renderers=dr.std_reg_renderers()) +ax_dna1.axis("off") +start, end = dr.renderDNA( + ax_dna2, + design2, + dr.SBOL_part_renderers(), + regs=reg2, + reg_renderers=dr.std_reg_renderers(), +) ax_dna2.set_xlim([start, end]) -ax_dna2.set_ylim([-27,27]) -ax_dna2.set_aspect('equal') +ax_dna2.set_ylim([-27, 27]) +ax_dna2.set_aspect("equal") ax_dna2.set_xticks([]) ax_dna2.set_yticks([]) -ax_dna2.axis('off') -start, end = dr.renderDNA(ax_dna3, design3, dr.SBOL_part_renderers(), - regs=reg3, reg_renderers=dr.std_reg_renderers()) +ax_dna2.axis("off") +start, end = dr.renderDNA( + ax_dna3, + design3, + dr.SBOL_part_renderers(), + regs=reg3, + reg_renderers=dr.std_reg_renderers(), +) ax_dna3.set_xlim([start, end]) -ax_dna3.set_ylim([-27,27]) -ax_dna3.set_aspect('equal') +ax_dna3.set_ylim([-27, 27]) +ax_dna3.set_aspect("equal") ax_dna3.set_xticks([]) ax_dna3.set_yticks([]) -ax_dna3.axis('off') -start, end = dr.renderDNA(ax_dna4, design4, dr.SBOL_part_renderers(), - regs=reg4, reg_renderers=dr.std_reg_renderers()) +ax_dna3.axis("off") +start, end = dr.renderDNA( + ax_dna4, + design4, + dr.SBOL_part_renderers(), + regs=reg4, + reg_renderers=dr.std_reg_renderers(), +) ax_dna4.set_xlim([start, end]) -ax_dna4.set_ylim([-27,27]) -ax_dna4.set_aspect('equal') +ax_dna4.set_ylim([-27, 27]) +ax_dna4.set_aspect("equal") ax_dna4.set_xticks([]) ax_dna4.set_yticks([]) -ax_dna4.axis('off') +ax_dna4.axis("off") # Save the figure -fig.savefig('xnor_truthtable.pdf', transparent=True) -fig.savefig('xnor_truthtable.png', dpi=300) +fig.savefig("xnor_truthtable.pdf", transparent=True) +fig.savefig("xnor_truthtable.png", dpi=300) # Clear the plotting cache -plt.close('all') - +plt.close("all") diff --git a/dnaplotlib/gallery/xnor_truthtable/xnor_truthtable.py b/dnaplotlib/gallery/xnor_truthtable/xnor_truthtable.py index 26daef5..02d298e 100644 --- a/dnaplotlib/gallery/xnor_truthtable/xnor_truthtable.py +++ b/dnaplotlib/gallery/xnor_truthtable/xnor_truthtable.py @@ -8,116 +8,437 @@ import matplotlib.pyplot as plt -__author__ = 'Bryan Der , Voigt Lab, MIT\n\ - Thomas Gorochowski , Voigt Lab, MIT' -__license__ = 'MIT' -__version__ = '1.0' +__author__ = "Bryan Der , Voigt Lab, MIT\n\ + Thomas Gorochowski , Voigt Lab, MIT" +__license__ = "MIT" +__version__ = "1.0" # Function to generate a ligher colour -def lighten_color (col, fac): - r = col[0] + (fac*(1.0-col[0])) - g = col[1] + (fac*(1.0-col[1])) - b = col[2] + (fac*(1.0-col[2])) - return (r,g,b) +def lighten_color(col, fac): + r = col[0] + (fac * (1.0 - col[0])) + g = col[1] + (fac * (1.0 - col[1])) + b = col[2] + (fac * (1.0 - col[2])) + return (r, g, b) + # Plot bar chart -fig = plt.figure(figsize=(3.7,2.32)) +fig = plt.figure(figsize=(3.7, 2.32)) ax = plt.axes([0.08, 0.14, 0.21, 0.80]) -ax.set_xscale('log') -ax.tick_params(axis='y', labelsize=8) -ax.tick_params(axis='x', labelsize=8) -ax.tick_params(axis='y', which='major', pad=3) -reu_to_rpu = 1.0/4.2 +ax.set_xscale("log") +ax.tick_params(axis="y", labelsize=8) +ax.tick_params(axis="x", labelsize=8) +ax.tick_params(axis="y", which="major", pad=3) +reu_to_rpu = 1.0 / 4.2 val = [2.5, 0.008, 0.012, 2.5] -val = [x*reu_to_rpu for x in val] -pos = arange(4)+.5 -barlist=ax.barh(pos,val,0.3, align='center', log=True) -barlist[0].set_color('black') -barlist[0].set_facecolor('black') -barlist[1].set_color('black') -barlist[1].set_facecolor('white') -barlist[2].set_color('black') -barlist[2].set_facecolor('white') -barlist[3].set_color('black') -barlist[3].set_facecolor('black') -ax.spines['top'].set_visible(False) -ax.spines['right'].set_visible(False) +val = [x * reu_to_rpu for x in val] +pos = arange(4) + 0.5 +barlist = ax.barh(pos, val, 0.3, align="center", log=True) +barlist[0].set_color("black") +barlist[0].set_facecolor("black") +barlist[1].set_color("black") +barlist[1].set_facecolor("white") +barlist[2].set_color("black") +barlist[2].set_facecolor("white") +barlist[3].set_color("black") +barlist[3].set_facecolor("black") +ax.spines["top"].set_visible(False) +ax.spines["right"].set_visible(False) ax.yaxis.tick_left() ax.xaxis.tick_bottom() -ax.set_xlim([0.005/4.2,10/4.2]) -ax.set_ylim([-0.1,3.9]) -plt.yticks(pos, ('+/+', '-/+', '+/-', '-/-')) -plt.xlabel('Output (RPU)', fontsize=8, labelpad=0) -plt.ylabel('Input', fontsize=8, labelpad=-1) +ax.set_xlim([0.005 / 4.2, 10 / 4.2]) +ax.set_ylim([-0.1, 3.9]) +plt.yticks(pos, ("+/+", "-/+", "+/-", "-/-")) +plt.xlabel("Output (RPU)", fontsize=8, labelpad=0) +plt.ylabel("Input", fontsize=8, labelpad=-1) plt.grid(False) # Colour map col_map = {} -col_map['black'] = (0.00, 0.00, 0.00) -col_map['white'] = (1.00, 1.00, 1.00) -col_map['red'] = (0.95, 0.30, 0.25) -col_map['green'] = (0.38, 0.82, 0.32) -col_map['blue'] = (0.38, 0.65, 0.87) -col_map['orange'] = (1.00, 0.75, 0.17) +col_map["black"] = (0.00, 0.00, 0.00) +col_map["white"] = (1.00, 1.00, 1.00) +col_map["red"] = (0.95, 0.30, 0.25) +col_map["green"] = (0.38, 0.82, 0.32) +col_map["blue"] = (0.38, 0.65, 0.87) +col_map["orange"] = (1.00, 0.75, 0.17) # Global line width lw = 1.0 # Define the parts -g0_OFF = {'type':'CDS', 'name':'g0_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['black'], 'x_extent':24}} #output -g0_ON = {'type':'CDS', 'name':'g0_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'edge_color':col_map['black'], 'x_extent':24, 'label':'Out', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -g1_OFF = {'type':'CDS', 'name':'g1_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['red'], 'x_extent':24}} -g1_ON = {'type':'CDS', 'name':'g1_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['red'], 'edge_color':col_map['red'], 'x_extent':24, 'label':'D', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -g2_OFF = {'type':'CDS', 'name':'g2_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['blue'], 'x_extent':24}} -g2_ON = {'type':'CDS', 'name':'g2_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['blue'], 'edge_color':col_map['blue'], 'x_extent':24, 'label':'C', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -g3_OFF = {'type':'CDS', 'name':'g3_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['green'], 'x_extent':24}} -g3_ON = {'type':'CDS', 'name':'g3_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['green'], 'edge_color':col_map['green'], 'x_extent':24, 'label':'B', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} -g4_OFF = {'type':'CDS', 'name':'g4_OFF', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['white'], 'edge_color':col_map['orange'], 'x_extent':24}} -g4_ON = {'type':'CDS', 'name':'g4_ON', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['orange'], 'edge_color':col_map['orange'], 'x_extent':24, 'label':'A', 'label_style':'italic', 'label_color':(1,1,1), 'label_x_offset':-3, 'label_y_offset':-1}} - -pA = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'label':'p1', 'label_y_offset':-8}} -pB = {'type':'Promoter', 'name':'pB', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'label':'p2', 'label_y_offset':-8}} -p1 = {'type':'Promoter', 'name':'p3', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['red']}} -p2 = {'type':'Promoter', 'name':'p4', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['blue']}} -p3 = {'type':'Promoter', 'name':'p5', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['green']}} -p4_1 = {'type':'Promoter', 'name':'p6', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['orange']}} -p4_2 = {'type':'Promoter', 'name':'p6', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['orange']}} +g0_OFF = { + "type": "CDS", + "name": "g0_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["black"], + "x_extent": 24, + }, +} # output +g0_ON = { + "type": "CDS", + "name": "g0_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "edge_color": col_map["black"], + "x_extent": 24, + "label": "Out", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +g1_OFF = { + "type": "CDS", + "name": "g1_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["red"], + "x_extent": 24, + }, +} +g1_ON = { + "type": "CDS", + "name": "g1_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["red"], + "edge_color": col_map["red"], + "x_extent": 24, + "label": "D", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +g2_OFF = { + "type": "CDS", + "name": "g2_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["blue"], + "x_extent": 24, + }, +} +g2_ON = { + "type": "CDS", + "name": "g2_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["blue"], + "edge_color": col_map["blue"], + "x_extent": 24, + "label": "C", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +g3_OFF = { + "type": "CDS", + "name": "g3_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["green"], + "x_extent": 24, + }, +} +g3_ON = { + "type": "CDS", + "name": "g3_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["green"], + "edge_color": col_map["green"], + "x_extent": 24, + "label": "B", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} +g4_OFF = { + "type": "CDS", + "name": "g4_OFF", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["white"], + "edge_color": col_map["orange"], + "x_extent": 24, + }, +} +g4_ON = { + "type": "CDS", + "name": "g4_ON", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["orange"], + "edge_color": col_map["orange"], + "x_extent": 24, + "label": "A", + "label_style": "italic", + "label_color": (1, 1, 1), + "label_x_offset": -3, + "label_y_offset": -1, + }, +} + +pA = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "label": "p1", + "label_y_offset": -8, + }, +} +pB = { + "type": "Promoter", + "name": "pB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "label": "p2", + "label_y_offset": -8, + }, +} +p1 = { + "type": "Promoter", + "name": "p3", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["red"]}, +} +p2 = { + "type": "Promoter", + "name": "p4", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["blue"]}, +} +p3 = { + "type": "Promoter", + "name": "p5", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["green"]}, +} +p4_1 = { + "type": "Promoter", + "name": "p6", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["orange"]}, +} +p4_2 = { + "type": "Promoter", + "name": "p6", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["orange"]}, +} # How much to lighten OFF components off_fac = 0.7 -print('black', lighten_color(col_map['black'],off_fac)) -print('red', lighten_color(col_map['red'],off_fac)) -print('green', lighten_color(col_map['green'],off_fac)) -print('blue', lighten_color(col_map['blue'],off_fac)) -print('orange', lighten_color(col_map['orange'],off_fac)) - -pA_OFF = {'type':'Promoter', 'name':'pA', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['black'],off_fac)}} -pB_OFF = {'type':'Promoter', 'name':'pB', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['black'],off_fac)}} -p1_OFF = {'type':'Promoter', 'name':'p3', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['red'],off_fac)}} -p2_OFF = {'type':'Promoter', 'name':'p4', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['blue'],off_fac)}} -p3_OFF = {'type':'Promoter', 'name':'p5', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['green'],off_fac)}} -p4_1_OFF = {'type':'Promoter', 'name':'p6', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['orange'],off_fac)}} -p4_2_OFF = {'type':'Promoter', 'name':'p6', 'fwd':True, 'opts':{'linewidth':lw, 'color':lighten_color(col_map['orange'],off_fac)}} - -t0 = {'type':'Terminator', 'name':'t0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t1 = {'type':'Terminator', 'name':'t1', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t2 = {'type':'Terminator', 'name':'t2', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t3 = {'type':'Terminator', 'name':'t3', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} -t4 = {'type':'Terminator', 'name':'t4', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-1}} - -u0 = {'type':'RBS', 'name':'u0', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -u1 = {'type':'RBS', 'name':'u1', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -u2 = {'type':'RBS', 'name':'u2', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -u3 = {'type':'RBS', 'name':'u3', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} -u4 = {'type':'RBS', 'name':'u4', 'fwd':True, 'opts':{'linewidth':lw, 'color':col_map['black'], 'start_pad':-6, 'x_extent':6}} +print("black", lighten_color(col_map["black"], off_fac)) +print("red", lighten_color(col_map["red"], off_fac)) +print("green", lighten_color(col_map["green"], off_fac)) +print("blue", lighten_color(col_map["blue"], off_fac)) +print("orange", lighten_color(col_map["orange"], off_fac)) + +pA_OFF = { + "type": "Promoter", + "name": "pA", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["black"], off_fac), + }, +} +pB_OFF = { + "type": "Promoter", + "name": "pB", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["black"], off_fac), + }, +} +p1_OFF = { + "type": "Promoter", + "name": "p3", + "fwd": True, + "opts": {"linewidth": lw, "color": lighten_color(col_map["red"], off_fac)}, +} +p2_OFF = { + "type": "Promoter", + "name": "p4", + "fwd": True, + "opts": {"linewidth": lw, "color": lighten_color(col_map["blue"], off_fac)}, +} +p3_OFF = { + "type": "Promoter", + "name": "p5", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["green"], off_fac), + }, +} +p4_1_OFF = { + "type": "Promoter", + "name": "p6", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["orange"], off_fac), + }, +} +p4_2_OFF = { + "type": "Promoter", + "name": "p6", + "fwd": True, + "opts": { + "linewidth": lw, + "color": lighten_color(col_map["orange"], off_fac), + }, +} + +t0 = { + "type": "Terminator", + "name": "t0", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t1 = { + "type": "Terminator", + "name": "t1", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t2 = { + "type": "Terminator", + "name": "t2", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t3 = { + "type": "Terminator", + "name": "t3", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} +t4 = { + "type": "Terminator", + "name": "t4", + "fwd": True, + "opts": {"linewidth": lw, "color": col_map["black"], "start_pad": -1}, +} + +u0 = { + "type": "RBS", + "name": "u0", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +u1 = { + "type": "RBS", + "name": "u1", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +u2 = { + "type": "RBS", + "name": "u2", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +u3 = { + "type": "RBS", + "name": "u3", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} +u4 = { + "type": "RBS", + "name": "u4", + "fwd": True, + "opts": { + "linewidth": lw, + "color": col_map["black"], + "start_pad": -6, + "x_extent": 6, + }, +} # Define the regulation -arc1 = {'type':'Repression', 'from_part':g1_ON, 'to_part':p1_OFF, 'opts':{'color':col_map['red'], 'linewidth':lw}} -arc2 = {'type':'Repression', 'from_part':g2_ON, 'to_part':p2_OFF, 'opts':{'color':col_map['blue'], 'linewidth':lw}} -arc3 = {'type':'Repression', 'from_part':g3_ON, 'to_part':p3_OFF, 'opts':{'color':col_map['green'], 'linewidth':lw, 'arc_height':25}} -arc4 = {'type':'Repression', 'from_part':g4_ON, 'to_part':p4_1_OFF, 'opts':{'color':col_map['orange'], 'linewidth':lw, 'arc_height':20}} -arc5 = {'type':'Repression', 'from_part':g4_ON, 'to_part':p4_2_OFF, 'opts':{'color':col_map['orange'], 'linewidth':lw, 'arc_height':20}} +arc1 = { + "type": "Repression", + "from_part": g1_ON, + "to_part": p1_OFF, + "opts": {"color": col_map["red"], "linewidth": lw}, +} +arc2 = { + "type": "Repression", + "from_part": g2_ON, + "to_part": p2_OFF, + "opts": {"color": col_map["blue"], "linewidth": lw}, +} +arc3 = { + "type": "Repression", + "from_part": g3_ON, + "to_part": p3_OFF, + "opts": {"color": col_map["green"], "linewidth": lw, "arc_height": 25}, +} +arc4 = { + "type": "Repression", + "from_part": g4_ON, + "to_part": p4_1_OFF, + "opts": {"color": col_map["orange"], "linewidth": lw, "arc_height": 20}, +} +arc5 = { + "type": "Repression", + "from_part": g4_ON, + "to_part": p4_2_OFF, + "opts": {"color": col_map["orange"], "linewidth": lw, "arc_height": 20}, +} reg1 = [arc2, arc3] reg2 = [arc1, arc2, arc4, arc5] @@ -125,10 +446,110 @@ def lighten_color (col, fac): reg4 = [arc2, arc3, arc4, arc5] # A design is merely a list of parts and their properties -design1 = [pA_OFF, pB_OFF, u4, g4_OFF, t4, pB_OFF, p4_1, u3, g3_ON, t3, pA_OFF, p4_2, u2, g2_ON, t2, p3_OFF, p2_OFF, u1, g1_OFF, t1, p1, u0, g0_ON, t0] -design2 = [pA, pB_OFF, u4, g4_ON, t4, pB_OFF, p4_1_OFF, u3, g3_OFF, t3, pA, p4_2_OFF, u2, g2_ON, t2, p3, p2_OFF, u1, g1_ON, t1, p1_OFF, u0, g0_OFF, t0] -design3 = [pA_OFF, pB, u4, g4_ON, t4, pB, p4_1_OFF, u3, g3_ON, t3, pA_OFF, p4_2_OFF, u2, g2_OFF, t2, p3_OFF, p2, u1, g1_ON, t1, p1_OFF, u0, g0_OFF, t0] -design4 = [pA, pB, u4, g4_ON, t4, pB, p4_1_OFF, u3, g3_ON, t3, pA, p4_2_OFF, u2, g2_ON, t2, p3_OFF, p2_OFF, u1, g1_OFF, t1, p1, u0, g0_ON, t0] +design1 = [ + pA_OFF, + pB_OFF, + u4, + g4_OFF, + t4, + pB_OFF, + p4_1, + u3, + g3_ON, + t3, + pA_OFF, + p4_2, + u2, + g2_ON, + t2, + p3_OFF, + p2_OFF, + u1, + g1_OFF, + t1, + p1, + u0, + g0_ON, + t0, +] +design2 = [ + pA, + pB_OFF, + u4, + g4_ON, + t4, + pB_OFF, + p4_1_OFF, + u3, + g3_OFF, + t3, + pA, + p4_2_OFF, + u2, + g2_ON, + t2, + p3, + p2_OFF, + u1, + g1_ON, + t1, + p1_OFF, + u0, + g0_OFF, + t0, +] +design3 = [ + pA_OFF, + pB, + u4, + g4_ON, + t4, + pB, + p4_1_OFF, + u3, + g3_ON, + t3, + pA_OFF, + p4_2_OFF, + u2, + g2_OFF, + t2, + p3_OFF, + p2, + u1, + g1_ON, + t1, + p1_OFF, + u0, + g0_OFF, + t0, +] +design4 = [ + pA, + pB, + u4, + g4_ON, + t4, + pB, + p4_1_OFF, + u3, + g3_ON, + t3, + pA, + p4_2_OFF, + u2, + g2_ON, + t2, + p3_OFF, + p2_OFF, + u1, + g1_OFF, + t1, + p1, + u0, + g0_ON, + t0, +] # Set up the axes for the genetic constructs ax_dna1 = plt.axes([0.135, 0.75, 1, 0.2]) @@ -140,43 +561,62 @@ def lighten_color (col, fac): dr = dpl.DNARenderer() # Redender the DNA to axis -start, end = dr.renderDNA(ax_dna1, design1, dr.SBOL_part_renderers(), - regs=reg1, reg_renderers=dr.std_reg_renderers()) +start, end = dr.renderDNA( + ax_dna1, + design1, + dr.SBOL_part_renderers(), + regs=reg1, + reg_renderers=dr.std_reg_renderers(), +) ax_dna1.set_xlim([start, end]) -ax_dna1.set_ylim([-27,27]) -ax_dna1.set_aspect('equal') +ax_dna1.set_ylim([-27, 27]) +ax_dna1.set_aspect("equal") ax_dna1.set_xticks([]) ax_dna1.set_yticks([]) -ax_dna1.axis('off') -start, end = dr.renderDNA(ax_dna2, design2, dr.SBOL_part_renderers(), - regs=reg2, reg_renderers=dr.std_reg_renderers()) +ax_dna1.axis("off") +start, end = dr.renderDNA( + ax_dna2, + design2, + dr.SBOL_part_renderers(), + regs=reg2, + reg_renderers=dr.std_reg_renderers(), +) ax_dna2.set_xlim([start, end]) -ax_dna2.set_ylim([-27,27]) -ax_dna2.set_aspect('equal') +ax_dna2.set_ylim([-27, 27]) +ax_dna2.set_aspect("equal") ax_dna2.set_xticks([]) ax_dna2.set_yticks([]) -ax_dna2.axis('off') -start, end = dr.renderDNA(ax_dna3, design3, dr.SBOL_part_renderers(), - regs=reg3, reg_renderers=dr.std_reg_renderers()) +ax_dna2.axis("off") +start, end = dr.renderDNA( + ax_dna3, + design3, + dr.SBOL_part_renderers(), + regs=reg3, + reg_renderers=dr.std_reg_renderers(), +) ax_dna3.set_xlim([start, end]) -ax_dna3.set_ylim([-27,27]) -ax_dna3.set_aspect('equal') +ax_dna3.set_ylim([-27, 27]) +ax_dna3.set_aspect("equal") ax_dna3.set_xticks([]) ax_dna3.set_yticks([]) -ax_dna3.axis('off') -start, end = dr.renderDNA(ax_dna4, design4, dr.SBOL_part_renderers(), - regs=reg4, reg_renderers=dr.std_reg_renderers()) +ax_dna3.axis("off") +start, end = dr.renderDNA( + ax_dna4, + design4, + dr.SBOL_part_renderers(), + regs=reg4, + reg_renderers=dr.std_reg_renderers(), +) ax_dna4.set_xlim([start, end]) -ax_dna4.set_ylim([-27,27]) -ax_dna4.set_aspect('equal') +ax_dna4.set_ylim([-27, 27]) +ax_dna4.set_aspect("equal") ax_dna4.set_xticks([]) ax_dna4.set_yticks([]) -ax_dna4.axis('off') +ax_dna4.axis("off") # Save the figure -fig.savefig('xnor_truthtable.pdf', transparent=True) -fig.savefig('xnor_truthtable.png', dpi=300) +fig.savefig("xnor_truthtable.pdf", transparent=True) +fig.savefig("xnor_truthtable.png", dpi=300) # Clear the plotting cache -plt.close('all') - +plt.close("all") diff --git a/dnaplotlib/other/hatch_line_width/backend_pdf 2.py b/dnaplotlib/other/hatch_line_width/backend_pdf 2.py index 19318c6..86202e0 100644 --- a/dnaplotlib/other/hatch_line_width/backend_pdf 2.py +++ b/dnaplotlib/other/hatch_line_width/backend_pdf 2.py @@ -4,8 +4,12 @@ A PDF matplotlib backend Author: Jouni K Sepp�nen """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) import six from six.moves import map @@ -24,6 +28,7 @@ from datetime import datetime from math import ceil, cos, floor, pi, sin + try: set except NameError: @@ -32,19 +37,34 @@ import matplotlib from matplotlib import __version__, rcParams from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ - FigureManagerBase, FigureCanvasBase +from matplotlib.backend_bases import ( + RendererBase, + GraphicsContextBase, + FigureManagerBase, + FigureCanvasBase, +) from matplotlib.backends.backend_mixed import MixedModeRenderer -from matplotlib.cbook import Bunch, is_string_like, \ - get_realpath_and_stat, is_writable_file_like, maxdict +from matplotlib.cbook import ( + Bunch, + is_string_like, + get_realpath_and_stat, + is_writable_file_like, + maxdict, +) from matplotlib.mlab import quad2cubic from matplotlib.figure import Figure from matplotlib.font_manager import findfont, is_opentype_cff_font from matplotlib.afm import AFM import matplotlib.type1font as type1font import matplotlib.dviread as dviread -from matplotlib.ft2font import FT2Font, FIXED_WIDTH, ITALIC, LOAD_NO_SCALE, \ - LOAD_NO_HINTING, KERNING_UNFITTED +from matplotlib.ft2font import ( + FT2Font, + FIXED_WIDTH, + ITALIC, + LOAD_NO_SCALE, + LOAD_NO_HINTING, + KERNING_UNFITTED, +) from matplotlib.mathtext import MathTextParser from matplotlib.transforms import Affine2D, BboxBase from matplotlib.path import Path @@ -112,11 +132,12 @@ def fill(strings, linelen=75): if currpos + length < linelen: currpos += length + 1 else: - result.append(b' '.join(strings[lasti:i])) + result.append(b" ".join(strings[lasti:i])) lasti = i currpos = length - result.append(b' '.join(strings[lasti:])) - return b'\n'.join(result) + result.append(b" ".join(strings[lasti:])) + return b"\n".join(result) + # PDF strings are supposed to be able to include any eight-bit data, # except that unbalanced parens and backslashes must be escaped by a @@ -124,17 +145,17 @@ def fill(strings, linelen=75): # character may get read as a newline; these characters correspond to # \gamma and \Omega in TeX's math font encoding. Escaping them fixes # the bug. -_string_escape_regex = re.compile(br'([\\()\r\n])') +_string_escape_regex = re.compile(br"([\\()\r\n])") def _string_escape(match): m = match.group(0) - if m in br'\()': - return b'\\' + m - elif m == b'\n': - return br'\n' - elif m == b'\r': - return br'\r' + if m in br"\()": + return b"\\" + m + elif m == b"\n": + return br"\n" + elif m == b"\r": + return br"\r" assert False @@ -142,7 +163,7 @@ def pdfRepr(obj): """Map Python objects to PDF syntax.""" # Some objects defined later have their own pdfRepr method. - if hasattr(obj, 'pdfRepr'): + if hasattr(obj, "pdfRepr"): return obj.pdfRepr() # Floats. PDF does not have exponential notation (1.0e-10) so we @@ -151,26 +172,26 @@ def pdfRepr(obj): elif isinstance(obj, (float, np.floating)): if not np.isfinite(obj): raise ValueError("Can only output finite numbers in PDF") - r = ("%.10f" % obj).encode('ascii') - return r.rstrip(b'0').rstrip(b'.') + r = ("%.10f" % obj).encode("ascii") + return r.rstrip(b"0").rstrip(b".") # Booleans. Needs to be tested before integers since # isinstance(True, int) is true. elif isinstance(obj, bool): - return [b'false', b'true'][obj] + return [b"false", b"true"][obj] # Integers are written as such. elif isinstance(obj, (six.integer_types, np.integer)): - return ("%d" % obj).encode('ascii') + return ("%d" % obj).encode("ascii") # Unicode strings are encoded in UTF-16BE with byte-order mark. elif isinstance(obj, six.text_type): try: # But maybe it's really ASCII? - s = obj.encode('ASCII') + s = obj.encode("ASCII") return pdfRepr(s) except UnicodeEncodeError: - s = codecs.BOM_UTF16_BE + obj.encode('UTF-16BE') + s = codecs.BOM_UTF16_BE + obj.encode("UTF-16BE") return pdfRepr(s) # Strings are written in parentheses, with backslashes and parens @@ -178,7 +199,7 @@ def pdfRepr(obj): # simpler to escape them all. TODO: cut long strings into lines; # I believe there is some maximum line length in PDF. elif isinstance(obj, bytes): - return b'(' + _string_escape_regex.sub(_string_escape, obj) + b')' + return b"(" + _string_escape_regex.sub(_string_escape, obj) + b")" # Dictionaries. The keys must be PDF names, so if we find strings # there, we make Name objects from them. The values may be @@ -186,8 +207,12 @@ def pdfRepr(obj): # represented as Name objects. elif isinstance(obj, dict): r = [b"<<"] - r.extend([Name(key).pdfRepr() + b" " + pdfRepr(val) - for key, val in six.iteritems(obj)]) + r.extend( + [ + Name(key).pdfRepr() + b" " + pdfRepr(val) + for key, val in six.iteritems(obj) + ] + ) r.append(b">>") return fill(r) @@ -200,17 +225,17 @@ def pdfRepr(obj): # The null keyword. elif obj is None: - return b'null' + return b"null" # A date. elif isinstance(obj, datetime): - r = obj.strftime('D:%Y%m%d%H%M%S') + r = obj.strftime("D:%Y%m%d%H%M%S") if time.daylight: z = time.altzone else: z = time.timezone if z == 0: - r += 'Z' + r += "Z" elif z < 0: r += "+%02d'%02d'" % ((-z) // 3600, (-z) % 3600) else: @@ -238,70 +263,102 @@ def __repr__(self): return "" % self.id def pdfRepr(self): - return ("%d 0 R" % self.id).encode('ascii') + return ("%d 0 R" % self.id).encode("ascii") def write(self, contents, file): write = file.write - write(("%d 0 obj\n" % self.id).encode('ascii')) + write(("%d 0 obj\n" % self.id).encode("ascii")) write(pdfRepr(contents)) write(b"\nendobj\n") class Name(object): """PDF name object.""" - __slots__ = ('name',) - _regex = re.compile(r'[^!-~]') + + __slots__ = ("name",) + _regex = re.compile(r"[^!-~]") def __init__(self, name): if isinstance(name, Name): self.name = name.name else: if isinstance(name, bytes): - name = name.decode('ascii') - self.name = self._regex.sub(Name.hexify, name).encode('ascii') + name = name.decode("ascii") + self.name = self._regex.sub(Name.hexify, name).encode("ascii") def __repr__(self): return "" % self.name def __str__(self): - return '/' + six.text_type(self.name) + return "/" + six.text_type(self.name) @staticmethod def hexify(match): - return '#%02x' % ord(match.group()) + return "#%02x" % ord(match.group()) def pdfRepr(self): - return b'/' + self.name + return b"/" + self.name class Operator(object): """PDF operator object.""" - __slots__ = ('op',) + + __slots__ = ("op",) def __init__(self, op): self.op = op def __repr__(self): - return '' % self.op + return "" % self.op def pdfRepr(self): return self.op + # PDF operators (not an exhaustive list) _pdfops = dict( - close_fill_stroke=b'b', fill_stroke=b'B', fill=b'f', closepath=b'h', - close_stroke=b's', stroke=b'S', endpath=b'n', begin_text=b'BT', - end_text=b'ET', curveto=b'c', rectangle=b're', lineto=b'l', moveto=b'm', - concat_matrix=b'cm', use_xobject=b'Do', setgray_stroke=b'G', - setgray_nonstroke=b'g', setrgb_stroke=b'RG', setrgb_nonstroke=b'rg', - setcolorspace_stroke=b'CS', setcolorspace_nonstroke=b'cs', - setcolor_stroke=b'SCN', setcolor_nonstroke=b'scn', setdash=b'd', - setlinejoin=b'j', setlinecap=b'J', setgstate=b'gs', gsave=b'q', - grestore=b'Q', textpos=b'Td', selectfont=b'Tf', textmatrix=b'Tm', - show=b'Tj', showkern=b'TJ', setlinewidth=b'w', clip=b'W', shading=b'sh') - -Op = Bunch(**dict([(name, Operator(value)) - for name, value in six.iteritems(_pdfops)])) + close_fill_stroke=b"b", + fill_stroke=b"B", + fill=b"f", + closepath=b"h", + close_stroke=b"s", + stroke=b"S", + endpath=b"n", + begin_text=b"BT", + end_text=b"ET", + curveto=b"c", + rectangle=b"re", + lineto=b"l", + moveto=b"m", + concat_matrix=b"cm", + use_xobject=b"Do", + setgray_stroke=b"G", + setgray_nonstroke=b"g", + setrgb_stroke=b"RG", + setrgb_nonstroke=b"rg", + setcolorspace_stroke=b"CS", + setcolorspace_nonstroke=b"cs", + setcolor_stroke=b"SCN", + setcolor_nonstroke=b"scn", + setdash=b"d", + setlinejoin=b"j", + setlinecap=b"J", + setgstate=b"gs", + gsave=b"q", + grestore=b"Q", + textpos=b"Td", + selectfont=b"Tf", + textmatrix=b"Tm", + show=b"Tj", + showkern=b"TJ", + setlinewidth=b"w", + clip=b"W", + shading=b"sh", +) + +Op = Bunch( + **dict([(name, Operator(value)) for name, value in six.iteritems(_pdfops)]) +) def _paint_path(closep, fillp, strokep): @@ -325,6 +382,8 @@ def _paint_path(closep, fillp, strokep): return Op.fill else: return Op.endpath + + Op.paint_path = _paint_path @@ -334,17 +393,18 @@ class Stream(object): This has no pdfRepr method. Instead, call begin(), then output the contents of the stream by calling write(), and finally call end(). """ - __slots__ = ('id', 'len', 'pdfFile', 'file', 'compressobj', 'extra', 'pos') + + __slots__ = ("id", "len", "pdfFile", "file", "compressobj", "extra", "pos") def __init__(self, id, len, file, extra=None): """id: object id of stream; len: an unused Reference object for the length of the stream, or None (to use a memory buffer); file: a PdfFile; extra: a dictionary of extra key-value pairs to - include in the stream header """ - self.id = id # object id - self.len = len # id of length object + include in the stream header""" + self.id = id # object id + self.len = len # id of length object self.pdfFile = file - self.file = file.fh # file to which the stream is written + self.file = file.fh # file to which the stream is written self.compressobj = None # compression object if extra is None: self.extra = dict() @@ -352,8 +412,8 @@ def __init__(self, id, len, file, extra=None): self.extra = extra self.pdfFile.recordXref(self.id) - if rcParams['pdf.compression']: - self.compressobj = zlib.compressobj(rcParams['pdf.compression']) + if rcParams["pdf.compression"]: + self.compressobj = zlib.compressobj(rcParams["pdf.compression"]) if self.len is None: self.file = BytesIO() else: @@ -362,11 +422,11 @@ def __init__(self, id, len, file, extra=None): def _writeHeader(self): write = self.file.write - write(("%d 0 obj\n" % self.id).encode('ascii')) + write(("%d 0 obj\n" % self.id).encode("ascii")) dict = self.extra - dict['Length'] = self.len - if rcParams['pdf.compression']: - dict['Filter'] = Name('FlateDecode') + dict["Length"] = self.len + if rcParams["pdf.compression"]: + dict["Filter"] = Name("FlateDecode") write(pdfRepr(dict)) write(b"\nstream\n") @@ -409,13 +469,13 @@ class PdfFile(object): """PDF file object.""" def __init__(self, filename): - self.nextObject = 1 # next free object id - self.xrefTable = [[0, 65535, 'the zero object']] + self.nextObject = 1 # next free object id + self.xrefTable = [[0, 65535, "the zero object"]] self.passed_in_file_object = False self.original_file_like = None self.tell_base = 0 if is_string_like(filename): - fh = open(filename, 'wb') + fh = open(filename, "wb") elif is_writable_file_like(filename): try: self.tell_base = filename.tell() @@ -429,44 +489,44 @@ def __init__(self, filename): raise ValueError("filename must be a path or a file-like object") self._core14fontdir = os.path.join( - rcParams['datapath'], 'fonts', 'pdfcorefonts') + rcParams["datapath"], "fonts", "pdfcorefonts" + ) self.fh = fh self.currentstream = None # stream object to write to, if any - fh.write(b"%PDF-1.4\n") # 1.4 is the first version to have alpha + fh.write(b"%PDF-1.4\n") # 1.4 is the first version to have alpha # Output some eight-bit chars as a comment so various utilities # recognize the file as binary by looking at the first few # lines (see note in section 3.4.1 of the PDF reference). fh.write(b"%\254\334 \253\272\n") - self.rootObject = self.reserveObject('root') - self.pagesObject = self.reserveObject('pages') + self.rootObject = self.reserveObject("root") + self.pagesObject = self.reserveObject("pages") self.pageList = [] - self.fontObject = self.reserveObject('fonts') - self.alphaStateObject = self.reserveObject('extended graphics states') - self.hatchObject = self.reserveObject('tiling patterns') - self.gouraudObject = self.reserveObject('Gouraud triangles') - self.XObjectObject = self.reserveObject('external objects') - self.resourceObject = self.reserveObject('resources') - - root = {'Type': Name('Catalog'), - 'Pages': self.pagesObject} + self.fontObject = self.reserveObject("fonts") + self.alphaStateObject = self.reserveObject("extended graphics states") + self.hatchObject = self.reserveObject("tiling patterns") + self.gouraudObject = self.reserveObject("Gouraud triangles") + self.XObjectObject = self.reserveObject("external objects") + self.resourceObject = self.reserveObject("resources") + + root = {"Type": Name("Catalog"), "Pages": self.pagesObject} self.writeObject(self.rootObject, root) - revision = '' + revision = "" self.infoDict = { - 'Creator': 'matplotlib %s, http://matplotlib.org' % __version__, - 'Producer': 'matplotlib pdf backend%s' % revision, - 'CreationDate': datetime.today() - } - - self.fontNames = {} # maps filenames to internal font names - self.nextFont = 1 # next free internal font name - self.dviFontInfo = {} # information on dvi fonts + "Creator": "matplotlib %s, http://matplotlib.org" % __version__, + "Producer": "matplotlib pdf backend%s" % revision, + "CreationDate": datetime.today(), + } + + self.fontNames = {} # maps filenames to internal font names + self.nextFont = 1 # next free internal font name + self.dviFontInfo = {} # information on dvi fonts self.type1Descriptors = {} # differently encoded Type-1 fonts may - # share the same descriptor + # share the same descriptor self.used_characters = {} - self.alphaStates = {} # maps alpha values to graphics state objects + self.alphaStates = {} # maps alpha values to graphics state objects self.nextAlphaState = 1 self.hatchPatterns = {} self.nextHatch = 1 @@ -481,51 +541,59 @@ def __init__(self, filename): self.paths = [] # The PDF spec recommends to include every procset - procsets = [Name(x) - for x in "PDF Text ImageB ImageC ImageI".split()] + procsets = [Name(x) for x in "PDF Text ImageB ImageC ImageI".split()] # Write resource dictionary. # Possibly TODO: more general ExtGState (graphics state dictionaries) # ColorSpace Pattern Shading Properties - resources = {'Font': self.fontObject, - 'XObject': self.XObjectObject, - 'ExtGState': self.alphaStateObject, - 'Pattern': self.hatchObject, - 'Shading': self.gouraudObject, - 'ProcSet': procsets} + resources = { + "Font": self.fontObject, + "XObject": self.XObjectObject, + "ExtGState": self.alphaStateObject, + "Pattern": self.hatchObject, + "Shading": self.gouraudObject, + "ProcSet": procsets, + } self.writeObject(self.resourceObject, resources) def newPage(self, width, height): self.endStream() self.width, self.height = width, height - contentObject = self.reserveObject('page contents') - thePage = {'Type': Name('Page'), - 'Parent': self.pagesObject, - 'Resources': self.resourceObject, - 'MediaBox': [0, 0, 72 * width, 72 * height], - 'Contents': contentObject, - 'Group': {'Type': Name('Group'), - 'S': Name('Transparency'), - 'CS': Name('DeviceRGB')} - } - pageObject = self.reserveObject('page') + contentObject = self.reserveObject("page contents") + thePage = { + "Type": Name("Page"), + "Parent": self.pagesObject, + "Resources": self.resourceObject, + "MediaBox": [0, 0, 72 * width, 72 * height], + "Contents": contentObject, + "Group": { + "Type": Name("Group"), + "S": Name("Transparency"), + "CS": Name("DeviceRGB"), + }, + } + pageObject = self.reserveObject("page") self.writeObject(pageObject, thePage) self.pageList.append(pageObject) - self.beginStream(contentObject.id, - self.reserveObject('length of content stream')) + self.beginStream( + contentObject.id, self.reserveObject("length of content stream") + ) # Initialize the pdf graphics state to match the default mpl # graphics context: currently only the join style needs to be set - self.output(GraphicsContextPdf.joinstyles['round'], Op.setlinejoin) + self.output(GraphicsContextPdf.joinstyles["round"], Op.setlinejoin) def close(self): self.endStream() # Write out the various deferred objects self.writeFonts() - self.writeObject(self.alphaStateObject, - dict([(val[0], val[1]) - for val in six.itervalues(self.alphaStates)])) + self.writeObject( + self.alphaStateObject, + dict( + [(val[0], val[1]) for val in six.itervalues(self.alphaStates)] + ), + ) self.writeHatches() self.writeGouraudTriangles() xobjects = dict(six.itervalues(self.images)) @@ -533,17 +601,30 @@ def close(self): xobjects[tup[0]] = tup[1] for name, value in six.iteritems(self.multi_byte_charprocs): xobjects[name] = value - for name, path, trans, ob, join, cap, padding, filled, stroked \ - in self.paths: + for ( + name, + path, + trans, + ob, + join, + cap, + padding, + filled, + stroked, + ) in self.paths: xobjects[name] = ob self.writeObject(self.XObjectObject, xobjects) self.writeImages() self.writeMarkers() self.writePathCollectionTemplates() - self.writeObject(self.pagesObject, - {'Type': Name('Pages'), - 'Kids': self.pageList, - 'Count': len(self.pageList)}) + self.writeObject( + self.pagesObject, + { + "Type": Name("Pages"), + "Kids": self.pageList, + "Count": len(self.pageList), + }, + ) self.writeInfoDict() # Finalize the file @@ -565,7 +646,7 @@ def write(self, data): def output(self, *data): self.write(fill(list(map(pdfRepr, data)))) - self.write(b'\n') + self.write(b"\n") def beginStream(self, id, len, extra=None): assert self.currentstream is None @@ -585,43 +666,46 @@ def fontName(self, fontprop): if is_string_like(fontprop): filename = fontprop - elif rcParams['pdf.use14corefonts']: + elif rcParams["pdf.use14corefonts"]: filename = findfont( - fontprop, fontext='afm', directory=self._core14fontdir) + fontprop, fontext="afm", directory=self._core14fontdir + ) if filename is None: filename = findfont( - "Helvetica", fontext='afm', directory=self._core14fontdir) + "Helvetica", fontext="afm", directory=self._core14fontdir + ) else: filename = findfont(fontprop) Fx = self.fontNames.get(filename) if Fx is None: - Fx = Name('F%d' % self.nextFont) + Fx = Name("F%d" % self.nextFont) self.fontNames[filename] = Fx self.nextFont += 1 matplotlib.verbose.report( - 'Assigning font %s = %r' % (Fx, filename), - 'debug') + "Assigning font %s = %r" % (Fx, filename), "debug" + ) return Fx def writeFonts(self): fonts = {} for filename, Fx in six.iteritems(self.fontNames): - matplotlib.verbose.report('Embedding font %s' % filename, 'debug') - if filename.endswith('.afm'): + matplotlib.verbose.report("Embedding font %s" % filename, "debug") + if filename.endswith(".afm"): # from pdf.use14corefonts - matplotlib.verbose.report('Writing AFM font', 'debug') + matplotlib.verbose.report("Writing AFM font", "debug") fonts[Fx] = self._write_afm_font(filename) elif filename in self.dviFontInfo: # a Type 1 font from a dvi file; # the filename is really the TeX name - matplotlib.verbose.report('Writing Type-1 font', 'debug') - fonts[Fx] = self.embedTeXFont(filename, - self.dviFontInfo[filename]) + matplotlib.verbose.report("Writing Type-1 font", "debug") + fonts[Fx] = self.embedTeXFont( + filename, self.dviFontInfo[filename] + ) else: # a normal TrueType font - matplotlib.verbose.report('Writing TrueType font', 'debug') + matplotlib.verbose.report("Writing TrueType font", "debug") realpath, stat_key = get_realpath_and_stat(filename) chars = self.used_characters.get(stat_key) if chars is not None and len(chars[1]): @@ -629,54 +713,63 @@ def writeFonts(self): self.writeObject(self.fontObject, fonts) def _write_afm_font(self, filename): - with open(filename, 'rb') as fh: + with open(filename, "rb") as fh: font = AFM(fh) fontname = font.get_fontname() - fontdict = {'Type': Name('Font'), - 'Subtype': Name('Type1'), - 'BaseFont': Name(fontname), - 'Encoding': Name('WinAnsiEncoding')} - fontdictObject = self.reserveObject('font dictionary') + fontdict = { + "Type": Name("Font"), + "Subtype": Name("Type1"), + "BaseFont": Name(fontname), + "Encoding": Name("WinAnsiEncoding"), + } + fontdictObject = self.reserveObject("font dictionary") self.writeObject(fontdictObject, fontdict) return fontdictObject def embedTeXFont(self, texname, fontinfo): - msg = ('Embedding TeX font ' + texname + ' - fontinfo=' + - repr(fontinfo.__dict__)) - matplotlib.verbose.report(msg, 'debug') + msg = ( + "Embedding TeX font " + + texname + + " - fontinfo=" + + repr(fontinfo.__dict__) + ) + matplotlib.verbose.report(msg, "debug") # Widths - widthsObject = self.reserveObject('font widths') + widthsObject = self.reserveObject("font widths") self.writeObject(widthsObject, fontinfo.dvifont.widths) # Font dictionary - fontdictObject = self.reserveObject('font dictionary') + fontdictObject = self.reserveObject("font dictionary") fontdict = { - 'Type': Name('Font'), - 'Subtype': Name('Type1'), - 'FirstChar': 0, - 'LastChar': len(fontinfo.dvifont.widths) - 1, - 'Widths': widthsObject, - } + "Type": Name("Font"), + "Subtype": Name("Type1"), + "FirstChar": 0, + "LastChar": len(fontinfo.dvifont.widths) - 1, + "Widths": widthsObject, + } # Encoding (if needed) if fontinfo.encodingfile is not None: enc = dviread.Encoding(fontinfo.encodingfile) differencesArray = [Name(ch) for ch in enc] differencesArray = [0] + differencesArray - fontdict['Encoding'] = \ - {'Type': Name('Encoding'), - 'Differences': differencesArray} + fontdict["Encoding"] = { + "Type": Name("Encoding"), + "Differences": differencesArray, + } # If no file is specified, stop short if fontinfo.fontfile is None: - msg = ('Because of TeX configuration (pdftex.map, see updmap ' - 'option pdftexDownloadBase14) the font {0} is not ' - 'embedded. This is deprecated as of PDF 1.5 and it may ' - 'cause the consumer application to show something that ' - 'was not intended.').format(fontinfo.basefont) + msg = ( + "Because of TeX configuration (pdftex.map, see updmap " + "option pdftexDownloadBase14) the font {0} is not " + "embedded. This is deprecated as of PDF 1.5 and it may " + "cause the consumer application to show something that " + "was not intended." + ).format(fontinfo.basefont) warnings.warn(msg) - fontdict['BaseFont'] = Name(fontinfo.basefont) + fontdict["BaseFont"] = Name(fontinfo.basefont) self.writeObject(fontdictObject, fontdict) return fontdictObject @@ -684,18 +777,20 @@ def embedTeXFont(self, texname, fontinfo): t1font = type1font.Type1Font(fontinfo.fontfile) if fontinfo.effects: t1font = t1font.transform(fontinfo.effects) - fontdict['BaseFont'] = Name(t1font.prop['FontName']) + fontdict["BaseFont"] = Name(t1font.prop["FontName"]) # Font descriptors may be shared between differently encoded # Type-1 fonts, so only create a new descriptor if there is no # existing descriptor for this font. - effects = (fontinfo.effects.get('slant', 0.0), - fontinfo.effects.get('extend', 1.0)) + effects = ( + fontinfo.effects.get("slant", 0.0), + fontinfo.effects.get("extend", 1.0), + ) fontdesc = self.type1Descriptors.get((fontinfo.fontfile, effects)) if fontdesc is None: fontdesc = self.createType1Descriptor(t1font, fontinfo.fontfile) self.type1Descriptors[(fontinfo.fontfile, effects)] = fontdesc - fontdict['FontDescriptor'] = fontdesc + fontdict["FontDescriptor"] = fontdesc self.writeObject(fontdictObject, fontdict) return fontdictObject @@ -703,11 +798,11 @@ def embedTeXFont(self, texname, fontinfo): def createType1Descriptor(self, t1font, fontfile): # Create and write the font descriptor and the font file # of a Type-1 font - fontdescObject = self.reserveObject('font descriptor') - fontfileObject = self.reserveObject('font file') + fontdescObject = self.reserveObject("font descriptor") + fontfileObject = self.reserveObject("font file") - italic_angle = t1font.prop['ItalicAngle'] - fixed_pitch = t1font.prop['isFixedPitch'] + italic_angle = t1font.prop["ItalicAngle"] + fixed_pitch = t1font.prop["isFixedPitch"] flags = 0 # fixed width @@ -738,28 +833,33 @@ def createType1Descriptor(self, t1font, fontfile): ft2font = FT2Font(fontfile) descriptor = { - 'Type': Name('FontDescriptor'), - 'FontName': Name(t1font.prop['FontName']), - 'Flags': flags, - 'FontBBox': ft2font.bbox, - 'ItalicAngle': italic_angle, - 'Ascent': ft2font.ascender, - 'Descent': ft2font.descender, - 'CapHeight': 1000, # TODO: find this out - 'XHeight': 500, # TODO: this one too - 'FontFile': fontfileObject, - 'FontFamily': t1font.prop['FamilyName'], - 'StemV': 50, # TODO + "Type": Name("FontDescriptor"), + "FontName": Name(t1font.prop["FontName"]), + "Flags": flags, + "FontBBox": ft2font.bbox, + "ItalicAngle": italic_angle, + "Ascent": ft2font.ascender, + "Descent": ft2font.descender, + "CapHeight": 1000, # TODO: find this out + "XHeight": 500, # TODO: this one too + "FontFile": fontfileObject, + "FontFamily": t1font.prop["FamilyName"], + "StemV": 50, # TODO # (see also revision 3874; but not all TeX distros have AFM files!) #'FontWeight': a number where 400 = Regular, 700 = Bold - } + } self.writeObject(fontdescObject, descriptor) - self.beginStream(fontfileObject.id, None, - {'Length1': len(t1font.parts[0]), - 'Length2': len(t1font.parts[1]), - 'Length3': 0}) + self.beginStream( + fontfileObject.id, + None, + { + "Length1": len(t1font.parts[0]), + "Length2": len(t1font.parts[1]), + "Length3": 0, + }, + ) self.currentstream.write(t1font.parts[0]) self.currentstream.write(t1font.parts[1]) self.endStream() @@ -769,7 +869,8 @@ def createType1Descriptor(self, t1font, fontfile): def _get_xobject_symbol_name(self, filename, symbol_name): return "%s-%s" % ( os.path.splitext(os.path.basename(filename))[0], - symbol_name) + symbol_name, + ) _identityToUnicodeCMap = """/CIDInit /ProcSet findresource begin 12 dict begin @@ -796,7 +897,7 @@ def embedTTF(self, filename, characters): """Embed the TTF font from the named file into the document.""" font = FT2Font(filename) - fonttype = rcParams['pdf.fonttype'] + fonttype = rcParams["pdf.fonttype"] def cvt(length, upe=font.units_per_EM, nearest=True): "Convert font coordinates to PDF glyph coordinates" @@ -812,51 +913,59 @@ def cvt(length, upe=font.units_per_EM, nearest=True): def embedTTFType3(font, characters, descriptor): """The Type 3-specific part of embedding a Truetype font""" - widthsObject = self.reserveObject('font widths') - fontdescObject = self.reserveObject('font descriptor') - fontdictObject = self.reserveObject('font dictionary') - charprocsObject = self.reserveObject('character procs') + widthsObject = self.reserveObject("font widths") + fontdescObject = self.reserveObject("font descriptor") + fontdictObject = self.reserveObject("font dictionary") + charprocsObject = self.reserveObject("character procs") differencesArray = [] firstchar, lastchar = 0, 255 bbox = [cvt(x, nearest=False) for x in font.bbox] fontdict = { - 'Type': Name('Font'), - 'BaseFont': ps_name, - 'FirstChar': firstchar, - 'LastChar': lastchar, - 'FontDescriptor': fontdescObject, - 'Subtype': Name('Type3'), - 'Name': descriptor['FontName'], - 'FontBBox': bbox, - 'FontMatrix': [.001, 0, 0, .001, 0, 0], - 'CharProcs': charprocsObject, - 'Encoding': { - 'Type': Name('Encoding'), - 'Differences': differencesArray}, - 'Widths': widthsObject - } + "Type": Name("Font"), + "BaseFont": ps_name, + "FirstChar": firstchar, + "LastChar": lastchar, + "FontDescriptor": fontdescObject, + "Subtype": Name("Type3"), + "Name": descriptor["FontName"], + "FontBBox": bbox, + "FontMatrix": [0.001, 0, 0, 0.001, 0, 0], + "CharProcs": charprocsObject, + "Encoding": { + "Type": Name("Encoding"), + "Differences": differencesArray, + }, + "Widths": widthsObject, + } # Make the "Widths" array from encodings import cp1252 + # The "decoding_map" was changed # to a "decoding_table" as of Python 2.5. - if hasattr(cp1252, 'decoding_map'): + if hasattr(cp1252, "decoding_map"): + def decode_char(charcode): return cp1252.decoding_map[charcode] or 0 + else: + def decode_char(charcode): return ord(cp1252.decoding_table[charcode]) def get_char_width(charcode): s = decode_char(charcode) width = font.load_char( - s, flags=LOAD_NO_SCALE | LOAD_NO_HINTING).horiAdvance + s, flags=LOAD_NO_SCALE | LOAD_NO_HINTING + ).horiAdvance return cvt(width) - widths = [get_char_width(charcode) - for charcode in range(firstchar, lastchar+1)] - descriptor['MaxWidth'] = max(widths) + widths = [ + get_char_width(charcode) + for charcode in range(firstchar, lastchar + 1) + ] + descriptor["MaxWidth"] = max(widths) # Make the "Differences" array, sort the ccodes < 255 from # the multi-byte ccodes, and build the whole set of glyph ids @@ -886,24 +995,25 @@ def get_char_width(charcode): # Make the charprocs array (using ttconv to generate the # actual outlines) rawcharprocs = ttconv.get_pdf_charprocs( - filename.encode(sys.getfilesystemencoding()), glyph_ids) + filename.encode(sys.getfilesystemencoding()), glyph_ids + ) charprocs = {} for charname, stream in six.iteritems(rawcharprocs): - charprocDict = {'Length': len(stream)} + charprocDict = {"Length": len(stream)} # The 2-byte characters are used as XObjects, so they # need extra info in their dictionary if charname in multi_byte_chars: - charprocDict['Type'] = Name('XObject') - charprocDict['Subtype'] = Name('Form') - charprocDict['BBox'] = bbox + charprocDict["Type"] = Name("XObject") + charprocDict["Subtype"] = Name("Form") + charprocDict["BBox"] = bbox # Each glyph includes bounding box information, # but xpdf and ghostscript can't handle it in a # Form XObject (they segfault!!!), so we remove it # from the stream here. It's not needed anyway, # since the Form XObject includes it in its BBox # value. - stream = stream[stream.find(b"d1") + 2:] - charprocObject = self.reserveObject('charProc') + stream = stream[stream.find(b"d1") + 2 :] + charprocObject = self.reserveObject("charProc") self.beginStream(charprocObject.id, None, charprocDict) self.currentstream.write(stream) self.endStream() @@ -926,44 +1036,46 @@ def get_char_width(charcode): def embedTTFType42(font, characters, descriptor): """The Type 42-specific part of embedding a Truetype font""" - fontdescObject = self.reserveObject('font descriptor') - cidFontDictObject = self.reserveObject('CID font dictionary') - type0FontDictObject = self.reserveObject('Type 0 font dictionary') - cidToGidMapObject = self.reserveObject('CIDToGIDMap stream') - fontfileObject = self.reserveObject('font file stream') - wObject = self.reserveObject('Type 0 widths') - toUnicodeMapObject = self.reserveObject('ToUnicode map') + fontdescObject = self.reserveObject("font descriptor") + cidFontDictObject = self.reserveObject("CID font dictionary") + type0FontDictObject = self.reserveObject("Type 0 font dictionary") + cidToGidMapObject = self.reserveObject("CIDToGIDMap stream") + fontfileObject = self.reserveObject("font file stream") + wObject = self.reserveObject("Type 0 widths") + toUnicodeMapObject = self.reserveObject("ToUnicode map") cidFontDict = { - 'Type': Name('Font'), - 'Subtype': Name('CIDFontType2'), - 'BaseFont': ps_name, - 'CIDSystemInfo': { - 'Registry': 'Adobe', - 'Ordering': 'Identity', - 'Supplement': 0}, - 'FontDescriptor': fontdescObject, - 'W': wObject, - 'CIDToGIDMap': cidToGidMapObject - } + "Type": Name("Font"), + "Subtype": Name("CIDFontType2"), + "BaseFont": ps_name, + "CIDSystemInfo": { + "Registry": "Adobe", + "Ordering": "Identity", + "Supplement": 0, + }, + "FontDescriptor": fontdescObject, + "W": wObject, + "CIDToGIDMap": cidToGidMapObject, + } type0FontDict = { - 'Type': Name('Font'), - 'Subtype': Name('Type0'), - 'BaseFont': ps_name, - 'Encoding': Name('Identity-H'), - 'DescendantFonts': [cidFontDictObject], - 'ToUnicode': toUnicodeMapObject - } + "Type": Name("Font"), + "Subtype": Name("Type0"), + "BaseFont": ps_name, + "Encoding": Name("Identity-H"), + "DescendantFonts": [cidFontDictObject], + "ToUnicode": toUnicodeMapObject, + } # Make fontfile stream - descriptor['FontFile2'] = fontfileObject - length1Object = self.reserveObject('decoded length of a font') + descriptor["FontFile2"] = fontfileObject + length1Object = self.reserveObject("decoded length of a font") self.beginStream( fontfileObject.id, - self.reserveObject('length of font stream'), - {'Length1': length1Object}) - with open(filename, 'rb') as fontfile: + self.reserveObject("length of font stream"), + {"Length1": length1Object}, + ) + with open(filename, "rb") as fontfile: length1 = 0 while True: data = fontfile.read(4096) @@ -976,7 +1088,7 @@ def embedTTFType42(font, characters, descriptor): # Make the 'W' (Widths) array, CidToGidMap and ToUnicode CMap # at the same time - cid_to_gid_map = ['\\u0000'] * 65536 + cid_to_gid_map = ["\\u0000"] * 65536 cmap = font.get_charmap() widths = [] max_ccode = 0 @@ -989,7 +1101,7 @@ def embedTTFType42(font, characters, descriptor): cid_to_gid_map[ccode] = chr(gind) max_ccode = max(ccode, max_ccode) widths.sort() - cid_to_gid_map = cid_to_gid_map[:max_ccode + 1] + cid_to_gid_map = cid_to_gid_map[: max_ccode + 1] last_ccode = -2 w = [] @@ -1009,29 +1121,34 @@ def embedTTFType42(font, characters, descriptor): unicode_bfrange = [] for start, end in unicode_groups: unicode_bfrange.append( - "<%04x> <%04x> [%s]" % - (start, end, - " ".join(["<%04x>" % x for x in range(start, end+1)]))) - unicode_cmap = (self._identityToUnicodeCMap % - (len(unicode_groups), - "\n".join(unicode_bfrange))).encode('ascii') + "<%04x> <%04x> [%s]" + % ( + start, + end, + " ".join(["<%04x>" % x for x in range(start, end + 1)]), + ) + ) + unicode_cmap = ( + self._identityToUnicodeCMap + % (len(unicode_groups), "\n".join(unicode_bfrange)) + ).encode("ascii") # CIDToGIDMap stream cid_to_gid_map = "".join(cid_to_gid_map).encode("utf-16be") - self.beginStream(cidToGidMapObject.id, - None, - {'Length': len(cid_to_gid_map)}) + self.beginStream( + cidToGidMapObject.id, None, {"Length": len(cid_to_gid_map)} + ) self.currentstream.write(cid_to_gid_map) self.endStream() # ToUnicode CMap - self.beginStream(toUnicodeMapObject.id, - None, - {'Length': unicode_cmap}) + self.beginStream( + toUnicodeMapObject.id, None, {"Length": unicode_cmap} + ) self.currentstream.write(unicode_cmap) self.endStream() - descriptor['MaxWidth'] = max_width + descriptor["MaxWidth"] = max_width # Write everything out self.writeObject(cidFontDictObject, cidFontDict) @@ -1046,15 +1163,15 @@ def embedTTFType42(font, characters, descriptor): # You are lost in a maze of TrueType tables, all different... sfnt = font.get_sfnt() try: - ps_name = sfnt[(1, 0, 0, 6)].decode('macroman') # Macintosh scheme + ps_name = sfnt[(1, 0, 0, 6)].decode("macroman") # Macintosh scheme except KeyError: # Microsoft scheme: - ps_name = sfnt[(3, 1, 0x0409, 6)].decode('utf-16be') + ps_name = sfnt[(3, 1, 0x0409, 6)].decode("utf-16be") # (see freetype/ttnameid.h) - ps_name = ps_name.encode('ascii', 'replace') + ps_name = ps_name.encode("ascii", "replace") ps_name = Name(ps_name) - pclt = font.get_sfnt_table('pclt') or {'capHeight': 0, 'xHeight': 0} - post = font.get_sfnt_table('post') or {'italicAngle': (0, 0)} + pclt = font.get_sfnt_table("pclt") or {"capHeight": 0, "xHeight": 0} + post = font.get_sfnt_table("post") or {"italicAngle": (0, 0)} ff = font.face_flags sf = font.style_flags @@ -1078,25 +1195,27 @@ def embedTTFType42(font, characters, descriptor): flags |= 1 << 18 descriptor = { - 'Type': Name('FontDescriptor'), - 'FontName': ps_name, - 'Flags': flags, - 'FontBBox': [cvt(x, nearest=False) for x in font.bbox], - 'Ascent': cvt(font.ascender, nearest=False), - 'Descent': cvt(font.descender, nearest=False), - 'CapHeight': cvt(pclt['capHeight'], nearest=False), - 'XHeight': cvt(pclt['xHeight']), - 'ItalicAngle': post['italicAngle'][1], # ??? - 'StemV': 0 # ??? - } + "Type": Name("FontDescriptor"), + "FontName": ps_name, + "Flags": flags, + "FontBBox": [cvt(x, nearest=False) for x in font.bbox], + "Ascent": cvt(font.ascender, nearest=False), + "Descent": cvt(font.descender, nearest=False), + "CapHeight": cvt(pclt["capHeight"], nearest=False), + "XHeight": cvt(pclt["xHeight"]), + "ItalicAngle": post["italicAngle"][1], # ??? + "StemV": 0, # ??? + } # The font subsetting to a Type 3 font does not work for # OpenType (.otf) that embed a Postscript CFF font, so avoid that -- # save as a (non-subsetted) Type 42 font instead. if is_opentype_cff_font(filename): fonttype = 42 - msg = ("'%s' can not be subsetted into a Type 3 font. " - "The entire font will be embedded in the output.") + msg = ( + "'%s' can not be subsetted into a Type 3 font. " + "The entire font will be embedded in the output." + ) warnings.warn(msg % os.path.basename(filename)) if fonttype == 3: @@ -1111,11 +1230,12 @@ def alphaState(self, alpha): if state is not None: return state[0] - name = Name('A%d' % self.nextAlphaState) + name = Name("A%d" % self.nextAlphaState) self.nextAlphaState += 1 - self.alphaStates[alpha] = \ - (name, {'Type': Name('ExtGState'), - 'CA': alpha[0], 'ca': alpha[1]}) + self.alphaStates[alpha] = ( + name, + {"Type": Name("ExtGState"), "CA": alpha[0], "ca": alpha[1]}, + ) return name def hatchPattern(self, hatch_style): @@ -1132,7 +1252,7 @@ def hatchPattern(self, hatch_style): if pattern is not None: return pattern - name = Name('H%d' % self.nextHatch) + name = Name("H%d" % self.nextHatch) self.nextHatch += 1 self.hatchPatterns[hatch_style] = name return name @@ -1141,17 +1261,27 @@ def writeHatches(self): hatchDict = dict() sidelen = 72.0 for hatch_style, name in six.iteritems(self.hatchPatterns): - ob = self.reserveObject('hatch pattern') + ob = self.reserveObject("hatch pattern") hatchDict[name] = ob - res = {'Procsets': - [Name(x) for x in "PDF Text ImageB ImageC ImageI".split()]} + res = { + "Procsets": [ + Name(x) for x in "PDF Text ImageB ImageC ImageI".split() + ] + } self.beginStream( - ob.id, None, - {'Type': Name('Pattern'), - 'PatternType': 1, 'PaintType': 1, 'TilingType': 1, - 'BBox': [0, 0, sidelen, sidelen], - 'XStep': sidelen, 'YStep': sidelen, - 'Resources': res}) + ob.id, + None, + { + "Type": Name("Pattern"), + "PatternType": 1, + "PaintType": 1, + "TilingType": 1, + "BBox": [0, 0, sidelen, sidelen], + "XStep": sidelen, + "YStep": sidelen, + "Resources": res, + }, + ) # lst is a tuple of stroke color, fill color, # number of - lines, number of / lines, @@ -1160,62 +1290,89 @@ def writeHatches(self): self.output(rgb[0], rgb[1], rgb[2], Op.setrgb_stroke) if hatch_style[1] is not None: rgb = hatch_style[1] - self.output(rgb[0], rgb[1], rgb[2], Op.setrgb_nonstroke, - 0, 0, sidelen, sidelen, Op.rectangle, - Op.fill) + self.output( + rgb[0], + rgb[1], + rgb[2], + Op.setrgb_nonstroke, + 0, + 0, + sidelen, + sidelen, + Op.rectangle, + Op.fill, + ) # [TEG] Trying to change hatch line width (default 0.1) self.output(0.8, Op.setlinewidth) # TODO: We could make this dpi-dependent, but that would be # an API change - self.output(*self.pathOperations( - Path.hatch(hatch_style[2]), - Affine2D().scale(sidelen), - simplify=False)) + self.output( + *self.pathOperations( + Path.hatch(hatch_style[2]), + Affine2D().scale(sidelen), + simplify=False, + ) + ) self.output(Op.stroke) self.endStream() self.writeObject(self.hatchObject, hatchDict) def addGouraudTriangles(self, points, colors): - name = Name('GT%d' % len(self.gouraudTriangles)) + name = Name("GT%d" % len(self.gouraudTriangles)) self.gouraudTriangles.append((name, points, colors)) return name def writeGouraudTriangles(self): gouraudDict = dict() for name, points, colors in self.gouraudTriangles: - ob = self.reserveObject('Gouraud triangle') + ob = self.reserveObject("Gouraud triangle") gouraudDict[name] = ob shape = points.shape flat_points = points.reshape((shape[0] * shape[1], 2)) flat_colors = colors.reshape((shape[0] * shape[1], 4)) points_min = np.min(flat_points, axis=0) - (1 << 8) points_max = np.max(flat_points, axis=0) + (1 << 8) - factor = float(0xffffffff) / (points_max - points_min) + factor = float(0xFFFFFFFF) / (points_max - points_min) self.beginStream( - ob.id, None, - {'ShadingType': 4, - 'BitsPerCoordinate': 32, - 'BitsPerComponent': 8, - 'BitsPerFlag': 8, - 'ColorSpace': Name('DeviceRGB'), - 'AntiAlias': True, - 'Decode': [points_min[0], points_max[0], - points_min[1], points_max[1], - 0, 1, 0, 1, 0, 1] - }) + ob.id, + None, + { + "ShadingType": 4, + "BitsPerCoordinate": 32, + "BitsPerComponent": 8, + "BitsPerFlag": 8, + "ColorSpace": Name("DeviceRGB"), + "AntiAlias": True, + "Decode": [ + points_min[0], + points_max[0], + points_min[1], + points_max[1], + 0, + 1, + 0, + 1, + 0, + 1, + ], + }, + ) streamarr = np.empty( (shape[0] * shape[1],), - dtype=[(str('flags'), str('u1')), - (str('points'), str('>u4'), (2,)), - (str('colors'), str('u1'), (3,))]) - streamarr['flags'] = 0 - streamarr['points'] = (flat_points - points_min) * factor - streamarr['colors'] = flat_colors[:, :3] * 255.0 + dtype=[ + (str("flags"), str("u1")), + (str("points"), str(">u4"), (2,)), + (str("colors"), str("u1"), (3,)), + ], + ) + streamarr["flags"] = 0 + streamarr["points"] = (flat_points - points_min) * factor + streamarr["colors"] = flat_colors[:, :3] * 255.0 self.write(streamarr.tostring()) self.endStream() @@ -1228,8 +1385,8 @@ def imageObject(self, image): if pair is not None: return pair[0] - name = Name('I%d' % self.nextImage) - ob = self.reserveObject('image %d' % self.nextImage) + name = Name("I%d" % self.nextImage) + ob = self.reserveObject("image %d" % self.nextImage) self.nextImage += 1 self.images[image] = (name, ob) return name @@ -1254,7 +1411,7 @@ def _gray(self, im, rc=0.3, gc=0.59, bc=0.11): r = rgba_f[:, :, 0] g = rgba_f[:, :, 1] b = rgba_f[:, :, 2] - gray = (r*rc + g*gc + b*bc).astype(np.uint8) + gray = (r * rc + g * gc + b * bc).astype(np.uint8) return rgbat[0], rgbat[1], gray.tostring() def writeImages(self): @@ -1264,10 +1421,16 @@ def writeImages(self): height, width, data = self._gray(img) self.beginStream( pair[1].id, - self.reserveObject('length of image stream'), - {'Type': Name('XObject'), 'Subtype': Name('Image'), - 'Width': width, 'Height': height, - 'ColorSpace': Name('DeviceGray'), 'BitsPerComponent': 8}) + self.reserveObject("length of image stream"), + { + "Type": Name("XObject"), + "Subtype": Name("Image"), + "Width": width, + "Height": height, + "ColorSpace": Name("DeviceGray"), + "BitsPerComponent": 8, + }, + ) # TODO: predictors (i.e., output png) self.currentstream.write(data) self.endStream() @@ -1276,29 +1439,42 @@ def writeImages(self): smaskObject = self.reserveObject("smask") self.beginStream( smaskObject.id, - self.reserveObject('length of smask stream'), - {'Type': Name('XObject'), 'Subtype': Name('Image'), - 'Width': width, 'Height': height, - 'ColorSpace': Name('DeviceGray'), 'BitsPerComponent': 8}) + self.reserveObject("length of smask stream"), + { + "Type": Name("XObject"), + "Subtype": Name("Image"), + "Width": width, + "Height": height, + "ColorSpace": Name("DeviceGray"), + "BitsPerComponent": 8, + }, + ) # TODO: predictors (i.e., output png) self.currentstream.write(adata) self.endStream() self.beginStream( pair[1].id, - self.reserveObject('length of image stream'), - {'Type': Name('XObject'), 'Subtype': Name('Image'), - 'Width': width, 'Height': height, - 'ColorSpace': Name('DeviceRGB'), 'BitsPerComponent': 8, - 'SMask': smaskObject}) + self.reserveObject("length of image stream"), + { + "Type": Name("XObject"), + "Subtype": Name("Image"), + "Width": width, + "Height": height, + "ColorSpace": Name("DeviceRGB"), + "BitsPerComponent": 8, + "SMask": smaskObject, + }, + ) # TODO: predictors (i.e., output png) self.currentstream.write(data) self.endStream() img.flipud_out() - def markerObject(self, path, trans, fillp, strokep, lw, joinstyle, - capstyle): + def markerObject( + self, path, trans, fillp, strokep, lw, joinstyle, capstyle + ): """Return name of a marker XObject representing the given path.""" # self.markers used by markerObject, writeMarkers, close: # mapping from (path operations, fill?, stroke?) to @@ -1316,8 +1492,8 @@ def markerObject(self, path, trans, fillp, strokep, lw, joinstyle, key = (tuple(pathops), bool(fillp), bool(strokep), joinstyle, capstyle) result = self.markers.get(key) if result is None: - name = Name('M%d' % len(self.markers)) - ob = self.reserveObject('marker %d' % len(self.markers)) + name = Name("M%d" % len(self.markers)) + ob = self.reserveObject("marker %d" % len(self.markers)) bbox = path.get_extents(trans) self.markers[key] = [name, ob, bbox, lw] else: @@ -1327,31 +1503,58 @@ def markerObject(self, path, trans, fillp, strokep, lw, joinstyle, return name def writeMarkers(self): - for ((pathops, fillp, strokep, joinstyle, capstyle), - (name, ob, bbox, lw)) in six.iteritems(self.markers): + for ( + (pathops, fillp, strokep, joinstyle, capstyle), + (name, ob, bbox, lw), + ) in six.iteritems(self.markers): bbox = bbox.padded(lw * 0.5) self.beginStream( - ob.id, None, - {'Type': Name('XObject'), 'Subtype': Name('Form'), - 'BBox': list(bbox.extents)}) - self.output(GraphicsContextPdf.joinstyles[joinstyle], - Op.setlinejoin) + ob.id, + None, + { + "Type": Name("XObject"), + "Subtype": Name("Form"), + "BBox": list(bbox.extents), + }, + ) + self.output( + GraphicsContextPdf.joinstyles[joinstyle], Op.setlinejoin + ) self.output(GraphicsContextPdf.capstyles[capstyle], Op.setlinecap) self.output(*pathops) self.output(Op.paint_path(False, fillp, strokep)) self.endStream() def pathCollectionObject(self, gc, path, trans, padding, filled, stroked): - name = Name('P%d' % len(self.paths)) - ob = self.reserveObject('path %d' % len(self.paths)) + name = Name("P%d" % len(self.paths)) + ob = self.reserveObject("path %d" % len(self.paths)) self.paths.append( - (name, path, trans, ob, gc.get_joinstyle(), gc.get_capstyle(), - padding, filled, stroked)) + ( + name, + path, + trans, + ob, + gc.get_joinstyle(), + gc.get_capstyle(), + padding, + filled, + stroked, + ) + ) return name def writePathCollectionTemplates(self): - for (name, path, trans, ob, joinstyle, capstyle, padding, filled, - stroked) in self.paths: + for ( + name, + path, + trans, + ob, + joinstyle, + capstyle, + padding, + filled, + stroked, + ) in self.paths: pathops = self.pathOperations(path, trans, simplify=False) bbox = path.get_extents(trans) if not np.all(np.isfinite(bbox.extents)): @@ -1360,11 +1563,17 @@ def writePathCollectionTemplates(self): bbox = bbox.padded(padding) extents = list(bbox.extents) self.beginStream( - ob.id, None, - {'Type': Name('XObject'), 'Subtype': Name('Form'), - 'BBox': extents}) - self.output(GraphicsContextPdf.joinstyles[joinstyle], - Op.setlinejoin) + ob.id, + None, + { + "Type": Name("XObject"), + "Subtype": Name("Form"), + "BBox": extents, + }, + ) + self.output( + GraphicsContextPdf.joinstyles[joinstyle], Op.setlinejoin + ) self.output(GraphicsContextPdf.capstyles[capstyle], Op.setlinecap) self.output(*pathops) self.output(Op.paint_path(False, filled, stroked)) @@ -1374,9 +1583,9 @@ def writePathCollectionTemplates(self): def pathOperations(path, transform, clip=None, simplify=None, sketch=None): cmds = [] last_points = None - for points, code in path.iter_segments(transform, clip=clip, - simplify=simplify, - sketch=sketch): + for points, code in path.iter_segments( + transform, clip=clip, simplify=simplify, sketch=sketch + ): if code == Path.MOVETO: # This is allowed anywhere in the path cmds.extend(points) @@ -1385,7 +1594,7 @@ def pathOperations(path, transform, clip=None, simplify=None, sketch=None): cmds.append(Op.closepath) elif last_points is None: # The other operations require a previous point - raise ValueError('Path lacks initial MOVETO') + raise ValueError("Path lacks initial MOVETO") elif code == Path.LINETO: cmds.extend(points) cmds.append(Op.lineto) @@ -1406,11 +1615,12 @@ def writePath(self, path, transform, clip=False, sketch=None): else: clip = None simplify = False - cmds = self.pathOperations(path, transform, clip, simplify=simplify, - sketch=sketch) + cmds = self.pathOperations( + path, transform, clip, simplify=simplify, sketch=sketch + ) self.output(*cmds) - def reserveObject(self, name=''): + def reserveObject(self, name=""): """Reserve an ID for an indirect object. The name is used for debugging in case we forget to print out the object with writeObject. @@ -1432,61 +1642,73 @@ def writeXref(self): """Write out the xref table.""" self.startxref = self.fh.tell() - self.tell_base - self.write(("xref\n0 %d\n" % self.nextObject).encode('ascii')) + self.write(("xref\n0 %d\n" % self.nextObject).encode("ascii")) i = 0 borken = False for offset, generation, name in self.xrefTable: if offset is None: - print('No offset for object %d (%s)' % (i, name), - file=sys.stderr) + print( + "No offset for object %d (%s)" % (i, name), file=sys.stderr + ) borken = True else: - if name == 'the zero object': + if name == "the zero object": key = "f" else: key = "n" text = "%010d %05d %s \n" % (offset, generation, key) - self.write(text.encode('ascii')) + self.write(text.encode("ascii")) i += 1 if borken: - raise AssertionError('Indirect object does not exist') + raise AssertionError("Indirect object does not exist") def writeInfoDict(self): """Write out the info dictionary, checking it for good form""" is_date = lambda x: isinstance(x, datetime) - check_trapped = (lambda x: isinstance(x, Name) and - x.name in ('True', 'False', 'Unknown')) - keywords = {'Title': is_string_like, - 'Author': is_string_like, - 'Subject': is_string_like, - 'Keywords': is_string_like, - 'Creator': is_string_like, - 'Producer': is_string_like, - 'CreationDate': is_date, - 'ModDate': is_date, - 'Trapped': check_trapped} + check_trapped = lambda x: isinstance(x, Name) and x.name in ( + "True", + "False", + "Unknown", + ) + keywords = { + "Title": is_string_like, + "Author": is_string_like, + "Subject": is_string_like, + "Keywords": is_string_like, + "Creator": is_string_like, + "Producer": is_string_like, + "CreationDate": is_date, + "ModDate": is_date, + "Trapped": check_trapped, + } for k in six.iterkeys(self.infoDict): if k not in keywords: - warnings.warn('Unknown infodict keyword: %s' % k) + warnings.warn("Unknown infodict keyword: %s" % k) else: if not keywords[k](self.infoDict[k]): - warnings.warn('Bad value for infodict keyword %s' % k) + warnings.warn("Bad value for infodict keyword %s" % k) - self.infoObject = self.reserveObject('info') + self.infoObject = self.reserveObject("info") self.writeObject(self.infoObject, self.infoDict) def writeTrailer(self): """Write out the PDF trailer.""" self.write(b"trailer\n") - self.write(pdfRepr( - {'Size': self.nextObject, - 'Root': self.rootObject, - 'Info': self.infoObject})) + self.write( + pdfRepr( + { + "Size": self.nextObject, + "Root": self.rootObject, + "Info": self.infoObject, + } + ) + ) # Could add 'ID' - self.write(("\nstartxref\n%d\n%%%%EOF\n" % - self.startxref).encode('ascii')) + self.write( + ("\nstartxref\n%d\n%%%%EOF\n" % self.startxref).encode("ascii") + ) class RendererPdf(RendererBase): @@ -1505,10 +1727,10 @@ def finalize(self): self.file.output(*self.gc.finalize()) def check_gc(self, gc, fillcolor=None): - orig_fill = getattr(gc, '_fillcolor', (0., 0., 0.)) + orig_fill = getattr(gc, "_fillcolor", (0.0, 0.0, 0.0)) gc._fillcolor = fillcolor - orig_alphas = getattr(gc, '_effective_alphas', (1.0, 1.0)) + orig_alphas = getattr(gc, "_effective_alphas", (1.0, 1.0)) if gc._forced_alpha: gc._effective_alphas = (gc._alpha, gc._alpha) @@ -1527,8 +1749,9 @@ def check_gc(self, gc, fillcolor=None): def tex_font_mapping(self, texfont): if self.tex_font_map is None: - self.tex_font_map = \ - dviread.PsfontsMap(dviread.find_tex_file('pdftex.map')) + self.tex_font_map = dviread.PsfontsMap( + dviread.find_tex_file("pdftex.map") + ) return self.tex_font_map[texfont] def track_characters(self, font, s): @@ -1540,17 +1763,19 @@ def track_characters(self, font, s): fname = font.fname realpath, stat_key = get_realpath_and_stat(fname) used_characters = self.file.used_characters.setdefault( - stat_key, (realpath, set())) + stat_key, (realpath, set()) + ) used_characters[1].update([ord(x) for x in s]) def merge_used_characters(self, other): for stat_key, (realpath, charset) in six.iteritems(other): used_characters = self.file.used_characters.setdefault( - stat_key, (realpath, set())) + stat_key, (realpath, set()) + ) used_characters[1].update(charset) def get_image_magnification(self): - return self.image_dpi/72.0 + return self.image_dpi / 72.0 def option_scale_image(self): """ @@ -1564,41 +1789,81 @@ def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): h, w = im.get_size_out() if dx is None: - w = 72.0*w/self.image_dpi + w = 72.0 * w / self.image_dpi else: w = dx if dy is None: - h = 72.0*h/self.image_dpi + h = 72.0 * h / self.image_dpi else: h = dy imob = self.file.imageObject(im) if transform is None: - self.file.output(Op.gsave, - w, 0, 0, h, x, y, Op.concat_matrix, - imob, Op.use_xobject, Op.grestore) + self.file.output( + Op.gsave, + w, + 0, + 0, + h, + x, + y, + Op.concat_matrix, + imob, + Op.use_xobject, + Op.grestore, + ) else: tr1, tr2, tr3, tr4, tr5, tr6 = transform.to_values() - self.file.output(Op.gsave, - tr1, tr2, tr3, tr4, tr5, tr6, Op.concat_matrix, - w, 0, 0, h, x, y, Op.concat_matrix, - imob, Op.use_xobject, Op.grestore) + self.file.output( + Op.gsave, + tr1, + tr2, + tr3, + tr4, + tr5, + tr6, + Op.concat_matrix, + w, + 0, + 0, + h, + x, + y, + Op.concat_matrix, + imob, + Op.use_xobject, + Op.grestore, + ) def draw_path(self, gc, path, transform, rgbFace=None): self.check_gc(gc, rgbFace) self.file.writePath( - path, transform, + path, + transform, rgbFace is None and gc.get_hatch_path() is None, - gc.get_sketch_params()) + gc.get_sketch_params(), + ) self.file.output(self.gc.paint()) - def draw_path_collection(self, gc, master_transform, paths, all_transforms, - offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds, urls, - offset_position): + def draw_path_collection( + self, + gc, + master_transform, + paths, + all_transforms, + offsets, + offsetTrans, + facecolors, + edgecolors, + linewidths, + linestyles, + antialiaseds, + urls, + offset_position, + ): # We can only reuse the objects if the presence of fill and # stroke (and the amount of alpha for each) is the same for # all of them @@ -1625,41 +1890,70 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, if not can_do_optimization: return RendererBase.draw_path_collection( - self, gc, master_transform, paths, all_transforms, - offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds, urls, - offset_position) + self, + gc, + master_transform, + paths, + all_transforms, + offsets, + offsetTrans, + facecolors, + edgecolors, + linewidths, + linestyles, + antialiaseds, + urls, + offset_position, + ) padding = np.max(linewidths) path_codes = [] - for i, (path, transform) in enumerate(self._iter_collection_raw_paths( - master_transform, paths, all_transforms)): + for i, (path, transform) in enumerate( + self._iter_collection_raw_paths( + master_transform, paths, all_transforms + ) + ): name = self.file.pathCollectionObject( - gc, path, transform, padding, filled, stroked) + gc, path, transform, padding, filled, stroked + ) path_codes.append(name) output = self.file.output output(*self.gc.push()) lastx, lasty = 0, 0 for xo, yo, path_id, gc0, rgbFace in self._iter_collection( - gc, master_transform, all_transforms, path_codes, offsets, - offsetTrans, facecolors, edgecolors, linewidths, linestyles, - antialiaseds, urls, offset_position): + gc, + master_transform, + all_transforms, + path_codes, + offsets, + offsetTrans, + facecolors, + edgecolors, + linewidths, + linestyles, + antialiaseds, + urls, + offset_position, + ): self.check_gc(gc0, rgbFace) dx, dy = xo - lastx, yo - lasty - output(1, 0, 0, 1, dx, dy, Op.concat_matrix, path_id, - Op.use_xobject) + output( + 1, 0, 0, 1, dx, dy, Op.concat_matrix, path_id, Op.use_xobject + ) lastx, lasty = xo, yo output(*self.gc.pop()) - def draw_markers(self, gc, marker_path, marker_trans, path, trans, - rgbFace=None): + def draw_markers( + self, gc, marker_path, marker_trans, path, trans, rgbFace=None + ): # For simple paths or small numbers of markers, don't bother # making an XObject if len(path) * len(marker_path) <= 10: - RendererBase.draw_markers(self, gc, marker_path, marker_trans, - path, trans, rgbFace) + RendererBase.draw_markers( + self, gc, marker_path, marker_trans, path, trans, rgbFace + ) return self.check_gc(gc, rgbFace) @@ -1668,31 +1962,42 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, output = self.file.output marker = self.file.markerObject( - marker_path, marker_trans, fillp, strokep, self.gc._linewidth, - gc.get_joinstyle(), gc.get_capstyle()) + marker_path, + marker_trans, + fillp, + strokep, + self.gc._linewidth, + gc.get_joinstyle(), + gc.get_capstyle(), + ) output(Op.gsave) lastx, lasty = 0, 0 for vertices, code in path.iter_segments( - trans, - clip=(0, 0, self.file.width*72, self.file.height*72), - simplify=False): + trans, + clip=(0, 0, self.file.width * 72, self.file.height * 72), + simplify=False, + ): if len(vertices): x, y = vertices[-2:] - if (x < 0 or - y < 0 or - x > self.file.width * 72 or - y > self.file.height * 72): + if ( + x < 0 + or y < 0 + or x > self.file.width * 72 + or y > self.file.height * 72 + ): continue dx, dy = x - lastx, y - lasty - output(1, 0, 0, 1, dx, dy, Op.concat_matrix, - marker, Op.use_xobject) + output( + 1, 0, 0, 1, dx, dy, Op.concat_matrix, marker, Op.use_xobject + ) lastx, lasty = x, y output(Op.grestore) def draw_gouraud_triangle(self, gc, points, colors, trans): - self.draw_gouraud_triangles(gc, points.reshape((1, 3, 2)), - colors.reshape((1, 3, 4)), trans) + self.draw_gouraud_triangles( + gc, points.reshape((1, 3, 2)), colors.reshape((1, 3, 4)), trans + ) def draw_gouraud_triangles(self, gc, points, colors, trans): assert len(points) == len(colors) @@ -1716,27 +2021,40 @@ def _setup_textpos(self, x, y, angle, oldx=0, oldy=0, oldangle=0): self.file.output(x - oldx, y - oldy, Op.textpos) else: angle = angle / 180.0 * pi - self.file.output(cos(angle), sin(angle), - -sin(angle), cos(angle), - x, y, Op.textmatrix) + self.file.output( + cos(angle), + sin(angle), + -sin(angle), + cos(angle), + x, + y, + Op.textmatrix, + ) self.file.output(0, 0, Op.textpos) def draw_mathtext(self, gc, x, y, s, prop, angle): # TODO: fix positioning and encoding - width, height, descent, glyphs, rects, used_characters = \ - self.mathtext_parser.parse(s, 72, prop) + ( + width, + height, + descent, + glyphs, + rects, + used_characters, + ) = self.mathtext_parser.parse(s, 72, prop) self.merge_used_characters(used_characters) # When using Type 3 fonts, we can't use character codes higher # than 255, so we use the "Do" command to render those # instead. - global_fonttype = rcParams['pdf.fonttype'] + global_fonttype = rcParams["pdf.fonttype"] # Set up a global transformation matrix for the whole math expression a = angle / 180.0 * pi self.file.output(Op.gsave) - self.file.output(cos(a), sin(a), -sin(a), cos(a), x, y, - Op.concat_matrix) + self.file.output( + cos(a), sin(a), -sin(a), cos(a), x, y, Op.concat_matrix + ) self.check_gc(gc, gc._rgb) self.file.output(Op.begin_text) @@ -1752,11 +2070,13 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): self._setup_textpos(ox, oy, 0, oldx, oldy) oldx, oldy = ox, oy if (fontname, fontsize) != prev_font: - self.file.output(self.file.fontName(fontname), fontsize, - Op.selectfont) + self.file.output( + self.file.fontName(fontname), fontsize, Op.selectfont + ) prev_font = fontname, fontsize - self.file.output(self.encode_string(chr(num), fonttype), - Op.show) + self.file.output( + self.encode_string(chr(num), fonttype), Op.show + ) self.file.output(Op.end_text) # If using Type 3 fonts, render all of the multi-byte characters @@ -1770,24 +2090,39 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): if fonttype == 3 and num > 255: self.file.fontName(fontname) - self.file.output(Op.gsave, - 0.001 * fontsize, 0, - 0, 0.001 * fontsize, - ox, oy, Op.concat_matrix) + self.file.output( + Op.gsave, + 0.001 * fontsize, + 0, + 0, + 0.001 * fontsize, + ox, + oy, + Op.concat_matrix, + ) name = self.file._get_xobject_symbol_name( - fontname, symbol_name) + fontname, symbol_name + ) self.file.output(Name(name), Op.use_xobject) self.file.output(Op.grestore) # Draw any horizontal lines in the math layout for ox, oy, width, height in rects: - self.file.output(Op.gsave, ox, oy, width, height, - Op.rectangle, Op.fill, Op.grestore) + self.file.output( + Op.gsave, + ox, + oy, + width, + height, + Op.rectangle, + Op.fill, + Op.grestore, + ) # Pop off the global transformation self.file.output(Op.grestore) - def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): + def draw_tex(self, gc, x, y, s, prop, angle, ismath="TeX!", mtext=None): texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) @@ -1815,31 +2150,33 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): basefont=psfont.psname, encodingfile=psfont.encoding, effects=psfont.effects, - dvifont=dvifont) - seq += [['font', pdfname, dvifont.size]] + dvifont=dvifont, + ) + seq += [["font", pdfname, dvifont.size]] oldfont = dvifont # We need to convert the glyph numbers to bytes, and the easiest # way to do this on both Python 2 and 3 is .encode('latin-1') - seq += [['text', x1, y1, - [six.chr(glyph).encode('latin-1')], x1+width]] + seq += [ + ["text", x1, y1, [six.chr(glyph).encode("latin-1")], x1 + width] + ] # Find consecutive text strings with constant y coordinate and # combine into a sequence of strings and kerns, or just one # string (if any kerns would be less than 0.1 points). i, curx, fontsize = 0, 0, None - while i < len(seq)-1: - elt, nxt = seq[i:i+2] - if elt[0] == 'font': + while i < len(seq) - 1: + elt, nxt = seq[i : i + 2] + if elt[0] == "font": fontsize = elt[2] - elif elt[0] == nxt[0] == 'text' and elt[2] == nxt[2]: + elif elt[0] == nxt[0] == "text" and elt[2] == nxt[2]: offset = elt[4] - nxt[1] if abs(offset) < 0.1: elt[3][-1] += nxt[3][0] - elt[4] += nxt[4]-nxt[1] + elt[4] += nxt[4] - nxt[1] else: - elt[3] += [offset*1000.0/fontsize, nxt[3][0]] + elt[3] += [offset * 1000.0 / fontsize, nxt[3][0]] elt[4] = nxt[4] - del seq[i+1] + del seq[i + 1] continue i += 1 @@ -1851,9 +2188,9 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): self.file.output(Op.begin_text) curx, cury, oldx, oldy = 0, 0, 0, 0 for elt in seq: - if elt[0] == 'font': + if elt[0] == "font": self.file.output(elt[1], elt[2], Op.selectfont) - elif elt[0] == 'text': + elif elt[0] == "text": curx, cury = mytrans.transform((elt[1], elt[2])) self._setup_textpos(curx, cury, angle, oldx, oldy) oldx, oldy = curx, cury @@ -1870,17 +2207,30 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): boxgc = self.new_gc() boxgc.copy_properties(gc) boxgc.set_linewidth(0) - pathops = [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, - Path.CLOSEPOLY] + pathops = [ + Path.MOVETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.CLOSEPOLY, + ] for x1, y1, h, w in page.boxes: - path = Path([[x1, y1], [x1+w, y1], [x1+w, y1+h], [x1, y1+h], - [0, 0]], pathops) + path = Path( + [ + [x1, y1], + [x1 + w, y1], + [x1 + w, y1 + h], + [x1, y1 + h], + [0, 0], + ], + pathops, + ) self.draw_path(boxgc, path, mytrans, gc._rgb) def encode_string(self, s, fonttype): if fonttype in (1, 3): - return s.encode('cp1252', 'replace') - return s.encode('utf-16be', 'replace') + return s.encode("cp1252", "replace") + return s.encode("utf-16be", "replace") def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): # TODO: combine consecutive texts into one BT/ET delimited section @@ -1902,7 +2252,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): fontsize = prop.get_size_in_points() - if rcParams['pdf.use14corefonts']: + if rcParams["pdf.use14corefonts"]: font = self._get_font_afm(prop) l, b, w, h = font.get_str_bbox(s) fonttype = 1 @@ -1911,7 +2261,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): self.track_characters(font, s) font.set_text(s, 0.0, flags=LOAD_NO_HINTING) - fonttype = rcParams['pdf.fonttype'] + fonttype = rcParams["pdf.fonttype"] # We can't subset all OpenType fonts, so switch to Type 42 # in that case. @@ -1925,7 +2275,7 @@ def check_simple_method(s): use_simple_method = True chunks = [] - if not rcParams['pdf.use14corefonts']: + if not rcParams["pdf.use14corefonts"]: if fonttype == 3 and not isinstance(s, bytes) and len(s) != 0: # Break the string into chunks where each chunk is either # a string of chars <= 255, or a single character > 255. @@ -1939,33 +2289,33 @@ def check_simple_method(s): chunks[-1][1].append(c) else: chunks.append((char_type, [c])) - use_simple_method = (len(chunks) == 1 - and chunks[-1][0] == 1) + use_simple_method = len(chunks) == 1 and chunks[-1][0] == 1 return use_simple_method, chunks def draw_text_simple(): """Outputs text using the simple method.""" - self.file.output(Op.begin_text, - self.file.fontName(prop), - fontsize, - Op.selectfont) + self.file.output( + Op.begin_text, self.file.fontName(prop), fontsize, Op.selectfont + ) self._setup_textpos(x, y, angle) - self.file.output(self.encode_string(s, fonttype), Op.show, - Op.end_text) + self.file.output( + self.encode_string(s, fonttype), Op.show, Op.end_text + ) def draw_text_woven(chunks): """Outputs text using the woven method, alternating between chunks of 1-byte characters and 2-byte characters. Only used for Type 3 fonts.""" - chunks = [(a, ''.join(b)) for a, b in chunks] + chunks = [(a, "".join(b)) for a, b in chunks] cmap = font.get_charmap() # Do the rotation and global translation as a single matrix # concatenation up front self.file.output(Op.gsave) a = angle / 180.0 * pi - self.file.output(cos(a), sin(a), -sin(a), cos(a), x, y, - Op.concat_matrix) + self.file.output( + cos(a), sin(a), -sin(a), cos(a), x, y, Op.concat_matrix + ) # Output all the 1-byte characters in a BT/ET group, then # output all the 2-byte characters. @@ -1973,16 +2323,19 @@ def draw_text_woven(chunks): newx = oldx = 0 # Output a 1-byte character chunk if mode == 1: - self.file.output(Op.begin_text, - self.file.fontName(prop), - fontsize, - Op.selectfont) + self.file.output( + Op.begin_text, + self.file.fontName(prop), + fontsize, + Op.selectfont, + ) for chunk_type, chunk in chunks: if mode == 1 and chunk_type == 1: self._setup_textpos(newx, 0, 0, oldx, 0, 0) - self.file.output(self.encode_string(chunk, fonttype), - Op.show) + self.file.output( + self.encode_string(chunk, fonttype), Op.show + ) oldx = newx lastgind = None @@ -1993,25 +2346,34 @@ def draw_text_woven(chunks): if mode == 2 and chunk_type == 2: glyph_name = font.get_glyph_name(gind) self.file.output(Op.gsave) - self.file.output(0.001 * fontsize, 0, - 0, 0.001 * fontsize, - newx, 0, Op.concat_matrix) + self.file.output( + 0.001 * fontsize, + 0, + 0, + 0.001 * fontsize, + newx, + 0, + Op.concat_matrix, + ) name = self.file._get_xobject_symbol_name( - font.fname, glyph_name) + font.fname, glyph_name + ) self.file.output(Name(name), Op.use_xobject) self.file.output(Op.grestore) # Move the pointer based on the character width # and kerning - glyph = font.load_char(ccode, - flags=LOAD_NO_HINTING) + glyph = font.load_char(ccode, flags=LOAD_NO_HINTING) if lastgind is not None: kern = font.get_kerning( - lastgind, gind, KERNING_UNFITTED) + lastgind, gind, KERNING_UNFITTED + ) else: kern = 0 lastgind = gind - newx += kern/64.0 + glyph.linearHoriAdvance/65536.0 + newx += ( + kern / 64.0 + glyph.linearHoriAdvance / 65536.0 + ) if mode == 1: self.file.output(Op.end_text) @@ -2025,18 +2387,25 @@ def draw_text_woven(chunks): return draw_text_woven(chunks) def get_text_width_height_descent(self, s, prop, ismath): - if rcParams['text.usetex']: + if rcParams["text.usetex"]: texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() - w, h, d = texmanager.get_text_width_height_descent(s, fontsize, - renderer=self) + w, h, d = texmanager.get_text_width_height_descent( + s, fontsize, renderer=self + ) return w, h, d if ismath: - w, h, d, glyphs, rects, used_characters = \ - self.mathtext_parser.parse(s, 72, prop) - - elif rcParams['pdf.use14corefonts']: + ( + w, + h, + d, + glyphs, + rects, + used_characters, + ) = self.mathtext_parser.parse(s, 72, prop) + + elif rcParams["pdf.use14corefonts"]: font = self._get_font_afm(prop) l, b, w, h, d = font.get_str_bbox_and_descent(s) scale = prop.get_size_in_points() @@ -2047,7 +2416,7 @@ def get_text_width_height_descent(self, s, prop, ismath): font = self._get_font_ttf(prop) font.set_text(s, 0.0, flags=LOAD_NO_HINTING) w, h = font.get_width_height() - scale = (1.0 / 64.0) + scale = 1.0 / 64.0 w *= scale h *= scale d = font.get_descent() @@ -2059,14 +2428,17 @@ def _get_font_afm(self, prop): font = self.afm_font_cache.get(key) if font is None: filename = findfont( - prop, fontext='afm', directory=self.file._core14fontdir) + prop, fontext="afm", directory=self.file._core14fontdir + ) if filename is None: filename = findfont( - "Helvetica", fontext='afm', - directory=self.file._core14fontdir) + "Helvetica", + fontext="afm", + directory=self.file._core14fontdir, + ) font = self.afm_font_cache.get(filename) if font is None: - with open(filename, 'rb') as fh: + with open(filename, "rb") as fh: font = AFM(fh) self.afm_font_cache[filename] = font self.afm_font_cache[key] = font @@ -2097,7 +2469,6 @@ def new_gc(self): class GraphicsContextPdf(GraphicsContextBase): - def __init__(self, file): GraphicsContextBase.__init__(self) self._fillcolor = (0.0, 0.0, 0.0) @@ -2107,8 +2478,8 @@ def __init__(self, file): def __repr__(self): d = dict(self.__dict__) - del d['file'] - del d['parent'] + del d["file"] + del d["parent"] return repr(d) def strokep(self): @@ -2119,8 +2490,11 @@ def strokep(self): """ # _linewidth > 0: in pdf a line of width 0 is drawn at minimum # possible device width, but e.g., agg doesn't draw at all - return (self._linewidth > 0 and self._alpha > 0 and - (len(self._rgb) <= 3 or self._rgb[3] != 0.0)) + return ( + self._linewidth > 0 + and self._alpha > 0 + and (len(self._rgb) <= 3 or self._rgb[3] != 0.0) + ) def fillp(self, *args): """ @@ -2133,9 +2507,10 @@ def fillp(self, *args): _fillcolor = args[0] else: _fillcolor = self._fillcolor - return (self._hatch or - (_fillcolor is not None and - (len(_fillcolor) <= 3 or _fillcolor[3] != 0.0))) + return self._hatch or ( + _fillcolor is not None + and (len(_fillcolor) <= 3 or _fillcolor[3] != 0.0) + ) def close_and_paint(self): """ @@ -2151,8 +2526,8 @@ def paint(self): """ return Op.paint_path(False, self.fillp(), self.strokep()) - capstyles = {'butt': 0, 'round': 1, 'projecting': 2} - joinstyles = {'miter': 0, 'round': 1, 'bevel': 2} + capstyles = {"butt": 0, "round": 1, "projecting": 2} + joinstyles = {"miter": 0, "round": 1, "bevel": 2} def capstyle_cmd(self, style): return [self.capstyles[style], Op.setlinecap] @@ -2179,15 +2554,19 @@ def hatch_cmd(self, hatch): if self._fillcolor is not None: return self.fillcolor_cmd(self._fillcolor) else: - return [Name('DeviceRGB'), Op.setcolorspace_nonstroke] + return [Name("DeviceRGB"), Op.setcolorspace_nonstroke] else: hatch_style = (self._rgb, self._fillcolor, hatch) name = self.file.hatchPattern(hatch_style) - return [Name('Pattern'), Op.setcolorspace_nonstroke, - name, Op.setcolor_nonstroke] + return [ + Name("Pattern"), + Op.setcolorspace_nonstroke, + name, + Op.setcolor_nonstroke, + ] def rgb_cmd(self, rgb): - if rcParams['pdf.inheritcolor']: + if rcParams["pdf.inheritcolor"]: return [] if rgb[0] == rgb[1] == rgb[2]: return [rgb[0], Op.setgray_stroke] @@ -2195,7 +2574,7 @@ def rgb_cmd(self, rgb): return list(rgb[:3]) + [Op.setrgb_stroke] def fillcolor_cmd(self, rgb): - if rgb is None or rcParams['pdf.inheritcolor']: + if rgb is None or rcParams["pdf.inheritcolor"]: return [] elif rgb[0] == rgb[1] == rgb[2]: return [rgb[0], Op.setgray_nonstroke] @@ -2219,34 +2598,39 @@ def clip_cmd(self, cliprect, clippath): """Set clip rectangle. Calls self.pop() and self.push().""" cmds = [] # Pop graphics state until we hit the right one or the stack is empty - while ((self._cliprect, self._clippath) != (cliprect, clippath) - and self.parent is not None): + while (self._cliprect, self._clippath) != ( + cliprect, + clippath, + ) and self.parent is not None: cmds.extend(self.pop()) # Unless we hit the right one, set the clip polygon - if ((self._cliprect, self._clippath) != (cliprect, clippath) or - self.parent is None): + if (self._cliprect, self._clippath) != ( + cliprect, + clippath, + ) or self.parent is None: cmds.extend(self.push()) if self._cliprect != cliprect: cmds.extend([cliprect, Op.rectangle, Op.clip, Op.endpath]) if self._clippath != clippath: path, affine = clippath.get_transformed_path_and_affine() cmds.extend( - PdfFile.pathOperations(path, affine, simplify=False) + - [Op.clip, Op.endpath]) + PdfFile.pathOperations(path, affine, simplify=False) + + [Op.clip, Op.endpath] + ) return cmds commands = ( # must come first since may pop - (('_cliprect', '_clippath'), clip_cmd), - (('_alpha', '_forced_alpha', '_effective_alphas'), alpha_cmd), - (('_capstyle',), capstyle_cmd), - (('_fillcolor',), fillcolor_cmd), - (('_joinstyle',), joinstyle_cmd), - (('_linewidth',), linewidth_cmd), - (('_dashes',), dash_cmd), - (('_rgb',), rgb_cmd), - (('_hatch',), hatch_cmd), # must come after fillcolor and rgb - ) + (("_cliprect", "_clippath"), clip_cmd), + (("_alpha", "_forced_alpha", "_effective_alphas"), alpha_cmd), + (("_capstyle",), capstyle_cmd), + (("_fillcolor",), fillcolor_cmd), + (("_joinstyle",), joinstyle_cmd), + (("_linewidth",), linewidth_cmd), + (("_dashes",), dash_cmd), + (("_rgb",), rgb_cmd), + (("_hatch",), hatch_cmd), # must come after fillcolor and rgb + ) # TODO: _linestyle @@ -2266,8 +2650,9 @@ def delta(self, other): except ValueError: ours = np.asarray(ours) theirs = np.asarray(theirs) - different = (ours.shape != theirs.shape or - np.any(ours != theirs)) + different = ours.shape != theirs.shape or np.any( + ours != theirs + ) if different: break @@ -2283,9 +2668,10 @@ def copy_properties(self, other): Copy properties of other into self. """ GraphicsContextBase.copy_properties(self, other) - fillcolor = getattr(other, '_fillcolor', self._fillcolor) - effective_alphas = getattr(other, '_effective_alphas', - self._effective_alphas) + fillcolor = getattr(other, "_fillcolor", self._fillcolor) + effective_alphas = getattr( + other, "_effective_alphas", self._effective_alphas + ) self._fillcolor = fillcolor self._effective_alphas = effective_alphas @@ -2298,6 +2684,7 @@ def finalize(self): cmds.extend(self.pop()) return cmds + ######################################################################## # # The following functions and classes are for pylab and implement @@ -2314,7 +2701,7 @@ def new_figure_manager(num, *args, **kwargs): # do it -- see backend_wx, backend_wxagg and backend_tkagg for # examples. Not all GUIs require explicit instantiation of a # main-level app (egg backend_gtk, backend_gtkagg) for pylab - FigureClass = kwargs.pop('FigureClass', Figure) + FigureClass = kwargs.pop("FigureClass", Figure) thisFig = FigureClass(*args, **kwargs) return new_figure_manager_given_figure(num, thisFig) @@ -2351,7 +2738,8 @@ class PdfPages(object): order to avoid confusion when using :func:`~matplotlib.pyplot.savefig` and forgetting the format argument. """ - __slots__ = ('_file', 'keep_empty') + + __slots__ = ("_file", "keep_empty") def __init__(self, filename, keep_empty=True): """ @@ -2383,8 +2771,11 @@ def close(self): PDF file. """ self._file.close() - if (self.get_pagecount() == 0 and not self.keep_empty - and not self._file.passed_in_file_object): + if ( + self.get_pagecount() == 0 + and not self.keep_empty + and not self._file.passed_in_file_object + ): os.remove(self._file.fh.name) self._file = None @@ -2413,7 +2804,7 @@ def savefig(self, figure=None, **kwargs): the figure instance to save is looked up by number. """ if isinstance(figure, Figure): - figure.savefig(self, format='pdf', **kwargs) + figure.savefig(self, format="pdf", **kwargs) else: if figure is None: figureManager = Gcf.get_active() @@ -2422,8 +2813,9 @@ def savefig(self, figure=None, **kwargs): if figureManager is None: raise ValueError("No such figure: " + repr(figure)) else: - figureManager.canvas.figure.savefig(self, format='pdf', - **kwargs) + figureManager.canvas.figure.savefig( + self, format="pdf", **kwargs + ) def get_pagecount(self): """ @@ -2447,14 +2839,14 @@ class FigureCanvasPdf(FigureCanvasBase): def draw(self): pass - filetypes = {'pdf': 'Portable Document Format'} + filetypes = {"pdf": "Portable Document Format"} def get_default_filetype(self): - return 'pdf' + return "pdf" def print_pdf(self, filename, **kwargs): - image_dpi = kwargs.get('dpi', 72) # dpi to use for images - self.figure.set_dpi(72) # there are 72 pdf points to an inch + image_dpi = kwargs.get("dpi", 72) # dpi to use for images + self.figure.set_dpi(72) # there are 72 pdf points to an inch width, height = self.figure.get_size_inches() if isinstance(filename, PdfPages): file = filename._file @@ -2464,15 +2856,19 @@ def print_pdf(self, filename, **kwargs): file.newPage(width, height) _bbox_inches_restore = kwargs.pop("bbox_inches_restore", None) renderer = MixedModeRenderer( - self.figure, width, height, image_dpi, + self.figure, + width, + height, + image_dpi, RendererPdf(file, image_dpi), - bbox_inches_restore=_bbox_inches_restore) + bbox_inches_restore=_bbox_inches_restore, + ) self.figure.draw(renderer) renderer.finalize() finally: if isinstance(filename, PdfPages): # finish off this page file.endStream() - else: # we opened the file above; now finish it off + else: # we opened the file above; now finish it off file.close() diff --git a/dnaplotlib/other/hatch_line_width/backend_pdf.py b/dnaplotlib/other/hatch_line_width/backend_pdf.py index 19318c6..86202e0 100644 --- a/dnaplotlib/other/hatch_line_width/backend_pdf.py +++ b/dnaplotlib/other/hatch_line_width/backend_pdf.py @@ -4,8 +4,12 @@ A PDF matplotlib backend Author: Jouni K Sepp�nen """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) import six from six.moves import map @@ -24,6 +28,7 @@ from datetime import datetime from math import ceil, cos, floor, pi, sin + try: set except NameError: @@ -32,19 +37,34 @@ import matplotlib from matplotlib import __version__, rcParams from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ - FigureManagerBase, FigureCanvasBase +from matplotlib.backend_bases import ( + RendererBase, + GraphicsContextBase, + FigureManagerBase, + FigureCanvasBase, +) from matplotlib.backends.backend_mixed import MixedModeRenderer -from matplotlib.cbook import Bunch, is_string_like, \ - get_realpath_and_stat, is_writable_file_like, maxdict +from matplotlib.cbook import ( + Bunch, + is_string_like, + get_realpath_and_stat, + is_writable_file_like, + maxdict, +) from matplotlib.mlab import quad2cubic from matplotlib.figure import Figure from matplotlib.font_manager import findfont, is_opentype_cff_font from matplotlib.afm import AFM import matplotlib.type1font as type1font import matplotlib.dviread as dviread -from matplotlib.ft2font import FT2Font, FIXED_WIDTH, ITALIC, LOAD_NO_SCALE, \ - LOAD_NO_HINTING, KERNING_UNFITTED +from matplotlib.ft2font import ( + FT2Font, + FIXED_WIDTH, + ITALIC, + LOAD_NO_SCALE, + LOAD_NO_HINTING, + KERNING_UNFITTED, +) from matplotlib.mathtext import MathTextParser from matplotlib.transforms import Affine2D, BboxBase from matplotlib.path import Path @@ -112,11 +132,12 @@ def fill(strings, linelen=75): if currpos + length < linelen: currpos += length + 1 else: - result.append(b' '.join(strings[lasti:i])) + result.append(b" ".join(strings[lasti:i])) lasti = i currpos = length - result.append(b' '.join(strings[lasti:])) - return b'\n'.join(result) + result.append(b" ".join(strings[lasti:])) + return b"\n".join(result) + # PDF strings are supposed to be able to include any eight-bit data, # except that unbalanced parens and backslashes must be escaped by a @@ -124,17 +145,17 @@ def fill(strings, linelen=75): # character may get read as a newline; these characters correspond to # \gamma and \Omega in TeX's math font encoding. Escaping them fixes # the bug. -_string_escape_regex = re.compile(br'([\\()\r\n])') +_string_escape_regex = re.compile(br"([\\()\r\n])") def _string_escape(match): m = match.group(0) - if m in br'\()': - return b'\\' + m - elif m == b'\n': - return br'\n' - elif m == b'\r': - return br'\r' + if m in br"\()": + return b"\\" + m + elif m == b"\n": + return br"\n" + elif m == b"\r": + return br"\r" assert False @@ -142,7 +163,7 @@ def pdfRepr(obj): """Map Python objects to PDF syntax.""" # Some objects defined later have their own pdfRepr method. - if hasattr(obj, 'pdfRepr'): + if hasattr(obj, "pdfRepr"): return obj.pdfRepr() # Floats. PDF does not have exponential notation (1.0e-10) so we @@ -151,26 +172,26 @@ def pdfRepr(obj): elif isinstance(obj, (float, np.floating)): if not np.isfinite(obj): raise ValueError("Can only output finite numbers in PDF") - r = ("%.10f" % obj).encode('ascii') - return r.rstrip(b'0').rstrip(b'.') + r = ("%.10f" % obj).encode("ascii") + return r.rstrip(b"0").rstrip(b".") # Booleans. Needs to be tested before integers since # isinstance(True, int) is true. elif isinstance(obj, bool): - return [b'false', b'true'][obj] + return [b"false", b"true"][obj] # Integers are written as such. elif isinstance(obj, (six.integer_types, np.integer)): - return ("%d" % obj).encode('ascii') + return ("%d" % obj).encode("ascii") # Unicode strings are encoded in UTF-16BE with byte-order mark. elif isinstance(obj, six.text_type): try: # But maybe it's really ASCII? - s = obj.encode('ASCII') + s = obj.encode("ASCII") return pdfRepr(s) except UnicodeEncodeError: - s = codecs.BOM_UTF16_BE + obj.encode('UTF-16BE') + s = codecs.BOM_UTF16_BE + obj.encode("UTF-16BE") return pdfRepr(s) # Strings are written in parentheses, with backslashes and parens @@ -178,7 +199,7 @@ def pdfRepr(obj): # simpler to escape them all. TODO: cut long strings into lines; # I believe there is some maximum line length in PDF. elif isinstance(obj, bytes): - return b'(' + _string_escape_regex.sub(_string_escape, obj) + b')' + return b"(" + _string_escape_regex.sub(_string_escape, obj) + b")" # Dictionaries. The keys must be PDF names, so if we find strings # there, we make Name objects from them. The values may be @@ -186,8 +207,12 @@ def pdfRepr(obj): # represented as Name objects. elif isinstance(obj, dict): r = [b"<<"] - r.extend([Name(key).pdfRepr() + b" " + pdfRepr(val) - for key, val in six.iteritems(obj)]) + r.extend( + [ + Name(key).pdfRepr() + b" " + pdfRepr(val) + for key, val in six.iteritems(obj) + ] + ) r.append(b">>") return fill(r) @@ -200,17 +225,17 @@ def pdfRepr(obj): # The null keyword. elif obj is None: - return b'null' + return b"null" # A date. elif isinstance(obj, datetime): - r = obj.strftime('D:%Y%m%d%H%M%S') + r = obj.strftime("D:%Y%m%d%H%M%S") if time.daylight: z = time.altzone else: z = time.timezone if z == 0: - r += 'Z' + r += "Z" elif z < 0: r += "+%02d'%02d'" % ((-z) // 3600, (-z) % 3600) else: @@ -238,70 +263,102 @@ def __repr__(self): return "" % self.id def pdfRepr(self): - return ("%d 0 R" % self.id).encode('ascii') + return ("%d 0 R" % self.id).encode("ascii") def write(self, contents, file): write = file.write - write(("%d 0 obj\n" % self.id).encode('ascii')) + write(("%d 0 obj\n" % self.id).encode("ascii")) write(pdfRepr(contents)) write(b"\nendobj\n") class Name(object): """PDF name object.""" - __slots__ = ('name',) - _regex = re.compile(r'[^!-~]') + + __slots__ = ("name",) + _regex = re.compile(r"[^!-~]") def __init__(self, name): if isinstance(name, Name): self.name = name.name else: if isinstance(name, bytes): - name = name.decode('ascii') - self.name = self._regex.sub(Name.hexify, name).encode('ascii') + name = name.decode("ascii") + self.name = self._regex.sub(Name.hexify, name).encode("ascii") def __repr__(self): return "" % self.name def __str__(self): - return '/' + six.text_type(self.name) + return "/" + six.text_type(self.name) @staticmethod def hexify(match): - return '#%02x' % ord(match.group()) + return "#%02x" % ord(match.group()) def pdfRepr(self): - return b'/' + self.name + return b"/" + self.name class Operator(object): """PDF operator object.""" - __slots__ = ('op',) + + __slots__ = ("op",) def __init__(self, op): self.op = op def __repr__(self): - return '' % self.op + return "" % self.op def pdfRepr(self): return self.op + # PDF operators (not an exhaustive list) _pdfops = dict( - close_fill_stroke=b'b', fill_stroke=b'B', fill=b'f', closepath=b'h', - close_stroke=b's', stroke=b'S', endpath=b'n', begin_text=b'BT', - end_text=b'ET', curveto=b'c', rectangle=b're', lineto=b'l', moveto=b'm', - concat_matrix=b'cm', use_xobject=b'Do', setgray_stroke=b'G', - setgray_nonstroke=b'g', setrgb_stroke=b'RG', setrgb_nonstroke=b'rg', - setcolorspace_stroke=b'CS', setcolorspace_nonstroke=b'cs', - setcolor_stroke=b'SCN', setcolor_nonstroke=b'scn', setdash=b'd', - setlinejoin=b'j', setlinecap=b'J', setgstate=b'gs', gsave=b'q', - grestore=b'Q', textpos=b'Td', selectfont=b'Tf', textmatrix=b'Tm', - show=b'Tj', showkern=b'TJ', setlinewidth=b'w', clip=b'W', shading=b'sh') - -Op = Bunch(**dict([(name, Operator(value)) - for name, value in six.iteritems(_pdfops)])) + close_fill_stroke=b"b", + fill_stroke=b"B", + fill=b"f", + closepath=b"h", + close_stroke=b"s", + stroke=b"S", + endpath=b"n", + begin_text=b"BT", + end_text=b"ET", + curveto=b"c", + rectangle=b"re", + lineto=b"l", + moveto=b"m", + concat_matrix=b"cm", + use_xobject=b"Do", + setgray_stroke=b"G", + setgray_nonstroke=b"g", + setrgb_stroke=b"RG", + setrgb_nonstroke=b"rg", + setcolorspace_stroke=b"CS", + setcolorspace_nonstroke=b"cs", + setcolor_stroke=b"SCN", + setcolor_nonstroke=b"scn", + setdash=b"d", + setlinejoin=b"j", + setlinecap=b"J", + setgstate=b"gs", + gsave=b"q", + grestore=b"Q", + textpos=b"Td", + selectfont=b"Tf", + textmatrix=b"Tm", + show=b"Tj", + showkern=b"TJ", + setlinewidth=b"w", + clip=b"W", + shading=b"sh", +) + +Op = Bunch( + **dict([(name, Operator(value)) for name, value in six.iteritems(_pdfops)]) +) def _paint_path(closep, fillp, strokep): @@ -325,6 +382,8 @@ def _paint_path(closep, fillp, strokep): return Op.fill else: return Op.endpath + + Op.paint_path = _paint_path @@ -334,17 +393,18 @@ class Stream(object): This has no pdfRepr method. Instead, call begin(), then output the contents of the stream by calling write(), and finally call end(). """ - __slots__ = ('id', 'len', 'pdfFile', 'file', 'compressobj', 'extra', 'pos') + + __slots__ = ("id", "len", "pdfFile", "file", "compressobj", "extra", "pos") def __init__(self, id, len, file, extra=None): """id: object id of stream; len: an unused Reference object for the length of the stream, or None (to use a memory buffer); file: a PdfFile; extra: a dictionary of extra key-value pairs to - include in the stream header """ - self.id = id # object id - self.len = len # id of length object + include in the stream header""" + self.id = id # object id + self.len = len # id of length object self.pdfFile = file - self.file = file.fh # file to which the stream is written + self.file = file.fh # file to which the stream is written self.compressobj = None # compression object if extra is None: self.extra = dict() @@ -352,8 +412,8 @@ def __init__(self, id, len, file, extra=None): self.extra = extra self.pdfFile.recordXref(self.id) - if rcParams['pdf.compression']: - self.compressobj = zlib.compressobj(rcParams['pdf.compression']) + if rcParams["pdf.compression"]: + self.compressobj = zlib.compressobj(rcParams["pdf.compression"]) if self.len is None: self.file = BytesIO() else: @@ -362,11 +422,11 @@ def __init__(self, id, len, file, extra=None): def _writeHeader(self): write = self.file.write - write(("%d 0 obj\n" % self.id).encode('ascii')) + write(("%d 0 obj\n" % self.id).encode("ascii")) dict = self.extra - dict['Length'] = self.len - if rcParams['pdf.compression']: - dict['Filter'] = Name('FlateDecode') + dict["Length"] = self.len + if rcParams["pdf.compression"]: + dict["Filter"] = Name("FlateDecode") write(pdfRepr(dict)) write(b"\nstream\n") @@ -409,13 +469,13 @@ class PdfFile(object): """PDF file object.""" def __init__(self, filename): - self.nextObject = 1 # next free object id - self.xrefTable = [[0, 65535, 'the zero object']] + self.nextObject = 1 # next free object id + self.xrefTable = [[0, 65535, "the zero object"]] self.passed_in_file_object = False self.original_file_like = None self.tell_base = 0 if is_string_like(filename): - fh = open(filename, 'wb') + fh = open(filename, "wb") elif is_writable_file_like(filename): try: self.tell_base = filename.tell() @@ -429,44 +489,44 @@ def __init__(self, filename): raise ValueError("filename must be a path or a file-like object") self._core14fontdir = os.path.join( - rcParams['datapath'], 'fonts', 'pdfcorefonts') + rcParams["datapath"], "fonts", "pdfcorefonts" + ) self.fh = fh self.currentstream = None # stream object to write to, if any - fh.write(b"%PDF-1.4\n") # 1.4 is the first version to have alpha + fh.write(b"%PDF-1.4\n") # 1.4 is the first version to have alpha # Output some eight-bit chars as a comment so various utilities # recognize the file as binary by looking at the first few # lines (see note in section 3.4.1 of the PDF reference). fh.write(b"%\254\334 \253\272\n") - self.rootObject = self.reserveObject('root') - self.pagesObject = self.reserveObject('pages') + self.rootObject = self.reserveObject("root") + self.pagesObject = self.reserveObject("pages") self.pageList = [] - self.fontObject = self.reserveObject('fonts') - self.alphaStateObject = self.reserveObject('extended graphics states') - self.hatchObject = self.reserveObject('tiling patterns') - self.gouraudObject = self.reserveObject('Gouraud triangles') - self.XObjectObject = self.reserveObject('external objects') - self.resourceObject = self.reserveObject('resources') - - root = {'Type': Name('Catalog'), - 'Pages': self.pagesObject} + self.fontObject = self.reserveObject("fonts") + self.alphaStateObject = self.reserveObject("extended graphics states") + self.hatchObject = self.reserveObject("tiling patterns") + self.gouraudObject = self.reserveObject("Gouraud triangles") + self.XObjectObject = self.reserveObject("external objects") + self.resourceObject = self.reserveObject("resources") + + root = {"Type": Name("Catalog"), "Pages": self.pagesObject} self.writeObject(self.rootObject, root) - revision = '' + revision = "" self.infoDict = { - 'Creator': 'matplotlib %s, http://matplotlib.org' % __version__, - 'Producer': 'matplotlib pdf backend%s' % revision, - 'CreationDate': datetime.today() - } - - self.fontNames = {} # maps filenames to internal font names - self.nextFont = 1 # next free internal font name - self.dviFontInfo = {} # information on dvi fonts + "Creator": "matplotlib %s, http://matplotlib.org" % __version__, + "Producer": "matplotlib pdf backend%s" % revision, + "CreationDate": datetime.today(), + } + + self.fontNames = {} # maps filenames to internal font names + self.nextFont = 1 # next free internal font name + self.dviFontInfo = {} # information on dvi fonts self.type1Descriptors = {} # differently encoded Type-1 fonts may - # share the same descriptor + # share the same descriptor self.used_characters = {} - self.alphaStates = {} # maps alpha values to graphics state objects + self.alphaStates = {} # maps alpha values to graphics state objects self.nextAlphaState = 1 self.hatchPatterns = {} self.nextHatch = 1 @@ -481,51 +541,59 @@ def __init__(self, filename): self.paths = [] # The PDF spec recommends to include every procset - procsets = [Name(x) - for x in "PDF Text ImageB ImageC ImageI".split()] + procsets = [Name(x) for x in "PDF Text ImageB ImageC ImageI".split()] # Write resource dictionary. # Possibly TODO: more general ExtGState (graphics state dictionaries) # ColorSpace Pattern Shading Properties - resources = {'Font': self.fontObject, - 'XObject': self.XObjectObject, - 'ExtGState': self.alphaStateObject, - 'Pattern': self.hatchObject, - 'Shading': self.gouraudObject, - 'ProcSet': procsets} + resources = { + "Font": self.fontObject, + "XObject": self.XObjectObject, + "ExtGState": self.alphaStateObject, + "Pattern": self.hatchObject, + "Shading": self.gouraudObject, + "ProcSet": procsets, + } self.writeObject(self.resourceObject, resources) def newPage(self, width, height): self.endStream() self.width, self.height = width, height - contentObject = self.reserveObject('page contents') - thePage = {'Type': Name('Page'), - 'Parent': self.pagesObject, - 'Resources': self.resourceObject, - 'MediaBox': [0, 0, 72 * width, 72 * height], - 'Contents': contentObject, - 'Group': {'Type': Name('Group'), - 'S': Name('Transparency'), - 'CS': Name('DeviceRGB')} - } - pageObject = self.reserveObject('page') + contentObject = self.reserveObject("page contents") + thePage = { + "Type": Name("Page"), + "Parent": self.pagesObject, + "Resources": self.resourceObject, + "MediaBox": [0, 0, 72 * width, 72 * height], + "Contents": contentObject, + "Group": { + "Type": Name("Group"), + "S": Name("Transparency"), + "CS": Name("DeviceRGB"), + }, + } + pageObject = self.reserveObject("page") self.writeObject(pageObject, thePage) self.pageList.append(pageObject) - self.beginStream(contentObject.id, - self.reserveObject('length of content stream')) + self.beginStream( + contentObject.id, self.reserveObject("length of content stream") + ) # Initialize the pdf graphics state to match the default mpl # graphics context: currently only the join style needs to be set - self.output(GraphicsContextPdf.joinstyles['round'], Op.setlinejoin) + self.output(GraphicsContextPdf.joinstyles["round"], Op.setlinejoin) def close(self): self.endStream() # Write out the various deferred objects self.writeFonts() - self.writeObject(self.alphaStateObject, - dict([(val[0], val[1]) - for val in six.itervalues(self.alphaStates)])) + self.writeObject( + self.alphaStateObject, + dict( + [(val[0], val[1]) for val in six.itervalues(self.alphaStates)] + ), + ) self.writeHatches() self.writeGouraudTriangles() xobjects = dict(six.itervalues(self.images)) @@ -533,17 +601,30 @@ def close(self): xobjects[tup[0]] = tup[1] for name, value in six.iteritems(self.multi_byte_charprocs): xobjects[name] = value - for name, path, trans, ob, join, cap, padding, filled, stroked \ - in self.paths: + for ( + name, + path, + trans, + ob, + join, + cap, + padding, + filled, + stroked, + ) in self.paths: xobjects[name] = ob self.writeObject(self.XObjectObject, xobjects) self.writeImages() self.writeMarkers() self.writePathCollectionTemplates() - self.writeObject(self.pagesObject, - {'Type': Name('Pages'), - 'Kids': self.pageList, - 'Count': len(self.pageList)}) + self.writeObject( + self.pagesObject, + { + "Type": Name("Pages"), + "Kids": self.pageList, + "Count": len(self.pageList), + }, + ) self.writeInfoDict() # Finalize the file @@ -565,7 +646,7 @@ def write(self, data): def output(self, *data): self.write(fill(list(map(pdfRepr, data)))) - self.write(b'\n') + self.write(b"\n") def beginStream(self, id, len, extra=None): assert self.currentstream is None @@ -585,43 +666,46 @@ def fontName(self, fontprop): if is_string_like(fontprop): filename = fontprop - elif rcParams['pdf.use14corefonts']: + elif rcParams["pdf.use14corefonts"]: filename = findfont( - fontprop, fontext='afm', directory=self._core14fontdir) + fontprop, fontext="afm", directory=self._core14fontdir + ) if filename is None: filename = findfont( - "Helvetica", fontext='afm', directory=self._core14fontdir) + "Helvetica", fontext="afm", directory=self._core14fontdir + ) else: filename = findfont(fontprop) Fx = self.fontNames.get(filename) if Fx is None: - Fx = Name('F%d' % self.nextFont) + Fx = Name("F%d" % self.nextFont) self.fontNames[filename] = Fx self.nextFont += 1 matplotlib.verbose.report( - 'Assigning font %s = %r' % (Fx, filename), - 'debug') + "Assigning font %s = %r" % (Fx, filename), "debug" + ) return Fx def writeFonts(self): fonts = {} for filename, Fx in six.iteritems(self.fontNames): - matplotlib.verbose.report('Embedding font %s' % filename, 'debug') - if filename.endswith('.afm'): + matplotlib.verbose.report("Embedding font %s" % filename, "debug") + if filename.endswith(".afm"): # from pdf.use14corefonts - matplotlib.verbose.report('Writing AFM font', 'debug') + matplotlib.verbose.report("Writing AFM font", "debug") fonts[Fx] = self._write_afm_font(filename) elif filename in self.dviFontInfo: # a Type 1 font from a dvi file; # the filename is really the TeX name - matplotlib.verbose.report('Writing Type-1 font', 'debug') - fonts[Fx] = self.embedTeXFont(filename, - self.dviFontInfo[filename]) + matplotlib.verbose.report("Writing Type-1 font", "debug") + fonts[Fx] = self.embedTeXFont( + filename, self.dviFontInfo[filename] + ) else: # a normal TrueType font - matplotlib.verbose.report('Writing TrueType font', 'debug') + matplotlib.verbose.report("Writing TrueType font", "debug") realpath, stat_key = get_realpath_and_stat(filename) chars = self.used_characters.get(stat_key) if chars is not None and len(chars[1]): @@ -629,54 +713,63 @@ def writeFonts(self): self.writeObject(self.fontObject, fonts) def _write_afm_font(self, filename): - with open(filename, 'rb') as fh: + with open(filename, "rb") as fh: font = AFM(fh) fontname = font.get_fontname() - fontdict = {'Type': Name('Font'), - 'Subtype': Name('Type1'), - 'BaseFont': Name(fontname), - 'Encoding': Name('WinAnsiEncoding')} - fontdictObject = self.reserveObject('font dictionary') + fontdict = { + "Type": Name("Font"), + "Subtype": Name("Type1"), + "BaseFont": Name(fontname), + "Encoding": Name("WinAnsiEncoding"), + } + fontdictObject = self.reserveObject("font dictionary") self.writeObject(fontdictObject, fontdict) return fontdictObject def embedTeXFont(self, texname, fontinfo): - msg = ('Embedding TeX font ' + texname + ' - fontinfo=' + - repr(fontinfo.__dict__)) - matplotlib.verbose.report(msg, 'debug') + msg = ( + "Embedding TeX font " + + texname + + " - fontinfo=" + + repr(fontinfo.__dict__) + ) + matplotlib.verbose.report(msg, "debug") # Widths - widthsObject = self.reserveObject('font widths') + widthsObject = self.reserveObject("font widths") self.writeObject(widthsObject, fontinfo.dvifont.widths) # Font dictionary - fontdictObject = self.reserveObject('font dictionary') + fontdictObject = self.reserveObject("font dictionary") fontdict = { - 'Type': Name('Font'), - 'Subtype': Name('Type1'), - 'FirstChar': 0, - 'LastChar': len(fontinfo.dvifont.widths) - 1, - 'Widths': widthsObject, - } + "Type": Name("Font"), + "Subtype": Name("Type1"), + "FirstChar": 0, + "LastChar": len(fontinfo.dvifont.widths) - 1, + "Widths": widthsObject, + } # Encoding (if needed) if fontinfo.encodingfile is not None: enc = dviread.Encoding(fontinfo.encodingfile) differencesArray = [Name(ch) for ch in enc] differencesArray = [0] + differencesArray - fontdict['Encoding'] = \ - {'Type': Name('Encoding'), - 'Differences': differencesArray} + fontdict["Encoding"] = { + "Type": Name("Encoding"), + "Differences": differencesArray, + } # If no file is specified, stop short if fontinfo.fontfile is None: - msg = ('Because of TeX configuration (pdftex.map, see updmap ' - 'option pdftexDownloadBase14) the font {0} is not ' - 'embedded. This is deprecated as of PDF 1.5 and it may ' - 'cause the consumer application to show something that ' - 'was not intended.').format(fontinfo.basefont) + msg = ( + "Because of TeX configuration (pdftex.map, see updmap " + "option pdftexDownloadBase14) the font {0} is not " + "embedded. This is deprecated as of PDF 1.5 and it may " + "cause the consumer application to show something that " + "was not intended." + ).format(fontinfo.basefont) warnings.warn(msg) - fontdict['BaseFont'] = Name(fontinfo.basefont) + fontdict["BaseFont"] = Name(fontinfo.basefont) self.writeObject(fontdictObject, fontdict) return fontdictObject @@ -684,18 +777,20 @@ def embedTeXFont(self, texname, fontinfo): t1font = type1font.Type1Font(fontinfo.fontfile) if fontinfo.effects: t1font = t1font.transform(fontinfo.effects) - fontdict['BaseFont'] = Name(t1font.prop['FontName']) + fontdict["BaseFont"] = Name(t1font.prop["FontName"]) # Font descriptors may be shared between differently encoded # Type-1 fonts, so only create a new descriptor if there is no # existing descriptor for this font. - effects = (fontinfo.effects.get('slant', 0.0), - fontinfo.effects.get('extend', 1.0)) + effects = ( + fontinfo.effects.get("slant", 0.0), + fontinfo.effects.get("extend", 1.0), + ) fontdesc = self.type1Descriptors.get((fontinfo.fontfile, effects)) if fontdesc is None: fontdesc = self.createType1Descriptor(t1font, fontinfo.fontfile) self.type1Descriptors[(fontinfo.fontfile, effects)] = fontdesc - fontdict['FontDescriptor'] = fontdesc + fontdict["FontDescriptor"] = fontdesc self.writeObject(fontdictObject, fontdict) return fontdictObject @@ -703,11 +798,11 @@ def embedTeXFont(self, texname, fontinfo): def createType1Descriptor(self, t1font, fontfile): # Create and write the font descriptor and the font file # of a Type-1 font - fontdescObject = self.reserveObject('font descriptor') - fontfileObject = self.reserveObject('font file') + fontdescObject = self.reserveObject("font descriptor") + fontfileObject = self.reserveObject("font file") - italic_angle = t1font.prop['ItalicAngle'] - fixed_pitch = t1font.prop['isFixedPitch'] + italic_angle = t1font.prop["ItalicAngle"] + fixed_pitch = t1font.prop["isFixedPitch"] flags = 0 # fixed width @@ -738,28 +833,33 @@ def createType1Descriptor(self, t1font, fontfile): ft2font = FT2Font(fontfile) descriptor = { - 'Type': Name('FontDescriptor'), - 'FontName': Name(t1font.prop['FontName']), - 'Flags': flags, - 'FontBBox': ft2font.bbox, - 'ItalicAngle': italic_angle, - 'Ascent': ft2font.ascender, - 'Descent': ft2font.descender, - 'CapHeight': 1000, # TODO: find this out - 'XHeight': 500, # TODO: this one too - 'FontFile': fontfileObject, - 'FontFamily': t1font.prop['FamilyName'], - 'StemV': 50, # TODO + "Type": Name("FontDescriptor"), + "FontName": Name(t1font.prop["FontName"]), + "Flags": flags, + "FontBBox": ft2font.bbox, + "ItalicAngle": italic_angle, + "Ascent": ft2font.ascender, + "Descent": ft2font.descender, + "CapHeight": 1000, # TODO: find this out + "XHeight": 500, # TODO: this one too + "FontFile": fontfileObject, + "FontFamily": t1font.prop["FamilyName"], + "StemV": 50, # TODO # (see also revision 3874; but not all TeX distros have AFM files!) #'FontWeight': a number where 400 = Regular, 700 = Bold - } + } self.writeObject(fontdescObject, descriptor) - self.beginStream(fontfileObject.id, None, - {'Length1': len(t1font.parts[0]), - 'Length2': len(t1font.parts[1]), - 'Length3': 0}) + self.beginStream( + fontfileObject.id, + None, + { + "Length1": len(t1font.parts[0]), + "Length2": len(t1font.parts[1]), + "Length3": 0, + }, + ) self.currentstream.write(t1font.parts[0]) self.currentstream.write(t1font.parts[1]) self.endStream() @@ -769,7 +869,8 @@ def createType1Descriptor(self, t1font, fontfile): def _get_xobject_symbol_name(self, filename, symbol_name): return "%s-%s" % ( os.path.splitext(os.path.basename(filename))[0], - symbol_name) + symbol_name, + ) _identityToUnicodeCMap = """/CIDInit /ProcSet findresource begin 12 dict begin @@ -796,7 +897,7 @@ def embedTTF(self, filename, characters): """Embed the TTF font from the named file into the document.""" font = FT2Font(filename) - fonttype = rcParams['pdf.fonttype'] + fonttype = rcParams["pdf.fonttype"] def cvt(length, upe=font.units_per_EM, nearest=True): "Convert font coordinates to PDF glyph coordinates" @@ -812,51 +913,59 @@ def cvt(length, upe=font.units_per_EM, nearest=True): def embedTTFType3(font, characters, descriptor): """The Type 3-specific part of embedding a Truetype font""" - widthsObject = self.reserveObject('font widths') - fontdescObject = self.reserveObject('font descriptor') - fontdictObject = self.reserveObject('font dictionary') - charprocsObject = self.reserveObject('character procs') + widthsObject = self.reserveObject("font widths") + fontdescObject = self.reserveObject("font descriptor") + fontdictObject = self.reserveObject("font dictionary") + charprocsObject = self.reserveObject("character procs") differencesArray = [] firstchar, lastchar = 0, 255 bbox = [cvt(x, nearest=False) for x in font.bbox] fontdict = { - 'Type': Name('Font'), - 'BaseFont': ps_name, - 'FirstChar': firstchar, - 'LastChar': lastchar, - 'FontDescriptor': fontdescObject, - 'Subtype': Name('Type3'), - 'Name': descriptor['FontName'], - 'FontBBox': bbox, - 'FontMatrix': [.001, 0, 0, .001, 0, 0], - 'CharProcs': charprocsObject, - 'Encoding': { - 'Type': Name('Encoding'), - 'Differences': differencesArray}, - 'Widths': widthsObject - } + "Type": Name("Font"), + "BaseFont": ps_name, + "FirstChar": firstchar, + "LastChar": lastchar, + "FontDescriptor": fontdescObject, + "Subtype": Name("Type3"), + "Name": descriptor["FontName"], + "FontBBox": bbox, + "FontMatrix": [0.001, 0, 0, 0.001, 0, 0], + "CharProcs": charprocsObject, + "Encoding": { + "Type": Name("Encoding"), + "Differences": differencesArray, + }, + "Widths": widthsObject, + } # Make the "Widths" array from encodings import cp1252 + # The "decoding_map" was changed # to a "decoding_table" as of Python 2.5. - if hasattr(cp1252, 'decoding_map'): + if hasattr(cp1252, "decoding_map"): + def decode_char(charcode): return cp1252.decoding_map[charcode] or 0 + else: + def decode_char(charcode): return ord(cp1252.decoding_table[charcode]) def get_char_width(charcode): s = decode_char(charcode) width = font.load_char( - s, flags=LOAD_NO_SCALE | LOAD_NO_HINTING).horiAdvance + s, flags=LOAD_NO_SCALE | LOAD_NO_HINTING + ).horiAdvance return cvt(width) - widths = [get_char_width(charcode) - for charcode in range(firstchar, lastchar+1)] - descriptor['MaxWidth'] = max(widths) + widths = [ + get_char_width(charcode) + for charcode in range(firstchar, lastchar + 1) + ] + descriptor["MaxWidth"] = max(widths) # Make the "Differences" array, sort the ccodes < 255 from # the multi-byte ccodes, and build the whole set of glyph ids @@ -886,24 +995,25 @@ def get_char_width(charcode): # Make the charprocs array (using ttconv to generate the # actual outlines) rawcharprocs = ttconv.get_pdf_charprocs( - filename.encode(sys.getfilesystemencoding()), glyph_ids) + filename.encode(sys.getfilesystemencoding()), glyph_ids + ) charprocs = {} for charname, stream in six.iteritems(rawcharprocs): - charprocDict = {'Length': len(stream)} + charprocDict = {"Length": len(stream)} # The 2-byte characters are used as XObjects, so they # need extra info in their dictionary if charname in multi_byte_chars: - charprocDict['Type'] = Name('XObject') - charprocDict['Subtype'] = Name('Form') - charprocDict['BBox'] = bbox + charprocDict["Type"] = Name("XObject") + charprocDict["Subtype"] = Name("Form") + charprocDict["BBox"] = bbox # Each glyph includes bounding box information, # but xpdf and ghostscript can't handle it in a # Form XObject (they segfault!!!), so we remove it # from the stream here. It's not needed anyway, # since the Form XObject includes it in its BBox # value. - stream = stream[stream.find(b"d1") + 2:] - charprocObject = self.reserveObject('charProc') + stream = stream[stream.find(b"d1") + 2 :] + charprocObject = self.reserveObject("charProc") self.beginStream(charprocObject.id, None, charprocDict) self.currentstream.write(stream) self.endStream() @@ -926,44 +1036,46 @@ def get_char_width(charcode): def embedTTFType42(font, characters, descriptor): """The Type 42-specific part of embedding a Truetype font""" - fontdescObject = self.reserveObject('font descriptor') - cidFontDictObject = self.reserveObject('CID font dictionary') - type0FontDictObject = self.reserveObject('Type 0 font dictionary') - cidToGidMapObject = self.reserveObject('CIDToGIDMap stream') - fontfileObject = self.reserveObject('font file stream') - wObject = self.reserveObject('Type 0 widths') - toUnicodeMapObject = self.reserveObject('ToUnicode map') + fontdescObject = self.reserveObject("font descriptor") + cidFontDictObject = self.reserveObject("CID font dictionary") + type0FontDictObject = self.reserveObject("Type 0 font dictionary") + cidToGidMapObject = self.reserveObject("CIDToGIDMap stream") + fontfileObject = self.reserveObject("font file stream") + wObject = self.reserveObject("Type 0 widths") + toUnicodeMapObject = self.reserveObject("ToUnicode map") cidFontDict = { - 'Type': Name('Font'), - 'Subtype': Name('CIDFontType2'), - 'BaseFont': ps_name, - 'CIDSystemInfo': { - 'Registry': 'Adobe', - 'Ordering': 'Identity', - 'Supplement': 0}, - 'FontDescriptor': fontdescObject, - 'W': wObject, - 'CIDToGIDMap': cidToGidMapObject - } + "Type": Name("Font"), + "Subtype": Name("CIDFontType2"), + "BaseFont": ps_name, + "CIDSystemInfo": { + "Registry": "Adobe", + "Ordering": "Identity", + "Supplement": 0, + }, + "FontDescriptor": fontdescObject, + "W": wObject, + "CIDToGIDMap": cidToGidMapObject, + } type0FontDict = { - 'Type': Name('Font'), - 'Subtype': Name('Type0'), - 'BaseFont': ps_name, - 'Encoding': Name('Identity-H'), - 'DescendantFonts': [cidFontDictObject], - 'ToUnicode': toUnicodeMapObject - } + "Type": Name("Font"), + "Subtype": Name("Type0"), + "BaseFont": ps_name, + "Encoding": Name("Identity-H"), + "DescendantFonts": [cidFontDictObject], + "ToUnicode": toUnicodeMapObject, + } # Make fontfile stream - descriptor['FontFile2'] = fontfileObject - length1Object = self.reserveObject('decoded length of a font') + descriptor["FontFile2"] = fontfileObject + length1Object = self.reserveObject("decoded length of a font") self.beginStream( fontfileObject.id, - self.reserveObject('length of font stream'), - {'Length1': length1Object}) - with open(filename, 'rb') as fontfile: + self.reserveObject("length of font stream"), + {"Length1": length1Object}, + ) + with open(filename, "rb") as fontfile: length1 = 0 while True: data = fontfile.read(4096) @@ -976,7 +1088,7 @@ def embedTTFType42(font, characters, descriptor): # Make the 'W' (Widths) array, CidToGidMap and ToUnicode CMap # at the same time - cid_to_gid_map = ['\\u0000'] * 65536 + cid_to_gid_map = ["\\u0000"] * 65536 cmap = font.get_charmap() widths = [] max_ccode = 0 @@ -989,7 +1101,7 @@ def embedTTFType42(font, characters, descriptor): cid_to_gid_map[ccode] = chr(gind) max_ccode = max(ccode, max_ccode) widths.sort() - cid_to_gid_map = cid_to_gid_map[:max_ccode + 1] + cid_to_gid_map = cid_to_gid_map[: max_ccode + 1] last_ccode = -2 w = [] @@ -1009,29 +1121,34 @@ def embedTTFType42(font, characters, descriptor): unicode_bfrange = [] for start, end in unicode_groups: unicode_bfrange.append( - "<%04x> <%04x> [%s]" % - (start, end, - " ".join(["<%04x>" % x for x in range(start, end+1)]))) - unicode_cmap = (self._identityToUnicodeCMap % - (len(unicode_groups), - "\n".join(unicode_bfrange))).encode('ascii') + "<%04x> <%04x> [%s]" + % ( + start, + end, + " ".join(["<%04x>" % x for x in range(start, end + 1)]), + ) + ) + unicode_cmap = ( + self._identityToUnicodeCMap + % (len(unicode_groups), "\n".join(unicode_bfrange)) + ).encode("ascii") # CIDToGIDMap stream cid_to_gid_map = "".join(cid_to_gid_map).encode("utf-16be") - self.beginStream(cidToGidMapObject.id, - None, - {'Length': len(cid_to_gid_map)}) + self.beginStream( + cidToGidMapObject.id, None, {"Length": len(cid_to_gid_map)} + ) self.currentstream.write(cid_to_gid_map) self.endStream() # ToUnicode CMap - self.beginStream(toUnicodeMapObject.id, - None, - {'Length': unicode_cmap}) + self.beginStream( + toUnicodeMapObject.id, None, {"Length": unicode_cmap} + ) self.currentstream.write(unicode_cmap) self.endStream() - descriptor['MaxWidth'] = max_width + descriptor["MaxWidth"] = max_width # Write everything out self.writeObject(cidFontDictObject, cidFontDict) @@ -1046,15 +1163,15 @@ def embedTTFType42(font, characters, descriptor): # You are lost in a maze of TrueType tables, all different... sfnt = font.get_sfnt() try: - ps_name = sfnt[(1, 0, 0, 6)].decode('macroman') # Macintosh scheme + ps_name = sfnt[(1, 0, 0, 6)].decode("macroman") # Macintosh scheme except KeyError: # Microsoft scheme: - ps_name = sfnt[(3, 1, 0x0409, 6)].decode('utf-16be') + ps_name = sfnt[(3, 1, 0x0409, 6)].decode("utf-16be") # (see freetype/ttnameid.h) - ps_name = ps_name.encode('ascii', 'replace') + ps_name = ps_name.encode("ascii", "replace") ps_name = Name(ps_name) - pclt = font.get_sfnt_table('pclt') or {'capHeight': 0, 'xHeight': 0} - post = font.get_sfnt_table('post') or {'italicAngle': (0, 0)} + pclt = font.get_sfnt_table("pclt") or {"capHeight": 0, "xHeight": 0} + post = font.get_sfnt_table("post") or {"italicAngle": (0, 0)} ff = font.face_flags sf = font.style_flags @@ -1078,25 +1195,27 @@ def embedTTFType42(font, characters, descriptor): flags |= 1 << 18 descriptor = { - 'Type': Name('FontDescriptor'), - 'FontName': ps_name, - 'Flags': flags, - 'FontBBox': [cvt(x, nearest=False) for x in font.bbox], - 'Ascent': cvt(font.ascender, nearest=False), - 'Descent': cvt(font.descender, nearest=False), - 'CapHeight': cvt(pclt['capHeight'], nearest=False), - 'XHeight': cvt(pclt['xHeight']), - 'ItalicAngle': post['italicAngle'][1], # ??? - 'StemV': 0 # ??? - } + "Type": Name("FontDescriptor"), + "FontName": ps_name, + "Flags": flags, + "FontBBox": [cvt(x, nearest=False) for x in font.bbox], + "Ascent": cvt(font.ascender, nearest=False), + "Descent": cvt(font.descender, nearest=False), + "CapHeight": cvt(pclt["capHeight"], nearest=False), + "XHeight": cvt(pclt["xHeight"]), + "ItalicAngle": post["italicAngle"][1], # ??? + "StemV": 0, # ??? + } # The font subsetting to a Type 3 font does not work for # OpenType (.otf) that embed a Postscript CFF font, so avoid that -- # save as a (non-subsetted) Type 42 font instead. if is_opentype_cff_font(filename): fonttype = 42 - msg = ("'%s' can not be subsetted into a Type 3 font. " - "The entire font will be embedded in the output.") + msg = ( + "'%s' can not be subsetted into a Type 3 font. " + "The entire font will be embedded in the output." + ) warnings.warn(msg % os.path.basename(filename)) if fonttype == 3: @@ -1111,11 +1230,12 @@ def alphaState(self, alpha): if state is not None: return state[0] - name = Name('A%d' % self.nextAlphaState) + name = Name("A%d" % self.nextAlphaState) self.nextAlphaState += 1 - self.alphaStates[alpha] = \ - (name, {'Type': Name('ExtGState'), - 'CA': alpha[0], 'ca': alpha[1]}) + self.alphaStates[alpha] = ( + name, + {"Type": Name("ExtGState"), "CA": alpha[0], "ca": alpha[1]}, + ) return name def hatchPattern(self, hatch_style): @@ -1132,7 +1252,7 @@ def hatchPattern(self, hatch_style): if pattern is not None: return pattern - name = Name('H%d' % self.nextHatch) + name = Name("H%d" % self.nextHatch) self.nextHatch += 1 self.hatchPatterns[hatch_style] = name return name @@ -1141,17 +1261,27 @@ def writeHatches(self): hatchDict = dict() sidelen = 72.0 for hatch_style, name in six.iteritems(self.hatchPatterns): - ob = self.reserveObject('hatch pattern') + ob = self.reserveObject("hatch pattern") hatchDict[name] = ob - res = {'Procsets': - [Name(x) for x in "PDF Text ImageB ImageC ImageI".split()]} + res = { + "Procsets": [ + Name(x) for x in "PDF Text ImageB ImageC ImageI".split() + ] + } self.beginStream( - ob.id, None, - {'Type': Name('Pattern'), - 'PatternType': 1, 'PaintType': 1, 'TilingType': 1, - 'BBox': [0, 0, sidelen, sidelen], - 'XStep': sidelen, 'YStep': sidelen, - 'Resources': res}) + ob.id, + None, + { + "Type": Name("Pattern"), + "PatternType": 1, + "PaintType": 1, + "TilingType": 1, + "BBox": [0, 0, sidelen, sidelen], + "XStep": sidelen, + "YStep": sidelen, + "Resources": res, + }, + ) # lst is a tuple of stroke color, fill color, # number of - lines, number of / lines, @@ -1160,62 +1290,89 @@ def writeHatches(self): self.output(rgb[0], rgb[1], rgb[2], Op.setrgb_stroke) if hatch_style[1] is not None: rgb = hatch_style[1] - self.output(rgb[0], rgb[1], rgb[2], Op.setrgb_nonstroke, - 0, 0, sidelen, sidelen, Op.rectangle, - Op.fill) + self.output( + rgb[0], + rgb[1], + rgb[2], + Op.setrgb_nonstroke, + 0, + 0, + sidelen, + sidelen, + Op.rectangle, + Op.fill, + ) # [TEG] Trying to change hatch line width (default 0.1) self.output(0.8, Op.setlinewidth) # TODO: We could make this dpi-dependent, but that would be # an API change - self.output(*self.pathOperations( - Path.hatch(hatch_style[2]), - Affine2D().scale(sidelen), - simplify=False)) + self.output( + *self.pathOperations( + Path.hatch(hatch_style[2]), + Affine2D().scale(sidelen), + simplify=False, + ) + ) self.output(Op.stroke) self.endStream() self.writeObject(self.hatchObject, hatchDict) def addGouraudTriangles(self, points, colors): - name = Name('GT%d' % len(self.gouraudTriangles)) + name = Name("GT%d" % len(self.gouraudTriangles)) self.gouraudTriangles.append((name, points, colors)) return name def writeGouraudTriangles(self): gouraudDict = dict() for name, points, colors in self.gouraudTriangles: - ob = self.reserveObject('Gouraud triangle') + ob = self.reserveObject("Gouraud triangle") gouraudDict[name] = ob shape = points.shape flat_points = points.reshape((shape[0] * shape[1], 2)) flat_colors = colors.reshape((shape[0] * shape[1], 4)) points_min = np.min(flat_points, axis=0) - (1 << 8) points_max = np.max(flat_points, axis=0) + (1 << 8) - factor = float(0xffffffff) / (points_max - points_min) + factor = float(0xFFFFFFFF) / (points_max - points_min) self.beginStream( - ob.id, None, - {'ShadingType': 4, - 'BitsPerCoordinate': 32, - 'BitsPerComponent': 8, - 'BitsPerFlag': 8, - 'ColorSpace': Name('DeviceRGB'), - 'AntiAlias': True, - 'Decode': [points_min[0], points_max[0], - points_min[1], points_max[1], - 0, 1, 0, 1, 0, 1] - }) + ob.id, + None, + { + "ShadingType": 4, + "BitsPerCoordinate": 32, + "BitsPerComponent": 8, + "BitsPerFlag": 8, + "ColorSpace": Name("DeviceRGB"), + "AntiAlias": True, + "Decode": [ + points_min[0], + points_max[0], + points_min[1], + points_max[1], + 0, + 1, + 0, + 1, + 0, + 1, + ], + }, + ) streamarr = np.empty( (shape[0] * shape[1],), - dtype=[(str('flags'), str('u1')), - (str('points'), str('>u4'), (2,)), - (str('colors'), str('u1'), (3,))]) - streamarr['flags'] = 0 - streamarr['points'] = (flat_points - points_min) * factor - streamarr['colors'] = flat_colors[:, :3] * 255.0 + dtype=[ + (str("flags"), str("u1")), + (str("points"), str(">u4"), (2,)), + (str("colors"), str("u1"), (3,)), + ], + ) + streamarr["flags"] = 0 + streamarr["points"] = (flat_points - points_min) * factor + streamarr["colors"] = flat_colors[:, :3] * 255.0 self.write(streamarr.tostring()) self.endStream() @@ -1228,8 +1385,8 @@ def imageObject(self, image): if pair is not None: return pair[0] - name = Name('I%d' % self.nextImage) - ob = self.reserveObject('image %d' % self.nextImage) + name = Name("I%d" % self.nextImage) + ob = self.reserveObject("image %d" % self.nextImage) self.nextImage += 1 self.images[image] = (name, ob) return name @@ -1254,7 +1411,7 @@ def _gray(self, im, rc=0.3, gc=0.59, bc=0.11): r = rgba_f[:, :, 0] g = rgba_f[:, :, 1] b = rgba_f[:, :, 2] - gray = (r*rc + g*gc + b*bc).astype(np.uint8) + gray = (r * rc + g * gc + b * bc).astype(np.uint8) return rgbat[0], rgbat[1], gray.tostring() def writeImages(self): @@ -1264,10 +1421,16 @@ def writeImages(self): height, width, data = self._gray(img) self.beginStream( pair[1].id, - self.reserveObject('length of image stream'), - {'Type': Name('XObject'), 'Subtype': Name('Image'), - 'Width': width, 'Height': height, - 'ColorSpace': Name('DeviceGray'), 'BitsPerComponent': 8}) + self.reserveObject("length of image stream"), + { + "Type": Name("XObject"), + "Subtype": Name("Image"), + "Width": width, + "Height": height, + "ColorSpace": Name("DeviceGray"), + "BitsPerComponent": 8, + }, + ) # TODO: predictors (i.e., output png) self.currentstream.write(data) self.endStream() @@ -1276,29 +1439,42 @@ def writeImages(self): smaskObject = self.reserveObject("smask") self.beginStream( smaskObject.id, - self.reserveObject('length of smask stream'), - {'Type': Name('XObject'), 'Subtype': Name('Image'), - 'Width': width, 'Height': height, - 'ColorSpace': Name('DeviceGray'), 'BitsPerComponent': 8}) + self.reserveObject("length of smask stream"), + { + "Type": Name("XObject"), + "Subtype": Name("Image"), + "Width": width, + "Height": height, + "ColorSpace": Name("DeviceGray"), + "BitsPerComponent": 8, + }, + ) # TODO: predictors (i.e., output png) self.currentstream.write(adata) self.endStream() self.beginStream( pair[1].id, - self.reserveObject('length of image stream'), - {'Type': Name('XObject'), 'Subtype': Name('Image'), - 'Width': width, 'Height': height, - 'ColorSpace': Name('DeviceRGB'), 'BitsPerComponent': 8, - 'SMask': smaskObject}) + self.reserveObject("length of image stream"), + { + "Type": Name("XObject"), + "Subtype": Name("Image"), + "Width": width, + "Height": height, + "ColorSpace": Name("DeviceRGB"), + "BitsPerComponent": 8, + "SMask": smaskObject, + }, + ) # TODO: predictors (i.e., output png) self.currentstream.write(data) self.endStream() img.flipud_out() - def markerObject(self, path, trans, fillp, strokep, lw, joinstyle, - capstyle): + def markerObject( + self, path, trans, fillp, strokep, lw, joinstyle, capstyle + ): """Return name of a marker XObject representing the given path.""" # self.markers used by markerObject, writeMarkers, close: # mapping from (path operations, fill?, stroke?) to @@ -1316,8 +1492,8 @@ def markerObject(self, path, trans, fillp, strokep, lw, joinstyle, key = (tuple(pathops), bool(fillp), bool(strokep), joinstyle, capstyle) result = self.markers.get(key) if result is None: - name = Name('M%d' % len(self.markers)) - ob = self.reserveObject('marker %d' % len(self.markers)) + name = Name("M%d" % len(self.markers)) + ob = self.reserveObject("marker %d" % len(self.markers)) bbox = path.get_extents(trans) self.markers[key] = [name, ob, bbox, lw] else: @@ -1327,31 +1503,58 @@ def markerObject(self, path, trans, fillp, strokep, lw, joinstyle, return name def writeMarkers(self): - for ((pathops, fillp, strokep, joinstyle, capstyle), - (name, ob, bbox, lw)) in six.iteritems(self.markers): + for ( + (pathops, fillp, strokep, joinstyle, capstyle), + (name, ob, bbox, lw), + ) in six.iteritems(self.markers): bbox = bbox.padded(lw * 0.5) self.beginStream( - ob.id, None, - {'Type': Name('XObject'), 'Subtype': Name('Form'), - 'BBox': list(bbox.extents)}) - self.output(GraphicsContextPdf.joinstyles[joinstyle], - Op.setlinejoin) + ob.id, + None, + { + "Type": Name("XObject"), + "Subtype": Name("Form"), + "BBox": list(bbox.extents), + }, + ) + self.output( + GraphicsContextPdf.joinstyles[joinstyle], Op.setlinejoin + ) self.output(GraphicsContextPdf.capstyles[capstyle], Op.setlinecap) self.output(*pathops) self.output(Op.paint_path(False, fillp, strokep)) self.endStream() def pathCollectionObject(self, gc, path, trans, padding, filled, stroked): - name = Name('P%d' % len(self.paths)) - ob = self.reserveObject('path %d' % len(self.paths)) + name = Name("P%d" % len(self.paths)) + ob = self.reserveObject("path %d" % len(self.paths)) self.paths.append( - (name, path, trans, ob, gc.get_joinstyle(), gc.get_capstyle(), - padding, filled, stroked)) + ( + name, + path, + trans, + ob, + gc.get_joinstyle(), + gc.get_capstyle(), + padding, + filled, + stroked, + ) + ) return name def writePathCollectionTemplates(self): - for (name, path, trans, ob, joinstyle, capstyle, padding, filled, - stroked) in self.paths: + for ( + name, + path, + trans, + ob, + joinstyle, + capstyle, + padding, + filled, + stroked, + ) in self.paths: pathops = self.pathOperations(path, trans, simplify=False) bbox = path.get_extents(trans) if not np.all(np.isfinite(bbox.extents)): @@ -1360,11 +1563,17 @@ def writePathCollectionTemplates(self): bbox = bbox.padded(padding) extents = list(bbox.extents) self.beginStream( - ob.id, None, - {'Type': Name('XObject'), 'Subtype': Name('Form'), - 'BBox': extents}) - self.output(GraphicsContextPdf.joinstyles[joinstyle], - Op.setlinejoin) + ob.id, + None, + { + "Type": Name("XObject"), + "Subtype": Name("Form"), + "BBox": extents, + }, + ) + self.output( + GraphicsContextPdf.joinstyles[joinstyle], Op.setlinejoin + ) self.output(GraphicsContextPdf.capstyles[capstyle], Op.setlinecap) self.output(*pathops) self.output(Op.paint_path(False, filled, stroked)) @@ -1374,9 +1583,9 @@ def writePathCollectionTemplates(self): def pathOperations(path, transform, clip=None, simplify=None, sketch=None): cmds = [] last_points = None - for points, code in path.iter_segments(transform, clip=clip, - simplify=simplify, - sketch=sketch): + for points, code in path.iter_segments( + transform, clip=clip, simplify=simplify, sketch=sketch + ): if code == Path.MOVETO: # This is allowed anywhere in the path cmds.extend(points) @@ -1385,7 +1594,7 @@ def pathOperations(path, transform, clip=None, simplify=None, sketch=None): cmds.append(Op.closepath) elif last_points is None: # The other operations require a previous point - raise ValueError('Path lacks initial MOVETO') + raise ValueError("Path lacks initial MOVETO") elif code == Path.LINETO: cmds.extend(points) cmds.append(Op.lineto) @@ -1406,11 +1615,12 @@ def writePath(self, path, transform, clip=False, sketch=None): else: clip = None simplify = False - cmds = self.pathOperations(path, transform, clip, simplify=simplify, - sketch=sketch) + cmds = self.pathOperations( + path, transform, clip, simplify=simplify, sketch=sketch + ) self.output(*cmds) - def reserveObject(self, name=''): + def reserveObject(self, name=""): """Reserve an ID for an indirect object. The name is used for debugging in case we forget to print out the object with writeObject. @@ -1432,61 +1642,73 @@ def writeXref(self): """Write out the xref table.""" self.startxref = self.fh.tell() - self.tell_base - self.write(("xref\n0 %d\n" % self.nextObject).encode('ascii')) + self.write(("xref\n0 %d\n" % self.nextObject).encode("ascii")) i = 0 borken = False for offset, generation, name in self.xrefTable: if offset is None: - print('No offset for object %d (%s)' % (i, name), - file=sys.stderr) + print( + "No offset for object %d (%s)" % (i, name), file=sys.stderr + ) borken = True else: - if name == 'the zero object': + if name == "the zero object": key = "f" else: key = "n" text = "%010d %05d %s \n" % (offset, generation, key) - self.write(text.encode('ascii')) + self.write(text.encode("ascii")) i += 1 if borken: - raise AssertionError('Indirect object does not exist') + raise AssertionError("Indirect object does not exist") def writeInfoDict(self): """Write out the info dictionary, checking it for good form""" is_date = lambda x: isinstance(x, datetime) - check_trapped = (lambda x: isinstance(x, Name) and - x.name in ('True', 'False', 'Unknown')) - keywords = {'Title': is_string_like, - 'Author': is_string_like, - 'Subject': is_string_like, - 'Keywords': is_string_like, - 'Creator': is_string_like, - 'Producer': is_string_like, - 'CreationDate': is_date, - 'ModDate': is_date, - 'Trapped': check_trapped} + check_trapped = lambda x: isinstance(x, Name) and x.name in ( + "True", + "False", + "Unknown", + ) + keywords = { + "Title": is_string_like, + "Author": is_string_like, + "Subject": is_string_like, + "Keywords": is_string_like, + "Creator": is_string_like, + "Producer": is_string_like, + "CreationDate": is_date, + "ModDate": is_date, + "Trapped": check_trapped, + } for k in six.iterkeys(self.infoDict): if k not in keywords: - warnings.warn('Unknown infodict keyword: %s' % k) + warnings.warn("Unknown infodict keyword: %s" % k) else: if not keywords[k](self.infoDict[k]): - warnings.warn('Bad value for infodict keyword %s' % k) + warnings.warn("Bad value for infodict keyword %s" % k) - self.infoObject = self.reserveObject('info') + self.infoObject = self.reserveObject("info") self.writeObject(self.infoObject, self.infoDict) def writeTrailer(self): """Write out the PDF trailer.""" self.write(b"trailer\n") - self.write(pdfRepr( - {'Size': self.nextObject, - 'Root': self.rootObject, - 'Info': self.infoObject})) + self.write( + pdfRepr( + { + "Size": self.nextObject, + "Root": self.rootObject, + "Info": self.infoObject, + } + ) + ) # Could add 'ID' - self.write(("\nstartxref\n%d\n%%%%EOF\n" % - self.startxref).encode('ascii')) + self.write( + ("\nstartxref\n%d\n%%%%EOF\n" % self.startxref).encode("ascii") + ) class RendererPdf(RendererBase): @@ -1505,10 +1727,10 @@ def finalize(self): self.file.output(*self.gc.finalize()) def check_gc(self, gc, fillcolor=None): - orig_fill = getattr(gc, '_fillcolor', (0., 0., 0.)) + orig_fill = getattr(gc, "_fillcolor", (0.0, 0.0, 0.0)) gc._fillcolor = fillcolor - orig_alphas = getattr(gc, '_effective_alphas', (1.0, 1.0)) + orig_alphas = getattr(gc, "_effective_alphas", (1.0, 1.0)) if gc._forced_alpha: gc._effective_alphas = (gc._alpha, gc._alpha) @@ -1527,8 +1749,9 @@ def check_gc(self, gc, fillcolor=None): def tex_font_mapping(self, texfont): if self.tex_font_map is None: - self.tex_font_map = \ - dviread.PsfontsMap(dviread.find_tex_file('pdftex.map')) + self.tex_font_map = dviread.PsfontsMap( + dviread.find_tex_file("pdftex.map") + ) return self.tex_font_map[texfont] def track_characters(self, font, s): @@ -1540,17 +1763,19 @@ def track_characters(self, font, s): fname = font.fname realpath, stat_key = get_realpath_and_stat(fname) used_characters = self.file.used_characters.setdefault( - stat_key, (realpath, set())) + stat_key, (realpath, set()) + ) used_characters[1].update([ord(x) for x in s]) def merge_used_characters(self, other): for stat_key, (realpath, charset) in six.iteritems(other): used_characters = self.file.used_characters.setdefault( - stat_key, (realpath, set())) + stat_key, (realpath, set()) + ) used_characters[1].update(charset) def get_image_magnification(self): - return self.image_dpi/72.0 + return self.image_dpi / 72.0 def option_scale_image(self): """ @@ -1564,41 +1789,81 @@ def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): h, w = im.get_size_out() if dx is None: - w = 72.0*w/self.image_dpi + w = 72.0 * w / self.image_dpi else: w = dx if dy is None: - h = 72.0*h/self.image_dpi + h = 72.0 * h / self.image_dpi else: h = dy imob = self.file.imageObject(im) if transform is None: - self.file.output(Op.gsave, - w, 0, 0, h, x, y, Op.concat_matrix, - imob, Op.use_xobject, Op.grestore) + self.file.output( + Op.gsave, + w, + 0, + 0, + h, + x, + y, + Op.concat_matrix, + imob, + Op.use_xobject, + Op.grestore, + ) else: tr1, tr2, tr3, tr4, tr5, tr6 = transform.to_values() - self.file.output(Op.gsave, - tr1, tr2, tr3, tr4, tr5, tr6, Op.concat_matrix, - w, 0, 0, h, x, y, Op.concat_matrix, - imob, Op.use_xobject, Op.grestore) + self.file.output( + Op.gsave, + tr1, + tr2, + tr3, + tr4, + tr5, + tr6, + Op.concat_matrix, + w, + 0, + 0, + h, + x, + y, + Op.concat_matrix, + imob, + Op.use_xobject, + Op.grestore, + ) def draw_path(self, gc, path, transform, rgbFace=None): self.check_gc(gc, rgbFace) self.file.writePath( - path, transform, + path, + transform, rgbFace is None and gc.get_hatch_path() is None, - gc.get_sketch_params()) + gc.get_sketch_params(), + ) self.file.output(self.gc.paint()) - def draw_path_collection(self, gc, master_transform, paths, all_transforms, - offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds, urls, - offset_position): + def draw_path_collection( + self, + gc, + master_transform, + paths, + all_transforms, + offsets, + offsetTrans, + facecolors, + edgecolors, + linewidths, + linestyles, + antialiaseds, + urls, + offset_position, + ): # We can only reuse the objects if the presence of fill and # stroke (and the amount of alpha for each) is the same for # all of them @@ -1625,41 +1890,70 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms, if not can_do_optimization: return RendererBase.draw_path_collection( - self, gc, master_transform, paths, all_transforms, - offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds, urls, - offset_position) + self, + gc, + master_transform, + paths, + all_transforms, + offsets, + offsetTrans, + facecolors, + edgecolors, + linewidths, + linestyles, + antialiaseds, + urls, + offset_position, + ) padding = np.max(linewidths) path_codes = [] - for i, (path, transform) in enumerate(self._iter_collection_raw_paths( - master_transform, paths, all_transforms)): + for i, (path, transform) in enumerate( + self._iter_collection_raw_paths( + master_transform, paths, all_transforms + ) + ): name = self.file.pathCollectionObject( - gc, path, transform, padding, filled, stroked) + gc, path, transform, padding, filled, stroked + ) path_codes.append(name) output = self.file.output output(*self.gc.push()) lastx, lasty = 0, 0 for xo, yo, path_id, gc0, rgbFace in self._iter_collection( - gc, master_transform, all_transforms, path_codes, offsets, - offsetTrans, facecolors, edgecolors, linewidths, linestyles, - antialiaseds, urls, offset_position): + gc, + master_transform, + all_transforms, + path_codes, + offsets, + offsetTrans, + facecolors, + edgecolors, + linewidths, + linestyles, + antialiaseds, + urls, + offset_position, + ): self.check_gc(gc0, rgbFace) dx, dy = xo - lastx, yo - lasty - output(1, 0, 0, 1, dx, dy, Op.concat_matrix, path_id, - Op.use_xobject) + output( + 1, 0, 0, 1, dx, dy, Op.concat_matrix, path_id, Op.use_xobject + ) lastx, lasty = xo, yo output(*self.gc.pop()) - def draw_markers(self, gc, marker_path, marker_trans, path, trans, - rgbFace=None): + def draw_markers( + self, gc, marker_path, marker_trans, path, trans, rgbFace=None + ): # For simple paths or small numbers of markers, don't bother # making an XObject if len(path) * len(marker_path) <= 10: - RendererBase.draw_markers(self, gc, marker_path, marker_trans, - path, trans, rgbFace) + RendererBase.draw_markers( + self, gc, marker_path, marker_trans, path, trans, rgbFace + ) return self.check_gc(gc, rgbFace) @@ -1668,31 +1962,42 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, output = self.file.output marker = self.file.markerObject( - marker_path, marker_trans, fillp, strokep, self.gc._linewidth, - gc.get_joinstyle(), gc.get_capstyle()) + marker_path, + marker_trans, + fillp, + strokep, + self.gc._linewidth, + gc.get_joinstyle(), + gc.get_capstyle(), + ) output(Op.gsave) lastx, lasty = 0, 0 for vertices, code in path.iter_segments( - trans, - clip=(0, 0, self.file.width*72, self.file.height*72), - simplify=False): + trans, + clip=(0, 0, self.file.width * 72, self.file.height * 72), + simplify=False, + ): if len(vertices): x, y = vertices[-2:] - if (x < 0 or - y < 0 or - x > self.file.width * 72 or - y > self.file.height * 72): + if ( + x < 0 + or y < 0 + or x > self.file.width * 72 + or y > self.file.height * 72 + ): continue dx, dy = x - lastx, y - lasty - output(1, 0, 0, 1, dx, dy, Op.concat_matrix, - marker, Op.use_xobject) + output( + 1, 0, 0, 1, dx, dy, Op.concat_matrix, marker, Op.use_xobject + ) lastx, lasty = x, y output(Op.grestore) def draw_gouraud_triangle(self, gc, points, colors, trans): - self.draw_gouraud_triangles(gc, points.reshape((1, 3, 2)), - colors.reshape((1, 3, 4)), trans) + self.draw_gouraud_triangles( + gc, points.reshape((1, 3, 2)), colors.reshape((1, 3, 4)), trans + ) def draw_gouraud_triangles(self, gc, points, colors, trans): assert len(points) == len(colors) @@ -1716,27 +2021,40 @@ def _setup_textpos(self, x, y, angle, oldx=0, oldy=0, oldangle=0): self.file.output(x - oldx, y - oldy, Op.textpos) else: angle = angle / 180.0 * pi - self.file.output(cos(angle), sin(angle), - -sin(angle), cos(angle), - x, y, Op.textmatrix) + self.file.output( + cos(angle), + sin(angle), + -sin(angle), + cos(angle), + x, + y, + Op.textmatrix, + ) self.file.output(0, 0, Op.textpos) def draw_mathtext(self, gc, x, y, s, prop, angle): # TODO: fix positioning and encoding - width, height, descent, glyphs, rects, used_characters = \ - self.mathtext_parser.parse(s, 72, prop) + ( + width, + height, + descent, + glyphs, + rects, + used_characters, + ) = self.mathtext_parser.parse(s, 72, prop) self.merge_used_characters(used_characters) # When using Type 3 fonts, we can't use character codes higher # than 255, so we use the "Do" command to render those # instead. - global_fonttype = rcParams['pdf.fonttype'] + global_fonttype = rcParams["pdf.fonttype"] # Set up a global transformation matrix for the whole math expression a = angle / 180.0 * pi self.file.output(Op.gsave) - self.file.output(cos(a), sin(a), -sin(a), cos(a), x, y, - Op.concat_matrix) + self.file.output( + cos(a), sin(a), -sin(a), cos(a), x, y, Op.concat_matrix + ) self.check_gc(gc, gc._rgb) self.file.output(Op.begin_text) @@ -1752,11 +2070,13 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): self._setup_textpos(ox, oy, 0, oldx, oldy) oldx, oldy = ox, oy if (fontname, fontsize) != prev_font: - self.file.output(self.file.fontName(fontname), fontsize, - Op.selectfont) + self.file.output( + self.file.fontName(fontname), fontsize, Op.selectfont + ) prev_font = fontname, fontsize - self.file.output(self.encode_string(chr(num), fonttype), - Op.show) + self.file.output( + self.encode_string(chr(num), fonttype), Op.show + ) self.file.output(Op.end_text) # If using Type 3 fonts, render all of the multi-byte characters @@ -1770,24 +2090,39 @@ def draw_mathtext(self, gc, x, y, s, prop, angle): if fonttype == 3 and num > 255: self.file.fontName(fontname) - self.file.output(Op.gsave, - 0.001 * fontsize, 0, - 0, 0.001 * fontsize, - ox, oy, Op.concat_matrix) + self.file.output( + Op.gsave, + 0.001 * fontsize, + 0, + 0, + 0.001 * fontsize, + ox, + oy, + Op.concat_matrix, + ) name = self.file._get_xobject_symbol_name( - fontname, symbol_name) + fontname, symbol_name + ) self.file.output(Name(name), Op.use_xobject) self.file.output(Op.grestore) # Draw any horizontal lines in the math layout for ox, oy, width, height in rects: - self.file.output(Op.gsave, ox, oy, width, height, - Op.rectangle, Op.fill, Op.grestore) + self.file.output( + Op.gsave, + ox, + oy, + width, + height, + Op.rectangle, + Op.fill, + Op.grestore, + ) # Pop off the global transformation self.file.output(Op.grestore) - def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): + def draw_tex(self, gc, x, y, s, prop, angle, ismath="TeX!", mtext=None): texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() dvifile = texmanager.make_dvi(s, fontsize) @@ -1815,31 +2150,33 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): basefont=psfont.psname, encodingfile=psfont.encoding, effects=psfont.effects, - dvifont=dvifont) - seq += [['font', pdfname, dvifont.size]] + dvifont=dvifont, + ) + seq += [["font", pdfname, dvifont.size]] oldfont = dvifont # We need to convert the glyph numbers to bytes, and the easiest # way to do this on both Python 2 and 3 is .encode('latin-1') - seq += [['text', x1, y1, - [six.chr(glyph).encode('latin-1')], x1+width]] + seq += [ + ["text", x1, y1, [six.chr(glyph).encode("latin-1")], x1 + width] + ] # Find consecutive text strings with constant y coordinate and # combine into a sequence of strings and kerns, or just one # string (if any kerns would be less than 0.1 points). i, curx, fontsize = 0, 0, None - while i < len(seq)-1: - elt, nxt = seq[i:i+2] - if elt[0] == 'font': + while i < len(seq) - 1: + elt, nxt = seq[i : i + 2] + if elt[0] == "font": fontsize = elt[2] - elif elt[0] == nxt[0] == 'text' and elt[2] == nxt[2]: + elif elt[0] == nxt[0] == "text" and elt[2] == nxt[2]: offset = elt[4] - nxt[1] if abs(offset) < 0.1: elt[3][-1] += nxt[3][0] - elt[4] += nxt[4]-nxt[1] + elt[4] += nxt[4] - nxt[1] else: - elt[3] += [offset*1000.0/fontsize, nxt[3][0]] + elt[3] += [offset * 1000.0 / fontsize, nxt[3][0]] elt[4] = nxt[4] - del seq[i+1] + del seq[i + 1] continue i += 1 @@ -1851,9 +2188,9 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): self.file.output(Op.begin_text) curx, cury, oldx, oldy = 0, 0, 0, 0 for elt in seq: - if elt[0] == 'font': + if elt[0] == "font": self.file.output(elt[1], elt[2], Op.selectfont) - elif elt[0] == 'text': + elif elt[0] == "text": curx, cury = mytrans.transform((elt[1], elt[2])) self._setup_textpos(curx, cury, angle, oldx, oldy) oldx, oldy = curx, cury @@ -1870,17 +2207,30 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): boxgc = self.new_gc() boxgc.copy_properties(gc) boxgc.set_linewidth(0) - pathops = [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, - Path.CLOSEPOLY] + pathops = [ + Path.MOVETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.CLOSEPOLY, + ] for x1, y1, h, w in page.boxes: - path = Path([[x1, y1], [x1+w, y1], [x1+w, y1+h], [x1, y1+h], - [0, 0]], pathops) + path = Path( + [ + [x1, y1], + [x1 + w, y1], + [x1 + w, y1 + h], + [x1, y1 + h], + [0, 0], + ], + pathops, + ) self.draw_path(boxgc, path, mytrans, gc._rgb) def encode_string(self, s, fonttype): if fonttype in (1, 3): - return s.encode('cp1252', 'replace') - return s.encode('utf-16be', 'replace') + return s.encode("cp1252", "replace") + return s.encode("utf-16be", "replace") def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): # TODO: combine consecutive texts into one BT/ET delimited section @@ -1902,7 +2252,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): fontsize = prop.get_size_in_points() - if rcParams['pdf.use14corefonts']: + if rcParams["pdf.use14corefonts"]: font = self._get_font_afm(prop) l, b, w, h = font.get_str_bbox(s) fonttype = 1 @@ -1911,7 +2261,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): self.track_characters(font, s) font.set_text(s, 0.0, flags=LOAD_NO_HINTING) - fonttype = rcParams['pdf.fonttype'] + fonttype = rcParams["pdf.fonttype"] # We can't subset all OpenType fonts, so switch to Type 42 # in that case. @@ -1925,7 +2275,7 @@ def check_simple_method(s): use_simple_method = True chunks = [] - if not rcParams['pdf.use14corefonts']: + if not rcParams["pdf.use14corefonts"]: if fonttype == 3 and not isinstance(s, bytes) and len(s) != 0: # Break the string into chunks where each chunk is either # a string of chars <= 255, or a single character > 255. @@ -1939,33 +2289,33 @@ def check_simple_method(s): chunks[-1][1].append(c) else: chunks.append((char_type, [c])) - use_simple_method = (len(chunks) == 1 - and chunks[-1][0] == 1) + use_simple_method = len(chunks) == 1 and chunks[-1][0] == 1 return use_simple_method, chunks def draw_text_simple(): """Outputs text using the simple method.""" - self.file.output(Op.begin_text, - self.file.fontName(prop), - fontsize, - Op.selectfont) + self.file.output( + Op.begin_text, self.file.fontName(prop), fontsize, Op.selectfont + ) self._setup_textpos(x, y, angle) - self.file.output(self.encode_string(s, fonttype), Op.show, - Op.end_text) + self.file.output( + self.encode_string(s, fonttype), Op.show, Op.end_text + ) def draw_text_woven(chunks): """Outputs text using the woven method, alternating between chunks of 1-byte characters and 2-byte characters. Only used for Type 3 fonts.""" - chunks = [(a, ''.join(b)) for a, b in chunks] + chunks = [(a, "".join(b)) for a, b in chunks] cmap = font.get_charmap() # Do the rotation and global translation as a single matrix # concatenation up front self.file.output(Op.gsave) a = angle / 180.0 * pi - self.file.output(cos(a), sin(a), -sin(a), cos(a), x, y, - Op.concat_matrix) + self.file.output( + cos(a), sin(a), -sin(a), cos(a), x, y, Op.concat_matrix + ) # Output all the 1-byte characters in a BT/ET group, then # output all the 2-byte characters. @@ -1973,16 +2323,19 @@ def draw_text_woven(chunks): newx = oldx = 0 # Output a 1-byte character chunk if mode == 1: - self.file.output(Op.begin_text, - self.file.fontName(prop), - fontsize, - Op.selectfont) + self.file.output( + Op.begin_text, + self.file.fontName(prop), + fontsize, + Op.selectfont, + ) for chunk_type, chunk in chunks: if mode == 1 and chunk_type == 1: self._setup_textpos(newx, 0, 0, oldx, 0, 0) - self.file.output(self.encode_string(chunk, fonttype), - Op.show) + self.file.output( + self.encode_string(chunk, fonttype), Op.show + ) oldx = newx lastgind = None @@ -1993,25 +2346,34 @@ def draw_text_woven(chunks): if mode == 2 and chunk_type == 2: glyph_name = font.get_glyph_name(gind) self.file.output(Op.gsave) - self.file.output(0.001 * fontsize, 0, - 0, 0.001 * fontsize, - newx, 0, Op.concat_matrix) + self.file.output( + 0.001 * fontsize, + 0, + 0, + 0.001 * fontsize, + newx, + 0, + Op.concat_matrix, + ) name = self.file._get_xobject_symbol_name( - font.fname, glyph_name) + font.fname, glyph_name + ) self.file.output(Name(name), Op.use_xobject) self.file.output(Op.grestore) # Move the pointer based on the character width # and kerning - glyph = font.load_char(ccode, - flags=LOAD_NO_HINTING) + glyph = font.load_char(ccode, flags=LOAD_NO_HINTING) if lastgind is not None: kern = font.get_kerning( - lastgind, gind, KERNING_UNFITTED) + lastgind, gind, KERNING_UNFITTED + ) else: kern = 0 lastgind = gind - newx += kern/64.0 + glyph.linearHoriAdvance/65536.0 + newx += ( + kern / 64.0 + glyph.linearHoriAdvance / 65536.0 + ) if mode == 1: self.file.output(Op.end_text) @@ -2025,18 +2387,25 @@ def draw_text_woven(chunks): return draw_text_woven(chunks) def get_text_width_height_descent(self, s, prop, ismath): - if rcParams['text.usetex']: + if rcParams["text.usetex"]: texmanager = self.get_texmanager() fontsize = prop.get_size_in_points() - w, h, d = texmanager.get_text_width_height_descent(s, fontsize, - renderer=self) + w, h, d = texmanager.get_text_width_height_descent( + s, fontsize, renderer=self + ) return w, h, d if ismath: - w, h, d, glyphs, rects, used_characters = \ - self.mathtext_parser.parse(s, 72, prop) - - elif rcParams['pdf.use14corefonts']: + ( + w, + h, + d, + glyphs, + rects, + used_characters, + ) = self.mathtext_parser.parse(s, 72, prop) + + elif rcParams["pdf.use14corefonts"]: font = self._get_font_afm(prop) l, b, w, h, d = font.get_str_bbox_and_descent(s) scale = prop.get_size_in_points() @@ -2047,7 +2416,7 @@ def get_text_width_height_descent(self, s, prop, ismath): font = self._get_font_ttf(prop) font.set_text(s, 0.0, flags=LOAD_NO_HINTING) w, h = font.get_width_height() - scale = (1.0 / 64.0) + scale = 1.0 / 64.0 w *= scale h *= scale d = font.get_descent() @@ -2059,14 +2428,17 @@ def _get_font_afm(self, prop): font = self.afm_font_cache.get(key) if font is None: filename = findfont( - prop, fontext='afm', directory=self.file._core14fontdir) + prop, fontext="afm", directory=self.file._core14fontdir + ) if filename is None: filename = findfont( - "Helvetica", fontext='afm', - directory=self.file._core14fontdir) + "Helvetica", + fontext="afm", + directory=self.file._core14fontdir, + ) font = self.afm_font_cache.get(filename) if font is None: - with open(filename, 'rb') as fh: + with open(filename, "rb") as fh: font = AFM(fh) self.afm_font_cache[filename] = font self.afm_font_cache[key] = font @@ -2097,7 +2469,6 @@ def new_gc(self): class GraphicsContextPdf(GraphicsContextBase): - def __init__(self, file): GraphicsContextBase.__init__(self) self._fillcolor = (0.0, 0.0, 0.0) @@ -2107,8 +2478,8 @@ def __init__(self, file): def __repr__(self): d = dict(self.__dict__) - del d['file'] - del d['parent'] + del d["file"] + del d["parent"] return repr(d) def strokep(self): @@ -2119,8 +2490,11 @@ def strokep(self): """ # _linewidth > 0: in pdf a line of width 0 is drawn at minimum # possible device width, but e.g., agg doesn't draw at all - return (self._linewidth > 0 and self._alpha > 0 and - (len(self._rgb) <= 3 or self._rgb[3] != 0.0)) + return ( + self._linewidth > 0 + and self._alpha > 0 + and (len(self._rgb) <= 3 or self._rgb[3] != 0.0) + ) def fillp(self, *args): """ @@ -2133,9 +2507,10 @@ def fillp(self, *args): _fillcolor = args[0] else: _fillcolor = self._fillcolor - return (self._hatch or - (_fillcolor is not None and - (len(_fillcolor) <= 3 or _fillcolor[3] != 0.0))) + return self._hatch or ( + _fillcolor is not None + and (len(_fillcolor) <= 3 or _fillcolor[3] != 0.0) + ) def close_and_paint(self): """ @@ -2151,8 +2526,8 @@ def paint(self): """ return Op.paint_path(False, self.fillp(), self.strokep()) - capstyles = {'butt': 0, 'round': 1, 'projecting': 2} - joinstyles = {'miter': 0, 'round': 1, 'bevel': 2} + capstyles = {"butt": 0, "round": 1, "projecting": 2} + joinstyles = {"miter": 0, "round": 1, "bevel": 2} def capstyle_cmd(self, style): return [self.capstyles[style], Op.setlinecap] @@ -2179,15 +2554,19 @@ def hatch_cmd(self, hatch): if self._fillcolor is not None: return self.fillcolor_cmd(self._fillcolor) else: - return [Name('DeviceRGB'), Op.setcolorspace_nonstroke] + return [Name("DeviceRGB"), Op.setcolorspace_nonstroke] else: hatch_style = (self._rgb, self._fillcolor, hatch) name = self.file.hatchPattern(hatch_style) - return [Name('Pattern'), Op.setcolorspace_nonstroke, - name, Op.setcolor_nonstroke] + return [ + Name("Pattern"), + Op.setcolorspace_nonstroke, + name, + Op.setcolor_nonstroke, + ] def rgb_cmd(self, rgb): - if rcParams['pdf.inheritcolor']: + if rcParams["pdf.inheritcolor"]: return [] if rgb[0] == rgb[1] == rgb[2]: return [rgb[0], Op.setgray_stroke] @@ -2195,7 +2574,7 @@ def rgb_cmd(self, rgb): return list(rgb[:3]) + [Op.setrgb_stroke] def fillcolor_cmd(self, rgb): - if rgb is None or rcParams['pdf.inheritcolor']: + if rgb is None or rcParams["pdf.inheritcolor"]: return [] elif rgb[0] == rgb[1] == rgb[2]: return [rgb[0], Op.setgray_nonstroke] @@ -2219,34 +2598,39 @@ def clip_cmd(self, cliprect, clippath): """Set clip rectangle. Calls self.pop() and self.push().""" cmds = [] # Pop graphics state until we hit the right one or the stack is empty - while ((self._cliprect, self._clippath) != (cliprect, clippath) - and self.parent is not None): + while (self._cliprect, self._clippath) != ( + cliprect, + clippath, + ) and self.parent is not None: cmds.extend(self.pop()) # Unless we hit the right one, set the clip polygon - if ((self._cliprect, self._clippath) != (cliprect, clippath) or - self.parent is None): + if (self._cliprect, self._clippath) != ( + cliprect, + clippath, + ) or self.parent is None: cmds.extend(self.push()) if self._cliprect != cliprect: cmds.extend([cliprect, Op.rectangle, Op.clip, Op.endpath]) if self._clippath != clippath: path, affine = clippath.get_transformed_path_and_affine() cmds.extend( - PdfFile.pathOperations(path, affine, simplify=False) + - [Op.clip, Op.endpath]) + PdfFile.pathOperations(path, affine, simplify=False) + + [Op.clip, Op.endpath] + ) return cmds commands = ( # must come first since may pop - (('_cliprect', '_clippath'), clip_cmd), - (('_alpha', '_forced_alpha', '_effective_alphas'), alpha_cmd), - (('_capstyle',), capstyle_cmd), - (('_fillcolor',), fillcolor_cmd), - (('_joinstyle',), joinstyle_cmd), - (('_linewidth',), linewidth_cmd), - (('_dashes',), dash_cmd), - (('_rgb',), rgb_cmd), - (('_hatch',), hatch_cmd), # must come after fillcolor and rgb - ) + (("_cliprect", "_clippath"), clip_cmd), + (("_alpha", "_forced_alpha", "_effective_alphas"), alpha_cmd), + (("_capstyle",), capstyle_cmd), + (("_fillcolor",), fillcolor_cmd), + (("_joinstyle",), joinstyle_cmd), + (("_linewidth",), linewidth_cmd), + (("_dashes",), dash_cmd), + (("_rgb",), rgb_cmd), + (("_hatch",), hatch_cmd), # must come after fillcolor and rgb + ) # TODO: _linestyle @@ -2266,8 +2650,9 @@ def delta(self, other): except ValueError: ours = np.asarray(ours) theirs = np.asarray(theirs) - different = (ours.shape != theirs.shape or - np.any(ours != theirs)) + different = ours.shape != theirs.shape or np.any( + ours != theirs + ) if different: break @@ -2283,9 +2668,10 @@ def copy_properties(self, other): Copy properties of other into self. """ GraphicsContextBase.copy_properties(self, other) - fillcolor = getattr(other, '_fillcolor', self._fillcolor) - effective_alphas = getattr(other, '_effective_alphas', - self._effective_alphas) + fillcolor = getattr(other, "_fillcolor", self._fillcolor) + effective_alphas = getattr( + other, "_effective_alphas", self._effective_alphas + ) self._fillcolor = fillcolor self._effective_alphas = effective_alphas @@ -2298,6 +2684,7 @@ def finalize(self): cmds.extend(self.pop()) return cmds + ######################################################################## # # The following functions and classes are for pylab and implement @@ -2314,7 +2701,7 @@ def new_figure_manager(num, *args, **kwargs): # do it -- see backend_wx, backend_wxagg and backend_tkagg for # examples. Not all GUIs require explicit instantiation of a # main-level app (egg backend_gtk, backend_gtkagg) for pylab - FigureClass = kwargs.pop('FigureClass', Figure) + FigureClass = kwargs.pop("FigureClass", Figure) thisFig = FigureClass(*args, **kwargs) return new_figure_manager_given_figure(num, thisFig) @@ -2351,7 +2738,8 @@ class PdfPages(object): order to avoid confusion when using :func:`~matplotlib.pyplot.savefig` and forgetting the format argument. """ - __slots__ = ('_file', 'keep_empty') + + __slots__ = ("_file", "keep_empty") def __init__(self, filename, keep_empty=True): """ @@ -2383,8 +2771,11 @@ def close(self): PDF file. """ self._file.close() - if (self.get_pagecount() == 0 and not self.keep_empty - and not self._file.passed_in_file_object): + if ( + self.get_pagecount() == 0 + and not self.keep_empty + and not self._file.passed_in_file_object + ): os.remove(self._file.fh.name) self._file = None @@ -2413,7 +2804,7 @@ def savefig(self, figure=None, **kwargs): the figure instance to save is looked up by number. """ if isinstance(figure, Figure): - figure.savefig(self, format='pdf', **kwargs) + figure.savefig(self, format="pdf", **kwargs) else: if figure is None: figureManager = Gcf.get_active() @@ -2422,8 +2813,9 @@ def savefig(self, figure=None, **kwargs): if figureManager is None: raise ValueError("No such figure: " + repr(figure)) else: - figureManager.canvas.figure.savefig(self, format='pdf', - **kwargs) + figureManager.canvas.figure.savefig( + self, format="pdf", **kwargs + ) def get_pagecount(self): """ @@ -2447,14 +2839,14 @@ class FigureCanvasPdf(FigureCanvasBase): def draw(self): pass - filetypes = {'pdf': 'Portable Document Format'} + filetypes = {"pdf": "Portable Document Format"} def get_default_filetype(self): - return 'pdf' + return "pdf" def print_pdf(self, filename, **kwargs): - image_dpi = kwargs.get('dpi', 72) # dpi to use for images - self.figure.set_dpi(72) # there are 72 pdf points to an inch + image_dpi = kwargs.get("dpi", 72) # dpi to use for images + self.figure.set_dpi(72) # there are 72 pdf points to an inch width, height = self.figure.get_size_inches() if isinstance(filename, PdfPages): file = filename._file @@ -2464,15 +2856,19 @@ def print_pdf(self, filename, **kwargs): file.newPage(width, height) _bbox_inches_restore = kwargs.pop("bbox_inches_restore", None) renderer = MixedModeRenderer( - self.figure, width, height, image_dpi, + self.figure, + width, + height, + image_dpi, RendererPdf(file, image_dpi), - bbox_inches_restore=_bbox_inches_restore) + bbox_inches_restore=_bbox_inches_restore, + ) self.figure.draw(renderer) renderer.finalize() finally: if isinstance(filename, PdfPages): # finish off this page file.endStream() - else: # we opened the file above; now finish it off + else: # we opened the file above; now finish it off file.close() diff --git a/dnaplotlib/setup.py b/dnaplotlib/setup.py index 76c970a..227f45f 100755 --- a/dnaplotlib/setup.py +++ b/dnaplotlib/setup.py @@ -1,16 +1,23 @@ from distutils.core import setup + setup( - name = 'dnaplotlib', - packages = ['dnaplotlib','dnaplotlib.sbol'], - version = '1.0', - description = 'Genetic design visualization', - author = 'Thomas Gorochowski, ', - author_email = 'tom@chofski.co.uk', - url = 'https://github.com/VoigtLab/dnaplotlib', - download_url = 'https://github.com/VoigtLab/dnaplotlib/archive/1.0.tar.gz', - keywords = ['visualization', 'SBOLv', 'genetic design', 'synthetic biology', 'systems biology'], - classifiers = [], - scripts=['apps/quick.py', 'apps/library_plot.py'] + name="dnaplotlib", + packages=["dnaplotlib", "dnaplotlib.sbol"], + version="1.0", + description="Genetic design visualization", + author="Thomas Gorochowski, ", + author_email="tom@chofski.co.uk", + url="https://github.com/VoigtLab/dnaplotlib", + download_url="https://github.com/VoigtLab/dnaplotlib/archive/1.0.tar.gz", + keywords=[ + "visualization", + "SBOLv", + "genetic design", + "synthetic biology", + "systems biology", + ], + classifiers=[], + scripts=["apps/quick.py", "apps/library_plot.py"], ) # http://peterdowns.com/posts/first-time-with-pypi.html diff --git a/jackson_input.svg b/jackson_input.svg new file mode 100644 index 0000000..bb47a31 --- /dev/null +++ b/jackson_input.svg @@ -0,0 +1,507 @@ + + + + + + + + + 2021-02-22T14:45:41.155725 + image/svg+xml + + + Matplotlib v3.3.4, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jackson_input.txt b/jackson_input.txt new file mode 100644 index 0000000..2dc4365 --- /dev/null +++ b/jackson_input.txt @@ -0,0 +1,6 @@ +p Cph8 6 +? OmpR 4 +p Pomp 2 +? LacZ 2 +# Arcs +OmpR ing Pomp \ No newline at end of file diff --git a/pigeon_test.png b/pigeon_test.png new file mode 100644 index 0000000..2522bba Binary files /dev/null and b/pigeon_test.png differ diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..91f95ac --- /dev/null +++ b/poetry.lock @@ -0,0 +1,449 @@ +[[package]] +name = "antlr4-python3-runtime" +version = "4.9.1" +description = "ANTLR 4.9.1 runtime for Python 3.7" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "black" +version = "20.8b1" +description = "The uncompromising code formatter." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +appdirs = "*" +click = ">=7.1.2" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.6,<1" +regex = ">=2020.1.8" +toml = ">=0.10.1" +typed-ast = ">=1.4.0" +typing-extensions = ">=3.7.4" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] + +[[package]] +name = "click" +version = "7.1.2" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "cycler" +version = "0.10.0" +description = "Composable style cycles" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" + +[[package]] +name = "graphviz" +version = "0.16" +description = "Simple Python interface for Graphviz" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" + +[package.extras] +dev = ["tox (>=3)", "flake8", "pep8-naming", "wheel", "twine"] +docs = ["sphinx (>=1.8)", "sphinx-rtd-theme"] +test = ["mock (>=3)", "pytest (>=4)", "pytest-mock (>=2)", "pytest-cov"] + +[[package]] +name = "kiwisolver" +version = "1.3.1" +description = "A fast implementation of the Cassowary constraint solver" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "matplotlib" +version = "3.3.4" +description = "Python plotting package" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cycler = ">=0.10" +kiwisolver = ">=1.0.1" +numpy = ">=1.15" +pillow = ">=6.2.0" +pyparsing = ">=2.0.3,<2.0.4 || >2.0.4,<2.1.2 || >2.1.2,<2.1.6 || >2.1.6" +python-dateutil = ">=2.1" + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "numpy" +version = "1.20.1" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pathspec" +version = "0.8.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pillow" +version = "8.1.0" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "pygraphviz" +version = "1.7" +description = "Python interface to Graphviz" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "python-dateutil" +version = "2.8.1" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "regex" +version = "2020.11.13" +description = "Alternative regular expression module, to replace re." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "six" +version = "1.15.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "typed-ast" +version = "1.4.2" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "typing-extensions" +version = "3.7.4.3" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "main" +optional = false +python-versions = "*" + +[metadata] +lock-version = "1.1" +python-versions = "^3.8" +content-hash = "72e4870ed4848786356b3a56060bd7b1215546806acc3d3ba4db4a71680f3aab" + +[metadata.files] +antlr4-python3-runtime = [ + {file = "antlr4-python3-runtime-4.9.1.tar.gz", hash = "sha256:759eddb70061ff7387bc877f5b59e3344ab374843604f757afa5b308cb68669a"}, +] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] +black = [ + {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, +] +click = [ + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, +] +cycler = [ + {file = "cycler-0.10.0-py2.py3-none-any.whl", hash = "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d"}, + {file = "cycler-0.10.0.tar.gz", hash = "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"}, +] +graphviz = [ + {file = "graphviz-0.16-py2.py3-none-any.whl", hash = "sha256:3cad5517c961090dfc679df6402a57de62d97703e2880a1a46147bb0dc1639eb"}, + {file = "graphviz-0.16.zip", hash = "sha256:d2d25af1c199cad567ce4806f0449cb74eb30cf451fd7597251e1da099ac6e57"}, +] +kiwisolver = [ + {file = "kiwisolver-1.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fd34fbbfbc40628200730bc1febe30631347103fc8d3d4fa012c21ab9c11eca9"}, + {file = "kiwisolver-1.3.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:d3155d828dec1d43283bd24d3d3e0d9c7c350cdfcc0bd06c0ad1209c1bbc36d0"}, + {file = "kiwisolver-1.3.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5a7a7dbff17e66fac9142ae2ecafb719393aaee6a3768c9de2fd425c63b53e21"}, + {file = "kiwisolver-1.3.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:f8d6f8db88049a699817fd9178782867bf22283e3813064302ac59f61d95be05"}, + {file = "kiwisolver-1.3.1-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:5f6ccd3dd0b9739edcf407514016108e2280769c73a85b9e59aa390046dbf08b"}, + {file = "kiwisolver-1.3.1-cp36-cp36m-win32.whl", hash = "sha256:225e2e18f271e0ed8157d7f4518ffbf99b9450fca398d561eb5c4a87d0986dd9"}, + {file = "kiwisolver-1.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:cf8b574c7b9aa060c62116d4181f3a1a4e821b2ec5cbfe3775809474113748d4"}, + {file = "kiwisolver-1.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:232c9e11fd7ac3a470d65cd67e4359eee155ec57e822e5220322d7b2ac84fbf0"}, + {file = "kiwisolver-1.3.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b38694dcdac990a743aa654037ff1188c7a9801ac3ccc548d3341014bc5ca278"}, + {file = "kiwisolver-1.3.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ca3820eb7f7faf7f0aa88de0e54681bddcb46e485beb844fcecbcd1c8bd01689"}, + {file = "kiwisolver-1.3.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:c8fd0f1ae9d92b42854b2979024d7597685ce4ada367172ed7c09edf2cef9cb8"}, + {file = "kiwisolver-1.3.1-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:1e1bc12fb773a7b2ffdeb8380609f4f8064777877b2225dec3da711b421fda31"}, + {file = "kiwisolver-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:72c99e39d005b793fb7d3d4e660aed6b6281b502e8c1eaf8ee8346023c8e03bc"}, + {file = "kiwisolver-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:8be8d84b7d4f2ba4ffff3665bcd0211318aa632395a1a41553250484a871d454"}, + {file = "kiwisolver-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:31dfd2ac56edc0ff9ac295193eeaea1c0c923c0355bf948fbd99ed6018010b72"}, + {file = "kiwisolver-1.3.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:563c649cfdef27d081c84e72a03b48ea9408c16657500c312575ae9d9f7bc1c3"}, + {file = "kiwisolver-1.3.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:78751b33595f7f9511952e7e60ce858c6d64db2e062afb325985ddbd34b5c131"}, + {file = "kiwisolver-1.3.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a357fd4f15ee49b4a98b44ec23a34a95f1e00292a139d6015c11f55774ef10de"}, + {file = "kiwisolver-1.3.1-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:5989db3b3b34b76c09253deeaf7fbc2707616f130e166996606c284395da3f18"}, + {file = "kiwisolver-1.3.1-cp38-cp38-win32.whl", hash = "sha256:c08e95114951dc2090c4a630c2385bef681cacf12636fb0241accdc6b303fd81"}, + {file = "kiwisolver-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:44a62e24d9b01ba94ae7a4a6c3fb215dc4af1dde817e7498d901e229aaf50e4e"}, + {file = "kiwisolver-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:50af681a36b2a1dee1d3c169ade9fdc59207d3c31e522519181e12f1b3ba7000"}, + {file = "kiwisolver-1.3.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:a53d27d0c2a0ebd07e395e56a1fbdf75ffedc4a05943daf472af163413ce9598"}, + {file = "kiwisolver-1.3.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:834ee27348c4aefc20b479335fd422a2c69db55f7d9ab61721ac8cd83eb78882"}, + {file = "kiwisolver-1.3.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5c3e6455341008a054cccee8c5d24481bcfe1acdbc9add30aa95798e95c65621"}, + {file = "kiwisolver-1.3.1-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:acef3d59d47dd85ecf909c359d0fd2c81ed33bdff70216d3956b463e12c38a54"}, + {file = "kiwisolver-1.3.1-cp39-cp39-win32.whl", hash = "sha256:c5518d51a0735b1e6cee1fdce66359f8d2b59c3ca85dc2b0813a8aa86818a030"}, + {file = "kiwisolver-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:b9edd0110a77fc321ab090aaa1cfcaba1d8499850a12848b81be2222eab648f6"}, + {file = "kiwisolver-1.3.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0cd53f403202159b44528498de18f9285b04482bab2a6fc3f5dd8dbb9352e30d"}, + {file = "kiwisolver-1.3.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:33449715e0101e4d34f64990352bce4095c8bf13bed1b390773fc0a7295967b3"}, + {file = "kiwisolver-1.3.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:401a2e9afa8588589775fe34fc22d918ae839aaaf0c0e96441c0fdbce6d8ebe6"}, + {file = "kiwisolver-1.3.1.tar.gz", hash = "sha256:950a199911a8d94683a6b10321f9345d5a3a8433ec58b217ace979e18f16e248"}, +] +matplotlib = [ + {file = "matplotlib-3.3.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:672960dd114e342b7c610bf32fb99d14227f29919894388b41553217457ba7ef"}, + {file = "matplotlib-3.3.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:7c155437ae4fd366e2700e2716564d1787700687443de46bcb895fe0f84b761d"}, + {file = "matplotlib-3.3.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:a17f0a10604fac7627ec82820439e7db611722e80c408a726cd00d8c974c2fb3"}, + {file = "matplotlib-3.3.4-cp36-cp36m-win32.whl", hash = "sha256:215e2a30a2090221a9481db58b770ce56b8ef46f13224ae33afe221b14b24dc1"}, + {file = "matplotlib-3.3.4-cp36-cp36m-win_amd64.whl", hash = "sha256:348e6032f666ffd151b323342f9278b16b95d4a75dfacae84a11d2829a7816ae"}, + {file = "matplotlib-3.3.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:94bdd1d55c20e764d8aea9d471d2ae7a7b2c84445e0fa463f02e20f9730783e1"}, + {file = "matplotlib-3.3.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a1acb72f095f1d58ecc2538ed1b8bca0b57df313b13db36ed34b8cdf1868e674"}, + {file = "matplotlib-3.3.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:46b1a60a04e6d884f0250d5cc8dc7bd21a9a96c584a7acdaab44698a44710bab"}, + {file = "matplotlib-3.3.4-cp37-cp37m-win32.whl", hash = "sha256:ed4a9e6dcacba56b17a0a9ac22ae2c72a35b7f0ef0693aa68574f0b2df607a89"}, + {file = "matplotlib-3.3.4-cp37-cp37m-win_amd64.whl", hash = "sha256:c24c05f645aef776e8b8931cb81e0f1632d229b42b6d216e30836e2e145a2b40"}, + {file = "matplotlib-3.3.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7310e353a4a35477c7f032409966920197d7df3e757c7624fd842f3eeb307d3d"}, + {file = "matplotlib-3.3.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:451cc89cb33d6652c509fc6b588dc51c41d7246afdcc29b8624e256b7663ed1f"}, + {file = "matplotlib-3.3.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d2eb9c1cc254d0ffa90bc96fde4b6005d09c2228f99dfd493a4219c1af99644"}, + {file = "matplotlib-3.3.4-cp38-cp38-win32.whl", hash = "sha256:e15fa23d844d54e7b3b7243afd53b7567ee71c721f592deb0727ee85e668f96a"}, + {file = "matplotlib-3.3.4-cp38-cp38-win_amd64.whl", hash = "sha256:1de0bb6cbfe460725f0e97b88daa8643bcf9571c18ba90bb8e41432aaeca91d6"}, + {file = "matplotlib-3.3.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f44149a0ef5b4991aaef12a93b8e8d66d6412e762745fea1faa61d98524e0ba9"}, + {file = "matplotlib-3.3.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:746a1df55749629e26af7f977ea426817ca9370ad1569436608dc48d1069b87c"}, + {file = "matplotlib-3.3.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:5f571b92a536206f7958f7cb2d367ff6c9a1fa8229dc35020006e4cdd1ca0acd"}, + {file = "matplotlib-3.3.4-cp39-cp39-win32.whl", hash = "sha256:9265ae0fb35e29f9b8cc86c2ab0a2e3dcddc4dd9de4b85bf26c0f63fe5c1c2ca"}, + {file = "matplotlib-3.3.4-cp39-cp39-win_amd64.whl", hash = "sha256:9a79e5dd7bb797aa611048f5b70588b23c5be05b63eefd8a0d152ac77c4243db"}, + {file = "matplotlib-3.3.4-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1e850163579a8936eede29fad41e202b25923a0a8d5ffd08ce50fc0a97dcdc93"}, + {file = "matplotlib-3.3.4-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:d738acfdfb65da34c91acbdb56abed46803db39af259b7f194dc96920360dbe4"}, + {file = "matplotlib-3.3.4-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:aa49571d8030ad0b9ac39708ee77bd2a22f87815e12bdee52ecaffece9313ed8"}, + {file = "matplotlib-3.3.4-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:cf3a7e54eff792f0815dbbe9b85df2f13d739289c93d346925554f71d484be78"}, + {file = "matplotlib-3.3.4.tar.gz", hash = "sha256:3e477db76c22929e4c6876c44f88d790aacdf3c3f8f3a90cb1975c0bf37825b0"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +numpy = [ + {file = "numpy-1.20.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ae61f02b84a0211abb56462a3b6cd1e7ec39d466d3160eb4e1da8bf6717cdbeb"}, + {file = "numpy-1.20.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:65410c7f4398a0047eea5cca9b74009ea61178efd78d1be9847fac1d6716ec1e"}, + {file = "numpy-1.20.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d7e27442599104ee08f4faed56bb87c55f8b10a5494ac2ead5c98a4b289e61f"}, + {file = "numpy-1.20.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4ed8e96dc146e12c1c5cdd6fb9fd0757f2ba66048bf94c5126b7efebd12d0090"}, + {file = "numpy-1.20.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:ecb5b74c702358cdc21268ff4c37f7466357871f53a30e6f84c686952bef16a9"}, + {file = "numpy-1.20.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b9410c0b6fed4a22554f072a86c361e417f0258838957b78bd063bde2c7f841f"}, + {file = "numpy-1.20.1-cp37-cp37m-win32.whl", hash = "sha256:3d3087e24e354c18fb35c454026af3ed8997cfd4997765266897c68d724e4845"}, + {file = "numpy-1.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:89f937b13b8dd17b0099c7c2e22066883c86ca1575a975f754babc8fbf8d69a9"}, + {file = "numpy-1.20.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a1d7995d1023335e67fb070b2fae6f5968f5be3802b15ad6d79d81ecaa014fe0"}, + {file = "numpy-1.20.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:60759ab15c94dd0e1ed88241fd4fa3312db4e91d2c8f5a2d4cf3863fad83d65b"}, + {file = "numpy-1.20.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:125a0e10ddd99a874fd357bfa1b636cd58deb78ba4a30b5ddb09f645c3512e04"}, + {file = "numpy-1.20.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c26287dfc888cf1e65181f39ea75e11f42ffc4f4529e5bd19add57ad458996e2"}, + {file = "numpy-1.20.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:7199109fa46277be503393be9250b983f325880766f847885607d9b13848f257"}, + {file = "numpy-1.20.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:72251e43ac426ff98ea802a931922c79b8d7596480300eb9f1b1e45e0543571e"}, + {file = "numpy-1.20.1-cp38-cp38-win32.whl", hash = "sha256:c91ec9569facd4757ade0888371eced2ecf49e7982ce5634cc2cf4e7331a4b14"}, + {file = "numpy-1.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:13adf545732bb23a796914fe5f891a12bd74cf3d2986eed7b7eba2941eea1590"}, + {file = "numpy-1.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:104f5e90b143dbf298361a99ac1af4cf59131218a045ebf4ee5990b83cff5fab"}, + {file = "numpy-1.20.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:89e5336f2bec0c726ac7e7cdae181b325a9c0ee24e604704ed830d241c5e47ff"}, + {file = "numpy-1.20.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:032be656d89bbf786d743fee11d01ef318b0781281241997558fa7950028dd29"}, + {file = "numpy-1.20.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:66b467adfcf628f66ea4ac6430ded0614f5cc06ba530d09571ea404789064adc"}, + {file = "numpy-1.20.1-cp39-cp39-win32.whl", hash = "sha256:12e4ba5c6420917571f1a5becc9338abbde71dd811ce40b37ba62dec7b39af6d"}, + {file = "numpy-1.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:9c94cab5054bad82a70b2e77741271790304651d584e2cdfe2041488e753863b"}, + {file = "numpy-1.20.1-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:9eb551d122fadca7774b97db8a112b77231dcccda8e91a5bc99e79890797175e"}, + {file = "numpy-1.20.1.zip", hash = "sha256:3bc63486a870294683980d76ec1e3efc786295ae00128f9ea38e2c6e74d5a60a"}, +] +pathspec = [ + {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, + {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, +] +pillow = [ + {file = "Pillow-8.1.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:d355502dce85ade85a2511b40b4c61a128902f246504f7de29bbeec1ae27933a"}, + {file = "Pillow-8.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:93a473b53cc6e0b3ce6bf51b1b95b7b1e7e6084be3a07e40f79b42e83503fbf2"}, + {file = "Pillow-8.1.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2353834b2c49b95e1313fb34edf18fca4d57446675d05298bb694bca4b194174"}, + {file = "Pillow-8.1.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:1d208e670abfeb41b6143537a681299ef86e92d2a3dac299d3cd6830d5c7bded"}, + {file = "Pillow-8.1.0-cp36-cp36m-win32.whl", hash = "sha256:dd9eef866c70d2cbbea1ae58134eaffda0d4bfea403025f4db6859724b18ab3d"}, + {file = "Pillow-8.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:b09e10ec453de97f9a23a5aa5e30b334195e8d2ddd1ce76cc32e52ba63c8b31d"}, + {file = "Pillow-8.1.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:b02a0b9f332086657852b1f7cb380f6a42403a6d9c42a4c34a561aa4530d5234"}, + {file = "Pillow-8.1.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ca20739e303254287138234485579b28cb0d524401f83d5129b5ff9d606cb0a8"}, + {file = "Pillow-8.1.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:604815c55fd92e735f9738f65dabf4edc3e79f88541c221d292faec1904a4b17"}, + {file = "Pillow-8.1.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cf6e33d92b1526190a1de904df21663c46a456758c0424e4f947ae9aa6088bf7"}, + {file = "Pillow-8.1.0-cp37-cp37m-win32.whl", hash = "sha256:47c0d93ee9c8b181f353dbead6530b26980fe4f5485aa18be8f1fd3c3cbc685e"}, + {file = "Pillow-8.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:96d4dc103d1a0fa6d47c6c55a47de5f5dafd5ef0114fa10c85a1fd8e0216284b"}, + {file = "Pillow-8.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:7916cbc94f1c6b1301ac04510d0881b9e9feb20ae34094d3615a8a7c3db0dcc0"}, + {file = "Pillow-8.1.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3de6b2ee4f78c6b3d89d184ade5d8fa68af0848f9b6b6da2b9ab7943ec46971a"}, + {file = "Pillow-8.1.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cdbbe7dff4a677fb555a54f9bc0450f2a21a93c5ba2b44e09e54fcb72d2bd13d"}, + {file = "Pillow-8.1.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f50e7a98b0453f39000619d845be8b06e611e56ee6e8186f7f60c3b1e2f0feae"}, + {file = "Pillow-8.1.0-cp38-cp38-win32.whl", hash = "sha256:cb192176b477d49b0a327b2a5a4979552b7a58cd42037034316b8018ac3ebb59"}, + {file = "Pillow-8.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6c5275bd82711cd3dcd0af8ce0bb99113ae8911fc2952805f1d012de7d600a4c"}, + {file = "Pillow-8.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:165c88bc9d8dba670110c689e3cc5c71dbe4bfb984ffa7cbebf1fac9554071d6"}, + {file = "Pillow-8.1.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:5e2fe3bb2363b862671eba632537cd3a823847db4d98be95690b7e382f3d6378"}, + {file = "Pillow-8.1.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7612520e5e1a371d77e1d1ca3a3ee6227eef00d0a9cddb4ef7ecb0b7396eddf7"}, + {file = "Pillow-8.1.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d673c4990acd016229a5c1c4ee8a9e6d8f481b27ade5fc3d95938697fa443ce0"}, + {file = "Pillow-8.1.0-cp39-cp39-win32.whl", hash = "sha256:dc577f4cfdda354db3ae37a572428a90ffdbe4e51eda7849bf442fb803f09c9b"}, + {file = "Pillow-8.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:22d070ca2e60c99929ef274cfced04294d2368193e935c5d6febfd8b601bf865"}, + {file = "Pillow-8.1.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:a3d3e086474ef12ef13d42e5f9b7bbf09d39cf6bd4940f982263d6954b13f6a9"}, + {file = "Pillow-8.1.0-pp36-pypy36_pp73-manylinux2010_i686.whl", hash = "sha256:731ca5aabe9085160cf68b2dbef95fc1991015bc0a3a6ea46a371ab88f3d0913"}, + {file = "Pillow-8.1.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:bba80df38cfc17f490ec651c73bb37cd896bc2400cfba27d078c2135223c1206"}, + {file = "Pillow-8.1.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c3d911614b008e8a576b8e5303e3db29224b455d3d66d1b2848ba6ca83f9ece9"}, + {file = "Pillow-8.1.0-pp37-pypy37_pp73-manylinux2010_i686.whl", hash = "sha256:39725acf2d2e9c17356e6835dccebe7a697db55f25a09207e38b835d5e1bc032"}, + {file = "Pillow-8.1.0-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:81c3fa9a75d9f1afafdb916d5995633f319db09bd773cb56b8e39f1e98d90820"}, + {file = "Pillow-8.1.0-pp37-pypy37_pp73-win32.whl", hash = "sha256:b6f00ad5ebe846cc91763b1d0c6d30a8042e02b2316e27b05de04fa6ec831ec5"}, + {file = "Pillow-8.1.0.tar.gz", hash = "sha256:887668e792b7edbfb1d3c9d8b5d8c859269a0f0eba4dda562adb95500f60dbba"}, +] +pygraphviz = [ + {file = "pygraphviz-1.7.zip", hash = "sha256:a7bec6609f37cf1e64898c59f075afd659106cf9356c5f387cecaa2e0cdb2304"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, + {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, +] +regex = [ + {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, + {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, + {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, + {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, + {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, + {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, + {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, + {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, + {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, + {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, + {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, + {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, + {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, +] +six = [ + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +typed-ast = [ + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, + {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, + {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, + {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, + {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, + {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, + {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, + {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, + {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, + {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, + {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, + {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, + {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, + {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, + {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, + {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, + {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, + {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, + {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, + {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, + {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, +] +typing-extensions = [ + {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, + {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, + {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..61b75b7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "pigeon" +version = "0.1.0" +description = "" +authors = ["Your Name "] + +[tool.poetry.dependencies] +python = "^3.8" +matplotlib = "^3.3.4" +antlr4-python3-runtime = "^4.9.1" +graphviz = "^0.16" +pygraphviz = "^1.7" +black = "^20.8b1" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/server.py b/server.py index 1a085f7..0cbea02 100644 --- a/server.py +++ b/server.py @@ -3,21 +3,21 @@ from io import StringIO -pigeon_app = Flask(__name__, static_url_path='') +pigeon_app = Flask(__name__, static_url_path="") -@pigeon_app.route('/') +@pigeon_app.route("/") def index(): - return render_template('index.html') + return render_template("index.html") -@pigeon_app.route('/parse', methods=['GET']) +@pigeon_app.route("/parse", methods=["GET"]) def parse(): - script = request.args.get('script') + script = request.args.get("script") parser = Pigeon.Pigeon() fig = parser.parseAndGenerateImage(script) imgdata = StringIO() - fig.savefig(imgdata, format='svg') + fig.savefig(imgdata, format="svg") return imgdata.getvalue() @@ -33,16 +33,3 @@ def add_header(r): r.headers["Expires"] = "0" # r.headers['Cache-Control'] = 'public, max-age=0' return r - - - - - - - - - - - - -