# How to draw timing diagram from a list of values?

What is the most elegant way to draw a timing diagram specified by a list of zeros and ones?

In the following code I attempt to draw the clock pulse diagram, and I'd like to continue drawing the timing diagram for a given input of 0's and 1's, e.g., {11011011,11100110}.

clockWidth = 0.2;
pulseHgh = 0.1;
rowHgh = pulseHgh + 0.1;
pNum = 8;
diagWidth = 2;
yb = 0;
clock = Table[
Line[{ {xb,
yb} , {xb, yb} + {0, pulseHgh}, {xb, yb} + {clockWidth/2,
pulseHgh}, {xb, yb} + {clockWidth/2, 0}, {xb,
yb} + {clockWidth, 0}}], {xb, 0, clockWidth*pNum, clockWidth}];
txt = Table[
Text[Style[n, 12, Italic], {n*clockWidth + clockWidth/2,
yb + 0.13}], {n, 0, pNum}];
Graphics[{clock}, Epilog -> {Text["Clock", {2, yb}], txt},
PlotRange -> {-0.2, 0.2} ]


I'd like the result to look somewhat like the figure shown below. • ListLinePlot[IntegerDigits@11011011, InterpolationOrder -> 0, AspectRatio -> 1/10] is a good start :)
– rm -rf
Jul 14 '14 at 2:06
• @rm-rf I believe the way I created the clock pulse is clumsy enough. Jul 14 '14 at 2:07

## Edit

I found this a very interesting question, and I developed a solution at the Graphics level rather that the Plot level. My implementation approach is classic divide-and-conquer, building up the main function from a number of small ones. This made development straightforward, but also makes the code rather long for answers posted on this site.

## Component code

### Binary signals

Binary signals (bit streams) are represented by lists of ones and zeros. Signal data are expected to be string representations of binary numbers, e.g., "01100100001101000100".

bitStringToDigits[bitstr_String] := ToExpression @ Characters@ bitstr


The clock's bit stream is standardized as alternating ones and zeros beginning with a one. It only needs to be given the length of the stream.

clockDigits[tMax_Integer /; tMax > 0] := Table[Mod[i, 2], {i, tMax}]


### Graphics items

What is drawn on the screen to represent the bit at time t depends on both the value of the bit and the value of the bit that precedes it. The first argument to bit distinguishes the four possible cases. The second argument is the bit's position, t.

• {0, 0}$\ \ \ \ \$zero-bit preceded by a zero-bit
• {1, 0}$\ \ \ \ \$zero-bit preceded by a one-bit
• {1, 1}$\ \ \ \ \$one-bit preceded by a one-bit
• {0, 1}$\ \ \ \ \$one-bit preceded by a zero-bit

Note that bit draws zeros at $y=0$ and ones at $y=1$. In a chart with multiple bit streams, the bits in any given stream will be translated vertically to their proper height in the chart.

bit[{0, 0}, t_Integer] := {Line[{{t, 0}, {t + 1, 0}}]}
bit[{1, 0}, t_Integer] := {Line[{{t, 1}, {t, 0}}], Line[{{t, 0}, {t + 1, 0}}]}
bit[{1, 1}, t_Integer] := {Line[{{t, 1}, {t + 1, 1}}]}
bit[{0, 1}, t_Integer] := {Line[{{t, 0}, {t, 1}}], Line[{{t, 1}, {t + 1, 1}}]}


Given a list where every element is either zero or one, signalGraphicsItem returns a list of Line expressions which will draw the bit stream represented by the input list.

