Exemplo n.º 1
0
def make_wordcloud(words, counts, width=400, height=200):
    # sort words by counts
    inds = np.argsort(counts)[::-1]
    counts = counts[inds]
    words = words[inds]
    # create image
    img = Image.new("L", (width, height))
    draw = ImageDraw.Draw(img)
    #i = 0
    integral = np.zeros((height, width), dtype=np.uint)
    img_array = np.asarray(img)
    for word, count in zip(words, counts):
        font_path = "/usr/share/fonts/truetype/droid/DroidSansMono.ttf"
        #img_array = img_array.sum(axis=2)
        # set font size
        font_size = int(np.log(count)) * 20
        runs = 0
        while True:
            font = ImageFont.truetype(font_path, font_size)
            # transpose font optionally
            orientation = random.choice([None, Image.ROTATE_90])
            transposed_font = ImageFont.TransposedFont(font,
                                                       orientation=orientation)
            draw.setfont(transposed_font)
            # get size of resulting text
            size = draw.textsize(word)
            # find possible places using integral image:
            result = query_integral_image(integral, size[1], size[0])
            if result is not None:
                break
            # if we didn't find a place, make font smaller
            font_size -= 1
            runs += 1
        x, y = result
        draw.text((result[1], result[0]), word, fill="white")
        # recompute integral image
        img_array = np.asarray(img)
        # recompute bottom right
        partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                     axis=0)
        # paste into old image
        # if x or y is zero it is a bit annoying
        if x > 0:
            if y > 0:
                partial_integral += (integral[x - 1, y:]
                                     - integral[x - 1, y - 1])
            else:
                partial_integral += integral[x - 1, y:]
        if y > 0:
            partial_integral += integral[x:, y - 1][:, np.newaxis]

        integral[x:, y:] = partial_integral

    img.show()
Exemplo n.º 2
0
 def sample_position(self, size_x, size_y, random_state):
     return query_integral_image(self.integral, size_x, size_y,
                                 random_state)
Exemplo n.º 3
0
def make_wordcloud(words, counts, fname, font_path=None, width=400, height=200,
                   margin=5, ranks_only=False):
    """Build word cloud using word counts, store in image.

    Parameters
    ----------
    words : numpy array of strings
        Words that will be drawn in the image.

    counts : numpy array of word counts
        Word counts or weighting of words. Determines the size of the word in
        the final image.
        Will be normalized to lie between zero and one.

    font_path : string
        Font path to the font that will be used.
        Defaults to DroidSansMono path.

    fname : sting
        Output filename. Extension determins image type
        (written with PIL).

    width : int (default=400)
        Width of the word cloud image.

    height : int (default=200)
        Height of the word cloud image.

    ranks_only : boolean (default=False)
        Only use the rank of the words, not the actual counts.

    Notes
    -----
    Larger Images with make the code significantly slower.
    If you need a large image, you can try running the algorithm at a lower
    resolution and then drawing the result at the desired resolution.

    In the current form it actually just uses the rank of the counts,
    i.e. the relative differences don't matter.
    Play with setting the font_size in the main loop vor differnt styles.

    Colors are used completely at random. Currently the colors are sampled
    from HSV space with a fixed S and V.
    Adjusting the percentages at the very end gives differnt color ranges.
    Obviously you can also set all at random - haven't tried that.

    """
    if len(counts) <= 0:
        print("We need at least 1 word to plot a word cloud, got %d."
              % len(counts))

    if font_path is None:
        font_path = FONT_PATH

    if not os.path.exists(font_path):
        raise ValueError("The provided font %s does not exist." % font_path)

    # normalize counts
    counts = counts / float(counts.max())
    # sort words by counts
    inds = np.argsort(counts)[::-1]
    counts = counts[inds]
    words = words[inds]
    # create image
    img_grey = Image.new("L", (width, height))
    draw = ImageDraw.Draw(img_grey)
    integral = np.zeros((height, width), dtype=np.uint32)
    img_array = np.asarray(img_grey)
    font_sizes, positions, orientations = [], [], []
    # intitiallize font size "large enough"
    font_size = 1000
    # start drawing grey image
    for word, count in zip(words, counts):
        # alternative way to set the font size
        if not ranks_only:
            font_size = min(font_size, int(100 * np.log(count + 100)))
        while True:
            # try to find a position
            font = ImageFont.truetype(font_path, font_size)
            # transpose font optionally
            orientation = random.choice([None, Image.ROTATE_90])
            transposed_font = ImageFont.TransposedFont(font,
                                                       orientation=orientation)
            draw.setfont(transposed_font)
            # get size of resulting text
            box_size = draw.textsize(word)
            # find possible places using integral image:
            result = query_integral_image(integral, box_size[1] + margin,
                                          box_size[0] + margin)
            if result is not None or font_size == 0:
                break
            # if we didn't find a place, make font smaller
            font_size -= 1

        if font_size == 0:
            # we were unable to draw any more
            break

        x, y = np.array(result) + margin // 2
        # actually draw the text
        draw.text((y, x), word, fill="white")
        positions.append((x, y))
        orientations.append(orientation)
        font_sizes.append(font_size)
        # recompute integral image
        img_array = np.asarray(img_grey)
        # recompute bottom right
        # the order of the cumsum's is important for speed ?!
        partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                     axis=0)
        # paste recomputed part into old image
        # if x or y is zero it is a bit annoying
        if x > 0:
            if y > 0:
                partial_integral += (integral[x - 1, y:]
                                     - integral[x - 1, y - 1])
            else:
                partial_integral += integral[x - 1, y:]
        if y > 0:
            partial_integral += integral[x:, y - 1][:, np.newaxis]

        integral[x:, y:] = partial_integral

    # redraw in color
    img = Image.new("RGB", (width, height))
    draw = ImageDraw.Draw(img)
    everything = zip(words, font_sizes, positions, orientations)
    for word, font_size, position, orientation in everything:
        font = ImageFont.truetype(font_path, font_size)
        # transpose font optionally
        transposed_font = ImageFont.TransposedFont(font,
                                                   orientation=orientation)
        draw.setfont(transposed_font)
        draw.text((position[1], position[0]), word,
                  fill="hsl(%d" % random.randint(0, 255) + ", %d" % random.randint(90, 100) + "%, 50%)")
    #img.show()
    img.save(fname)
    return img
