This tutorial is part of the skills labs within Interactive Data Science and Visualization.

Color and Style

In our previous tutorial which explored form as a preattentive feature, we investigated drawing different shapes. In this tutorial, we continue Skills Lab 3 by looking at our next preattentive features: color. Indeed, color is one part of a broader set of glyph attributes often referred to simply as style. This suite of options can help as important encoding device and, when used together with other preattentive features, can help increase data density.
Contents

Hex Codes

Our glyphs can actually have multiple potential colors at the same time. However, the first step is finding the color we want. We discussed some options in class: ColorBrewer and I Want Hue both provide good options. If you have Python installed on your machine, you might also take a look at Viscm. Finally, if you just need to manipulate some colors, a great tool is HSL Color Picker, which can work on multiple color spaces at the same time. All that said, many (maybe most) tools will work with hex codes or offer hex codes as an option. I'll be using those color codes below but you can see what they correspond to (and change them) using HSL Color Picker. Indeed, many of these colors will come from ColorBrewer. On that note, be sure to check out a short hex code primer if you are unfamiliar with color hex codes.

Fill

The easiest place to start for styling in Sketchingpy is the fill color for a shape. Let's use circles to demonstrate! Here, we can draw circles with different colors as well one circle which has no fill (will pass through to any figures drawn behind):
import sketchingpy

sketch = sketchingpy.Sketch2D(500, 500)

sketch.set_fill("#a6cee3")
sketch.draw_ellipse(150, 250, 100, 100)

sketch.clear_fill()
sketch.draw_ellipse(250, 250, 100, 100)

sketch.set_fill("#b2df8a")
sketch.draw_ellipse(350, 250, 100, 100)

sketch.show()
Try using some of our color tools to specify a different fill color!

Transparency

With our circles overlapping, we notice that what is drawn first goes at the bottom and is obsurced by whatever is drawn afterwards. This is called the Painter's Algorithm which basically says you should draw your scene from back to front. Let's let the user peer through those overlapping shapes though by adding transparency to our color. Appending two additional numbers to our hex codes specifies opacity where 00 means fully transparent and FF means fully opaque.
import sketchingpy

sketch = sketchingpy.Sketch2D(500, 500)

sketch.set_fill("#a6cee399")
sketch.draw_ellipse(150, 250, 100, 100)

sketch.clear_fill()
sketch.draw_ellipse(250, 250, 100, 100)

sketch.set_fill("#b2df8a99")
sketch.draw_ellipse(350, 250, 100, 100)

sketch.show()
Try changing the order in which the colors are set and the opacity part of the color code.

Stroke

So far, we've been manipulating the insides of our circles. Let's change the outsides. Same thing as before, let's have one circle that's different.
import sketchingpy

sketch = sketchingpy.Sketch2D(500, 500)

sketch.set_stroke("#1f78b4")
sketch.clear_fill()
sketch.draw_ellipse(150, 250, 100, 100)

sketch.set_fill("#C0C0C0")
sketch.clear_stroke()
sketch.draw_ellipse(250, 250, 100, 100)

sketch.set_stroke("#33a02c")
sketch.clear_fill()
sketch.draw_ellipse(350, 250, 100, 100)

sketch.show()
Try changing the colors again. When the area is smaller, is the contrast needed for readability higher?

Weight

Let's continue that thought around the size of these areas. We change the stroke width through its weight:
import sketchingpy

sketch = sketchingpy.Sketch2D(500, 500)

sketch.set_stroke_weight(3)

sketch.set_stroke("#1f78b4")
sketch.clear_fill()
sketch.draw_ellipse(150, 250, 100, 100)

sketch.set_fill("#C0C0C0")
sketch.clear_stroke()
sketch.draw_ellipse(250, 250, 100, 100)

sketch.set_stroke("#33a02c")
sketch.clear_fill()
sketch.draw_ellipse(350, 250, 100, 100)

sketch.show()
Try changing the strokes such that the first and last circle have different weights.

Context

Before we move on to the transformation matrix, we have a chance to play with some of the concepts around relative color interpretation and figure / ground as discussed in lectures. Try this sketch out for a moment which uses colors which could be useful for a quantitative scale:
import sketchingpy

sketch = sketchingpy.Sketch2D(500, 500)

sketch.clear('#FFFFFF')

sketch.set_ellipse_mode("radius")

def draw_circles(y):
    sketch.set_stroke("#000000")

    sketch.set_fill("#edf8fb")
    sketch.draw_ellipse(150, y, 20, 20)

    sketch.set_fill("#b2e2e2")
    sketch.draw_ellipse(200, y, 20, 20)

    sketch.set_fill("#66c2a4")
    sketch.draw_ellipse(250, y, 20, 20)

    sketch.set_fill("#2ca25f")
    sketch.draw_ellipse(300, y, 20, 20)

    sketch.set_fill("#006d2c")
    sketch.draw_ellipse(350, y, 20, 20)

draw_circles(125)

sketch.set_rect_mode("corner")
sketch.clear_stroke()
sketch.set_fill("#555555")
sketch.draw_rect(0, 250, 500, 250)

draw_circles(375)

sketch.show()
Note that this uses clear. Let's assume for a moment that this is a heatmap. We don't have a color scale listed. However, based on the background, which dot do you think corresponds to the highest and lowest number? Does your answer change depending on the background? It is possible that, using the concept of figure / ground from lecture, you may think the color with the highest luminance contrast corresponds to the highest number. That is a common recommendation! In other words, the rightmost dot may be seen as the highest in the top part of the graphic and the leftmost dot may be seen as the highest in the bottom part of the graphic.

Next

We are starting to build up a comprehensive set of tools to bring into our data visualization work. Next, continue on to Tutorial 6 to learn about the transformation matrix and our next preattentive feature: position.
Citations