10 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/91110971f1b3/ Changeset: 91110971f1b3 User: jmchilton Date: 2014-08-14 03:36:10 Summary: Add galaxy.workflow.render module - try to decrease dup between ts and gx. Affected #: 3 files diff -r fb6a06ce35f08f516b8a5d80d2105225c243201b -r 91110971f1b37f121e177cc983d26f777805c1c4 lib/galaxy/webapps/galaxy/controllers/workflow.py --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -39,6 +39,7 @@ edgelist_for_workflow_steps, order_workflow_steps_with_levels, ) +from galaxy.worklfow.render import WorkflowCanvas class StoredWorkflowListGrid( grids.Grid ): @@ -1554,11 +1555,11 @@ def _workflow_to_svg_canvas( self, trans, stored ): workflow = stored.latest_workflow data = [] - canvas = svgfig.canvas(style="stroke:black; fill:none; stroke-width:1px; stroke-linejoin:round; text-anchor:left") - text = svgfig.SVG("g") - connectors = svgfig.SVG("g") - boxes = svgfig.SVG("g") - svgfig.Text.defaults["font-size"] = "10px" + workflow_canvas = WorkflowCanvas() + canvas = workflow_canvas.canvas + text = workflow_canvas.text + connectors = workflow_canvas.connectors + boxes = workflow_canvas.boxes in_pos = {} out_pos = {} margin = 5 @@ -1641,14 +1642,7 @@ text.append( svgfig.SVG("circle", cx=out_conn_pos[0] + widths[output_dict['id']] - margin, cy=out_conn_pos[1] - margin, r=5, fill="#ffffff" ) ) connectors.append( svgfig.Line(adjusted[0], adjusted[1] - margin, in_coords[0] - 10, in_coords[1], arrow_end="true" ).SVG() ) - canvas.append(connectors) - canvas.append(boxes) - canvas.append(text) - width, height = (max_x + max_width + 50), max_y + 300 - canvas['width'] = "%spx" % width - canvas['height'] = "%spx" % height - canvas['viewBox'] = "0 0 %s %s" % (width, height) - + workflow_canvas.finish( max_x, max_width, max_y ) return canvas diff -r fb6a06ce35f08f516b8a5d80d2105225c243201b -r 91110971f1b37f121e177cc983d26f777805c1c4 lib/galaxy/workflow/render.py --- /dev/null +++ b/lib/galaxy/workflow/render.py @@ -0,0 +1,25 @@ +from galaxy import eggs + +eggs.require( "SVGFig" ) +import svgfig + + +class WorkflowCanvas( object ): + + def __init__( self ): + self.canvas = svgfig.canvas( style="stroke:black; fill:none; stroke-width:1px; stroke-linejoin:round; text-anchor:left" ) + self.text = svgfig.SVG( "g" ) + self.connectors = svgfig.SVG( "g" ) + self.boxes = svgfig.SVG( "g" ) + + svgfig.Text.defaults[ "font-size" ] = "10px" + + def finish( self, max_x, max_width, max_y ): + canvas = self.canvas + canvas.append( self.connectors ) + canvas.append( self.boxes ) + canvas.append( self.text ) + width, height = ( max_x + max_width + 50 ), max_y + 300 + canvas[ 'width' ] = "%s px" % width + canvas[ 'height' ] = "%s px" % height + canvas[ 'viewBox' ] = "0 0 %s %s" % ( width, height ) diff -r fb6a06ce35f08f516b8a5d80d2105225c243201b -r 91110971f1b37f121e177cc983d26f777805c1c4 lib/tool_shed/util/workflow_util.py --- a/lib/tool_shed/util/workflow_util.py +++ b/lib/tool_shed/util/workflow_util.py @@ -7,6 +7,7 @@ from galaxy import eggs from galaxy.util import json from galaxy.util.sanitize_html import sanitize_html +from galaxy.worklfow.render import WorkflowCanvas from galaxy.workflow.modules import InputDataModule from galaxy.workflow.modules import ToolModule from galaxy.workflow.modules import WorkflowModuleFactory @@ -207,11 +208,12 @@ repository_id=repository_id, changeset_revision=changeset_revision ) data = [] - canvas = svgfig.canvas( style="stroke:black; fill:none; stroke-width:1px; stroke-linejoin:round; text-anchor:left" ) - text = svgfig.SVG( "g" ) - connectors = svgfig.SVG( "g" ) - boxes = svgfig.SVG( "g" ) - svgfig.Text.defaults[ "font-size" ] = "10px" + workflow_canvas = WorkflowCanvas() + canvas = workflow_canvas.canvas + text = workflow_canvas.text + connectors = workflow_canvas.connectors + boxes = workflow_canvas.boxes + in_pos = {} out_pos = {} margin = 5 @@ -311,13 +313,7 @@ in_coords[ 0 ] - 10, in_coords[ 1 ], arrow_end = "true" ).SVG() ) - canvas.append( connectors ) - canvas.append( boxes ) - canvas.append( text ) - width, height = ( max_x + max_width + 50 ), max_y + 300 - canvas[ 'width' ] = "%s px" % width - canvas[ 'height' ] = "%s px" % height - canvas[ 'viewBox' ] = "0 0 %s %s" % ( width, height ) + workflow_canvas.finish( max_x, max_width, max_y ) trans.response.set_content_type( "image/svg+xml" ) return canvas.standalone_xml() https://bitbucket.org/galaxy/galaxy-central/commits/e88f0fe18454/ Changeset: e88f0fe18454 User: jmchilton Date: 2014-08-14 03:36:10 Summary: More SVG rendering de-dup. Affected #: 3 files diff -r 91110971f1b37f121e177cc983d26f777805c1c4 -r e88f0fe184543ce8c64d11e6af445ba4f7ea2a82 lib/galaxy/webapps/galaxy/controllers/workflow.py --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -39,7 +39,7 @@ edgelist_for_workflow_steps, order_workflow_steps_with_levels, ) -from galaxy.worklfow.render import WorkflowCanvas +from galaxy.workflow.render import WorkflowCanvas, MARGIN, LINE_SPACING class StoredWorkflowListGrid( grids.Grid ): @@ -1559,14 +1559,7 @@ canvas = workflow_canvas.canvas text = workflow_canvas.text connectors = workflow_canvas.connectors - boxes = workflow_canvas.boxes - in_pos = {} - out_pos = {} - margin = 5 - line_px = 16 # how much spacing between input/outputs - widths = {} # store px width for boxes of each step - max_width, max_x, max_y = 0, 0, 0 - + margin = MARGIN for step in workflow.steps: # Load from database representation module = module_factory.from_workflow_step( trans, step ) @@ -1588,61 +1581,27 @@ data.append(step_dict) x, y = step.position['left'], step.position['top'] - count = 0 max_len = len(module.get_name()) * 1.5 text.append( svgfig.Text(x, y + 20, module.get_name(), **{"font-size": "14px"} ).SVG() ) - y += 45 - for di in module.get_data_inputs(): - cur_y = y + count * line_px - if step.order_index not in in_pos: - in_pos[step.order_index] = {} - in_pos[step.order_index][di['name']] = (x, cur_y) - text.append( svgfig.Text(x, cur_y, di['label']).SVG() ) - count += 1 - max_len = max(max_len, len(di['label'])) - - if len(module.get_data_inputs()) > 0: - y += 15 - - for do in module.get_data_outputs(): - cur_y = y + count * line_px - if step.order_index not in out_pos: - out_pos[step.order_index] = {} - out_pos[step.order_index][do['name']] = (x, cur_y) - text.append( svgfig.Text(x, cur_y, do['name']).SVG() ) - count += 1 - max_len = max(max_len, len(do['name'])) - - widths[step.order_index] = max_len * 5.5 - max_x = max(max_x, step.position['left']) - max_y = max(max_y, step.position['top']) - max_width = max(max_width, widths[step.order_index]) + module_data_inputs = module.get_data_inputs() + module_data_outputs = module.get_data_outputs() + order_index = step.order_index + workflow_canvas.add_text( module_data_inputs, module_data_outputs, order_index, x, y, max_len ) for step_dict in data: - width = widths[step_dict['id']] - x, y = step_dict['position']['left'], step_dict['position']['top'] - boxes.append( svgfig.Rect(x - margin, y, x + width - margin, y + 30, fill="#EBD9B2").SVG() ) - box_height = (len(step_dict['data_inputs']) + len(step_dict['data_outputs'])) * line_px + margin - - # Draw separator line - if len(step_dict['data_inputs']) > 0: - box_height += 15 - sep_y = y + len(step_dict['data_inputs']) * line_px + 40 - text.append( svgfig.Line(x - margin, sep_y, x + width - margin, sep_y).SVG() ) - - # input/output box - boxes.append( svgfig.Rect(x - margin, y + 30, x + width - margin, y + 30 + box_height, fill="#ffffff").SVG() ) - + fill = "#EBD9B2" + width = workflow_canvas.widths[step_dict['id']] + workflow_canvas.add_boxes( step_dict, width, fill ) for conn, output_dict in step_dict['input_connections'].iteritems(): - in_coords = in_pos[step_dict['id']][conn] - out_conn_pos = out_pos[output_dict['id']][output_dict['output_name']] - adjusted = (out_conn_pos[0] + widths[output_dict['id']], out_conn_pos[1]) - text.append( svgfig.SVG("circle", cx=out_conn_pos[0] + widths[output_dict['id']] - margin, cy=out_conn_pos[1] - margin, r=5, fill="#ffffff" ) ) + in_coords = workflow_canvas.in_pos[step_dict['id']][conn] + out_conn_pos = workflow_canvas.out_pos[output_dict['id']][output_dict['output_name']] + adjusted = (out_conn_pos[0] + workflow_canvas.widths[output_dict['id']], out_conn_pos[1]) + text.append( svgfig.SVG("circle", cx=out_conn_pos[0] + workflow_canvas.widths[output_dict['id']] - margin, cy=out_conn_pos[1] - margin, r=5, fill="#ffffff" ) ) connectors.append( svgfig.Line(adjusted[0], adjusted[1] - margin, in_coords[0] - 10, in_coords[1], arrow_end="true" ).SVG() ) - workflow_canvas.finish( max_x, max_width, max_y ) + workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) return canvas diff -r 91110971f1b37f121e177cc983d26f777805c1c4 -r e88f0fe184543ce8c64d11e6af445ba4f7ea2a82 lib/galaxy/workflow/render.py --- a/lib/galaxy/workflow/render.py +++ b/lib/galaxy/workflow/render.py @@ -3,6 +3,9 @@ eggs.require( "SVGFig" ) import svgfig +MARGIN = 5 +LINE_SPACING = 15 + class WorkflowCanvas( object ): @@ -14,6 +17,13 @@ svgfig.Text.defaults[ "font-size" ] = "10px" + self.in_pos = {} + self.out_pos = {} + self.widths = {} + self.max_x = 0 + self.max_y = 0 + self.max_width = 0 + def finish( self, max_x, max_width, max_y ): canvas = self.canvas canvas.append( self.connectors ) @@ -23,3 +33,50 @@ canvas[ 'width' ] = "%s px" % width canvas[ 'height' ] = "%s px" % height canvas[ 'viewBox' ] = "0 0 %s %s" % ( width, height ) + + def add_boxes( self, step_dict, width, name_fill ): + margin = MARGIN + line_px = LINE_SPACING + + x, y = step_dict[ 'position' ][ 'left' ], step_dict[ 'position' ][ 'top' ] + self.boxes.append( svgfig.Rect( x - margin, y, x + width - margin, y + 30, fill=name_fill ).SVG() ) + box_height = ( len( step_dict[ 'data_inputs' ] ) + len( step_dict[ 'data_outputs' ] ) ) * line_px + margin + # Draw separator line. + if len( step_dict[ 'data_inputs' ] ) > 0: + box_height += 15 + sep_y = y + len( step_dict[ 'data_inputs' ] ) * line_px + 40 + self.text.append( svgfig.Line( x - margin, sep_y, x + width - margin, sep_y ).SVG() ) + # Define an input/output box. + self.boxes.append( svgfig.Rect( x - margin, y + 30, x + width - margin, y + 30 + box_height, fill="#ffffff" ).SVG() ) + + def add_text( self, module_data_inputs, module_data_outputs, order_index, left, top, max_len ): + x, y = left, top + y += 45 + + count = 0 + line_px = LINE_SPACING + in_pos = self.in_pos + out_pos = self.out_pos + + for di in module_data_inputs: + cur_y = y + count * line_px + if order_index not in in_pos: + in_pos[ order_index ] = {} + in_pos[ order_index ][ di[ 'name' ] ] = ( x, cur_y ) + self.text.append( svgfig.Text( x, cur_y, di[ 'label' ] ).SVG() ) + count += 1 + max_len = max( max_len, len( di[ 'label' ] ) ) + if len( module_data_inputs ) > 0: + y += 15 + for do in module_data_outputs: + cur_y = y + count * line_px + if order_index not in out_pos: + out_pos[ order_index ] = {} + out_pos[ order_index ][ do[ 'name' ] ] = ( x, cur_y ) + self.text.append( svgfig.Text( x, cur_y, do[ 'name' ] ).SVG() ) + count += 1 + max_len = max( max_len, len( do['name' ] ) ) + self.widths[ order_index ] = max_len * 5.5 + self.max_x = max( self.max_x, left ) + self.max_y = max( self.max_y, top ) + self.max_width = max( self.max_width, self.widths[ order_index ] ) diff -r 91110971f1b37f121e177cc983d26f777805c1c4 -r e88f0fe184543ce8c64d11e6af445ba4f7ea2a82 lib/tool_shed/util/workflow_util.py --- a/lib/tool_shed/util/workflow_util.py +++ b/lib/tool_shed/util/workflow_util.py @@ -7,7 +7,7 @@ from galaxy import eggs from galaxy.util import json from galaxy.util.sanitize_html import sanitize_html -from galaxy.worklfow.render import WorkflowCanvas +from galaxy.workflow.render import WorkflowCanvas, MARGIN, LINE_SPACING from galaxy.workflow.modules import InputDataModule from galaxy.workflow.modules import ToolModule from galaxy.workflow.modules import WorkflowModuleFactory @@ -212,16 +212,9 @@ canvas = workflow_canvas.canvas text = workflow_canvas.text connectors = workflow_canvas.connectors - boxes = workflow_canvas.boxes - in_pos = {} - out_pos = {} - margin = 5 - # Spacing between input/outputs. - line_px = 16 + margin = MARGIN # Store px width for boxes of each step. - widths = {} - max_width, max_x, max_y = 0, 0, 0 for step in workflow.steps: step.upgrade_messages = {} module = module_factory.from_workflow_step( trans, repository_id, changeset_revision, tools_metadata, step ) @@ -239,72 +232,42 @@ step_dict[ 'input_connections' ] = input_conn_dict data.append( step_dict ) x, y = step.position[ 'left' ], step.position[ 'top' ] - count = 0 module_name = get_workflow_module_name( module, missing_tool_tups ) max_len = len( module_name ) * 1.5 text.append( svgfig.Text( x, y + 20, module_name, **{ "font-size": "14px" } ).SVG() ) - y += 45 - for di in module_data_inputs: - cur_y = y + count * line_px - if step.order_index not in in_pos: - in_pos[ step.order_index ] = {} - in_pos[ step.order_index ][ di[ 'name' ] ] = ( x, cur_y ) - text.append( svgfig.Text( x, cur_y, di[ 'label' ] ).SVG() ) - count += 1 - max_len = max( max_len, len( di[ 'label' ] ) ) - if len( module.get_data_inputs() ) > 0: - y += 15 - for do in module_data_outputs: - cur_y = y + count * line_px - if step.order_index not in out_pos: - out_pos[ step.order_index ] = {} - out_pos[ step.order_index ][ do[ 'name' ] ] = ( x, cur_y ) - text.append( svgfig.Text( x, cur_y, do[ 'name' ] ).SVG() ) - count += 1 - max_len = max( max_len, len( do['name' ] ) ) - widths[ step.order_index ] = max_len * 5.5 - max_x = max( max_x, step.position[ 'left' ] ) - max_y = max( max_y, step.position[ 'top' ] ) - max_width = max( max_width, widths[ step.order_index ] ) + order_index = step.order_index + workflow_canvas.add_text( module_data_inputs, module_data_outputs, order_index, x, y, max_len ) for step_dict in data: + # Only highlight missing tools if displaying in the tool shed. tool_unavailable = step_dict[ 'tool_errors' ] - width = widths[ step_dict[ 'id' ] ] - x, y = step_dict[ 'position' ][ 'left' ], step_dict[ 'position' ][ 'top' ] - # Only highlight missing tools if displaying in the tool shed. if trans.webapp.name == 'tool_shed' and tool_unavailable: fill = "#EBBCB2" else: fill = "#EBD9B2" - boxes.append( svgfig.Rect( x - margin, y, x + width - margin, y + 30, fill=fill ).SVG() ) - box_height = ( len( step_dict[ 'data_inputs' ] ) + len( step_dict[ 'data_outputs' ] ) ) * line_px + margin - # Draw separator line. - if len( step_dict[ 'data_inputs' ] ) > 0: - box_height += 15 - sep_y = y + len( step_dict[ 'data_inputs' ] ) * line_px + 40 - text.append( svgfig.Line( x - margin, sep_y, x + width - margin, sep_y ).SVG() ) - # Define an input/output box. - boxes.append( svgfig.Rect( x - margin, y + 30, x + width - margin, y + 30 + box_height, fill="#ffffff" ).SVG() ) + + width = workflow_canvas.widths[ step_dict[ 'id' ] ] + workflow_canvas.add_boxes( step_dict, width, fill ) for conn, output_dict in step_dict[ 'input_connections' ].iteritems(): - in_coords = in_pos[ step_dict[ 'id' ] ][ conn ] + in_coords = workflow_canvas.in_pos[ step_dict[ 'id' ] ][ conn ] # out_pos_index will be a step number like 1, 2, 3... out_pos_index = output_dict[ 'id' ] # out_pos_name will be a string like 'o', 'o2', etc. out_pos_name = output_dict[ 'output_name' ] - if out_pos_index in out_pos: + if out_pos_index in workflow_canvas.out_pos: # out_conn_index_dict will be something like: # 7: {'o': (824.5, 618)} - out_conn_index_dict = out_pos[ out_pos_index ] + out_conn_index_dict = workflow_canvas.out_pos[ out_pos_index ] if out_pos_name in out_conn_index_dict: - out_conn_pos = out_pos[ out_pos_index ][ out_pos_name ] + out_conn_pos = workflow_canvas.out_pos[ out_pos_index ][ out_pos_name ] else: # Take any key / value pair available in out_conn_index_dict. # A problem will result if the dictionary is empty. if out_conn_index_dict.keys(): key = out_conn_index_dict.keys()[0] - out_conn_pos = out_pos[ out_pos_index ][ key ] - adjusted = ( out_conn_pos[ 0 ] + widths[ output_dict[ 'id' ] ], out_conn_pos[ 1 ] ) + out_conn_pos = workflow_canvas.out_pos[ out_pos_index ][ key ] + adjusted = ( out_conn_pos[ 0 ] + workflow_canvas.widths[ output_dict[ 'id' ] ], out_conn_pos[ 1 ] ) text.append( svgfig.SVG( "circle", - cx=out_conn_pos[ 0 ] + widths[ output_dict[ 'id' ] ] - margin, + cx=out_conn_pos[ 0 ] + workflow_canvas.widths[ output_dict[ 'id' ] ] - margin, cy=out_conn_pos[ 1 ] - margin, r = 5, fill="#ffffff" ) ) @@ -313,7 +276,7 @@ in_coords[ 0 ] - 10, in_coords[ 1 ], arrow_end = "true" ).SVG() ) - workflow_canvas.finish( max_x, max_width, max_y ) + workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) trans.response.set_content_type( "image/svg+xml" ) return canvas.standalone_xml() https://bitbucket.org/galaxy/galaxy-central/commits/b9858d6d9a22/ Changeset: b9858d6d9a22 User: jmchilton Date: 2014-08-14 03:36:10 Summary: More SVG rendering de-dup. Affected #: 3 files diff -r e88f0fe184543ce8c64d11e6af445ba4f7ea2a82 -r b9858d6d9a22f8d8c177ed39e51c35e2b6e9325c lib/galaxy/webapps/galaxy/controllers/workflow.py --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -1580,15 +1580,10 @@ data.append(step_dict) - x, y = step.position['left'], step.position['top'] - - max_len = len(module.get_name()) * 1.5 - text.append( svgfig.Text(x, y + 20, module.get_name(), **{"font-size": "14px"} ).SVG() ) - + module_name = module.get_name() module_data_inputs = module.get_data_inputs() module_data_outputs = module.get_data_outputs() - order_index = step.order_index - workflow_canvas.add_text( module_data_inputs, module_data_outputs, order_index, x, y, max_len ) + workflow_canvas.add_text( module_data_inputs, module_data_outputs, step, module_name ) for step_dict in data: fill = "#EBD9B2" diff -r e88f0fe184543ce8c64d11e6af445ba4f7ea2a82 -r b9858d6d9a22f8d8c177ed39e51c35e2b6e9325c lib/galaxy/workflow/render.py --- a/lib/galaxy/workflow/render.py +++ b/lib/galaxy/workflow/render.py @@ -49,8 +49,13 @@ # Define an input/output box. self.boxes.append( svgfig.Rect( x - margin, y + 30, x + width - margin, y + 30 + box_height, fill="#ffffff" ).SVG() ) - def add_text( self, module_data_inputs, module_data_outputs, order_index, left, top, max_len ): + def add_text( self, module_data_inputs, module_data_outputs, step, module_name ): + left, top = step.position[ 'left' ], step.position[ 'top' ] x, y = left, top + order_index = step.order_index + max_len = len( module_name ) * 1.5 + self.text.append( svgfig.Text( x, y + 20, module_name, **{ "font-size": "14px" } ).SVG() ) + y += 45 count = 0 diff -r e88f0fe184543ce8c64d11e6af445ba4f7ea2a82 -r b9858d6d9a22f8d8c177ed39e51c35e2b6e9325c lib/tool_shed/util/workflow_util.py --- a/lib/tool_shed/util/workflow_util.py +++ b/lib/tool_shed/util/workflow_util.py @@ -231,12 +231,8 @@ input_conn_dict[ conn.input_name ] = dict( id=conn.output_step.order_index, output_name=conn.output_name ) step_dict[ 'input_connections' ] = input_conn_dict data.append( step_dict ) - x, y = step.position[ 'left' ], step.position[ 'top' ] module_name = get_workflow_module_name( module, missing_tool_tups ) - max_len = len( module_name ) * 1.5 - text.append( svgfig.Text( x, y + 20, module_name, **{ "font-size": "14px" } ).SVG() ) - order_index = step.order_index - workflow_canvas.add_text( module_data_inputs, module_data_outputs, order_index, x, y, max_len ) + workflow_canvas.add_text( module_data_inputs, module_data_outputs, step, module_name ) for step_dict in data: # Only highlight missing tools if displaying in the tool shed. tool_unavailable = step_dict[ 'tool_errors' ] https://bitbucket.org/galaxy/galaxy-central/commits/c12e8b96a97c/ Changeset: c12e8b96a97c User: jmchilton Date: 2014-08-14 03:36:10 Summary: Refactor ts/gx workflow svg rendering slightly so they look more similar. Affected #: 2 files diff -r b9858d6d9a22f8d8c177ed39e51c35e2b6e9325c -r c12e8b96a97c802d33c3d276232350e59cafb506 lib/galaxy/webapps/galaxy/controllers/workflow.py --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -1591,7 +1591,14 @@ workflow_canvas.add_boxes( step_dict, width, fill ) for conn, output_dict in step_dict['input_connections'].iteritems(): in_coords = workflow_canvas.in_pos[step_dict['id']][conn] - out_conn_pos = workflow_canvas.out_pos[output_dict['id']][output_dict['output_name']] + # out_pos_index will be a step number like 1, 2, 3... + out_pos_index = output_dict[ 'id' ] + # out_pos_name will be a string like 'o', 'o2', etc. + out_pos_name = output_dict[ 'output_name' ] + # out_conn_index_dict will be something like: + # 7: {'o': (824.5, 618)} + out_conn_index_dict = workflow_canvas.out_pos[ out_pos_index ] + out_conn_pos = out_conn_index_dict[out_pos_name] adjusted = (out_conn_pos[0] + workflow_canvas.widths[output_dict['id']], out_conn_pos[1]) text.append( svgfig.SVG("circle", cx=out_conn_pos[0] + workflow_canvas.widths[output_dict['id']] - margin, cy=out_conn_pos[1] - margin, r=5, fill="#ffffff" ) ) connectors.append( svgfig.Line(adjusted[0], adjusted[1] - margin, in_coords[0] - 10, in_coords[1], arrow_end="true" ).SVG() ) diff -r b9858d6d9a22f8d8c177ed39e51c35e2b6e9325c -r c12e8b96a97c802d33c3d276232350e59cafb506 lib/tool_shed/util/workflow_util.py --- a/lib/tool_shed/util/workflow_util.py +++ b/lib/tool_shed/util/workflow_util.py @@ -254,7 +254,7 @@ # 7: {'o': (824.5, 618)} out_conn_index_dict = workflow_canvas.out_pos[ out_pos_index ] if out_pos_name in out_conn_index_dict: - out_conn_pos = workflow_canvas.out_pos[ out_pos_index ][ out_pos_name ] + out_conn_pos = out_conn_index_dict[ out_pos_name ] else: # Take any key / value pair available in out_conn_index_dict. # A problem will result if the dictionary is empty. https://bitbucket.org/galaxy/galaxy-central/commits/287b8c5c6f8e/ Changeset: 287b8c5c6f8e User: jmchilton Date: 2014-08-14 03:36:10 Summary: More SVG rendering de-dup. Using more conservative logic from the tool shed - not sure picking random connections the way it is doing however is appropriate. Affected #: 3 files diff -r c12e8b96a97c802d33c3d276232350e59cafb506 -r 287b8c5c6f8e05c29dc5c8c262e28aaa621cd77b lib/galaxy/webapps/galaxy/controllers/workflow.py --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -1590,18 +1590,7 @@ width = workflow_canvas.widths[step_dict['id']] workflow_canvas.add_boxes( step_dict, width, fill ) for conn, output_dict in step_dict['input_connections'].iteritems(): - in_coords = workflow_canvas.in_pos[step_dict['id']][conn] - # out_pos_index will be a step number like 1, 2, 3... - out_pos_index = output_dict[ 'id' ] - # out_pos_name will be a string like 'o', 'o2', etc. - out_pos_name = output_dict[ 'output_name' ] - # out_conn_index_dict will be something like: - # 7: {'o': (824.5, 618)} - out_conn_index_dict = workflow_canvas.out_pos[ out_pos_index ] - out_conn_pos = out_conn_index_dict[out_pos_name] - adjusted = (out_conn_pos[0] + workflow_canvas.widths[output_dict['id']], out_conn_pos[1]) - text.append( svgfig.SVG("circle", cx=out_conn_pos[0] + workflow_canvas.widths[output_dict['id']] - margin, cy=out_conn_pos[1] - margin, r=5, fill="#ffffff" ) ) - connectors.append( svgfig.Line(adjusted[0], adjusted[1] - margin, in_coords[0] - 10, in_coords[1], arrow_end="true" ).SVG() ) + workflow_canvas.add_connection( step_dict, conn, output_dict ) workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) return canvas diff -r c12e8b96a97c802d33c3d276232350e59cafb506 -r 287b8c5c6f8e05c29dc5c8c262e28aaa621cd77b lib/galaxy/workflow/render.py --- a/lib/galaxy/workflow/render.py +++ b/lib/galaxy/workflow/render.py @@ -85,3 +85,35 @@ self.max_x = max( self.max_x, left ) self.max_y = max( self.max_y, top ) self.max_width = max( self.max_width, self.widths[ order_index ] ) + + def add_connection( self, step_dict, conn, output_dict): + margin = MARGIN + + in_coords = self.in_pos[ step_dict[ 'id' ] ][ conn ] + # out_pos_index will be a step number like 1, 2, 3... + out_pos_index = output_dict[ 'id' ] + # out_pos_name will be a string like 'o', 'o2', etc. + out_pos_name = output_dict[ 'output_name' ] + if out_pos_index in self.out_pos: + # out_conn_index_dict will be something like: + # 7: {'o': (824.5, 618)} + out_conn_index_dict = self.out_pos[ out_pos_index ] + if out_pos_name in out_conn_index_dict: + out_conn_pos = out_conn_index_dict[ out_pos_name ] + else: + # Take any key / value pair available in out_conn_index_dict. + # A problem will result if the dictionary is empty. + if out_conn_index_dict.keys(): + key = out_conn_index_dict.keys()[0] + out_conn_pos = self.out_pos[ out_pos_index ][ key ] + adjusted = ( out_conn_pos[ 0 ] + self.widths[ output_dict[ 'id' ] ], out_conn_pos[ 1 ] ) + self.text.append( svgfig.SVG( "circle", + cx=out_conn_pos[ 0 ] + self.widths[ output_dict[ 'id' ] ] - margin, + cy=out_conn_pos[ 1 ] - margin, + r=5, + fill="#ffffff" ) ) + self.connectors.append( svgfig.Line( adjusted[ 0 ], + adjusted[ 1 ] - margin, + in_coords[ 0 ] - 10, + in_coords[ 1 ], + arrow_end="true" ).SVG() ) diff -r c12e8b96a97c802d33c3d276232350e59cafb506 -r 287b8c5c6f8e05c29dc5c8c262e28aaa621cd77b lib/tool_shed/util/workflow_util.py --- a/lib/tool_shed/util/workflow_util.py +++ b/lib/tool_shed/util/workflow_util.py @@ -244,34 +244,7 @@ width = workflow_canvas.widths[ step_dict[ 'id' ] ] workflow_canvas.add_boxes( step_dict, width, fill ) for conn, output_dict in step_dict[ 'input_connections' ].iteritems(): - in_coords = workflow_canvas.in_pos[ step_dict[ 'id' ] ][ conn ] - # out_pos_index will be a step number like 1, 2, 3... - out_pos_index = output_dict[ 'id' ] - # out_pos_name will be a string like 'o', 'o2', etc. - out_pos_name = output_dict[ 'output_name' ] - if out_pos_index in workflow_canvas.out_pos: - # out_conn_index_dict will be something like: - # 7: {'o': (824.5, 618)} - out_conn_index_dict = workflow_canvas.out_pos[ out_pos_index ] - if out_pos_name in out_conn_index_dict: - out_conn_pos = out_conn_index_dict[ out_pos_name ] - else: - # Take any key / value pair available in out_conn_index_dict. - # A problem will result if the dictionary is empty. - if out_conn_index_dict.keys(): - key = out_conn_index_dict.keys()[0] - out_conn_pos = workflow_canvas.out_pos[ out_pos_index ][ key ] - adjusted = ( out_conn_pos[ 0 ] + workflow_canvas.widths[ output_dict[ 'id' ] ], out_conn_pos[ 1 ] ) - text.append( svgfig.SVG( "circle", - cx=out_conn_pos[ 0 ] + workflow_canvas.widths[ output_dict[ 'id' ] ] - margin, - cy=out_conn_pos[ 1 ] - margin, - r = 5, - fill="#ffffff" ) ) - connectors.append( svgfig.Line( adjusted[ 0 ], - adjusted[ 1 ] - margin, - in_coords[ 0 ] - 10, - in_coords[ 1 ], - arrow_end = "true" ).SVG() ) + workflow_canvas.add_connection( step_dict, conn, output_dict ) workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) trans.response.set_content_type( "image/svg+xml" ) return canvas.standalone_xml() https://bitbucket.org/galaxy/galaxy-central/commits/c9b972306e77/ Changeset: c9b972306e77 User: jmchilton Date: 2014-08-14 03:36:10 Summary: More SVG rendering de-dup. Affected #: 3 files diff -r 287b8c5c6f8e05c29dc5c8c262e28aaa621cd77b -r c9b972306e7730c9bede45ef60abb4073ad0cf31 lib/galaxy/webapps/galaxy/controllers/workflow.py --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -1585,13 +1585,7 @@ module_data_outputs = module.get_data_outputs() workflow_canvas.add_text( module_data_inputs, module_data_outputs, step, module_name ) - for step_dict in data: - fill = "#EBD9B2" - width = workflow_canvas.widths[step_dict['id']] - workflow_canvas.add_boxes( step_dict, width, fill ) - for conn, output_dict in step_dict['input_connections'].iteritems(): - workflow_canvas.add_connection( step_dict, conn, output_dict ) - + workflow_canvas.add_steps( data ) workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) return canvas diff -r 287b8c5c6f8e05c29dc5c8c262e28aaa621cd77b -r c9b972306e7730c9bede45ef60abb4073ad0cf31 lib/galaxy/workflow/render.py --- a/lib/galaxy/workflow/render.py +++ b/lib/galaxy/workflow/render.py @@ -117,3 +117,17 @@ in_coords[ 0 ] - 10, in_coords[ 1 ], arrow_end="true" ).SVG() ) + + def add_steps( self, data, highlight_errors=False ): + # Only highlight missing tools if displaying in the tool shed. + for step_dict in data: + tool_unavailable = step_dict[ 'tool_errors' ] + if highlight_errors and tool_unavailable: + fill = "#EBBCB2" + else: + fill = "#EBD9B2" + + width = self.widths[ step_dict[ 'id' ] ] + self.add_boxes( step_dict, width, fill ) + for conn, output_dict in step_dict[ 'input_connections' ].iteritems(): + self.add_connection( step_dict, conn, output_dict ) diff -r 287b8c5c6f8e05c29dc5c8c262e28aaa621cd77b -r c9b972306e7730c9bede45ef60abb4073ad0cf31 lib/tool_shed/util/workflow_util.py --- a/lib/tool_shed/util/workflow_util.py +++ b/lib/tool_shed/util/workflow_util.py @@ -233,18 +233,7 @@ data.append( step_dict ) module_name = get_workflow_module_name( module, missing_tool_tups ) workflow_canvas.add_text( module_data_inputs, module_data_outputs, step, module_name ) - for step_dict in data: - # Only highlight missing tools if displaying in the tool shed. - tool_unavailable = step_dict[ 'tool_errors' ] - if trans.webapp.name == 'tool_shed' and tool_unavailable: - fill = "#EBBCB2" - else: - fill = "#EBD9B2" - - width = workflow_canvas.widths[ step_dict[ 'id' ] ] - workflow_canvas.add_boxes( step_dict, width, fill ) - for conn, output_dict in step_dict[ 'input_connections' ].iteritems(): - workflow_canvas.add_connection( step_dict, conn, output_dict ) + workflow_canvas.add_steps( data, highlight_errors=True ) workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) trans.response.set_content_type( "image/svg+xml" ) return canvas.standalone_xml() https://bitbucket.org/galaxy/galaxy-central/commits/6482359d4a7c/ Changeset: 6482359d4a7c User: jmchilton Date: 2014-08-14 03:36:10 Summary: More SVG rendering de-dup. Affected #: 3 files diff -r c9b972306e7730c9bede45ef60abb4073ad0cf31 -r 6482359d4a7c429574ae4c4631eebf3f7bcf3350 lib/galaxy/webapps/galaxy/controllers/workflow.py --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -1554,7 +1554,6 @@ def _workflow_to_svg_canvas( self, trans, stored ): workflow = stored.latest_workflow - data = [] workflow_canvas = WorkflowCanvas() canvas = workflow_canvas.canvas text = workflow_canvas.text @@ -1563,29 +1562,17 @@ for step in workflow.steps: # Load from database representation module = module_factory.from_workflow_step( trans, step ) - - # Pack attributes into plain dictionary - step_dict = { - 'id': step.order_index, - 'data_inputs': module.get_data_inputs(), - 'data_outputs': module.get_data_outputs(), - 'position': step.position - } - - input_conn_dict = {} - for conn in step.input_connections: - input_conn_dict[ conn.input_name ] = \ - dict( id=conn.output_step.order_index, output_name=conn.output_name ) - step_dict['input_connections'] = input_conn_dict - - data.append(step_dict) - module_name = module.get_name() module_data_inputs = module.get_data_inputs() module_data_outputs = module.get_data_outputs() - workflow_canvas.add_text( module_data_inputs, module_data_outputs, step, module_name ) + workflow_canvas.populate_data_for_step( + step, + module_name, + module_data_inputs, + module_data_outputs, + ) - workflow_canvas.add_steps( data ) + workflow_canvas.add_steps( ) workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) return canvas diff -r c9b972306e7730c9bede45ef60abb4073ad0cf31 -r 6482359d4a7c429574ae4c4631eebf3f7bcf3350 lib/galaxy/workflow/render.py --- a/lib/galaxy/workflow/render.py +++ b/lib/galaxy/workflow/render.py @@ -24,6 +24,8 @@ self.max_y = 0 self.max_width = 0 + self.data = [] + def finish( self, max_x, max_width, max_y ): canvas = self.canvas canvas.append( self.connectors ) @@ -118,9 +120,9 @@ in_coords[ 1 ], arrow_end="true" ).SVG() ) - def add_steps( self, data, highlight_errors=False ): + def add_steps( self, highlight_errors=False ): # Only highlight missing tools if displaying in the tool shed. - for step_dict in data: + for step_dict in self.data: tool_unavailable = step_dict[ 'tool_errors' ] if highlight_errors and tool_unavailable: fill = "#EBBCB2" @@ -131,3 +133,22 @@ self.add_boxes( step_dict, width, fill ) for conn, output_dict in step_dict[ 'input_connections' ].iteritems(): self.add_connection( step_dict, conn, output_dict ) + + def populate_data_for_step( self, step, module_name, module_data_inputs, module_data_outputs, tool_errors=None ): + step_dict = { + 'id': step.order_index, + 'data_inputs': module_data_inputs, + 'data_outputs': module_data_outputs, + 'position': step.position + } + if tool_errors: + step_dict[ 'tool_errors' ] = tool_errors + + input_conn_dict = {} + for conn in step.input_connections: + input_conn_dict[ conn.input_name ] = \ + dict( id=conn.output_step.order_index, output_name=conn.output_name ) + step_dict['input_connections'] = input_conn_dict + + self.data.append(step_dict) + self.add_text( module_data_inputs, module_data_outputs, step, module_name ) diff -r c9b972306e7730c9bede45ef60abb4073ad0cf31 -r 6482359d4a7c429574ae4c4631eebf3f7bcf3350 lib/tool_shed/util/workflow_util.py --- a/lib/tool_shed/util/workflow_util.py +++ b/lib/tool_shed/util/workflow_util.py @@ -207,7 +207,6 @@ tools_metadata=tools_metadata, repository_id=repository_id, changeset_revision=changeset_revision ) - data = [] workflow_canvas = WorkflowCanvas() canvas = workflow_canvas.canvas text = workflow_canvas.text @@ -221,19 +220,15 @@ tool_errors = module.type == 'tool' and not module.tool module_data_inputs = get_workflow_data_inputs( step, module ) module_data_outputs = get_workflow_data_outputs( step, module, workflow.steps ) - step_dict = { 'id' : step.order_index, - 'data_inputs' : module_data_inputs, - 'data_outputs' : module_data_outputs, - 'position' : step.position, - 'tool_errors' : tool_errors } - input_conn_dict = {} - for conn in step.input_connections: - input_conn_dict[ conn.input_name ] = dict( id=conn.output_step.order_index, output_name=conn.output_name ) - step_dict[ 'input_connections' ] = input_conn_dict - data.append( step_dict ) module_name = get_workflow_module_name( module, missing_tool_tups ) - workflow_canvas.add_text( module_data_inputs, module_data_outputs, step, module_name ) - workflow_canvas.add_steps( data, highlight_errors=True ) + workflow_canvas.populate_data_for_step( + step, + module_name, + module_data_inputs, + module_data_outputs, + tool_errors=tool_errors + ) + workflow_canvas.add_steps( highlight_errors=True ) workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) trans.response.set_content_type( "image/svg+xml" ) return canvas.standalone_xml() https://bitbucket.org/galaxy/galaxy-central/commits/a464ba73488c/ Changeset: a464ba73488c User: jmchilton Date: 2014-08-14 03:36:10 Summary: More SVG rendering de-dup. Affected #: 3 files diff -r 6482359d4a7c429574ae4c4631eebf3f7bcf3350 -r a464ba73488cb4fc82e398d1c84bd019bf128524 lib/galaxy/webapps/galaxy/controllers/workflow.py --- a/lib/galaxy/webapps/galaxy/controllers/workflow.py +++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py @@ -1,12 +1,8 @@ -import pkg_resources -pkg_resources.require( "SVGFig" ) - import base64 import httplib import json import os import sgmllib -import svgfig import urllib2 from sqlalchemy import and_ @@ -1556,9 +1552,6 @@ workflow = stored.latest_workflow workflow_canvas = WorkflowCanvas() canvas = workflow_canvas.canvas - text = workflow_canvas.text - connectors = workflow_canvas.connectors - margin = MARGIN for step in workflow.steps: # Load from database representation module = module_factory.from_workflow_step( trans, step ) @@ -1573,7 +1566,7 @@ ) workflow_canvas.add_steps( ) - workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) + workflow_canvas.finish( ) return canvas diff -r 6482359d4a7c429574ae4c4631eebf3f7bcf3350 -r a464ba73488cb4fc82e398d1c84bd019bf128524 lib/galaxy/workflow/render.py --- a/lib/galaxy/workflow/render.py +++ b/lib/galaxy/workflow/render.py @@ -26,7 +26,9 @@ self.data = [] - def finish( self, max_x, max_width, max_y ): + def finish( self ): + max_x, max_y, max_width = self.max_x, self.max_y, self.max_width + canvas = self.canvas canvas.append( self.connectors ) canvas.append( self.boxes ) diff -r 6482359d4a7c429574ae4c4631eebf3f7bcf3350 -r a464ba73488cb4fc82e398d1c84bd019bf128524 lib/tool_shed/util/workflow_util.py --- a/lib/tool_shed/util/workflow_util.py +++ b/lib/tool_shed/util/workflow_util.py @@ -4,7 +4,6 @@ import galaxy.tools import galaxy.tools.parameters import galaxy.webapps.galaxy.controllers.workflow -from galaxy import eggs from galaxy.util import json from galaxy.util.sanitize_html import sanitize_html from galaxy.workflow.render import WorkflowCanvas, MARGIN, LINE_SPACING @@ -18,9 +17,6 @@ from tool_shed.util import metadata_util from tool_shed.util import shed_util_common as suc -eggs.require( "SVGFig" ) -import svgfig - log = logging.getLogger( __name__ ) @@ -209,10 +205,6 @@ changeset_revision=changeset_revision ) workflow_canvas = WorkflowCanvas() canvas = workflow_canvas.canvas - text = workflow_canvas.text - connectors = workflow_canvas.connectors - - margin = MARGIN # Store px width for boxes of each step. for step in workflow.steps: step.upgrade_messages = {} @@ -229,7 +221,7 @@ tool_errors=tool_errors ) workflow_canvas.add_steps( highlight_errors=True ) - workflow_canvas.finish( workflow_canvas.max_x, workflow_canvas.max_width, workflow_canvas.max_y ) + workflow_canvas.finish( ) trans.response.set_content_type( "image/svg+xml" ) return canvas.standalone_xml() https://bitbucket.org/galaxy/galaxy-central/commits/57980600c4e3/ Changeset: 57980600c4e3 User: jmchilton Date: 2014-08-14 03:36:10 Summary: Add unit test to merely walk through new workflow render module... ...small fix found by test. Affected #: 2 files diff -r a464ba73488cb4fc82e398d1c84bd019bf128524 -r 57980600c4e34d5a5097ebc2aac72d3ff709031b lib/galaxy/workflow/render.py --- a/lib/galaxy/workflow/render.py +++ b/lib/galaxy/workflow/render.py @@ -125,7 +125,7 @@ def add_steps( self, highlight_errors=False ): # Only highlight missing tools if displaying in the tool shed. for step_dict in self.data: - tool_unavailable = step_dict[ 'tool_errors' ] + tool_unavailable = step_dict.get( 'tool_errors', False ) if highlight_errors and tool_unavailable: fill = "#EBBCB2" else: diff -r a464ba73488cb4fc82e398d1c84bd019bf128524 -r 57980600c4e34d5a5097ebc2aac72d3ff709031b test/unit/workflows/test_render.py --- /dev/null +++ b/test/unit/workflows/test_render.py @@ -0,0 +1,80 @@ +from galaxy import model +from galaxy.util import bunch +from galaxy.workflow import render + + +def test_render(): + # Doesn't check anything about the render code - just exercises to + # ensure that obvious errors aren't thrown. + workflow_canvas = render.WorkflowCanvas() + + workflow = model.Workflow() + workflow.steps = [] + + def add_step( **kwds ): + workflow_step = model.WorkflowStep() + for key, value in kwds.iteritems(): + setattr(workflow_step, key, value) + workflow.steps.append( workflow_step ) + return workflow_step + + step_0 = add_step( + type="data_input", + order_index=0, + tool_inputs={"name": "input1"}, + input_connections=[], + position={"top": 3, "left": 3} + ) + step_1 = add_step( + type="data_input", + order_index=1, + tool_inputs={"name": "input2"}, + input_connections=[], + position={"top": 6, "left": 4} + ) + step_2 = add_step( + type="tool", + tool_id="cat1", + order_index=2, + input_connections=[ + bunch.Bunch(input_name="input1", output_step=step_0, output_name="di1") + ], + position={"top": 13, "left": 10} + ) + step_3 = add_step( + type="tool", + tool_id="cat1", + order_index=3, + input_connections=[ + bunch.Bunch(input_name="input1", output_step=step_0, output_name="di1") + ], + position={"top": 33, "left": 103} + ) + + workflow_canvas.populate_data_for_step( + step_0, + "input1", + [], + [{"name": "di1"}], + ) + workflow_canvas.populate_data_for_step( + step_1, + "input2", + [], + [{"name": "di1"}], + ) + workflow_canvas.populate_data_for_step( + step_2, + "cat wrapper", + [{"name": "input1", "label": "i1"}], + [{"name": "out1"}] + ) + workflow_canvas.populate_data_for_step( + step_3, + "cat wrapper", + [{"name": "input1", "label": "i1"}], + [{"name": "out1"}] + ) + workflow_canvas.add_steps() + workflow_canvas.finish() + assert workflow_canvas.canvas.standalone_xml() https://bitbucket.org/galaxy/galaxy-central/commits/be4079874172/ Changeset: be4079874172 User: jmchilton Date: 2014-08-14 03:36:10 Summary: Ensure elementtree is available (required) in workflow modules. Affected #: 1 file diff -r 57980600c4e34d5a5097ebc2aac72d3ff709031b -r be407987417297cb1543864e8448d49bb93851ab lib/galaxy/workflow/modules.py --- a/lib/galaxy/workflow/modules.py +++ b/lib/galaxy/workflow/modules.py @@ -5,6 +5,9 @@ import logging import re +from galaxy import eggs +eggs.require( "elementtree" ) + from elementtree.ElementTree import Element import galaxy.tools Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.