Exemplo n.º 4
0
def fit_words(words,
              font_path=None,
              width=400,
              height=200,
              margin=5,
              ranks_only=False,
              prefer_horiz=0.90):
    """Generate the positions for words.

    Parameters
    ----------
    words : array of tuples
        A tuple contains the word and its frequency.
    
    font_path : string
        Font path to the font that will be used (OTF or TTF).
        Defaults to DroidSansMono path, but you might not have it.

    width : int (default=400)
        Width of the canvas.

    height : int (default=200)
        Height of the canvas.

    ranks_only : boolean (default=False)
        Only use the rank of the words, not the actual counts.

    prefer_horiz : float (default=0.90)
        The ratio of times to try horizontal fitting as opposed to vertical.

    Notes
    -----
    Larger canvases with make the code significantly slower. If you need a large
    word cloud, run this function with a lower canvas size, and draw it with a
    larger scale.
    
    In the current form it actually just uses the rank of the counts, i.e. the
    relative differences don't matter. Play with setting the font_size in the
    main loop for different styles.
    """

    if len(words) <= 0:
        print("We need at least 1 word to plot a word cloud, got %d." %
              len(words))

    if font_path is None:
        font_path = FONT_PATH

    if not os.path.exists(font_path):
        raise ValueError("The font %s does not exist." % font_path)

    # create image
    img_grey = Image.new("L", (width, height))
    draw = ImageDraw.Draw(img_grey)
    integral = np.zeros((height, width), dtype=np.uint32)
    img_array = np.asarray(img_grey)
    font_sizes, positions, orientations = [], [], []

    # intitiallize font size "large enough"
    font_size = height

    # start drawing grey image
    for word, count in words:
        # alternative way to set the font size
        if not ranks_only:
            font_size = min(font_size, int(100 * np.log(count + 100)))
        while True:
            # try to find a position
            font = ImageFont.truetype(font_path, font_size)
            # transpose font optionally
            if random.random() < prefer_horiz:
                orientation = None
            else:
                orientation = Image.ROTATE_90
            transposed_font = ImageFont.TransposedFont(font,
                                                       orientation=orientation)
            draw.setfont(transposed_font)
            # get size of resulting text
            box_size = draw.textsize(word)
            # find possible places using integral image:
            result = query_integral_image(integral, box_size[1] + margin,
                                          box_size[0] + margin)
            if result is not None or font_size == 0:
                break
            # if we didn't find a place, make font smaller
            font_size -= 1

        if font_size == 0:
            # we were unable to draw any more
            break

        x, y = np.array(result) + margin // 2
        # actually draw the text
        draw.text((y, x), word, fill="white")
        positions.append((x, y))
        orientations.append(orientation)
        font_sizes.append(font_size)
        # recompute integral image
        img_array = np.asarray(img_grey)
        # recompute bottom right
        # the order of the cumsum's is important for speed ?!
        partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                     axis=0)
        # paste recomputed part into old image
        # if x or y is zero it is a bit annoying
        if x > 0:
            if y > 0:
                partial_integral += (integral[x - 1, y:] -
                                     integral[x - 1, y - 1])
            else:
                partial_integral += integral[x - 1, y:]
        if y > 0:
            partial_integral += integral[x:, y - 1][:, np.newaxis]

        integral[x:, y:] = partial_integral

    return zip(words, font_sizes, positions, orientations)
