Пример #1
0
 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
     in_pos = self.in_pos
     out_pos = self.out_pos
     for di in module_data_inputs:
         cur_y = y + count * LINE_SPACING
         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_SPACING
         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 ] )
Пример #2
0
    def draw_cell(cell_data):
        out = []

        if cell_data == 0:
            out.append(svgfig.Rect(0, 0, CELL_WIDTH, CELL_HEIGHT,
                                   fill="black"))
        elif type(cell_data) == type(1):
            out.append(svgfig.Rect(0, 0, CELL_WIDTH, CELL_HEIGHT))
            out.append(
                svgfig.Text(
                    10,
                    10,
                    cell_data,
                    text_anchor="middle",
                    font_size=12,
                    font_weight=600,
                    dominant_baseline="middle",
                    fill="brown",
                ))
        elif type(cell_data) == type(()):
            across = cell_data[0]
            down = cell_data[1]
            out.append(svgfig.Rect(0, 0, CELL_WIDTH, CELL_HEIGHT))
            out.append(
                svgfig.Line(
                    0,
                    0,
                    CELL_WIDTH,
                    CELL_HEIGHT,
                    stroke_width=1,
                ))
            if down == 0:
                points = ((0, 0), (0, CELL_HEIGHT), (CELL_WIDTH, CELL_HEIGHT))
                out.append(svgfig.Poly(points, "lines", fill="black"))
            else:
                out.append(
                    svgfig.Text(
                        2,
                        18,
                        down,
                        text_anchor="start",
                        font_size=7,
                        alignment_baseline="middle",
                    ))
            if across == 0:
                points = ((0, 0), (CELL_WIDTH, 0), (CELL_WIDTH, CELL_HEIGHT))
                out.append(svgfig.Poly(points, "lines", fill="black"))
            else:
                out.append(
                    svgfig.Text(
                        19,
                        7,
                        across,
                        text_anchor="end",
                        font_size=7,
                    ))
        else:
            raise Exception("")
        return out
Пример #3
0
def generate_workflow_image( trans, workflow_name, repository_metadata_id=None, repository_id=None ):
    """
    Return an svg image representation of a workflow dictionary created when the workflow was exported.  This method is called
    from both Galaxy and the tool shed.  When called from the tool shed, repository_metadata_id will have a value and repository_id
    will be None.  When called from Galaxy, repository_metadata_id will be None and repository_id will have a value.
    """
    workflow_name = encoding_util.tool_shed_decode( workflow_name )
    if trans.webapp.name == 'community':
        # We're in the tool shed.
        repository_metadata = suc.get_repository_metadata_by_id( trans, repository_metadata_id )
        repository_id = trans.security.encode_id( repository_metadata.repository_id )
        changeset_revision = repository_metadata.changeset_revision
        metadata = repository_metadata.metadata
    else:
        # We're in Galaxy.
        repository = suc.get_tool_shed_repository_by_id( trans, repository_id )
        changeset_revision = repository.changeset_revision
        metadata = repository.metadata
    # metadata[ 'workflows' ] is a list of tuples where each contained tuple is
    # [ <relative path to the .ga file in the repository>, <exported workflow dict> ]
    for workflow_tup in metadata[ 'workflows' ]:
        workflow_dict = workflow_tup[1]
        if workflow_dict[ 'name' ] == workflow_name:
            break
    if 'tools' in metadata:
        tools_metadata = metadata[ 'tools' ]
    else:
        tools_metadata = []
    workflow, missing_tool_tups = get_workflow_from_dict( trans=trans,
                                                          workflow_dict=workflow_dict,
                                                          tools_metadata=tools_metadata,
                                                          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"
    in_pos = {}
    out_pos = {}
    margin = 5
    # Spacing between input/outputs.
    line_px = 16
    # 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 )
        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 )
        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 ] )
    for step_dict in data:
        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 == 'community' 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() )
        for conn, output_dict in step_dict[ 'input_connections' ].iteritems():
            in_coords = 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:
                # out_conn_index_dict will be something like:
                # 7: {'o': (824.5, 618)}
                out_conn_index_dict = 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 ]
                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 ] )
            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' ] = "%s px" % width
    canvas[ 'height' ] = "%s px" % height
    canvas[ 'viewBox' ] = "0 0 %s %s" % ( width, height )
    trans.response.set_content_type( "image/svg+xml" )
    return canvas.standalone_xml()
