Overview

We need to refine the way users specify colors, to simplify the public API and eliminate inconsistencies. The challenge is to handle all of the ways in which a user might want to specify per-series / per-datum colors, while avoiding potential ambiguities.

Use-cases

  • Specify one explicit color for everything.
      toyplot.plot(x, y, color="red")
  • Specify an explicit color per series.
      toyplot.plot(x, y, color=["red", "cinnamon", "cardinal"])
  • Specify a palette for the series.
      toyplot.plot(x, y, color=toyplot.color.brewer("reds"))
  • Specify a colormap for the series.
      toyplot.plot(x, y, color=toyplot.color.LinearMap(toyplot.color.Palette(["red", "green", "blue"])))
  • Specify per-datum scalar values and have them mapped.
      toyplot.plot(x, y, color=temperature)
  • Specify per-datum scalar values and have them mapped, but override a few "special" values.
      colors = toyplot.color.broadcast(temperature)
      colors[numpy.argsort(temperature)[0]] = "blue"
      colors[numpy.argsort(temperature)[-1]] = "red"
      toyplot.plot(x, y, color=colors)
  • Specify explicit per-datum color values for everything (i.e. map them yourself).
      toyplot.plot(x, y, color=mycolors)

API

  • (values) - map the values with the default colormap.
  • (colormap) - Use the given colormap to map series $[0, N)$, or datum $[0, N)$ if there's only one series.
  • (palette) - Use the palette with a linear colormap to map series $[0, N)$, or datum $[0, N)$ if there's only one series.
  • (values, colormap) - map values with the given colormap.
  • (values, palette) - map values with a linear colormap and the given palette.

toyplot.color.broadcast(...) always returns a numpy color array (array with dtype == toyplot.color.dtype), with the given shape.

Values

  • "value" - a single CSS color value.
  • (r, g, b) - a single RGB color value.
  • (r, g, b, a) - a single RGBA color value.
  • toyplot.color.rgb() - a single RGB color value.
  • toyplot.color.rgba() - a single RGBA color value.
  • [value1, value2, ...] - 1D heterogeneous collection of CSS and tuple color values.
    • We don't allow scalar values in this case, because their domain would be ambiguous.
    • Have to be careful with the implementation here - we don't want a list of nothing-but-tuples to be misinterpreted as a 2D numpy array of scalars.
  • numpy string array with shape $M$ - 1D collection of CSS color values.
  • numpy string array with shape $M \times N$ - 2D collection of CSS color values.
  • numpy numeric array with shape $M$ - 1D collection of scalar values for mapping.
  • numpy numeric array with shape $M \times N$ - 2D collection of scalar values for mapping.
  • numpy color array with shape $M$ - 1D collection of color values.
  • numpy color array with shape $M \times N$ - 2D collection of color values.

In [1]:
import numpy
x = numpy.linspace(0, 1)
y = numpy.column_stack((x ** 2, x ** 3))
numpy.random.seed(1234)
temperature = numpy.random.uniform(size=y.shape)

In [2]:
import toyplot

In [3]:
toyplot.scatterplot(x, y, width=300);


0.00.51.00.00.51.0

In [4]:
toyplot.scatterplot(x, y, color="red", width=300);


0.00.51.00.00.51.0

In [5]:
toyplot.scatterplot(x, y, color=["red", "blue"], width=300);


0.00.51.00.00.51.0

In [6]:
toyplot.scatterplot(x, y, fill=temperature, width=300);


0.00.51.00.00.51.0

In [7]:
toyplot.scatterplot(x, y, fill=(temperature, toyplot.color.brewer("BlueRed")), width=300);


0.00.51.00.00.51.0

In [8]:
toyplot.scatterplot(x, y, fill=(temperature, toyplot.color.LinearMap()), width=300);


0.00.51.00.00.51.0

In [9]:
colors = toyplot.color.broadcast((temperature, toyplot.color.brewer("Greys")), y.shape)
colors[20:30, 1] = toyplot.color.css("yellow")
colors.flat[numpy.argmin(temperature)] = toyplot.color.css("blue")
colors.flat[numpy.argmax(temperature)] = toyplot.color.css("red")
toyplot.scatterplot(x, y, fill=colors, width=300);