Exemplo n.º 5
0
    def _fit_words(self, words):
        """Generate the positions for words.

        Parameters
        ----------
        words : array of tuples
            A tuple contains the word and its frequency.

        Returns
        -------
        layout_ : list of tuples (string, int, (int, int), int, color))
            Encodes the fitted word cloud. Encodes for each word the string, font
            size, position, orientation and color.

        Notes
        -----
        Larger canvases with make the code significantly slower. If you need a large
        word cloud, run this function with a lower canvas size, and draw it with a
        larger scale.

        In the current form it actually just uses the rank of the counts, i.e. the
        relative differences don't matter. Play with setting the font_size in the
        main loop for different styles.
        """
        if self.random_state is not None:
            random_state = self.random_state
        else:
            random_state = Random()

        if len(words) <= 0:
            print("We need at least 1 word to plot a word cloud, got %d." %
                  len(words))

        if self.mask is not None:
            width = self.mask.shape[1]
            height = self.mask.shape[0]
            # the order of the cumsum's is important for speed ?!
            integral = np.cumsum(np.cumsum(self.mask, axis=1),
                                 axis=0).astype(np.uint32)
        else:
            height, width = self.height, self.width
            integral = np.zeros((height, width), dtype=np.uint32)

        # create image
        img_grey = Image.new("L", (width, height))
        draw = ImageDraw.Draw(img_grey)
        img_array = np.asarray(img_grey)
        font_sizes, positions, orientations, colors = [], [], [], []

        font_size = self.max_font_size

        # start drawing grey image
        for word, count in words:
            # alternative way to set the font size
            if not self.ranks_only:
                font_size = min(font_size, int(100 * np.log(count + 100)))
            while True:
                # try to find a position
                font = ImageFont.truetype(self.font_path, font_size)
                # transpose font optionally
                if random_state.random() < self.prefer_horizontal:
                    orientation = None
                else:
                    orientation = Image.ROTATE_90
                transposed_font = ImageFont.TransposedFont(
                    font, orientation=orientation)
                draw.setfont(transposed_font)
                # get size of resulting text
                box_size = draw.textsize(word)
                # find possible places using integral image:
                result = query_integral_image(integral,
                                              box_size[1] + self.margin,
                                              box_size[0] + self.margin,
                                              random_state)
                if result is not None or font_size == 0:
                    break
                # if we didn't find a place, make font smaller
                font_size -= 1

            if font_size == 0:
                # we were unable to draw any more
                break

            x, y = np.array(result) + self.margin // 2
            # actually draw the text
            draw.text((y, x), word, fill="white")
            positions.append((x, y))
            orientations.append(orientation)
            font_sizes.append(font_size)
            colors.append(
                self.color_func(word,
                                font_size, (x, y),
                                orientation,
                                random_state=random_state))
            # recompute integral image
            if self.mask is None:
                img_array = np.asarray(img_grey)
            else:
                img_array = np.asarray(img_grey) + self.mask
            # recompute bottom right
            # the order of the cumsum's is important for speed ?!
            partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                         axis=0)
            # paste recomputed part into old image
            # if x or y is zero it is a bit annoying
            if x > 0:
                if y > 0:
                    partial_integral += (integral[x - 1, y:] -
                                         integral[x - 1, y - 1])
                else:
                    partial_integral += integral[x - 1, y:]
            if y > 0:
                partial_integral += integral[x:, y - 1][:, np.newaxis]

            integral[x:, y:] = partial_integral

        self.layout_ = zip(words, font_sizes, positions, orientations, colors)
        return self.layout_
Exemplo n.º 6
0
def fit_words(words, font_path=None, width=400, height=200, margin=5, ranks_only=False, prefer_horiz=0.90):
    """Generate the positions for words.

    Parameters
    ----------
    words : array of tuples
        A tuple contains the word and its frequency.
    
    font_path : string
        Font path to the font that will be used (OTF or TTF).
        Defaults to DroidSansMono path, but you might not have it.

    width : int (default=400)
        Width of the canvas.

    height : int (default=200)
        Height of the canvas.

    ranks_only : boolean (default=False)
        Only use the rank of the words, not the actual counts.

    prefer_horiz : float (default=0.90)
        The ratio of times to try horizontal fitting as opposed to vertical.

    Notes
    -----
    Larger canvases with make the code significantly slower. If you need a large
    word cloud, run this function with a lower canvas size, and draw it with a
    larger scale.
    
    In the current form it actually just uses the rank of the counts, i.e. the
    relative differences don't matter. Play with setting the font_size in the
    main loop for different styles.
    """

    if len(words) <= 0:
        print("We need at least 1 word to plot a word cloud, got %d." % len(words))

    if font_path is None:
        font_path = FONT_PATH

    if not os.path.exists(font_path):
        raise ValueError("The font %s does not exist." % font_path)

    # create image
    img_grey = Image.new("L", (width, height))
    draw = ImageDraw.Draw(img_grey)
    integral = np.zeros((height, width), dtype=np.uint32)
    img_array = np.asarray(img_grey)
    font_sizes, positions, orientations = [], [], []

    # intitiallize font size "large enough"
    font_size = height

    # start drawing grey image
    for word, count in words:
        # alternative way to set the font size
        if not ranks_only:
            font_size = min(font_size, int(100 * np.log(count + 100)))
        while True:
            # try to find a position
            font = ImageFont.truetype(font_path, font_size)
            # transpose font optionally
            if random.random() < prefer_horiz:
                orientation = None
            else:
                orientation = Image.ROTATE_90
            transposed_font = ImageFont.TransposedFont(font, orientation=orientation)
            draw.setfont(transposed_font)
            # get size of resulting text
            box_size = draw.textsize(word)
            # find possible places using integral image:
            result = query_integral_image(integral, box_size[1] + margin, box_size[0] + margin)
            if result is not None or font_size == 0:
                break
            # if we didn't find a place, make font smaller
            font_size -= 1

        if font_size == 0:
            # we were unable to draw any more
            break

        x, y = np.array(result) + margin // 2
        # actually draw the text
        draw.text((y, x), word, fill="white")
        positions.append((x, y))
        orientations.append(orientation)
        font_sizes.append(font_size)
        # recompute integral image
        img_array = np.asarray(img_grey)
        # recompute bottom right
        # the order of the cumsum's is important for speed ?!
        partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1), axis=0)
        # paste recomputed part into old image
        # if x or y is zero it is a bit annoying
        if x > 0:
            if y > 0:
                partial_integral += integral[x - 1, y:] - integral[x - 1, y - 1]
            else:
                partial_integral += integral[x - 1, y:]
        if y > 0:
            partial_integral += integral[x:, y - 1][:, np.newaxis]

        integral[x:, y:] = partial_integral

    return zip(words, font_sizes, positions, orientations)
