It's difficult to understand a khipu from tables. A rendering is necessary. To render khipu adequately, there's a list of must-haves and nice-to-haves.
Nice to Haves:
With that preliminary list of requirements let's start by explaining the code:
In the python OODB class library, there is a base graphics "class" called a KhipuTullpu (Tullpu being the Quechua word for paint, although maybe technically it should be called a tullpuchik, one-who-paints). It is the geometry expert providing support for translation,scaling, points, boxes, etc., and for drawing basic SVG objects.
Every object that inherits from a KhipuTullpu has bounds box, SVG drawing abilities, the ability to transform and do vector math, etc. So cords can draw themselves, knots, can draw themselves, etc.
I chose SVG as the drawing file format because I wanted a vector-based graphics output (as opposed to raster-based), with all the crispness that it brings, and I wanted to add the ability to hover over cords and have their cord info show up. Sadly, very late in the game so to speak, I discovered that only the Mozilla Firefox and Safari web browsers have proper SVG support. I had to change direction.
Existing open source software to convert SVGs to raster-based PNGs, such as CairoSVG, offered only low-quality images. To save the SVG files in high-quality PNG and JPG format, I ended up having to use AppleScript combined with (proprietary) Adobe Illustrator's SVG import. Unfortunately VERY large khipus, AS069 for example with 1831 cords break PNG bounds and JPG bounds and Adobe Illustrator will error out. What to do?
After another week of trial and error I finally settled on saving them as very large TIFFs, then using an open-source utility ImageMagick to slice up the TIFFs into sections, and save them as jpegs. Then I had to write HTML code that put all those jpegs back together again, without any seams, to appear as one giant jpeg... It's not a miracle the bear dances well. It's a miracle the bear dances at all.
Losing SVG has had pros and cons. It's almost doubled the length of time to build the final product. On the other hand, procedural texturing for mottled cords creates huge 50Mb SVG files. These are not a problem because they are then converted to pixels in jpeg. And the resolution/crispness of graphics remains. So that's nice!
We know that there are up-cords and "pendant" cords (i.e. down cords). In the EDA of the primary cord, we saw that there are 11682 U attachment cords, 10457 R attachment cords, and 9960 Verso attachment cords. I had assumed, based on an initial "correct" rendering of Locke's UR166, that U meant up. Apparently that is only true under certain circumstances. The current rendering assumes that if there are both up and down cords, that any up pendant cord is "up" all the way up, and any down pendant cord is down all the way down. Additionally if all the pendant cords are up, the code assumes that U means unknown and the code renders the cords as down cords. I am indebted to Manuel Medrano's communications about the history of the database with this convention.
After the database had incorrect cords, cord clusters, etc., cleansed and removed from the database, the next problem challenge became what to do with odd cords. Two proved problematic - 0 length cords, which rendered oddly (you can generate a really long primary cord when you divide by 0), and really long cords. One cord in khipu UR149 had a lenth of 615 cm..roughly 20 feet. With no knots. Which makes a whacky drawing. That particular cord is simply truncated to 115 cm. in the code. The 0 length cords are given dashed lines to the length of their furthest estimated knot location.
Cord notes often were uninformative or unnecessary. Notes such as "Length: 32 cm" are not displayed, as are other uninformative notes such as "Value now 45 cm" etc.
The classic approach to software engineering APIs (application programming interface) is to check inputs for validity and then is to reject invalid inputs. With this database, however, I had to distinguish between two types of invalid inputs, physical khipu data loss such as missing cords with knots, etc, and database bugs such as cords pointing to khipu1 with a subsidiary pointing to khipu2.
I chose to accept invalid physical khipu inputs (ie. cord length of 0, with knots at 10cm) and try to "reconstruct" the original. However, I was unwilling to accept database bugs, and no attempt was made at reconstructing valid khipus, from Excel files, for example. Consequently, I left approximately 140 khipu in the warehouse, so to speak, because I was unwilling to accept pointer or other database errors in the cleansed data.