Пример #4
0
    def placeLabel2(self, points, layer):
        def interp(a, b, val):
            slope = float(b[1] - a[1]) / float(b[0] - a[0])
            inter = a[1] - slope * a[0]
            return (val * slope) + inter

        def f_bl(x):
            point_range = range(len(points))
            #point_range.reverse()
            point_range = list(reversed(point_range))
            last_x = 0
            #for i in range(len(points) / 2):
            for i in range(int(len(points) / 2)):
                point = points[point_range[i]]
                #print str(point[0]) + "  " +str(x) + "  " + str(last_x)
                if x <= point[0] and x > last_x:
                    #print "Bang!"
                    return interp(point, points[point_range[i - 1]], x)
                last_x = point[0]
            return 0

        def f_tl(x):
            last_x = 0
            for i in range(int(len(points) / 2)):
                point = points[i]
                if x <= point[0] and x > last_x:
                    return interp(point, points[i - 1], x)
                last_x = point[0]
            return 0

        def is_box_in_shape(x1, y1, x2, y2):
            width = x2 - x1
            for j in range(resolution):
                x = x1 + ((width / float(resolution)) * j)
                y_lo = f_bl(x)
                y_hi = f_tl(x)
                if y1 < y_lo or y2 > y_hi:
                    return False
            return True

        # Get the label
        label = self.labels[layer]
        # Take a guess at the aspect ratio of the word
        label_aspect = len(label) * 0.7  #magic
        window_aspect = (self.x_max - self.x_min) / float(self.y_max * 1.3)
        total_aspect = (((1 / label_aspect) / window_aspect) *
                        self.canvas_aspect)

        # How slow vs. how good
        num_guesses = 500
        resolution = 15

        height_max = 0
        boxes = svgfig.SVG("g", id="boxes")
        x1_l = 0
        x2_l = 0
        y1_l = 0
        y2_l = 0
        for i in range(num_guesses):
            x1 = random.uniform(self.x_min, self.x_max)
            y_lo = f_bl(x1)
            y_hi = f_tl(x1)
            h = y_hi - y_lo
            y1 = random.uniform(y_lo, y_hi - (h / 8.0))
            y2 = random.uniform(y1, y_hi)
            height = y2 - y1
            x2 = x1 + height / float(total_aspect)
            if is_box_in_shape(x1, y1, x2, y2):
                if height_max < height:
                    height_max = height
                    x1_l = x1
                    y1_l = y1
                    x2_l = x2
                    y2_l = y2

        label_x = x1_l + ((x2_l - x1_l) / 2.0)
        label_y = y1_l + ((y2_l - y1_l) / 6.5)
        font_scale = self.y_max / 100.0
        font = ((y2_l - y1_l) / font_scale) * 0.9  #magic
        label = svgfig.Text(label_x,
                            label_y,
                            label,
                            font_family="Droid Sans",
                            font_size=str(font),
                            fill="#e7e7e7")

        return label
