A Flask App for Generative Visual Poetry from News Headlines

Pretty Mes generates “mesostic” poems in a graphic style inspired by American composer and artist John Cage.

I’m not a huge fan of expressive poetry. Too often I think it borders on self-indulgence. Vernacular language is so littered with idioms that in all but the most brilliant cases, expressive writing has an unfortunate habit of falling into the deeply etched ruts of cliché. While I was in grad school, in an attempt to feel like less of a philistine, I braved the amusement of my thesis advisors and expended one precious class credit to take Gary Lenhart’s legendary contemporary poetry class. It was there that I discovered Against Expression. Against Expression is a different kind of poetic anthology. You won’t find many villanelles here. Instead the book is a huge collection of conceptual, algorithmic, structural, and generative approaches to language. Among the experiments detailed herein are poems created with the help of Amazon’s Mechanical Turk, a work of Samuel Beckett overwritten with a transcription of the text’s own grammatical structure, a history of world written entirely from the author’s memory (without the assistance any reference material!), and a poem culled entirely from the subject headings of a Young Women’s Health Forum message board.

Recently I decided to do something interesting with language along these lines, and in particular, I wanted to build something in Flask. Although I’ve been working with Python for almost a decade, I don’t have much experience using Python within a web framework. Visual poetry — where the typographic choices of the artist form an integral part of the work’s aesthetic — seemed like a good opportunity to practice my front-end development skills as well.

John Cage’s Mesostic 26 (source)

In the 1960s American experimental composer and artist John Cage repurposed the existing “Acrostic” poetic form as a kind of found-text generator. In an acrostic, the first letter of each line in a poem forms a word or phrase when read from top to bottom on the vertical axis. In John Cage’s “mesostic” form, a keyword or phrase is first pre-selected. An existing text is then read until an occurrence of the first letter in the keyword is found within the source text. One then continues reading the source text until the next letter in the keyword is found, and this process continues until the keyword has been fully spelled out from the text. The keyword is, in essence, used to slice the source text into unpredictable chunks. A mesostic is usually formatted so that the keyword is visible on the poem’s vertical axis, as in an acrostic, but the keyword may occur down the middle of the poem, with excess intervening text laid out to the left and right as “wings” around this central spine.

At least two programmers or teams of programmers have written “mesostic generators” which are available online. P.S.: Meso, a Python-based app, was written by Nicki Hoffman in 2013, and a team at the University of Pennsylvania’s School of Arts and Sciences Computing group recently wrote another version in JavaScript. However, I was interested to additionally imitate the specific graphic style that John Cage used for some of his collections of mesostics. In particular Cage’s 1971 collection 62 Mesostics re Merce Cunningham introduced a disruptive typographic style in which the text of the poem is broken up into letters of widely varying sizes and typefaces, a technique literary scholar and poet Dani Spinosa has described, in his extensive writings about the poems, as “linguistic noise.”

“[…]the Cunningham mesostics do not produce meaning, do not satisfy a logical hypothesis, but rather, in their noise, they make observations about the problematic tension between semantic meaning and the materiality of language.”

While existing mesostic generators give the reader many options for how they want a mesostic poem to be generated, I also wanted to move away from the concept of an online “generator” and stay as close as possible to the philosophy of a “found” poem by using a minimalist user interface with few options and a text constructed from random source materials.

To parse the text into the form of a mesostic I started from scratch and wrote my own mesostic poem algorithm. This turned out to be more irritating than I expected, due in part to the requirement that no word in a line be presented incompletely, while a word containing two consecutive target letters must be repeated on consecutive lines. So while the input text can easily be compared against the keyword letter-by-letter, the resulting text fragments must be selected word-by word using Python’s Split function. Additionally the text “wings” on either side of the central spine must not repeat already used words.

In accordance with my design goal that mesostic poems be generated from existing found texts, I also implemented the News API from newsapi.org/. Using the News API, the source text is drawn from a collection of current headlines from the BBC, The Associated Press, Reuters, CNN, Bloomberg, and CNBC.

