Exemplo n.º 1
0
def createHeatmapChart(matrix, xLabels, yLabels, scopes = [0.2, 0.4, 0.6, 0.8, 1], 
                       recSize = 20, colorBG = (255, 255, 255), colorFG = (0, 0, 0), 
                       colorChartBG = (230, 230, 230), colorGrid = (100, 100, 100),
					   font = ImageFont.load_default()):
    """Creates a heatmap chart for the given values in the matrix labeled with the labels
        given in xDict and yDict TODO:
        
        options:
            - scopes - list of values that describe the scopes for the matrix values,
                        e.g. scopes = [0.2, 0.4, 0.6, 0.8, 1] (default)
            - font - font used
            - recSize - size of a single indicator rectangle in the heatmap
            - colorBG - background color of the chart as rgb value (default: (255, 255, 255))
            - colorFG - foreground color of the chart as rgb value (default: (0, 0, 0))
            - colorChartBG - background color of the chart as rgb value (default: (230, 230, 230))
            - colorGrid - color of the grid as rgb value (dafault: (100, 100, 100)); if set to
                            "None" no grid will be drawn
    """
    #===init===
    #margin to left and bottom
    margin = 5
    #maximal identifier length 
    maxIdLength = computeMaxIdLength(set(xLabels+yLabels), font)
    #size of the img
    maxX = margin + maxIdLength + ((len(xLabels)+2) * recSize)
    maxY = margin + maxIdLength + (len(yLabels)+2) * recSize
    #lower left corner fo the chart
    offset = (margin+maxIdLength+4, maxY-maxIdLength-margin)
    
    #===create img===
    img = Image.new("RGB", (maxX, maxY), colorBG)
    draw = ImageDraw.Draw(img)
    
    #draw chart background
    draw.rectangle((offset, (offset[0]+((len(xLabels)+1)*recSize), offset[1]-((len(yLabels)+1)*recSize))), fill=colorChartBG)
    
    #draw heatmap
    for row in xrange(len(matrix)):
        for col in xrange(len(matrix[0])):
            pos = (offset[0]+col*recSize, offset[1]-row*recSize, offset[0]+(col+1)*recSize, offset[1]-(row+1)*recSize)
            fill = getColorForScope(matrix[row][col], scopes, colorChartBG)
            draw.rectangle(pos, fill=fill)
    
    #draw grid
    #x-axis
    for i in xrange(len(yLabels)+1):
        yPos = offset[1]-((i+1)*recSize)
        draw.line(((offset[0], yPos), (offset[0]+recSize*(len(xLabels)+1), yPos)), fill=colorGrid)
    #y-axis
    for i in xrange(len(xLabels)+1):
        draw.line(((offset[0]+(i+1)*recSize, offset[1]), (offset[0]+(i+1)*recSize, offset[1]-recSize*(len(yLabels)+1))), fill=colorGrid)
    
    #draw axes
    #x-axis
    draw.line((offset, (offset[0]+recSize*(len(xLabels)+1), offset[1])), fill=colorFG)
    for i in xrange(len(xLabels)):
        draw.line(((offset[0]+recSize/2+i*recSize, offset[1]-2),(offset[0]+recSize/2+i*recSize, offset[1]+2)), fill=colorFG)
    #y-axis
    draw.line((offset, (offset[0], offset[1]-recSize*(len(yLabels)+1))), fill=colorFG)
    for i in xrange(len(yLabels)):
        draw.line(((offset[0]-2, offset[1]-(recSize/2+i*recSize)),(offset[0]+2, offset[1]-(recSize/2+i*recSize))), fill=colorFG)
    
    #draw ids
    for i in xrange(len(yLabels)):
        name = yLabels[i]
        pos = i
        draw.text((margin, offset[1]-((pos+1)*recSize)), name, font=font, fill=colorFG)
    for i in xrange(len(xLabels)):
        name = xLabels[i]
        pos = i
        img.paste(rotText(name, font=font, colorBG=colorBG, colorFG=colorFG), (offset[0]+(recSize/5)+((pos)*recSize), offset[1]+2))

    #clean up
    del draw

    #return heatmap chart img
    return img
