16

I want to plot a true/false or active/deactive binary data similar to the following picture: True/False Plot

The horizontal axis is time and the vertical axis is some entities(Here some sensors) which is active(white) or deactive(black). How can I plot such a graphs using pyplot.

I searched to find the name of these graphs but I couldn't find it.

Hadi
  • 5,328
  • 11
  • 46
  • 67

1 Answers1

33

What you are looking for is imshow:

import matplotlib.pyplot as plt
import numpy as np

# get some data with true @ probability 80 %
data = np.random.random((20, 500)) > .2

fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data, aspect='auto', cmap=plt.cm.gray, interpolation='nearest')

Then you will just have to get the Y labels from somewhere.

enter image description here

It seems that the image in your question has some interpolation in the image. Let us set a few more things:

import matplotlib.pyplot as plt
import numpy as np

# create a bit more realistic-looking data
# - looks complicated, but just has a constant switch-off and switch-on probabilities
#   per column
# - the result is a 20 x 500 array of booleans
p_switchon = 0.02
p_switchoff = 0.05
data = np.empty((20,500), dtype='bool')
data[:,0] = np.random.random(20) < .2
for c in range(1, 500):
    r = np.random.random(20)
    data[data[:,c-1],c] = (r > p_switchoff)[data[:,c-1]]
    data[-data[:,c-1],c] = (r < p_switchon)[-data[:,c-1]]

# create some labels
labels = [ "label_{0:d}".format(i) for i in range(20) ]

# this is the real plotting part
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data, aspect='auto', cmap=plt.cm.gray)
ax.set_yticks(np.arange(len(labels)))
ax.set_yticklabels(labels)

creates enter image description here

However, the interpolation is not necessarily a good thing here. To make the different rows easier to separate, one might use colors:

import matplotlib.pyplot as plt
import matplotlib.colors
import numpy as np

# create a bit more realistic-looking data
# - looks complicated, but just has a constant switch-off and switch-on probabilities
#   per column
# - the result is a 20 x 500 array of booleans
p_switchon = 0.02
p_switchoff = 0.05
data = np.empty((20,500), dtype='bool')
data[:,0] = np.random.random(20) < .2
for c in range(1, 500):
    r = np.random.random(20)
    data[data[:,c-1],c] = (r > p_switchoff)[data[:,c-1]]
    data[-data[:,c-1],c] = (r < p_switchon)[-data[:,c-1]]

# create some labels
labels = [ "label_{0:d}".format(i) for i in range(20) ]

# create a color map with random colors
colmap = matplotlib.colors.ListedColormap(np.random.random((21,3)))
colmap.colors[0] = [0,0,0]

# create some colorful data:
data_color = (1 + np.arange(data.shape[0]))[:, None] * data

# this is the real plotting part
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(data_color, aspect='auto', cmap=colmap, interpolation='nearest')
ax.set_yticks(np.arange(len(labels)))
ax.set_yticklabels(labels)

creates

enter image description here

Of course, you will want to use something less strange as the coloring scheme, but that is really up to your artistic views. Here the trick is that all True elements on row n have value n+1 and, and all False elements are 0 in data_color. This makes it possible to create a color map. Naturally, if you want a cyclic color map with two or three colors, just use the modulus of data_color in imshow by, e.g. data_color % 3.

DrV
  • 22,637
  • 7
  • 60
  • 72
  • 1
    Thanks for your answer! Do you know the name of these kinds of graphs? – Hadi Aug 24 '14 at 09:17
  • 1
    +1 seems that also the original was made using Matplotlib, looks exactly the same. For what it is worth, I find the use of interpolation misleading for this application, this suggest that there is a gradual transition between a fridge and a telephone! I would prefer straight bars, but maybe go for some nice colors instead. – Bas Swinckels Aug 24 '14 at 09:18
  • @Constantine: I would call it a timeline plot, but I really do not know if there would be a better name. Ribbon plot is unfortunately reserved for something else. – DrV Aug 24 '14 at 12:57
  • 1
    @BasSwinckels: Yep, the interpolation is not the best thing here. I added a non-interpolated version with colors (dunno about the niceness of the colors). From the visualization point of view I would actually have three rows of data (color/dark color) and one empty row (black) between the different blocks, as that would make it visually easier to follow each row. – DrV Aug 24 '14 at 12:58
  • 2
    Seriously high quality answer. This deserves some kind of award. – mjp May 08 '17 at 16:05
  • `---> 15 data[-data[:,c-1],c] = (r < p_switchon)[-data[:,c-1]]` The numpy boolean negative, the `-` operator, is not supported, use the `~` operator or the logical_not function instead. – weefwefwqg3 Jan 28 '18 at 18:10
  • data[data[:,c-1],c] # what is this? Data indexed by an array slice of itself and the x-axis value? – JamEnergy May 24 '18 at 09:17