Exemplo n.º 7
0
def make_wordcloud(words,
                   counts,
                   fname="words.png",
                   font_path=None,
                   width=400,
                   height=200,
                   margin=16):
    """Build word cloud using word counts, store in image.

    Parameters
    ----------
    words : numpy array of strings
        Words that will be drawn in the image.

    counts : numpy array of word counts
        Word counts or weighting of words. Determines the size of the word in
        the final image.
        Will be normalized to lie between zero and one.

    font_path : sting
        Font path to the font that will be used.
        Defaults to DroidSansMono path.

    fname : sting
        Output filename. Extension determins image type
        (written with PIL).

    width : int (default=400)
        Width of the word cloud image.

    height : int (default=200)
        Height of the word cloud image.

    Notes
    -----
    Larger Images with make the code significantly slower.
    If you need a large image, you can try running the algorithm at a lower
    resolution and then drawing the result at the desired resolution.

    In the current form it actually just uses the rank of the counts,
    i.e. the relative differences don't matter.
    Play with setting the font_size in the main loop vor differnt styles.

    Colors are used completely at random. Currently the colors are sampled
    from HSV space with a fixed S and V.
    Adjusting the percentages at the very end gives differnt color ranges.
    Obviously you can also set all at random - haven't tried that.

    """
    if len(counts) <= 0:
        print("We need at least 1 word to plot a word cloud, got %d." %
              len(counts))

    if font_path is None:
        font_path = FONT_PATH

    # normalize counts
    counts = counts / float(counts.max())
    # sort words by counts
    inds = np.argsort(counts)[::-1]
    counts = counts[inds]
    words = words[inds]
    # create image
    img_grey = Image.new("L", (width, height))
    draw = ImageDraw.Draw(img_grey)
    integral = np.zeros((height, width), dtype=np.uint32)
    img_array = np.asarray(img_grey)
    font_sizes, positions, orientations = [], [], []
    # intitiallize font size "large enough"
    font_size = 1000
    # start drawing grey image
    for word, count in zip(words, counts):
        # alternative way to set the font size
        #font_size = min(font_size, int(100 * np.log(count + 100)))
        while True:
            # try to find a position
            font = ImageFont.truetype(font_path, font_size)
            # transpose font optionally
            orientation = random.choice([None, Image.ROTATE_90])
            transposed_font = ImageFont.TransposedFont(font,
                                                       orientation=orientation)
            draw.setfont(transposed_font)
            # get size of resulting text

            box_size = draw.textsize(word)
            # find possible places using integral image:
            result = query_integral_image(integral, box_size[1] + margin,
                                          box_size[0] + margin)
            if result is not None or font_size == 0:
                break
            # if we didn't find a place, make font smaller
            font_size -= 1

        if font_size == 0:
            # we were unable to draw any more
            break

        x, y = np.array(result) + margin // 2
        # actually draw the text
        draw.text((y, x), word, fill="white")
        positions.append((x, y))
        orientations.append(orientation)
        font_sizes.append(font_size)
        # recompute integral image
        img_array = np.asarray(img_grey)
        # recompute bottom right
        # the order of the cumsum's is important for speed ?!
        partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                     axis=0)
        # paste recomputed part into old image
        # if x or y is zero it is a bit annoying
        if x > 0:
            if y > 0:
                partial_integral += (integral[x - 1, y:] -
                                     integral[x - 1, y - 1])
            else:
                partial_integral += integral[x - 1, y:]
        if y > 0:
            partial_integral += integral[x:, y - 1][:, np.newaxis]

        integral[x:, y:] = partial_integral

    # redraw in color
    img = Image.new("RGB", (width, height), "white")
    draw = ImageDraw.Draw(img)
    everything = zip(words, font_sizes, positions, orientations)
    e_length = len(everything)
    hues = np.round(np.linspace(1, 255 - e_length, e_length)).astype(int)
    for i, (word, font_size, position, orientation) in enumerate(everything):
        font = ImageFont.truetype(font_path, font_size)
        # transpose font optionally
        transposed_font = ImageFont.TransposedFont(font,
                                                   orientation=orientation)
        draw.setfont(transposed_font)
        draw.text((position[1], position[0]),
                  word,
                  fill="hsl(%d" % hues[i] + ", 55%, 35%)")
    # img.save(fname)
    return img
Exemplo n.º 8
0
def make_wordcloud(words, counts, fname, width=800, height=400,
                           margin=5, ranks_only=False):

    if len(counts) <= 0:
        print("We need at least 1 word to plot a word cloud, got %d."
                % len(counts))

    font_path = FONT_PATH
    max_count = float(max(counts))
    #normalize counts
    counts = counts/max_count
    #sort words by count
    inds = np.argsort(counts)[::-1]
    counts = counts[inds]
    words = words[inds]
    #create image
    img_grey = Image.new("L", (width, height))
    draw = ImageDraw.Draw(img_grey)
    integral = np.zeros((height, width), dtype=np.uint32)
    img_array = np.asarray(img_grey)
    font_sizes, positions, orientations = [], [], []
    # intitiallize font size "large enough"
    font_size = 1000
    # start drawing grey image
    for word, count in zip(words, counts):
        # alternative way to set the font size
        if not ranks_only:
            font_size = min(font_size, int(100 * np.log(count + 100)))
        while True:
            #try to find position
            font = ImageFont.truetype(font_path, font_size)
            #transpose font optionally
            orientation = random.choice([None, Image.ROTATE_90])
            transposed_font = ImageFont.TransposedFont(font,
                                                       orientation=orientation)
            draw.setfont(transposed_font)
            #get size of resulting text
            box_size = draw.textsize(word)
            #finding possible places using integral images
            result = query_integral_image(integral, box_size[1] + margin,
                                            box_size[0] + margin)
            if (result is not None or font_size == 0) :
                break
            #if we didn't find space make the font smaller
            font_size -= 1

        if font_size == 0:
            break

        x, y = np.array(result) + margin // 2
        # actually draw the text
        draw.text((y, x), word, fill="white")
        positions.append((x, y))
        orientations.append(orientation)
        font_sizes.append(font_size)
        # recompute integral image
        img_array = np.asarray(img_grey)
        # recompute bottom right
        # the order of the cumsum's is important for speed ?!
        partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                     axis=0)
        if x > 0:
            if y > 0:
                partial_integral += (integral[x - 1, y:]
                                     - integral[x - 1, y - 1])
            else:
                partial_integral += integral[x - 1, y:]
        if y > 0:
            partial_integral += integral[x:, y - 1][:, np.newaxis]

        integral[x:, y:] = partial_integral

    # redraw in color
    img = Image.new("RGB", (width, height))
    draw = ImageDraw.Draw(img)
    everything = zip(words, font_sizes, positions, orientations)
    for word, font_size, position, orientation in everything:
        font = ImageFont.truetype(font_path, font_size)
        #transpose font optionally
        transposed_font = ImageFont.TransposedFont(font,
                                                   orientation=orientation)
        draw.setfont(transposed_font)
        draw.text((position[1], position[0]), word,
                   fill="hsl(%d" % random.randint(0, 255) + ", 80%, 50%)")
    #img.show()
    img.save(fname)
Exemplo n.º 9
0
    def _fit_words(self, words):
        """Generate the positions for words.

        Parameters
        ----------
        words : array of tuples
            A tuple contains the word and its frequency.

        Returns
        -------
        layout_ : list of tuples (string, int, (int, int), int, color))
            Encodes the fitted word cloud. Encodes for each word the string, font
            size, position, orientation and color.

        Notes
        -----
        Larger canvases with make the code significantly slower. If you need a large
        word cloud, run this function with a lower canvas size, and draw it with a
        larger scale.

        In the current form it actually just uses the rank of the counts, i.e. the
        relative differences don't matter. Play with setting the font_size in the
        main loop for different styles.
        """
        if self.random_state is not None:
            random_state = self.random_state
        else:
            random_state = Random()

        if len(words) <= 0:
            print("We need at least 1 word to plot a word cloud, got %d."
                  % len(words))

        if self.mask is not None:
            width = self.mask.shape[1]
            height = self.mask.shape[0]
            # the order of the cumsum's is important for speed ?!
            integral = np.cumsum(np.cumsum(self.mask, axis=1), axis=0).astype(np.uint32)
        else:
            height, width = self.height, self.width
            integral = np.zeros((height, width), dtype=np.uint32)

        # create image
        img_grey = Image.new("L", (width, height))
        draw = ImageDraw.Draw(img_grey)
        img_array = np.asarray(img_grey)
        font_sizes, positions, orientations, colors = [], [], [], []

        font_size = self.max_font_size

        # start drawing grey image
        for word, count in words:
            # alternative way to set the font size
            if not self.ranks_only:
                font_size = min(font_size, int(100 * np.log(count + 100)))
            while True:
                # try to find a position
                font = ImageFont.truetype(self.font_path, font_size)
                # transpose font optionally
                if random_state.random() < self.prefer_horizontal:
                    orientation = None
                else:
                    orientation = Image.ROTATE_90
                transposed_font = ImageFont.TransposedFont(font,
                                                           orientation=orientation)
                draw.setfont(transposed_font)
                # get size of resulting text
                box_size = draw.textsize(word)
                # find possible places using integral image:
                result = query_integral_image(integral, box_size[1] + self.margin,
                                              box_size[0] + self.margin, random_state)
                if result is not None or font_size == 0:
                    break
                # if we didn't find a place, make font smaller
                font_size -= 1

            if font_size == 0:
                # we were unable to draw any more
                break

            x, y = np.array(result) + self.margin // 2
            # actually draw the text
            draw.text((y, x), word, fill="white")
            positions.append((x, y))
            orientations.append(orientation)
            font_sizes.append(font_size)
            colors.append(self.color_func(word, font_size, (x, y), orientation,
                                          random_state=random_state))
            # recompute integral image
            if self.mask is None:
                img_array = np.asarray(img_grey)
            else:
                img_array = np.asarray(img_grey) + self.mask
            # recompute bottom right
            # the order of the cumsum's is important for speed ?!
            partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                         axis=0)
            # paste recomputed part into old image
            # if x or y is zero it is a bit annoying
            if x > 0:
                if y > 0:
                    partial_integral += (integral[x - 1, y:]
                                         - integral[x - 1, y - 1])
                else:
                    partial_integral += integral[x - 1, y:]
            if y > 0:
                partial_integral += integral[x:, y - 1][:, np.newaxis]

            integral[x:, y:] = partial_integral

        self.layout_ = zip(words, font_sizes, positions, orientations, colors)
        return self.layout_
Exemplo n.º 10
0
    def draw(self):
        #### create image
        bwimg = Image.new("L", (self.width, self.height))
        draw = ImageDraw.Draw(bwimg)
        integral = np.zeros((self.height, self.width), dtype=np.uint32)
        img_array = np.asarray(bwimg)
        font_sizes, positions, orientations = [], [], []
        font_size = 1000

        # start drawing grey image
        for word, count in zip(self.words, self.counts):
            # alternative way to set the font size
            while True:
                # try to find a position
                font = ImageFont.truetype(self.font_path, font_size)
                # transpose font optionally
                orientation = random.choice([None, Image.ROTATE_90])
                transposed_font = ImageFont.TransposedFont(
                    font, orientation=orientation)
                draw.setfont(transposed_font)
                # get size of resulting text
                box_size = draw.textsize(word)
                # find possible places using integral image:
                result = query_integral_image(integral,
                                              box_size[1] + self.margin,
                                              box_size[0] + self.margin)
                if result is not None or font_size == 0:
                    break
            # if we didn't find a place, make font smaller
                font_size -= 1
            if font_size == 0:
                # we were unable to draw any more
                break

            x, y = np.array(result) + self.margin // 2
            # actually draw the text
            draw.text((y, x), word, fill="white")
            positions.append((x, y))
            orientations.append(orientation)
            font_sizes.append(font_size)
            # recompute integral image
            img_array = np.asarray(bwimg)
            # recompute bottom right
            # the order of the cumsum's is important for speed ?!
            partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                         axis=0)
            # paste recomputed part into old image
            # if x or y is zero it is a bit annoying
            if x > 0:
                if y > 0:
                    partial_integral += (integral[x - 1, y:] -
                                         integral[x - 1, y - 1])
                else:
                    partial_integral += integral[x - 1, y:]
            if y > 0:
                partial_integral += integral[x:, y - 1][:, np.newaxis]

            integral[x:, y:] = partial_integral

    # redraw in color
        img = Image.new("RGB", (self.width, self.height))
        draw = ImageDraw.Draw(img)
        everything = zip(self.words, font_sizes, positions, orientations)
        for word, font_size, position, orientation in everything:
            font = ImageFont.truetype(self.font_path, font_size)
            transposed_font = ImageFont.TransposedFont(font,
                                                       orientation=orientation)
            draw.setfont(transposed_font)
            draw.text((position[1], position[0]),
                      word,
                      fill="hsl(%d" % random.randint(0, 255) + ", 80%, 50%)")

        #img.show()
        return img
Exemplo n.º 11
0
    def acomodar_palabras(self):
        """El 'trabajo pesado' de distribuir las palabras
        de forma que encajen en la imágen a generar"""

        altura, largo = self.height, self.width
        integral = zeros((altura, largo), dtype=uint32)

        # Creación de imágen
        imagen = Image.new("L", (largo, altura))
        dibujo = ImageDraw.Draw(imagen)
        img_arreglo = asarray(imagen)
        tamaños, posiciones, orientaciones, colores = [], [], [], []

        font_actual = self.max_font_size

        # Inicio de dibujado
        for palabra, freq in self.palabras:

            # Hay que encontrar una posición para todas las palabras
            while True:

                # font_actual = min(self.max_font_size, int(100 * log(freq + 100)))
                fuente = ImageFont.truetype(self.font_path, font_actual)

                # Vemos si va horizontal o vertical y dibujamos
                if self.R.random() < self.horizontales:
                    orientacion = None
                else:
                    orientacion = Image.ROTATE_90
                font_transpuesta = ImageFont.TransposedFont(
                    fuente, orientation=orientacion)
                dibujo.setfont(font_transpuesta)
                tamaño_resultante = dibujo.textsize(palabra)

                # Buscamos posibles lugares
                resultado = query_integral_image(
                    integral, tamaño_resultante[1] + self.margin,
                    tamaño_resultante[0] + self.margin, self.R)

                # Si el resultado es posible o no podemos escribir más
                if resultado is not None or font_actual == 0:
                    break

                # Si no hay espacio, achicamos la fuente
                font_actual -= 1

            x, y = array(resultado) + self.margin // 2

            # Dibujar el resultado
            dibujo.text((y, x), palabra, fill="white")
            posiciones.append((x, y))
            orientaciones.append(orientacion)
            tamaños.append(font_actual)
            colores.append(
                self.color_func(palabra,
                                font_size=font_actual,
                                position=(x, y),
                                orientation=orientacion))

            # Recalcular imágen
            img_arreglo = asarray(imagen)
            integral_parcial = cumsum(cumsum(img_arreglo[x:, y:], axis=1),
                                      axis=0)

            # Pegar parte calculada a la imágen acumulada
            if x > 0:
                if y > 0:
                    integral_parcial += (integral[x - 1, y:] -
                                         integral[x - 1, y - 1])
                else:
                    integral_parcial += integral[x - 1, y:]
            if y > 0:
                integral_parcial += integral[x:, y - 1][:, newaxis]

            integral[x:, y:] = integral_parcial

        self.distribucion = list(
            zip(self.palabras, tamaños, posiciones, orientaciones, colores))
        self.imagen_generada = True
Exemplo n.º 12
0
def make_wordcloud(words,
                   counts,
                   font_path,
                   imagineName,
                   width=800,
                   height=600,
                   margin=5):
    # sort words by counts
    inds = np.argsort(counts)[::-1]
    counts = counts[inds]
    words = words[inds]
    # create image
    img_grey = Image.new("L", (width, height))
    draw = ImageDraw.Draw(img_grey)
    integral = np.zeros((height, width), dtype=np.uint32)
    img_array = np.asarray(img_grey)
    font_sizes, positions, orientations = [], [], []
    # intitiallize fontsize "large enough"
    font_size = 1000
    # start drawing grey image
    for word, count in zip(words, counts):
        # set font size
        #font_size = min(font_size, int(100 * np.log(count + 100)))
        while True:
            # try to find a position
            font = ImageFont.truetype(font_path, font_size)
            # transpose font optionally
            orientation = random.choice([None, Image.ROTATE_90])
            transposed_font = ImageFont.TransposedFont(font,
                                                       orientation=orientation)
            draw.setfont(transposed_font)
            # get size of resulting text
            box_size = draw.textsize(word)
            # find possible places using integral image:
            result = query_integral_image(integral, box_size[1] + margin,
                                          box_size[0] + margin)
            if result is not None or font_size == 0:
                break
            # if we didn't find a place, make font smaller
            font_size -= 1

        if font_size == 0:
            # we were unable to draw any more
            break

        x, y = np.array(result) + margin // 2
        # actually draw the text
        draw.text((y, x), word, fill="white")
        positions.append((x, y))
        orientations.append(orientation)
        font_sizes.append(font_size)
        # recompute integral image
        img_array = np.asarray(img_grey)
        # recompute bottom right
        # the order of the cumsum's is important for speed ?!
        partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                     axis=0)
        # paste recomputed part into old image
        # if x or y is zero it is a bit annoying
        if x > 0:
            if y > 0:
                partial_integral += (integral[x - 1, y:] -
                                     integral[x - 1, y - 1])
            else:
                partial_integral += integral[x - 1, y:]
        if y > 0:
            partial_integral += integral[x:, y - 1][:, np.newaxis]

        integral[x:, y:] = partial_integral

    # redraw in color
    img = Image.new("RGB", (width, height))
    draw = ImageDraw.Draw(img)
    everything = zip(words, font_sizes, positions, orientations)
    for word, font_size, position, orientation in everything:
        font = ImageFont.truetype(font_path, font_size)
        # transpose font optionally
        transposed_font = ImageFont.TransposedFont(font,
                                                   orientation=orientation)
        draw.setfont(transposed_font)
        draw.text((position[1], position[0]),
                  word,
                  fill="hsl(%d" % random.randint(0, 255) + ", 80%, 50%)")
    name = imagineName + '.png'
    # img.show()
    img.save(name)
    img.show()