Exemplo n.º 2
0
def addIds(img, idList, strLengthList, font=None):
    """Adds ids to the given image and returns it.
    
        Options: font - ImageFont   => if no font is set, 16pt Arial is used
    """
    #check preconditions
    if type(idList) != type([]) or type(strLengthList) != type([]):
        raise NoValidArgumentError, 'idList and strLengthList must be of type list []'
    elif len(idList) != len(strLengthList):
        raise AssertionError, 'idList and strLengthList must have the same size'
    elif len(idList)<2 or len(strLengthList)<2:
        raise AssertionError, 'idList and strLengthList must have a length > 2'
    
    #if no font is set use default font (Arial)
    if not font:
		font = ImageFont.load_default()

    #compute textsize for used font
    textsize = font.getsize("00")
    marginSpace = 10
    maxIdLength = computeMaxIdLength(set(idList), font)

    #create new Image (containing the ids + the old img with dotplots)
    if len(idList) == 2:
        x = img.size[0] + textsize[0] + (marginSpace*2)
        if x<(maxIdLength+(2*marginSpace)+textsize[0]):
            x = maxIdLength+(2*marginSpace)+textsize[0]
        #add extra space below for id legend
        y = img.size[1] + textsize[1] + (marginSpace*2) + ((marginSpace+textsize[1])*2)
        offset = (textsize[0]+marginSpace, textsize[1]+marginSpace)
    else:
        #add extra space for ids
        x = img.size[0] + textsize[0] + maxIdLength + (marginSpace*2)
        y = img.size[1] + textsize[1] + (marginSpace*2)
        offset = (textsize[0]+maxIdLength+marginSpace, textsize[1]+marginSpace)
        
    newImg = Image.new("L", (x, y), 255)
    #create a new draw instance on the new img
    draw = ImageDraw.Draw(newImg)
    
    #special case: two ids
    if len(idList) == 2:        
        #first id is above
        draw.text((textsize[0]+marginSpace+(strLengthList[0]/2), marginSpace/2), '1', font=font)
        #second id is to the left
        draw.text((marginSpace/2, textsize[1]+marginSpace+(strLengthList[1]/3)), '2', font=font)
        #draw id legend below
        draw.text((marginSpace, offset[1]+img.size[1]+marginSpace), "1 "+idList[0], font=font)
        draw.text((marginSpace, offset[1]+img.size[1]+(marginSpace*2)+textsize[1]), "2 "+idList[1], font=font)
    #more than 2 ids
    else:
        for n in xrange(0, len(strLengthList)):
            if n == 0:
                l = 0
            elif n == 1:
                l = strLengthList[0]
            else : l = reduce(lambda x, y: x+y, [strLengthList[i] for i in xrange(0, n)])
            xspace = l + strLengthList[n]/2
            yspace = l + strLengthList[n]/3
            #first id is above
            draw.text((offset[0]+xspace, marginSpace/2), str(n+1), font=font)
            #second id is to the left
            draw.text((marginSpace/2, offset[1]+yspace), str(n+1)+" "+idList[n], font=font)#str(n+1), font=font)            
        
    #add borders
    draw.rectangle([(offset[0]-2, offset[1]-2), (offset[0]+img.size[0]+1, offset[1]+img.size[1]+1)], fill=150)
    
    #paste image with dotplot on "id img"
    newImg.paste(img, (offset[0]-1, offset[1]-1))

    #release drawing instance
    del draw
    
    #return img
    return newImg
