Hello,

I want to plot some digital signals using matplotlib.

I want to plot some 6 digital signals (or say any arbitary number of

signals) in one figure.

For each signal I want a y-label displayed.One way to plot digital signals in one plot is that I add an offset to

other signals and then plot. But I thought if anyone knows a better

idea then it will be good.

Also how can I have different y-labels for each signal. I don't want

to use legends because with too many signals it will be dificult to

match the legend with where the signal is.I am attaching a picture which is generated by some other tools but

now I want to genrate somewhat similar way in matplotlib.

Can anyone give me some small hints?

There are a few ways to do it. You could make each signal a separate

axes and make the y label horizontal. This works fine for a small

number of signals (4-10 say) except the extra horizontal lines and

ticks around the axes may be annoying. It's on our list of things to

change the way these axes lines are draw, but it isn't done yet.

from pylab import figure, show, setp

from matplotlib.numerix import sin, cos, exp, pi, arange

yprops = dict(rotation=0,

horizontalalignment='right',

verticalalignment='center')

axprops = dict(yticks=[])

fig = figure()

t = arange(0.0, 2.0, 0.01)

ax1 =fig.add_axes([0.1, 0.7, 0.8, 0.2], **axprops)

ax1.plot(t, sin(2*pi*t))

ax1.set_ylabel('S1', **yprops)

# force x axes to remain in register, even with toolbar navigation

ax2 = fig.add_axes([0.1, 0.5, 0.8, 0.2], sharex=ax1, **axprops)

ax2.plot(t, exp(-t))

ax2.set_ylabel('S2', **yprops)

ax3 = fig.add_axes([0.1, 0.3, 0.8, 0.2], sharex=ax1, **axprops)

ax3.plot(t, sin(2*pi*t)*exp(-t))

ax3.set_ylabel('S3', **yprops)

ax4 = fig.add_axes([0.1, 0.1, 0.8, 0.2], sharex=ax1, **axprops)

ax4.plot(t, sin(2*pi*t)*cos(4*pi*t))

ax4.set_ylabel('S4', **yprops)

show()

It turns out that I lot signals in the way you suggest all the time

(EEG viewer), see a screenshot of the application that gave birth to

matplotlib at

http://matplotlib.sourceforge.net/screenshots/eeg_small.png . I've

been meaning to refactor the EEG viewer into a "multiline" viewer and

put it into matplotlib but haven't gotten around to it (the source

code is at http://pbrain.sf.net).

Here is an example of how I do it in my app with additional comments.

Note that this will break the y behavior of the toolbar because we

have changed all the default transforms. In my application I have a

custom toolbar to increase or decrease the y scale. In this example,

I bind the plus/minus keys to a function which increases or decreases

the y gain. Perhaps I will take this and wrap it up into a function

called plot_signals or something like that because the code is a bit

hairy since it makes heavy use of the somewhat arcane matplotlib

transforms. I suggest reading the header of

http://matplotlib.sourceforge.net/matplotlib.transforms.html before

trying to understand this example.

from pylab import figure, show, setp, connect, draw

from matplotlib.numerix import sin, cos, exp, pi, arange

from matplotlib.numerix.mlab import mean

from matplotlib.transforms import Bbox, Value, Point, \

get_bbox_transform, unit_bbox

# load the data

t = arange(0.0, 2.0, 0.01)

s1 = sin(2*pi*t)

s2 = exp(-t)

s3 = sin(2*pi*t)*exp(-t)

s4 = sin(2*pi*t)*cos(4*pi*t)

s5 = s1*s2

s6 = s1-s4

s7 = s3*s4-s1

signals = s1, s2, s3, s4, s5, s6, s7

for sig in signals:

sig = sig-mean(sig)

lineprops = dict(linewidth=1, color='black', linestyle='-')

fig = figure()

ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])

# The normal matplotlib transformation is the view lim bounding box

# (ax.viewLim) to the axes bounding box (ax.bbox). Where are going to

# define a new transform by defining a new input bounding box. See the

# matplotlib.transforms module helkp for more information on

# transforms

# This bounding reuses the x data of the viewLim for the xscale -10 to

# 10 on the y scale. -10 to 10 means that a signal with a min/max

# amplitude of 10 will span the entire vertical extent of the axes

scale = 10

boxin = Bbox(

Point(ax.viewLim.ll().x(), Value(-scale)),

Point(ax.viewLim.ur().x(), Value(scale)))

# height is a lazy value

height = ax.bbox.ur().y() - ax.bbox.ll().y()

boxout = Bbox(

Point(ax.bbox.ll().x(), Value(-0.5) * height),

Point(ax.bbox.ur().x(), Value( 0.5) * height))

# matplotlib transforms can accepts an offset, which is defined as a

# point and another transform to map that point to display. This

# transform maps x as identity and maps the 0-1 y interval to the

# vertical extent of the yaxis. This will be used to offset the lines

# and ticks vertically

transOffset = get_bbox_transform(

unit_bbox(),

Bbox( Point( Value(0), ax.bbox.ll().y()),

Point( Value(1), ax.bbox.ur().y())

))

# now add the signals, set the transform, and set the offset of each

# line

ticklocs = []

for i, s in enumerate(signals):

trans = get_bbox_transform(boxin, boxout)

offset = (i+1.)/(len(signals)+1.)

trans.set_offset( (0, offset), transOffset)

ax.plot(t, s, transform=trans, **lineprops)

ticklocs.append(offset)

ax.set_yticks(ticklocs)

ax.set_yticklabels(['S%d'%(i+1) for i in range(len(signals))])

# place all the y tick attributes in axes coords

all = []

labels = []

ax.set_yticks(ticklocs)

for tick in ax.yaxis.get_major_ticks():

all.extend(( tick.label1, tick.label2, tick.tick1line,

tick.tick2line, tick.gridline))

labels.append(tick.label1)

setp(all, transform=ax.transAxes)

setp(labels, x=-0.01)

ax.set_xlabel('time (s)')

# Because we have hacked the transforms, you need a special method to

# set the voltage gain; this is a naive implementation of how you

# might want to do this in real life (eg make the scale changes

# exponential ranther than linear) but it gives you the idea

def set_ygain(direction):

set_ygain.scale += direction

if set_ygain.scale <=0:

set_ygain.scale -= direction

return

for line in ax.lines:

trans = line.get_transform()

box1 = trans.get_bbox1()

box1.intervaly().set_bounds(-set_ygain.scale, set_ygain.scale)

draw()

set_ygain.scale = scale

def keypress(event):

if event.key in ('+', '='): set_ygain(-1)

elif event.key in ('-', '_'): set_ygain(1)

connect('key_press_event', keypress)

ax.set_title('Use + / - to change y gain')

show()

Also one more point is if I want all the signal colors in plot to be

same say black then how can I do it?. The default plot function varies

the colors of the signal plotted.

pass the color='black' argument to plot

plot(x, y, color='black')

For marker plots, you may also want to set the markerfacecolor and

markeredgecolor attributes.