Пример #5
0
    def test2_placeLabel(self, points, layer, window):
        def interp(a, b, val):
            slope = float(b[1] - a[1]) / float(b[0] - a[0])
            inter = a[1] - slope * a[0]
            return (val * slope) + inter

        def f_bl(x):
            point_range = range(len(points))
            point_range.reverse()
            last_x = 0
            for i in range(len(points) / 2):
                point = points[point_range[i]]
                #print str(point[0]) + "  " +str(x) + "  " + str(last_x)
                if x <= point[0] and x > last_x:
                    #print "Bang!"
                    return interp(point, points[point_range[i - 1]], x)
                last_x = point[0]
            return 0

        def f_tl(x):
            last_x = 0
            for i in range(len(points) / 2):
                point = points[i]
                if x <= point[0] and x > last_x:
                    return interp(point, points[i - 1], x)
                last_x = point[0]
            return 0

        def is_box_in_shape(x1, y1, x2, y2):
            width = x2 - x1
            for j in range(resolution):
                x = x1 + ((width / float(resolution)) * j)
                y_lo = f_bl(x)
                y_hi = f_tl(x)
                if y1 < y_lo or y2 > y_hi:
                    return False
            return True

        # Get the label
        label = self.labels[layer]
        # Take a guess at the aspect ratio of the word
        label_aspect = len(label) * 0.7  #magic
        window_aspect = (self.x_max - self.x_min) / float(self.y_max * 1.3)

        num_guesses = 400
        resolution = 10

        total_aspect = (((1 / label_aspect) / window_aspect) *
                        self.canvas_aspect)

        height_max = 0
        boxes = svgfig.SVG("g", id="boxes")
        x1_l = 0
        x2_l = 0
        y1_l = 0
        y2_l = 0
        for i in range(num_guesses):
            x1 = random.uniform(self.x_min, self.x_max)
            y_lo = f_bl(x1)
            y_hi = f_tl(x1)
            h = y_hi - y_lo
            y1 = random.uniform(y_lo, y_hi - (h / 8.0))
            y2 = random.uniform(y1, y_hi)
            height = y2 - y1
            x2 = x1 + height / float(total_aspect)
            if is_box_in_shape(x1, y1, x2, y2):
                if height_max < height:
                    height_max = height
                    x1_l = x1
                    y1_l = y1
                    x2_l = x2
                    y2_l = y2
                boxes.append(
                    svgfig.Rect(x1,
                                y1,
                                x2,
                                y2,
                                fill="#eeeeee",
                                fill_opacity="10%",
                                stroke_width="0").SVG(window))

        boxes.append(
            svgfig.Rect(x1_l,
                        y1_l,
                        x2_l,
                        y2_l,
                        fill="#eeeeee",
                        fill_opacity="23%",
                        stroke_width="0").SVG(window))

        label_x = x1_l + ((x2_l - x1_l) / 2.0)
        label_y = y1_l + ((y2_l - y1_l) / 6.0)
        #print (y2_l - y1_l)
        font = ((y2_l - y1_l) / 2.5)  #magic
        self.current_label = svgfig.Text(label_x,
                                         label_y,
                                         label,
                                         font_family="Droid Sans",
                                         font_size=str(font))

        return boxes