0.00.51.00.00.51.0

In [10]:
x = numpy.linspace(0, 1)
y = x ** 2

In [11]:
toyplot.bars(y, fill=(x, toyplot.color.brewer("Reds")), width=300);


010203040500.00.51.0

In [12]:
toyplot.bars(y, fill=toyplot.color.brewer("Reds"), width=300);


010203040500.00.51.0

In [13]:
toyplot.fill(x, numpy.column_stack((y, y/2, y/3, y/4, y/5)), baseline="symmetric", fill=(numpy.arange(5), toyplot.color.brewer("Reds")), width=300);


0.00.51.0-101

In [14]:
toyplot.fill(x, numpy.column_stack((y, y/2, y/3, y/4, y/5)), baseline="symmetric", fill=toyplot.color.brewer("Reds"), width=300);


0.00.51.0-101

In [15]:
toyplot.scatterplot(x, numpy.column_stack((y, y/2, y/3, y/4, y/5)), color=(numpy.arange(5), toyplot.color.brewer("Reds")), width=300);


0.00.51.00.00.51.0

In [16]:
toyplot.scatterplot(x, numpy.column_stack((y, y/2, y/3, y/4, y/5)), color=toyplot.color.brewer("Reds"), width=300);


0.00.51.00.00.51.0

In [17]:
canvas = toyplot.Canvas(width=300)
axes = canvas.axes()
axes.text(x, y, y, fill=(x, toyplot.color.brewer("Reds")));


0.00.0004164931278630.001665972511450.003748438150770.006663890045810.01041232819660.01499375260310.02040816326530.02665556018330.03373594335690.04164931278630.05039566847150.05997501041230.07038733860890.08163265306120.09371095376930.1066222407330.1203665139530.1349437734280.1503540191590.1665972511450.1836734693880.2015826738860.220324864640.2399000416490.2603082049150.2815493544360.3036234902120.3265306122450.3502707205330.3748438150770.4002498958770.4264889629320.4535610162430.481466055810.5102040816330.5397750937110.5701790920450.6014160766350.633486047480.6663890045810.7001249479380.7346938775510.7700957934190.8063306955440.8433985839230.8812994585590.920033319450.9596001665971.0-0.50.00.51.01.50.00.51.0

In [18]:
canvas = toyplot.Canvas(width=300)
axes = canvas.axes()
axes.text(x, y, y, fill=toyplot.color.brewer("Reds"));


0.00.0004164931278630.001665972511450.003748438150770.006663890045810.01041232819660.01499375260310.02040816326530.02665556018330.03373594335690.04164931278630.05039566847150.05997501041230.07038733860890.08163265306120.09371095376930.1066222407330.1203665139530.1349437734280.1503540191590.1665972511450.1836734693880.2015826738860.220324864640.2399000416490.2603082049150.2815493544360.3036234902120.3265306122450.3502707205330.3748438150770.4002498958770.4264889629320.4535610162430.481466055810.5102040816330.5397750937110.5701790920450.6014160766350.633486047480.6663890045810.7001249479380.7346938775510.7700957934190.8063306955440.8433985839230.8812994585590.920033319450.9596001665971.0-0.50.00.51.01.50.00.51.0

In [19]:
canvas = toyplot.Canvas(width=300)
axes = canvas.axes()
axes.hlines(x, stroke=(x, toyplot.color.brewer("Reds")));


-0.50.00.50.00.51.0

In [20]:
canvas = toyplot.Canvas(width=300)
axes = canvas.axes()
axes.hlines(x, stroke=toyplot.color.brewer("Reds"));


-0.50.00.50.00.51.0

In [21]:
canvas = toyplot.Canvas(width=300)
axes = canvas.axes()
axes.vlines(x, stroke=(x, toyplot.color.brewer("Reds")));


0.00.51.0-0.50.00.5

In [22]:
canvas = toyplot.Canvas(width=300)
axes = canvas.axes()
axes.vlines(x, stroke=toyplot.color.brewer("Reds"));


0.00.51.0-0.50.00.5

In [ ]: