How to use our tool

This is early documentation on how to use our tool. Notice that we’ve given it a tag, “hpc” that corresponds with a template in pages/tags/tag_hpc.html that will automatically generate a page for all posts tagged with “hpc.”

Quick Start

You might want to give the user a quick start, and follow with numbered steps. We are going to borrow a post on Pokemon Ascii to show a general example with different formatting. Here we go!

If you are a user of this place called the Internet, you will notice in many places that an icon or picture “avatar” is assigned to your user. Most of this is thanks to a service called Gravatar that makes it easy to generate a profile that is shared across sites. For example, in developing Singularity Hub I found that there are many Django plugins that make adding a user avatar to a page as easy as adding an image with a source (src) like https://secure.gravatar.com/avatar/hello.

The final avatar might look something like this:

This is the “retro” design, and in fact we can choose from one of many:


Command Line Avatars?

I recently started making a command line application that would require user authentication. To make it more interesting, I thought it would be fun to give the user an identity, or minimally, something nice to look at at starting up the application. My mind immediately drifted to avatars, because an access token required for the application could equivalently be used as a kind of unique identifier, and a hash generated to produce an avatar. But how can we show any kind of graphic in a terminal window?


Ascii to the rescue!

Remember chain emails from the mid 1990s? There was usually some message compelling you to send the email to ten of your closest friends or face immediate consequences (cue diabolical flames and screams of terror). And on top of being littered with exploding balloons and kittens, ascii art was a common thing.



 __     __        _           _                     _ 
 \ \   / /       | |         | |                   | |
  \ \_/ /__  __ _| |__     __| | __ ___      ____ _| |
   \   / _ \/ _` | '_ \   / _` |/ _` \ \ /\ / / _` | |
    | |  __/ (_| | | | | | (_| | (_| |\ V  V / (_| |_|
    |_|\___|\__,_|_| |_|  \__,_|\__,_| \_/\_/ \__, (_)
                                               __/ |  
                                              |___/   

or you can highlight like this:

 __     __        _           _                     _ 
 \ \   / /       | |         | |                   | |
  \ \_/ /__  __ _| |__     __| | __ ___      ____ _| |
   \   / _ \/ _` | '_ \   / _` |/ _` \ \ /\ / / _` | |
    | |  __/ (_| | | | | | (_| | (_| |\ V  V / (_| |_|
    |_|\___|\__,_|_| |_|  \__,_|\__,_| \_/\_/ \__, (_)
                                               __/ |  
                                              |___/   


Pokemon Ascii Avatars!

I had a simple goal - to create a command line based avatar generator that I could use in my application. Could there be any cute, sometimes scheming characters that be helpful toward this goal? Pokemon!! Of course :) Thus, the idea for the pokemon ascii avatar generator was born. If you want to skip the fluff and description, here is pokemon-ascii.

Generate a pokemon database

Using the Pokemon Database I wrote a script that produces a data structure that is stored with the module, and makes it painless to retrieve meta data and the ascii for each pokemon. The user can optionally run the script again to re-generate/update the database. It’s quite fun to watch!


The Pokemon Database has a unique ID for each pokemon, and so those IDs are the keys for the dictionary (the json linked above). I also store the raw images, in case they are needed and not available, or (in the future) if we want to generate the ascii’s programatically (for example, to change the size or characters) we need these images. I chose this “pre-generate” strategy over creating the ascii from the images on the fly because it’s slightly faster, but there are definitely good arguments for doing the latter.


Method to convert image to ascii

I first started with my own intuition, and decided to read in an image using the Image class from PIL, converting the RGB values to integers, and then mapping the integers onto the space of ascii characters, so each integer is assigned an ascii. I had an idea to look at the number of pixels that were represented in each character (to get a metric of how dark/gray/intense) each one was, that way the integer with value 0 (no color) could be mapped to an empty space. I would be interested if anyone has insight for how to derive this information. The closest thing I came to was determining the number of bits that are needed for different data types:


# String
"s".__sizeof__()
38

# Integer
x=1
x.__sizeof__()
24

# Unicode
unicode("s").__sizeof__()
56

# Boolean
True.__sizeof__()
24

# Float
float(x).__sizeof__()
24

Interesting, a float is equivalent to an integer. What about if there are decimal places?


float(1.2222222222).__sizeof__()
24

Nuts! I should probably not get distracted here. I ultimately decided it would be most reasonable to just make this decision visually. For example, the @ character is a lot thicker than a ., so it would be farther to the right in the list. My first efforts rendering a pokemon looked something like this:


I then was browsing around, and found a beautifully done implementation. The error in my approach was not normalizing the image first, and so I was getting a poor mapping between image values and characters. With the normalization, my second attempt looked much better:


I ultimately modified this code sightly to account for the fact that characters tend to be thinner than they are tall. This meant that, even though the proportion / size of the image was “correct” when rescaling it, the images always looked too tall. To adjust for this, I modified the functions to adjust the new height by a factor of 2:


def scale_image(image, new_width):
    """Resizes an image preserving the aspect ratio.
    """
    (original_width, original_height) = image.size
    aspect_ratio = original_height/float(original_width)
    new_height = int(aspect_ratio * new_width)

    # This scales it wider than tall, since characters are biased
    new_image = image.resize((new_width*2, new_height))
    return new_image

Huge thanks, and complete credit, goes to the author of the original code, and a huge thanks for sharing it! This is a great example of why people should share their code - new and awesome things can be built, and the world generally benefits!