This Python backend is packaged in a minimalist Flask implementation. The user may submit their own strings for the “keyword” variable (set to “John Cage” by default) and “text” (overwriting whatever is served up by the News API).

Previous mesostic poem generators have been able to implement the poem’s unique formatting by simply adding whitespace before lines. Since the extremely distorted typography of my mesostic poems introduces unpredictable letter widths and line heights, this was not found to be practical in my case. Instead the Pretty Mes mesostic poems are formatted via a series of flexboxes on the front end. These text boxes are instantiated when the page loads by the Jinja2 templating system. A Jinja2 “for-loop” takes a nested list of string (representing lines of the poem divided just before the spine letter) from the Python backend and dumps alternating strings into left- and right-justified flexboxes. The effect is that each line of the poem appears to be a single continuous line of text aligned to the spine letters.

{% for item in poem %}
{% if (loop.index0 == 0) or (loop.index0 is even) %}
<div class=”flexleft”>
<div class=”poem”>{{ poem[loop.index0] }}</div><br>
{% else %}
<div class=”flexright”>
<div id=”rightSide” class=”poem”>{{ poem[loop.index0] }}</div><br>
{% endif %}
{% endfor %}

This approach also conveniently allows us to use the CSS ::first-letter Pseudo-element set all the first letters of the right-hand flexbox to be red, a stylistic innovation I added above and beyond Cage’s monochromatic typography to slightly improve the readability of the spine keywords. Additionally a fine grey line (the left border of the right-hand flexbox) is added defining the vertical axis of the keyword.

Since it’s important visually to have each line of the poem align along the bottom of that line(with some overlaps allowed for large text which extends upwards into the previous line), we set “align-items: flex-end;” in the CSS.

An example of a mesostic poem with the stochastic typography turned off.

The unique text formatting for the mesostic poem is accomplished by using JavaScript to set a separate CSS style for each letter in the poem. In writing this bit of code, I got a major hint from Bill Mathews of StackOverflow whose code to randomly assign colors to each letter of a text works on the same principle. Basically we iterate over every member of a string and assign a CSS style to that member with the innerHTML property. In my case, I have separate functions to generate pseudorandom grey-tone color HEX codes, letter sizes, and Google fonts. The precise composition of the switch statements returning values from these functions allows some control over, for example, the density of ultra-large letters in the poem.

innerTextSplit[j] = ‘<span style=”color: ‘ + randomColor + ‘;’ + font + ‘;’ + ‘font-size:’ + randomSize + ‘pt’ + ‘“>’ + innerTextSplit[j] + ‘</span>’;paragraphs[i].innerHTML += innerTextSplit[j];

In the left-hand pop-out panel a few limited option allow the user to turn on or off the CSS formatting for the poem or enter their own keyword or text.

The left-hand pop-out panel includes a few (intentionally minimalist) options for controlling the output of the app.

As a finishing touch, Hexagram 3 from the I Ching is used in place of the “hamburger button” in the top-left corner of the app, an in-joke for those aware of Cage’s extensive use of the I Ching to generate random values for various artistic works throughout his later works.

My mesostic poem and typography generator is available online at https://prettymes.herokuapp.com/.




Full-stack developer and experimental sound artist. Writer for freeCodeCamp and Hacker Noon.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Introducing Local Trader — v5.2.0 is out

bluewallet bitcoin wallet local trader

Build a Social Media Website with Django — Part 3 (Users App Templates)

Leetcode — 378. Kth Smallest Element in a Sorted Matrix

Separation of Concerns

Build your own SQL fiddle with Docker & VSCode

VSCode and Docker

How to create Transit Gateway in AWS

Smooth In-page Scrolling CSS Only

Excited about Flutter 2 and Farewell to React Native

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Daniel Miller

Daniel Miller

Full-stack developer and experimental sound artist. Writer for freeCodeCamp and Hacker Noon.

More from Medium

Integrating LabelStudio in React Machine Learning Applications

Using SCSS/SASS with Django3

Django Image

Beginning With Rasa

RASA — Open Source

How to Create Flickr Search with JavaScript and Python