Exemplo n.º 3
0
def resultsToTorc(resultList, colored=False):
    """Takes the result and returns an image showing a Torc indicating the
        similarity relations of the compared texts in the results.
        
        A Torc is a kind of overview which allows the user to recognize the similarity
        relations between different texts. Therefore all texts are arranged on a circle.
        For each relation of similarity between two texts a connecting line is drawn.
    """
    #check preconditions
    if type(resultList) != type([]):
        raise NoValidArgumentError, 'Input must be of type list'
    elif len(resultList) == 0:
        return None
    else:
        for result in resultList:
            if type(result) != type(PlagResult()):
                raise NoValidArgumentError, 'Input list should only contain values of type PlagResult.'
    #1. get all identifiers of the results
    idSet = set()
    for result in resultList:
        for id in result.getIdentifier():
            idSet.add(id)
    idSet = list(idSet)
    idSet.sort()

    #2. create a circle with a size depending on the number of identifier
    font = ImageFont.load_default()
    freespace = computeMaxIdLength(idSet, font)
    margin = 10
    radius = computeRadius(
        len(idSet))  # computes radius depending on number of ids
    xM = freespace + radius + margin  #middle x pos of circle
    yM = freespace + radius + margin  #middle y pos of circle
    img = Image.new('RGB', (2 * xM, 2 * yM), (255, 255, 255))
    draw = ImageDraw.Draw(img)
    draw.arc((freespace + margin, freespace + margin, freespace + margin +
              (2 * radius), freespace + margin + (2 * radius)),
             0,
             360,
             fill=(150, 150, 150))

    #3. arrange the ids along the circle and save the coordinates for each id
    distToNextId = 360 / len(idSet)
    angles = range(0, 360, distToNextId)
    idPosDict = {}
    for idNr in xrange(0, len(idSet)):
        # x = xM + r * cos phi und y = yM + r * sin phi
        pos = (xM + (radius * cos(radians(angles[idNr]))),
               yM + (radius * sin(radians(angles[idNr]))))
        idPosDict.setdefault(idSet[idNr], pos)

    # use a truetype font and draw the id names
    for id in idPosDict:
        draw.text(computeFontPos(font, draw, str(id), idPosDict.get(id), xM,
                                 yM),
                  str(id),
                  font=font,
                  fill=(0, 0, 0))

    #4. walk through the results and plot the similarity relations as lines between the Ids
    if colored:
        #TODO: Params von aussen eingeben?
        clusters = getClusters(resultList,
                               onlyPositives=False,
                               onlyNonZeroSimilarities=False)

    for result in resultList:
        if result.isSuspectPlagiarism():
            ids = result.getIdentifier()
            if colored:
                color = getColorForScope(
                    getClusterNr(ids[0], ids[1], clusters),
                    range(len(clusters)))
            else:
                color = (0, 0, 0)
            draw.line([idPosDict.get(ids[0]),
                       idPosDict.get(ids[1])],
                      fill=color)

    del draw  #free draw instance

    #5. return the image
    return img
Exemplo n.º 4
0
def addIds(img, idList, strLengthList, font=None):
    """Adds ids to the given image and returns it.
    
        Options: font - ImageFont   => if no font is set, 16pt Arial is used
    """
    #check preconditions
    if type(idList) != type([]) or type(strLengthList) != type([]):
        raise NoValidArgumentError, 'idList and strLengthList must be of type list []'
    elif len(idList) != len(strLengthList):
        raise AssertionError, 'idList and strLengthList must have the same size'
    elif len(idList) < 2 or len(strLengthList) < 2:
        raise AssertionError, 'idList and strLengthList must have a length > 2'

    #if no font is set use default font (Arial)
    if not font:
        font = ImageFont.load_default()

    #compute textsize for used font
    textsize = font.getsize("00")
    marginSpace = 10
    maxIdLength = computeMaxIdLength(set(idList), font)

    #create new Image (containing the ids + the old img with dotplots)
    if len(idList) == 2:
        x = img.size[0] + textsize[0] + (marginSpace * 2)
        if x < (maxIdLength + (2 * marginSpace) + textsize[0]):
            x = maxIdLength + (2 * marginSpace) + textsize[0]
        #add extra space below for id legend
        y = img.size[1] + textsize[1] + (marginSpace * 2) + (
            (marginSpace + textsize[1]) * 2)
        offset = (textsize[0] + marginSpace, textsize[1] + marginSpace)
    else:
        #add extra space for ids
        x = img.size[0] + textsize[0] + maxIdLength + (marginSpace * 2)
        y = img.size[1] + textsize[1] + (marginSpace * 2)
        offset = (textsize[0] + maxIdLength + marginSpace,
                  textsize[1] + marginSpace)

    newImg = Image.new("L", (x, y), 255)
    #create a new draw instance on the new img
    draw = ImageDraw.Draw(newImg)

    #special case: two ids
    if len(idList) == 2:
        #first id is above
        draw.text((textsize[0] + marginSpace +
                   (strLengthList[0] / 2), marginSpace / 2),
                  '1',
                  font=font)
        #second id is to the left
        draw.text((marginSpace / 2, textsize[1] + marginSpace +
                   (strLengthList[1] / 3)),
                  '2',
                  font=font)
        #draw id legend below
        draw.text((marginSpace, offset[1] + img.size[1] + marginSpace),
                  "1 " + idList[0],
                  font=font)
        draw.text((marginSpace, offset[1] + img.size[1] +
                   (marginSpace * 2) + textsize[1]),
                  "2 " + idList[1],
                  font=font)
    #more than 2 ids
    else:
        for n in xrange(0, len(strLengthList)):
            if n == 0:
                l = 0
            elif n == 1:
                l = strLengthList[0]
            else:
                l = reduce(lambda x, y: x + y,
                           [strLengthList[i] for i in xrange(0, n)])
            xspace = l + strLengthList[n] / 2
            yspace = l + strLengthList[n] / 3
            #first id is above
            draw.text((offset[0] + xspace, marginSpace / 2),
                      str(n + 1),
                      font=font)
            #second id is to the left
            draw.text((marginSpace / 2, offset[1] + yspace),
                      str(n + 1) + " " + idList[n],
                      font=font)  #str(n+1), font=font)

    #add borders
    draw.rectangle(
        [(offset[0] - 2, offset[1] - 2),
         (offset[0] + img.size[0] + 1, offset[1] + img.size[1] + 1)],
        fill=150)

    #paste image with dotplot on "id img"
    newImg.paste(img, (offset[0] - 1, offset[1] - 1))

    #release drawing instance
    del draw

    #return img
    return newImg