Пример #6
0
class StreamGraph:
    """A class to generate a kind of data vizulazation called 'stream graphs'
  Based on the paper "Stacked Graphs - Geometry & Aesthetics" by Lee Byron & 
  Martin Wattenberg
  In general there are two things to consider:
    1.) The shape of the begginig layer, or g_0
    2.) The order you draw the layers.
  These two things will determine the shape and look of the graph.
  """

    # Data and meta-data. These should all be the same length!
    data = []  # The Data
    colors = []  # A list of colors for the layers
    labels = []  # A list of labels for the layers

    # Usefull things
    n_layers = 0  # Layers
    n_points = 0  # Points in a layer
    y_extent = []  # A list of maximum (stacked) y values for each x
    y_max = 0  # The maximun (stacked) y value for the whole dataset
    x_min = 0  # The smallest x vaule in the dataset
    x_max = 0  # The largets x vaule in the dataset
    canvas_aspect = 0  # Aspect Ratio of the canvas (image)
    current_label = svgfig.Text(0, 0, " ")

    def __init__(self, data, colors=None, labels=None):
        self.data = data
        self.colors = colors
        self.labels = labels
        self.preprocess()

    def draw(self,
             filename,
             graphshape=None,
             width=1280,
             height=720,
             show_labels=False):
        """This does the drawing. It starts by getting a function for the bottom
    most layer. As descrbed in Byron & Wattenberg this will control the overall
    shape of the graph. It then it prints a stacked graph on top of that bottom 
    line, whatever shape it is.  
    """

        # Preprocess some stuff
        aspect_ratio = float(width) / float(height)
        self.canvas_aspect = aspect_ratio
        x_offset = int(-((100 * aspect_ratio) - 100) / 2.0)

        # Get a g_0 depending in desired shape
        g_0 = self.themeRiver()  # Default (fallbacks)
        y_offset = 0
        if str(graphshape) == "Stacked_Graph":
            g_0 = self.stackedGraph()
            y_offset = 0
        if str(graphshape) == "Theme_River":
            g_0 = self.themeRiver()
            y_offset = -50
        if str(graphshape) == "Wiggle":
            g_0 = self.wiggle()
            y_offset = -50
        if str(graphshape) == "Weighted_Wiggle":
            g_0 = self.weighted_wiggle()
            y_offset = -50

        # Initilize a streamgraph groups in SVG.
        graph = svgfig.SVG("g", id="StreamGraph")
        labels = svgfig.SVG("g", id="Labels")

        # Initilize a SVG Window object to do the transormations on each object
        window = svgfig.window(self.x_min, self.x_max, 0,
                               self.y_max * 1.3, x_offset, y_offset,
                               int(100 * aspect_ratio), 100)

        # Loop through each layer
        for layer in range(self.n_layers):
            points = []
            point_range = range(self.n_points)
            # Forwards; draw top of the shape
            for i in point_range:
                x = self.data[layer][i][0]
                y = self.data[layer][i][1]
                # Start with g_0 and stack
                y_stacked = g_0[i] + y
                # Stack!
                for l in range(layer):
                    y_stacked += self.data[l][i][1]
                # Add the points to the shape
                points.append((x, y_stacked))
            # Backwards; draw bottom of the shape
            #point_range.reverse()
            point_range = reversed(point_range)
            for i in point_range:
                x = self.data[layer][i][0]
                # This time we don't include this layer
                y_stacked = g_0[i]
                # Stack!
                for l in range(layer):
                    y_stacked += self.data[l][i][1]
                points.append((x, y_stacked))
            # Shapes
            poly = svgfig.Poly(points,
                               "smooth",
                               stroke="#eeeeee",
                               fill=self.rgb2hex(self.colors[layer]),
                               stroke_width="0.05")
            graph.append(poly.SVG(window))
            if show_labels:
                #label = self.placeLabel(points, layer)
                #label = self.test_placeLabel(points, layer)
                #label = self.test2_placeLabel(points, layer, window)
                label = self.placeLabel2(points, layer)
                #for l in label:
                #  labels.append(l)
                labels.append(label.SVG(window))
        # End Loop

        # Add objects to the canvas and save it
        w = str(int(width)) + "px"
        h = str(int(height)) + "px"
        canv = svgfig.canvas(graph, labels, width=w, height=h)
        canv.save(filename)

    def placeLabel(self, points, layer):
        """Brute Force method to calculate a position for the labels. No other way 
    to do it except by hand.
    Starts by modeling the label as a rectangle, then tries to fit the rectangle
    in the current stream by making the box bigger and bigger
    """
        def interp(a, b, val):
            slope = float(b[1] - a[1]) / float(b[0] - a[0])
            inter = a[1] - slope * a[0]
            return (val * slope) + inter

        # Get the label
        label = self.labels[layer]

        # Take a guess at the aspect ratio of the word
        aspect_ratio = 0
        aspect_ratio = len(label) * 0.7  #magic

        max_area = 0
        max_area_x = 0
        max_area_y = 0

        end_of_line = (len(points) / 2)
        point_range = range(len(points))
        point_range.reverse()
        for i in range(1, end_of_line - 1):
            bottom_point = point_range[i]
            x = points[i][0]
            y = points[i][1]
            y_0 = points[bottom_point][1]
            xm1 = points[i - 1][0]
            ym1 = points[i - 1][1]
            ym1_0 = points[bottom_point + 1][1]
            xp1 = points[i + 1][0]
            yp1 = points[i + 1][1]
            yp1_0 = points[bottom_point - 1][1]
            height = y - y_0
            heightm1 = ym1 - ym1_0
            width = xp1 - x
            widthm1 = x - xm1
            area = (widthm1 * heightm1) + (height * height)
            if max_area < area:
                max_area = area
                max_area_index = i
                max_area_index_0 = bottom_point

        placement_x1 = points[max_area_index - 1][0]
        placement_x2 = points[max_area_index + 1][0]
        width = placement_x2 - placement_x1
        placement_x = points[max_area_index][0]
        placement_y1 = points[max_area_index_0][1]
        placement_y2 = points[max_area_index][1]
        height = placement_y2 - placement_y1
        placement_y = placement_y1 + (height * 0.3)

        scale_height = (self.y_max / 40.0)
        return svgfig.Text(placement_x,
                           placement_y,
                           label,
                           fill="#cccccc",
                           font_size=str(height / scale_height),
                           font_family="Droid Sans")
        #return svgfig.Rect(placement_x1, placement_y1, placement_x2, placement_y2, fill="#cccccc", fill_opacity="50%", stroke_width="0")

    def test_placeLabel(self, points, layer):
        """Use this for testing different packing algorthims.
    """

        # Get the label
        label = self.labels[layer]

        # Take a guess at the aspect ratio of the word
        label_aspect = len(label) * 0.7  #magic

        window_aspect = (self.x_max - self.x_min) / float(self.y_max * 1.3)

        iterations = 20
        end_of_line = (len(points) / 2)
        point_range = range(len(points))
        point_range.reverse()
        for i in range(0, end_of_line - 1):
            bottom_point = point_range[i]
            x = points[i][0]
            y = points[i][1]
            y_0 = points[bottom_point][1]
            height_init = y_0 - y
            for i in range(iterations):
                height = height_init - (i * (height_init / iterations))
                width = height / (label_aspect / window_aspect)

        yint = 6
        x = points[yint][0]
        y = points[yint][1]
        y_0 = points[point_range[yint]][1]
        height = y - y_0
        width = height / (label_aspect / window_aspect / self.canvas_aspect)

        x1 = x
        y1 = y_0
        x2 = x1 + width
        y2 = y

        return svgfig.Rect(x1,
                           y1,
                           x2,
                           y2,
                           fill="#cccccc",
                           fill_opacity="50%",
                           stroke_width="0")

    def test2_placeLabel(self, points, layer, window):
        def interp(a, b, val):
            slope = float(b[1] - a[1]) / float(b[0] - a[0])
            inter = a[1] - slope * a[0]
            return (val * slope) + inter

        def f_bl(x):
            point_range = range(len(points))
            point_range.reverse()
            last_x = 0
            for i in range(len(points) / 2):
                point = points[point_range[i]]
                #print str(point[0]) + "  " +str(x) + "  " + str(last_x)
                if x <= point[0] and x > last_x:
                    #print "Bang!"
                    return interp(point, points[point_range[i - 1]], x)
                last_x = point[0]
            return 0

        def f_tl(x):
            last_x = 0
            for i in range(len(points) / 2):
                point = points[i]
                if x <= point[0] and x > last_x:
                    return interp(point, points[i - 1], x)
                last_x = point[0]
            return 0

        def is_box_in_shape(x1, y1, x2, y2):
            width = x2 - x1
            for j in range(resolution):
                x = x1 + ((width / float(resolution)) * j)
                y_lo = f_bl(x)
                y_hi = f_tl(x)
                if y1 < y_lo or y2 > y_hi:
                    return False
            return True

        # Get the label
        label = self.labels[layer]
        # Take a guess at the aspect ratio of the word
        label_aspect = len(label) * 0.7  #magic
        window_aspect = (self.x_max - self.x_min) / float(self.y_max * 1.3)

        num_guesses = 400
        resolution = 10

        total_aspect = (((1 / label_aspect) / window_aspect) *
                        self.canvas_aspect)

        height_max = 0
        boxes = svgfig.SVG("g", id="boxes")
        x1_l = 0
        x2_l = 0
        y1_l = 0
        y2_l = 0
        for i in range(num_guesses):
            x1 = random.uniform(self.x_min, self.x_max)
            y_lo = f_bl(x1)
            y_hi = f_tl(x1)
            h = y_hi - y_lo
            y1 = random.uniform(y_lo, y_hi - (h / 8.0))
            y2 = random.uniform(y1, y_hi)
            height = y2 - y1
            x2 = x1 + height / float(total_aspect)
            if is_box_in_shape(x1, y1, x2, y2):
                if height_max < height:
                    height_max = height
                    x1_l = x1
                    y1_l = y1
                    x2_l = x2
                    y2_l = y2
                boxes.append(
                    svgfig.Rect(x1,
                                y1,
                                x2,
                                y2,
                                fill="#eeeeee",
                                fill_opacity="10%",
                                stroke_width="0").SVG(window))

        boxes.append(
            svgfig.Rect(x1_l,
                        y1_l,
                        x2_l,
                        y2_l,
                        fill="#eeeeee",
                        fill_opacity="23%",
                        stroke_width="0").SVG(window))

        label_x = x1_l + ((x2_l - x1_l) / 2.0)
        label_y = y1_l + ((y2_l - y1_l) / 6.0)
        #print (y2_l - y1_l)
        font = ((y2_l - y1_l) / 2.5)  #magic
        self.current_label = svgfig.Text(label_x,
                                         label_y,
                                         label,
                                         font_family="Droid Sans",
                                         font_size=str(font))

        return boxes

    def placeLabel2(self, points, layer):
        def interp(a, b, val):
            slope = float(b[1] - a[1]) / float(b[0] - a[0])
            inter = a[1] - slope * a[0]
            return (val * slope) + inter

        def f_bl(x):
            point_range = range(len(points))
            #point_range.reverse()
            point_range = list(reversed(point_range))
            last_x = 0
            #for i in range(len(points) / 2):
            for i in range(int(len(points) / 2)):
                point = points[point_range[i]]
                #print str(point[0]) + "  " +str(x) + "  " + str(last_x)
                if x <= point[0] and x > last_x:
                    #print "Bang!"
                    return interp(point, points[point_range[i - 1]], x)
                last_x = point[0]
            return 0

        def f_tl(x):
            last_x = 0
            for i in range(int(len(points) / 2)):
                point = points[i]
                if x <= point[0] and x > last_x:
                    return interp(point, points[i - 1], x)
                last_x = point[0]
            return 0

        def is_box_in_shape(x1, y1, x2, y2):
            width = x2 - x1
            for j in range(resolution):
                x = x1 + ((width / float(resolution)) * j)
                y_lo = f_bl(x)
                y_hi = f_tl(x)
                if y1 < y_lo or y2 > y_hi:
                    return False
            return True

        # Get the label
        label = self.labels[layer]
        # Take a guess at the aspect ratio of the word
        label_aspect = len(label) * 0.7  #magic
        window_aspect = (self.x_max - self.x_min) / float(self.y_max * 1.3)
        total_aspect = (((1 / label_aspect) / window_aspect) *
                        self.canvas_aspect)

        # How slow vs. how good
        num_guesses = 500
        resolution = 15

        height_max = 0
        boxes = svgfig.SVG("g", id="boxes")
        x1_l = 0
        x2_l = 0
        y1_l = 0
        y2_l = 0
        for i in range(num_guesses):
            x1 = random.uniform(self.x_min, self.x_max)
            y_lo = f_bl(x1)
            y_hi = f_tl(x1)
            h = y_hi - y_lo
            y1 = random.uniform(y_lo, y_hi - (h / 8.0))
            y2 = random.uniform(y1, y_hi)
            height = y2 - y1
            x2 = x1 + height / float(total_aspect)
            if is_box_in_shape(x1, y1, x2, y2):
                if height_max < height:
                    height_max = height
                    x1_l = x1
                    y1_l = y1
                    x2_l = x2
                    y2_l = y2

        label_x = x1_l + ((x2_l - x1_l) / 2.0)
        label_y = y1_l + ((y2_l - y1_l) / 6.5)
        font_scale = self.y_max / 100.0
        font = ((y2_l - y1_l) / font_scale) * 0.9  #magic
        label = svgfig.Text(label_x,
                            label_y,
                            label,
                            font_family="Droid Sans",
                            font_size=str(font),
                            fill="#e7e7e7")

        return label

    ## Begin Graph types

    def stackedGraph(self):
        """Returns a g_0 of exactly 0 (x-axis) for a traditional stacked graph 
    look
    """
        g_0 = []
        for i in range(0, self.n_points):
            g_0.append(0)
        return g_0

    def themeRiver(self):
        """The "Theme River" style is a basic stream graph and is symmetric around
    the x-axis
    """
        g_0 = []
        for i in range(self.n_points):
            g_0.append(-self.y_extent[i] / 2.0)
        return g_0

    def wiggle(self):
        """Seeks to minimize wiggle by taking the slope of the lines into account as 
    well as the overall sillouet.
    """
        g_0 = []
        n = self.n_layers
        for i in range(self.n_points):
            wiggle = 0
            for layer in range(1, n):
                wiggle += (n - layer + 1) * self.data[layer][i][1]
            g_0.append(-(1 / float(n + 1) * wiggle))
        return g_0

    def weighted_wiggle(self):
        """Similar to the wiggle method, but this seeks to minimize the wiggle on a
    weighted scale of stream thicknes (i.e., visual importance)
    """
        g_0 = []
        g_prime_0 = []
        n = self.n_layers
        for y in range(self.n_points):
            wiggle = 0
            last_f = self.data[0][y][1]
            last_x = self.data[0][y][0]
            for i in range(n):
                f = self.data[i][y][1]
                x = self.data[i][y][0]
                if (x - last_x) != 0:
                    f_prime = (f - last_x) / (x - last_x)
                else:
                    f_prime = 0
                sumf_prime = 0
                sublast_f = self.data[1][y][1]
                sublast_x = self.data[1][y][0]
                for j in range(1, i - 1):
                    subf = self.data[j][y][1]
                    subx = self.data[j][y][0]
                    if (subx - sublast_x) != 0:
                        sumf_prime += (subf - sublast_f) / (subx - sublast_x)
                    else:
                        sumf_prime += 0
                    sublast_f = subf
                    sublast_x = subx
                wiggle += (0.5 * f_prime + sumf_prime) * f
                last_f = f
                last_x = x
            g_prime_0.append(-(1 / self.y_extent[y]) * wiggle)

        g = 0
        last_x = self.data[0][y][0]
        for i in range(self.n_points):
            x = self.data[0][i][0]
            step = x - last_x
            g += g_prime_0[i] * step
            g_0.append(g)
            last_x = x

        return g_0

    ## End Graph Types

    ## Begin Utilities

    def preprocess(self):
        """Goes through the dataset at the beginning and figures out things so we
    don't have to calcualte them again later.
    """
        # Lengths for ranges
        self.n_layers = len(self.data)
        self.n_points = len(self.data[0])

        # Calculate the sum of the y values for each point
        for i in range(0, self.n_points):
            y_sum = 0
            for layer in range(0, self.n_layers):
                y_sum += self.data[layer][i][1]
            self.y_extent.append(y_sum)
            if self.y_max < y_sum: self.y_max = y_sum

        # Range of x vaules, assuming in order.
        self.x_min = self.data[0][0][0]
        self.x_max = self.data[0][-1][0]

    def rgb2hex(self, rgb):
        rgb = int(rgb[0] * 255), int(rgb[1] * 255), int(rgb[2] * 255)
        hexcolor = '#%02x%02x%02x' % rgb
        return hexcolor

    ## End Utilities


## End StreamGraph
Пример #7
0
    def placeLabel(self, points, layer):
        """Brute Force method to calculate a position for the labels. No other way 
    to do it except by hand.
    Starts by modeling the label as a rectangle, then tries to fit the rectangle
    in the current stream by making the box bigger and bigger
    """
        def interp(a, b, val):
            slope = float(b[1] - a[1]) / float(b[0] - a[0])
            inter = a[1] - slope * a[0]
            return (val * slope) + inter

        # Get the label
        label = self.labels[layer]

        # Take a guess at the aspect ratio of the word
        aspect_ratio = 0
        aspect_ratio = len(label) * 0.7  #magic

        max_area = 0
        max_area_x = 0
        max_area_y = 0

        end_of_line = (len(points) / 2)
        point_range = range(len(points))
        point_range.reverse()
        for i in range(1, end_of_line - 1):
            bottom_point = point_range[i]
            x = points[i][0]
            y = points[i][1]
            y_0 = points[bottom_point][1]
            xm1 = points[i - 1][0]
            ym1 = points[i - 1][1]
            ym1_0 = points[bottom_point + 1][1]
            xp1 = points[i + 1][0]
            yp1 = points[i + 1][1]
            yp1_0 = points[bottom_point - 1][1]
            height = y - y_0
            heightm1 = ym1 - ym1_0
            width = xp1 - x
            widthm1 = x - xm1
            area = (widthm1 * heightm1) + (height * height)
            if max_area < area:
                max_area = area
                max_area_index = i
                max_area_index_0 = bottom_point

        placement_x1 = points[max_area_index - 1][0]
        placement_x2 = points[max_area_index + 1][0]
        width = placement_x2 - placement_x1
        placement_x = points[max_area_index][0]
        placement_y1 = points[max_area_index_0][1]
        placement_y2 = points[max_area_index][1]
        height = placement_y2 - placement_y1
        placement_y = placement_y1 + (height * 0.3)

        scale_height = (self.y_max / 40.0)
        return svgfig.Text(placement_x,
                           placement_y,
                           label,
                           fill="#cccccc",
                           font_size=str(height / scale_height),
                           font_family="Droid Sans")
Пример #8
0
ntips = float(len(r.leaves()))
fontsize = h / ntips

## bbox = svgfig.Rect(1,1,w-1,h-1)
branches = []
labels = []
for n, c in n2c.items():
    if n.parent:
        pc = n2c[n.parent]
        d = ((c.x, c.y), (pc.x, c.y), (pc.x, pc.y))
        line = svgfig.Poly(d)
        branches.append(line)

    if n.label:
        label = svgfig.Text(c.x, c.y, n.label, font_size=fontsize)
        label.attr["text-anchor"] = "start"
        # this should vertically align the point to the middle of the
        # text, but doesn't:
        # label.attr["alignment-baseline"] ="middle"
        # so shift y down
        label.y += fontsize / 3
        labels.append(label)

fig = svgfig.Fig(svgfig.Fig(*branches), svgfig.Fig(*labels))
w = getwidth(fig, w, h)

svg = fig.SVG()
vb = "%s %s %s %s" % (-10, -10, w + 10, h + 10)
## print svgfig.canvas(svg, width=w, height=h, viewBox=vb).xml()
## svgfig.canvas(svg, width=w, height=h, viewBox=vb).save()
Пример #9
0
 def _txt(self, s, x, y, dy):
   txt = svgfig.Text(x, y-dy/2.5, s, font_size=dy*self.q, fill=self.color).SVG(trans=self.trans)
   return [txt]