Exemplo n.º 13
0
def make_wordcloud(words, counts, font_path, imagineName,width=400, height=200, margin=5):
    # sort words by counts
    inds = np.argsort(counts)[::-1]
    counts = counts[inds]
    words = words[inds]
    # create image
    img_grey = Image.new("L", (width, height))
    draw = ImageDraw.Draw(img_grey)
    integral = np.zeros((height, width), dtype=np.uint32)
    img_array = np.asarray(img_grey)
    font_sizes, positions, orientations = [], [], []
    # intitiallize fontsize "large enough"
    font_size = 1000
    # start drawing grey image
    for word, count in zip(words, counts):
        # set font size
        #font_size = min(font_size, int(100 * np.log(count + 100)))
        while True:
            # try to find a position
            font = ImageFont.truetype(font_path, font_size)
            # transpose font optionally
            orientation = random.choice([None, Image.ROTATE_90])
            transposed_font = ImageFont.TransposedFont(font,
                                                       orientation=orientation)
            draw.setfont(transposed_font)
            # get size of resulting text
            box_size = draw.textsize(word)
            # find possible places using integral image:
            result = query_integral_image(integral, box_size[1] + margin,
                                          box_size[0] + margin)
            if result is not None or font_size == 0:
                break
            # if we didn't find a place, make font smaller
            font_size -= 1

        if font_size == 0:
            # we were unable to draw any more
            break

        x, y = np.array(result) + margin // 2
        # actually draw the text
        draw.text((y, x), word, fill="white")
        positions.append((x, y))
        orientations.append(orientation)
        font_sizes.append(font_size)
        # recompute integral image
        img_array = np.asarray(img_grey)
        # recompute bottom right
        # the order of the cumsum's is important for speed ?!
        partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                     axis=0)
        # paste recomputed part into old image
        # if x or y is zero it is a bit annoying
        if x > 0:
            if y > 0:
                partial_integral += (integral[x - 1, y:]
                                     - integral[x - 1, y - 1])
            else:
                partial_integral += integral[x - 1, y:]
        if y > 0:
            partial_integral += integral[x:, y - 1][:, np.newaxis]

        integral[x:, y:] = partial_integral

    # redraw in color
    img = Image.new("RGB", (width, height))
    draw = ImageDraw.Draw(img)
    everything = zip(words, font_sizes, positions, orientations)
    for word, font_size, position, orientation in everything:
        font = ImageFont.truetype(font_path, font_size)
        # transpose font optionally
        transposed_font = ImageFont.TransposedFont(font,
                                                   orientation=orientation)
        draw.setfont(transposed_font)
        draw.text((position[1], position[0]), word,
                  fill="hsl(%d" % random.randint(0, 255) + ", 80%, 50%)")
    name=imagineName+'.png'
    # img.show()
    img.save(name)
    img.show()
Exemplo n.º 14
0
 def sample_position(self, size_x, size_y, random_state):
     return query_integral_image(self.integral, size_x, size_y, random_state)
