# Draw a graph using braille characters

I hacked together a way to make a small graph using Braille unicode codepoints by abusing unicodedata:

def plot(timeline):
ret = []
for r1, r2 in zip(timeline[::2], timeline[1::2]):
character_name = "BRAILLE PATTERN DOTS-"
dots  = [x for x, y in zip("7321", range(r1))]
dots += [x for x, y in zip("8654", range(r2))]
character_name += "".join(sorted(dots))
ret.append(unicodedata.lookup(character_name) if dots else " ")
return "".join(ret)

>>> print plot([random.randrange(0,4) for _ in range(100)])
⣆⣆⣶⣤⢠⡀⣦⡆⢀⡄⣰⣠⣦⣆⣰⢰⢠⢰⣄⡄ ⣀⣦⡆⣄⣶⣤⣠⡆⣠⣦⣆  ⣰⣴⡄⣤⣀ ⡀⣄⡀⣦⣶⣰⣶⣄⣴


Barring low-hanging incremental improvements such as memoizing the call to unicodedata.lookup, what would be a more proper way to perform this lookup?

• Probably the sanest thing is to use this kludge to precompute an array of array of characters once, then use that instead. – badp Jan 15 '16 at 22:22
• Can you explain what your concern is? What makes you think that this approach is improper? – Gareth Rees Jan 17 '16 at 11:40

### Why zip?

You have:

dots  = [x for x, y in zip("7321", range(r1))]
dots += [x for x, y in zip("8654", range(r2))]


You're never using the second part of that zip. So you're basically making lists for the two ranges, making lists for the two zips, making lists for the outcomes of those things, all to drop most of the information.

You can simplify that to just:

dots = '7321'[:r1] + '8654'[:r2]


### character name

Try to avoid building up strings with +=. Instead just use format:

character_name = "BRAILLE PATTERN DOTS-{}".format(join(sorted(dots)))


I'm a bit confused by your list comprehensions:

dots  = [x for x, y in zip("7321", range(r1))]


What's the significance of "7231"? It would benefit from being a named constant, clarifying what it is.

Likewise, using x means I can't inferr anything from that name. r1 and r2 are also meaningless. If you named these differently, then I might be able to follow what's happening even without knowing that this is for creating braile characters. Even if their significance is semi-random, you should note that!

Also, you don't seem to use y. If that's the case, it's more pythonic to use an underscore instead of a y, to make it clear that you don't intend to use that value for anything.

If I'm reading this right, you're just using range(r1) with zip to affect how many characters out of "7231", which is clever and effective but terribly unclear. A comment would clear up confusion here immensely and make it a lot easier to follow.

• Braille characters in Unicode are named after the dots they have, and the numbering is, left to right, top to bottom, 1 4 2 5 3 6 7 8. The first three rows are numbered top to bottom, the fourth row was added later and thus got the next two available digits. As a result I use those strings to store the digits corresponding to dots in each column. That's the significance of 7321. – badp Jan 15 '16 at 22:15
• I honestly was hoping in an approach that could get me those Unicode codepoints without having to build their name and look it up from a huge table of irrelevant things. – badp Jan 15 '16 at 22:17