signalGraphicsItem[bits_List] :=
Module[{pairs},
pairs = Partition[Join[{bits[]}, bits], 2, 1];
MapIndexed[bit[#1, #2[] - 1] &, pairs]]


Given an integer, tMax, clockGraphicsItem returns a list of graphics primitives that draws the bit train of a reference over the interval 0 to tMax time units. The bit train is labeled CLOCK to its left.

clockGraphicsItem[tMax_Integer /; tMax > 0] :=
{Text[Style["CLOCK", 14], {-.25, .5}, {1, 0}],  signalGraphicsItem[clockDigits[tMax]]}


Given a string representing a valid binary signal, bitsGraphicsItem returns a list of graphics primitives that draws the bit train of the signal. Otherwise, bitsGraphicsItem issues an error message and returns an empty list.

bitsGraphicsItem::badbits = "1 does not represent a valid binary signal";
With[{textHt = 14},
bitsGraphicsItem[bitstr_String] /; StringFreeQ[bitstr, Except["0" | "1"]] :=
{Text[Style[bitstr, textHt], {-.25, .5}, {1, 0}],
signalGraphicsItem[bitStringToDigits[bitstr]]}]


Put vertical dashed lines in the background, marking off the time steps.

With[{color = Red},
backgroundLines[tMax_Integer, nSignals_Integer, spacer_ /; spacer >= 0] :=
{color, Dashed,
Table[Line[{{i, 0}, {i, (1 + spacer) nSignals - spacer}}], {i, 0, tMax}]}]


Label the background lines with time indicators, top and bottom

timeLabel[tMax_Integer] := Table[Text[i, {i, 0}], {i, 0, tMax}]


## Binary signal chart

This is the main function. Given a list of strings representing valid binary signals, binarySignalChart draws charts like binarySignalChart takes two options.

• clock$\ \ \ \ \ \ \ \ \ \ \ \$default is True; if False, suppresses drawing of the clock bit train
• ImageSize$\ \ \ \ \$passed on to Graphics for controlling chart size

Protect[clock];
Options[binarySignalChart] = {clock -> True, ImageSize -> Medium};
With[{spacer = .5},
binarySignalChart[signals : {_String ..}, OptionsPattern[]] :=
Module[{n, items, tMax, displacements},
items = bitsGraphicsItem /@ signals;
tMax = Max[StringLength /@ signals];
If[OptionValue[clock],
PrependTo[items, clockGraphicsItem[tMax]]];
n = Length@items;
displacements = {0, 1 + spacer} # & /@ Range[0, n - 1];
Graphics[{
backgroundLines[tMax, n, spacer],
Translate[timeLabel[tMax], {0, -.25}],
Translate[timeLabel[tMax], displacements[[-1]] + {0, 1.2}]},
ImageSize -> OptionValue[ImageSize]]]]
binarySignalChart[signal_String, opt : OptionsPattern[]] :=
binarySignalChart[{signal}, opt]


## Examples

This is a minimal chart. The clock display is suppressed and because there is only one signal to display, there is no need to wrap it in a list.

With[{signal = "10110101011001"},
binarySignalChart[signal, clock -> False, ImageSize -> 500]] Any number of signals can be given. They do not have to be the same length. The vertical timing lines and the clock train are automatically extended to cover the longest signal train.

With[{signals = {"11100110", "0101100101100", "11011011"}},
binarySignalChart[signals, ImageSize -> Large]] An invalid input string is rejected, but the valid ones are drawn. An error message is printed.

With[{signals = {"11100110", "invalid", "11011011"}}, binarySignalChart[signals]]


bitsGraphicsItem::badbits: invalid does not represent a valid binary signal • Alternatives are always good in my opinion. Even as a terse code fanatic I'd like to see it. Jul 17 '14 at 12:02
• Believe me, it's about as far from your style as one can get in Mathematica ;D Jul 17 '14 at 17:43
• @m_goldberg I would like take a step further to ask, how to implement a program that can show a continuously flowing in inputs of random "0 and 1" strings. Just like the screen shown on an oscilloscope. Jul 17 '14 at 21:31
• That would be a nice feature, and it's certainly doable. Would have to give it some thought, though. Biggest challenge is keeping the left-hand labels static while the bits scroll by. I can see the use of what you ask for displaying long but given signals. However, don't see the worth of displaying random, dynamically generated bit streams. Could you explain? Jul 17 '14 at 21:55
• @m_goldberg There are much to learn in MM, the most important is to grasp the algorithms from the solutions made by the gurus, I believe. Random signals can mean anything, so it can be replaced by anything meaningful if necessary. Jul 17 '14 at 22:17

Perhaps (as per rm-rf):

str = {11011011, 11100110}
sig = {#1, #2 +
1.5} & @@ ((IntegerDigits /@ str) /. {1 -> Sequence[1, 1],
0 -> Sequence[0, 0]});
clock = Join @@ Table[{4, 3}, {Length[First@sig]/2}];
plt = ListLinePlot[Join[sig, {clock}], InterpolationOrder -> 0,
PlotRange -> {{0, 17}, Automatic},
FrameTicks -> {Thread[{Range[1.5, 15.5, 2], Range}],
Thread[{{0.5, 2, 3.5}, {str[], str[], "clock"}}], None,
None}, Frame -> True, FrameLabel -> {"Ticks", "Signals"},
ImageSize -> 500] UPDATE

As m_goldberg observes the above is an approach only for the test strings. To deal with other binary strings including starting zeros and to end on full clock cycle:

fun[str_] := Module[{dig, fs, clock, n, timd},
dig = (IntegerDigits[ToExpression@#, 10, StringLength[#]] & /@
str) /. {1 -> Sequence[1, 1], 0 -> Sequence[0, 0]};
fs = MapThread[Join[#1, {#2}] &, {dig, Last /@ dig}];
n = Length[First@dig]/2;
clock = Append[Join @@ Table[{1, 0}, {n}], 0];
timd = Join[fs, {clock}];
ListLinePlot[MapIndexed[#1 + 2 First@#2 - 2 &, timd],
InterpolationOrder -> 0, Frame -> True,
FrameTicks -> {Thread[{Range[1.5, 2 n - 0.5, 2], Range[n]}],
Thread[{Range[0.5, 2 Length@timd, 2], Join[str, {"clock"}]}],
None, None}, PlotRange -> {{0, 2 n + 2}, Automatic}]
]


This is not as nice as I would like, e.g.(i) I have not accounted for variable string lengths but this could be easily dealt with by just scaling to maximal string length or I could just truncate to shortest, or just only accept equal length...but I leave to needs/aims user (ii)have not programmed different clock rates relative to signal pulses (have just kept original).

An example:

fun[{"001101", "110111", "010101", "100101"}] Mr.Wizard here, for a bit of refactoring:

fun[str : {__String}] :=
Module[{fs, n, timd},
fs = Riffle[#, #] ~Append~ Last[#] & /@ ToExpression @ Characters @ str;
n = Length @ First @ fs;
timd = fs ~Append~ PadLeft[{0}, n, {0, 1}];

ListLinePlot[
MapIndexed[#1 + 2 First@#2 - 2 &, timd],
InterpolationOrder -> 0,
Frame -> True,
FrameTicks -> {
Thread[{Range[1.5, n - 1.5, 2], Range[n/2]}],
Thread[{Range[0.5, 2 Length@timd, 2], Join[str, {"clock"}]}],
None,
None
},
PlotRange -> {{0, n + 1}, Automatic}
]
]

• @rm-rf, ubpdqn Beautiful, Thanks a lot. Jul 14 '14 at 3:29
• @user16069 glad it was helpful... i merely applied window dressing to rm-rf 's answer...you can adapt and modify to your stylistic preferences Jul 14 '14 at 3:38
• My only problem with this answer is that won't work for cases where the signal stream starts with one or more zeros. Jul 16 '14 at 14:08
• @m_goldberg see edit Jul 17 '14 at 10:24
• @Mr.Wizard thank you very much for the improvements...I should learn to appreciate and use Riffle more..btw sorry i missed chance to help in your mma 10 quest...would have been more than happy to help Jul 17 '14 at 12:26

I'm not going to do the red lines and the numbers but here's a way to generate the coordinates of the horizontal and vertical lines that make up the graphs and to draw these:

drawGraph[str_, width_, height_] :=
Module[{values, vertical, horizontal},
values = Join[{First@#}, #, {Last@#}] &[ToExpression /@ Characters@str];
vertical = MapIndexed[
Transpose[{width {First@#2, First@#2}, height #}] &,
Partition[values, 2, 1]
];
horizontal = Partition[Rest@Flatten[vertical, 1], 2];
Graphics[{
Line[vertical],
Line[horizontal]
}, ImageSize -> 500]
]


Example:

Grid@Transpose[{
{"Clock", "11011011", "11100110"},
drawGraph[#, 1, 1] & /@ {"10101010", "11011011", "11100110"}
}] 