def make_wordcloud(words, counts, fname=None, font_path=None, width=400, height=200,
                   margin=5, ranks_only=False, backgroundweight=255):
    """Build word cloud using word counts, store in image.

    Parameters
    ----------
    words : numpy array of strings
        Words that will be drawn in the image.

    counts : numpy array of word counts
        Word counts or weighting of words. Determines the size of the word in
        the final image.
        Will be normalized to lie between zero and one.

    font_path : string
        Font path to the font that will be used.
        Defaults to DroidSansMono path.

    fname : sting
        Output filename. Extension determins image type
        (written with PIL).

    width : int (default=400)
        Width of the word cloud image.

    height : int (default=200)
        Height of the word cloud image.

    ranks_only : boolean (default=False)
        Only use the rank of the words, not the actual counts.

    backgroundweight : int (default=255)
        Weight that the background of the wordcloud is multiplied by.
        Applies in cases where there are more than 2 dimensions which charecterize the cloud;
        in our case it is the logged number of community population whose tweets resulted 
        in the cloud.

    Notes
    -----
    Larger Images with make the code significantly slower.
    If you need a large image, you can try running the algorithm at a lower
    resolution and then drawing the result at the desired resolution.

    In the current form it actually just uses the rank of the counts,
    i.e. the relative differences don't matter.
    Play with setting the font_size in the main loop vor differnt styles.

    Colors are used completely at random. Currently the colors are sampled
    from HSV space with a fixed S and V.
    Adjusting the percentages at the very end gives differnt color ranges.
    Obviously you can also set all at random - haven't tried that.

    """
    if len(counts) <= 0:
        print("We need at least 1 word to plot a word cloud, got %d."
              % len(counts))

    if font_path is None:
        font_path = FONT_PATH

    if not os.path.exists(font_path):
        raise ValueError("The provided font %s does not exist." % font_path)

    # normalize counts
    counts=[float(i/max(counts)) for i in counts]
    # sort words by counts
    inds = np.argsort(counts)[::-1]
    counts = [counts[i] for i in inds]
    words = [words[i] for i in inds]
    # create image
    img_grey = Image.new("L", (width, height))
    draw = ImageDraw.Draw(img_grey)
    integral = np.zeros((height, width), dtype=np.uint32)
    img_array = np.asarray(img_grey)
    font_sizes, positions, orientations = [], [], []
    # intitiallize font size "large enough"
    font_size = 1000
    # start drawing grey image
    for word, count in zip(words, counts):
        # alternative way to set the font size
        if not ranks_only:
            font_size = min(font_size, int(100 * np.log(count + 100)))
        while True:
            # try to find a position
            font = ImageFont.truetype(font_path, font_size, encoding = 'unic')
            # transpose font optionally
            orientation = random.choice([None, Image.ROTATE_90])
            transposed_font = ImageFont.TransposedFont(font, orientation=orientation)
            draw.setfont(transposed_font)
            # get size of resulting text
            box_size = draw.textsize(word)
            # find possible places using integral image:
            result = query_integral_image(integral, box_size[1] + margin,
                                          box_size[0] + margin)
            if result is not None or font_size == 0:
                break
            # if we didn't find a place, make font smaller
            font_size -= 1

        if font_size == 0:
            # we were unable to draw any more
            break

        x, y = np.array(result) + margin // 2
        # actually draw the text
        draw.text((y, x), word, fill="white")
        positions.append((x, y))
        orientations.append(orientation)
        font_sizes.append(font_size)
        # recompute integral image
        img_array = np.asarray(img_grey)
        # recompute bottom right
        # the order of the cumsum's is important for speed ?!
        partial_integral = np.cumsum(np.cumsum(img_array[x:, y:], axis=1),
                                     axis=0)
        # paste recomputed part into old image
        # if x or y is zero it is a bit annoying
        if x > 0:
            if y > 0:
                partial_integral += (integral[x - 1, y:]
                                     - integral[x - 1, y - 1])
            else:
                partial_integral += integral[x - 1, y:]
        if y > 0:
            partial_integral += integral[x:, y - 1][:, np.newaxis]

        integral[x:, y:] = partial_integral

    # redraw in color
    img = Image.new("RGB", (width, height), (backgroundweight,backgroundweight,backgroundweight))
    draw = ImageDraw.Draw(img)
    everything = zip(words, font_sizes, positions, orientations)
    for word, font_size, position, orientation in everything:
        font = ImageFont.truetype(font_path, font_size)
        # transpose font optionally
        transposed_font = ImageFont.TransposedFont(font, orientation=orientation)
        draw.setfont(transposed_font)
        draw.text((position[1], position[0]), word, #fill = "red")
                   fill="hsl(%d" % random.randint(0, 50) + ", 80%, 50%)")
    #img.show()
    try:
        img.save(fname)
    except:
        pass
    return img
Exemplo n.º 16
0
    def acomodar_palabras(self):
        """El 'trabajo pesado' de distribuir las palabras
        de forma que encajen en la imágen a generar"""

        altura, largo = self.height, self.width
        integral = zeros((altura, largo), dtype=uint32)

        # Creación de imágen
        imagen = Image.new("L", (largo, altura))
        dibujo = ImageDraw.Draw(imagen)
        img_arreglo = asarray(imagen)
        tamaños, posiciones, orientaciones, colores = [], [], [], []

        font_actual = self.max_font_size

        __ = 0

        # Inicio de dibujado
        for palabra, freq in self.palabras:

            print(str(__) + "/" + str(len(self.palabras)))
            __ += 1

            # Hay que encontrar una posición para todas las palabras
            while True:

                # font_actual = min(self.max_font_size, int(100 * log(freq + 100)))
                fuente = ImageFont.truetype(self.font_path, font_actual)

                # Vemos si va horizontal o vertical y dibujamos
                if self.R.random() < self.horizontales:
                    orientacion = None
                else:
                    orientacion = Image.ROTATE_90
                font_transpuesta = ImageFont.TransposedFont(fuente,
                                                            orientation=orientacion)
                dibujo.setfont(font_transpuesta)
                tamaño_resultante = dibujo.textsize(palabra)

                # Buscamos posibles lugares
                resultado = query_integral_image(integral, tamaño_resultante[1] + self.margin,
                                                 tamaño_resultante[0] + self.margin, self.R)

                # Si el resultado es posible o no podemos escribir más
                if resultado is not None or font_actual == 0:
                    break

                # Si no hay espacio, achicamos la fuente
                font_actual -= 1

            x, y = array(resultado) + self.margin // 2

            # Dibujar el resultado
            dibujo.text((y, x), palabra, fill="white")
            posiciones.append((x, y))
            orientaciones.append(orientacion)
            tamaños.append(font_actual)
            colores.append(self.color_func(palabra, font_size=font_actual,
                                           position=(x, y),
                                           orientation=orientacion))

            # Recalcular imágen
            img_arreglo = asarray(imagen)
            integral_parcial = cumsum(
                cumsum(img_arreglo[x:, y:], axis=1), axis=0)

            # Pegar parte calculada a la imágen acumulada
            if x > 0:
                if y > 0:
                    integral_parcial += (integral[x - 1, y:]
                                         - integral[x - 1, y - 1])
                else:
                    integral_parcial += integral[x - 1, y:]
            if y > 0:
                integral_parcial += integral[x:, y - 1][:, newaxis]

            integral[x:, y:] = integral_parcial

        print(__)

        self.distribucion = list(
            zip(self.palabras, tamaños, posiciones, orientaciones, colores))
        self.imagen_generada = True