Exemplo n.º 5
0
Arquivo: torc.py Projeto: dtgit/dtedu
def resultsToTorc(resultList, colored=False):
    """Takes the result and returns an image showing a Torc indicating the
        similarity relations of the compared texts in the results.
        
        A Torc is a kind of overview which allows the user to recognize the similarity
        relations between different texts. Therefore all texts are arranged on a circle.
        For each relation of similarity between two texts a connecting line is drawn.
    """
    #check preconditions
    if type(resultList) != type([]):
        raise NoValidArgumentError, 'Input must be of type list'
    elif len(resultList) == 0:
        return None
    else:
        for result in resultList:
            if type(result) != type(PlagResult()):
                raise NoValidArgumentError, 'Input list should only contain values of type PlagResult.'
    #1. get all identifiers of the results
    idSet = set()
    for result in resultList:
        for id in result.getIdentifier():
            idSet.add(id)
    idSet = list(idSet)
    idSet.sort()
            
    #2. create a circle with a size depending on the number of identifier
    font = ImageFont.load_default()
    freespace = computeMaxIdLength(idSet, font)
    margin = 10
    radius = computeRadius(len(idSet)) # computes radius depending on number of ids
    xM = freespace + radius + margin    #middle x pos of circle
    yM = freespace + radius + margin   #middle y pos of circle
    img = Image.new('RGB', (2*xM, 2*yM), (255, 255, 255))
    draw = ImageDraw.Draw(img)
    draw.arc((freespace+margin, freespace+margin, freespace+margin+(2*radius), freespace+margin+(2*radius)), 0, 360, fill = (150, 150, 150))
    
    #3. arrange the ids along the circle and save the coordinates for each id
    distToNextId = 360 / len(idSet)
    angles = range(0, 360, distToNextId)
    idPosDict = {}
    for idNr in xrange(0, len(idSet)):
        # x = xM + r * cos phi und y = yM + r * sin phi
        pos = (xM + (radius * cos(radians(angles[idNr]))), 
               yM + (radius * sin(radians(angles[idNr]))))
        idPosDict.setdefault(idSet[idNr], pos)
    
    # use a truetype font and draw the id names
    for id in idPosDict:
        draw.text(computeFontPos(font, draw, str(id), idPosDict.get(id), xM, yM), 
                  str(id), 
                  font=font,
                  fill = (0, 0, 0))
    
    #4. walk through the results and plot the similarity relations as lines between the Ids
    if colored:
        #TODO: Params von aussen eingeben?
        clusters = getClusters(resultList, onlyPositives=False, onlyNonZeroSimilarities=False)

    for result in resultList:
        if result.isSuspectPlagiarism():
            ids = result.getIdentifier()
            if colored:
                color = getColorForScope(getClusterNr(ids[0], ids[1], clusters), range(len(clusters)))
            else:
                color = (0,0,0)
            draw.line([idPosDict.get(ids[0]), idPosDict.get(ids[1])], fill = color)
        
    del draw #free draw instance
   
    #5. return the image
    return img