Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
98 - 1
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
2
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /><title>4.9. Streaming Plots</title><link rel="stylesheet" type="text/css" href="phplotdoc.css" /><meta name="generator" content="DocBook XSL Stylesheets V1.78.1" /><link rel="home" href="index.html" title="PHPlot Reference Manual" /><link rel="up" href="advanced.html" title="Chapter 4. PHPlot Advanced Topics" /><link rel="prev" href="adv-multiplot.html" title="4.8. Multiple Plots Per Image" /><link rel="next" href="adv-imgmap.html" title="4.10. Image Maps for Plot Data" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4.9. Streaming Plots</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="adv-multiplot.html">Prev</a> </td><th width="60%" align="center">Chapter 4. PHPlot Advanced Topics</th><td width="20%" align="right"> <a accesskey="n" href="adv-imgmap.html">Next</a></td></tr></table><hr /></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="adv-streaming"></a>4.9. Streaming Plots</h2></div></div></div><div class="abstract"><p class="title"><strong></strong></p><p>
3
This section contains information about producing streaming plots.
4
The end of this section contains a complete example.
5
  </p></div><p>
6
A script can use PHPlot to produce a series of plots that are streamed to a
7
browser or other viewing application. The result is a movie, or video,
8
consisting of a plot with changing data. This might be used to display
9
real-time data, to replay historical data, or for graphical display of
10
any data where adding a time dimension improves the presentation.
11
This feature was added in PHPlot-5.8.0.
12
</p><p>
13
This feature is intended for use when you want to update a plot one or more
14
times per second. If instead you want each plot to be displayed for one or
15
more seconds, consider using a refreshing page instead, for example
16
using using a "Refresh" meta-tag.
17
</p><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Warning</h3><p>
18
Producing streaming plots will place a significant load on your server.
19
See <a class="xref" href="adv-streaming.html#adv-streaming-performance" title="4.9.2. Streaming Plots - Performance Considerations">Section 4.9.2, &#8220;Streaming Plots - Performance Considerations&#8221;</a> below for more information.
20
  </p></div><p>
21
PHPlot produces streaming plots using
22
<a class="ulink" href="http://en.wikipedia.org/wiki/Motion_Jpeg" target="_top">Motion JPEG</a>
23
(M-JPEG), specifically Streaming M-JPEG over HTTP.
24
This method (which is not a standard) sends a series of JPEG images,
25
with appropriate MIME headers, in a stream to the browser or viewer.
26
PHPlot produces each plot as usual, and sends it out as part of the stream.
27
Your script is responsible for changing the data (or other plot
28
elements) between frames, and for the overall frame timing.
29
</p><p>
30
Browsers and viewers which have been found to be capable of displaying
31
a Motion-JPEG Stream over HTTP include recent versions of:
32
  </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>Mozilla Firefox</p></li><li class="listitem"><p>Mozilla Seamonkey</p></li><li class="listitem"><p>VLC Media Player</p></li></ul></div><p>
33
Note: Microsoft Internet Explorer is <span class="emphasis"><em>not</em></span> able to
34
display these streams without an add-on.
35
Google Chrome and Apple Safari are reported to be capable of displaying these
36
streams, but they have not been tested with PHPlot.
37
</p><p>
38
Although only JPEG images are used in this section, the same method
39
works in theory for other image types such as PNG, and PHPlot does not
40
force the use of JPEG with streaming plots.  Mozilla Firefox and
41
Seamonkey have been found to be able to display "Motion-PNG" streams - a
42
sequence of PNG images using the same MIME structure as Motion-JPEG.
43
(VLC Media Player cannot display them.) Since plot images using JPEG
44
compression are of poorer quality than PNG images, you might want to
45
consider using another format such as PNG, however compatibility with
46
viewers is a bigger issue than with JPEG.
47
</p><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="adv-streaming-using"></a>4.9.1. Streaming Plots - Creating Moving Plots</h3></div></div></div><p>
48
There are generally 3 parts to a script that produces streaming plots:
49
  </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
50
Creating a PHPlot object, and configuring your plot. This is the same as
51
for single image plots.
52
      </p></li><li class="listitem"><p>
53
You will need an incremental way to produce data for the plot. Typically,
54
it will produce one new row of a PHPlot data array for each plot frame.
55
      </p></li><li class="listitem"><p>
56
Your script will have a loop that produces frames and includes frame timing.
57
(If your data is produced at fixed intervals, your loop may not need any
58
additional timing.) You may choose to produce a fixed number of frames (or
59
equivalently, run for a fixed length of time), or run forever. The user can
60
always end the stream by stopping their browser or viewer, and the script
61
will terminate on the server.
62
      </p></li></ol></div><p>
63
</p><p>
64
You will use these PHPlot functions to produce streaming plots, in addition
65
to the functions used for static plots.
66
  </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
67
Use <a class="xref" href="SetPrintImage.html" title="SetPrintImage"><span class="refentrytitle">SetPrintImage</span></a>(False) to disable automatic printing
68
from <a class="xref" href="DrawGraph.html" title="DrawGraph"><span class="refentrytitle">DrawGraph</span></a>.
69
      </p></li><li class="listitem"><p>
70
Use <a class="xref" href="SetFileFormat.html" title="SetFileFormat"><span class="refentrytitle">SetFileFormat</span></a>('jpg') to select JPEG format. This is
71
the only format that is 'legal' with Motion-JPEG Streaming, although other
72
formats work with some browsers.
73
      </p></li><li class="listitem"><p>
74
Call <a class="xref" href="StartStream.html" title="StartStream"><span class="refentrytitle">StartStream</span></a> outside your main loop to begin the plot
75
stream.
76
      </p></li><li class="listitem"><p>
77
Within your main loop, use <a class="xref" href="SetDataValues.html" title="SetDataValues"><span class="refentrytitle">SetDataValues</span></a> to reload the
78
data array after addition the new row(s). This is necessary because PHPlot
79
creates a copy (rather than a reference) of your data.
80
      </p></li><li class="listitem"><p>
81
Use <a class="xref" href="DrawGraph.html" title="DrawGraph"><span class="refentrytitle">DrawGraph</span></a> to produce the plot (but not output it).
82
      </p></li><li class="listitem"><p>
83
Still within your main loop, use <a class="xref" href="PrintImageFrame.html" title="PrintImageFrame"><span class="refentrytitle">PrintImageFrame</span></a> to
84
output the plot as a single frame within the plot stream.
85
      </p></li><li class="listitem"><p>
86
If your plot stream ends at some point (rather than running until stopped
87
by the user), call <a class="xref" href="EndStream.html" title="EndStream"><span class="refentrytitle">EndStream</span></a> to cleanly end the plot stream.
88
      </p></li></ul></div><p>
89
</p><p>
90
Your PHP script should be referenced from an HTML page using an
91
<code class="literal">&lt;img&gt;</code> tag, just like when creating a single plot.
92
The MIME type returned by PHPlot (<code class="literal">multipart/x-mixed-replace</code>
93
rather than <code class="literal">image/jpeg</code> for example) tells the browser or
94
viewer to expect a stream rather than a single image.
95
</p><p>
96
Be aware that PHP is usually configured to time out scripts that run too
97
long, and will terminate your streaming plot script. To prevent this, use
98
the PHP function <code class="literal">set_time_limit($seconds)</code>. If you know
99
the total number of frames and frame rate, you can set the timeout to a bit
100
more than the total expected runtime.
101
Alternatively, you can call <code class="function">set_time_limit</code> within
102
your main loop, so it is called when each frame is produced. Because this
103
function resets the PHP timer, your script will not time out and can
104
produce frames forever.
105
</p><p>
106
For frame timing, you can use the PHP functions <code class="function">microtime()</code>
107
and <code class="function">time_sleep_until()</code>.
108
Call <code class="literal">microtime(TRUE)</code> once, to get a
109
precise timestamp as a floating point number. Then, within your main loop,
110
use <code class="literal">time_sleep_until($timestamp)</code> to put your script to
111
sleep until the time to start of the next frame.
112
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
113
Be sure your PHP script does not leak memory during the loop that produces
114
frames, especially if the script is designed to runs until stopped (rather
115
than producing a fixed number of frames). Appending to an array inside the
116
loop is an example of something to avoid.
117
  </p></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="adv-streaming-performance"></a>4.9.2. Streaming Plots - Performance Considerations</h3></div></div></div><p>
118
This section discusses performance considerations for streaming plots,
119
starting with some definitions.
120
  </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">Frame Rate</span></dt><dd><p>
121
The number of plots (frames) produced per second.
122
        </p></dd><dt><span class="term">Frame Time</span></dt><dd><p>
123
The total time per frame, equal to the reciprocal of the frame rate.
124
        </p></dd><dt><span class="term">Plot Time, Output Time, Idle Time</span></dt><dd><p>
125
These are the 3 parts of the Frame Time. The Plot Time is the time it takes
126
to prepare your data for each frame and draw the plot graphics. The Output
127
Time is the time to send the completed plot to the browser or viewer.
128
Idle time is when your script is sleeping, waiting for the next frame's time
129
interval.
130
        </p></dd><dt><span class="term">Frame Slippage, Missed Frames</span></dt><dd><p>
131
If your script and processor cannot keep up with the plot stream requirements,
132
the idle time will drop to zero. Frame slippage is when the frame time exceeds
133
the desired goal, so the frame rate drops (but no frames are lost).
134
A different approach is to enforce the frame time and drop frames to catch
135
up, resulting in missed frames.
136
        </p></dd></dl></div><p>
137
</p><p>
138
To produce a good plot stream, your script and server must be able to
139
consistently produce and output frames at the desired rate.
140
The frame rate you want will depend on your data and application, while the
141
rate you can achieve depends on the complexity of your script and your
142
available processing power. Although typical video runs at between 24 and
143
60 frames per second, those rates are likely too fast to be useful with plot
144
data.
145
A more realistic starting point for streaming plots is 10 frames per second.
146
This will provide the appearance of continuous motion of the graph(s),
147
but without too much blurring of the data.
148
</p><p>
149
Here are some real performance numbers, using a relatively simple plot, and
150
hardware that is old but was considered high performance when introduced
151
several year ago (circa 2007).
152
With a PHPlot script producing 10 frames per second, the Apache server
153
process was found to be using about 24% of one processor core's available
154
CPU time. (Keep in mind that this is not a short-term load, but means 24%
155
for the duration of the plot stream.) On the same hardware, 15 frames per
156
second used 35% CPU time, and 30 frames per second used 70% CPU time (of
157
one core).
158
</p><p>
159
You can measure the performance of your script with a small change, if you
160
are using a main loop like the one shown in the full example in the next
161
section (repeated briefly here).
162
  </p><pre class="programlisting">$timestamp = microtime(TRUE);
163
$frame_time = 1 / $frame_rate;
164
$slip = 0; // Number of slipped frames
165
$frame = 0; // Current frame number
166
while(1) {
167
    $frame++;
168
    ...
169
    $plot-&gt;DrawGraph();
170
    $plot-&gt;PrintImageFrame();
171
    if (!@time_sleep_until($timestamp += $frame_time)) $slip++;
172
}</pre><p>
173
The PHP function <code class="function">time_sleep_until()</code> returns FALSE if the
174
desired time already passed. (We use @ to suppress the message which would
175
be logged in that case.) The variable $slip counts the number of slipped
176
frames.
177
The ratio of $slip to $frame should be as low as possible, ideally zero.
178
If <code class="literal">($slip/$frame)</code> gets too high, you may need to use a
179
lower frame rate, because either your frame rate is too high, your plot is
180
too complex, or your server is too slow to keep up.
181
However, optimizing your plot may help.
182
</p><p>
183
To optimize performance of your streaming plot, you should avoid these more
184
expensive features:
185
  </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
186
Plots that use area fills are slower. This especially includes pie charts
187
with shading (because PHPlot redraws the filled pie segments for each
188
level of shading). Area plots and similar types have a lot of area fill.
189
Bar charts have some area fill, with shaded bar charts having more shading
190
(but not nearly as much as shaded pie charts).
191
The fastest plot types are line plots.
192
      </p></li><li class="listitem"><p>
193
TrueType fonts are slower than GD fonts. Consider using text in the HTML
194
page containing the image reference, rather than in the image itself.
195
      </p></li><li class="listitem"><p>
196
Some operations on truecolor images are slow (for example, gamma adjustment
197
or anti-aliasing) and should be avoided.
198
      </p></li><li class="listitem"><p>
199
Avoid using a background image, especially one which needs to be scaled.
200
      </p></li><li class="listitem"><p>
201
Avoid external factors that can affect performance. An obvious example is
202
database access, since a database server can take a variable amount of time
203
to respond to a query.
204
      </p></li></ul></div><p>
205
</p><p>
206
Note that PHPlot redraws the complete plot image for each frame, regardless
207
of which functions are used inside or outside your loop. For example, if
208
you use <a class="xref" href="SetTitle.html" title="SetTitle"><span class="refentrytitle">SetTitle</span></a> to set title text outside the frame loop,
209
the same title will be drawn into each frame. If it is inside the loop,
210
you can change the text for each frame. Either way, the time to draw the title
211
counts for each frame. The same is true for legend, labels, etc.
212
Although you should keep invariant PHPlot "Set...()" function calls outside
213
your frame loop, this does not significantly affect the performance.
214
</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="adv-streaming-example"></a>4.9.3. Streaming Plots - Example</h3></div></div></div><p>
215
This is a complete example that produces a streaming plot sequence showing
216
sin() and cos(). The frame rate and run time are set with variables at the
217
top.
218
</p><p>
219
  </p><pre class="programlisting">&lt;?php
220
# Example of Streaming Plots with PHPlot
221
# This simply plots sin(x) and cos(x), updating at the rate given below.
222
# Replace the function next_row() to plot something else.
223
# This must run using a web server, not CLI.
224
 
225
require_once 'phplot.php';
226
 
227
# Configuration:
228
# This is the fixed number of points along the X axis:
229
$n_rows = 40;
230
# Data range for Y:
231
$max_y = 1;
232
$min_y = -1;
233
# Frames per second:
234
$frame_rate = 10;
235
# Total runtime in seconds. Use 0 to run 'forever':
236
$run_for = 0;
237
 
238
# Derived:
239
$run_forever = $run_for == 0;
240
$frame_time = 1 / $frame_rate;
241
$n_frames = $frame_rate * $run_for;
242
 
243
# Return the next data row (per PHPlot text-data data type):
244
function next_row($x)
245
{
246
    global $frame_rate;
247
    # Map 8 seconds of frames into 360 degrees (360/8 = 45 degrees/second)
248
    $theta = deg2rad(45 * $x / $frame_rate);
249
    return array('', sin($theta), cos($theta));
250
}
251
 
252
# Create an initial data array with no values. New values will be
253
# shifted in to the end. This is text-data format; the X values
254
# are implicit and ignored (not plotted).
255
for ($i = 0; $i &lt; $n_rows; $i++) $data[$i] = array('', '', '');
256
 
257
# Create and configure the PHPlot object:
258
$plot = new PHPlot(640, 480);
259
$plot-&gt;SetDataType('text-data');
260
$plot-&gt;SetPlotType('lines');
261
$plot-&gt;SetFileFormat('jpg');
262
$plot-&gt;SetXTickLabelPos('none');
263
$plot-&gt;SetXTickPos('none');
264
$plot-&gt;SetXDataLabelPos('none');
265
# Don't draw the initial, empty values:
266
$plot-&gt;SetDrawBrokenLines(True);
267
# Force the Y range, or it will use the first frame to calculate:
268
$plot-&gt;SetPlotAreaWorld(NULL, $min_y, NULL, $max_y);
269
$plot-&gt;SetPrintImage(False);
270
 
271
# Main loop:
272
$plot-&gt;StartStream();
273
$timestamp = microtime(TRUE);
274
for ($frame = 0; $run_forever || $frame &lt; $n_frames; $frame++) {
275
    # Set PHP timeout so it won't terminate the script early.
276
    set_time_limit(60);
277
    # Discard the oldest data row, and shift in the new row:
278
    array_shift($data);
279
    $data[] = next_row($frame);
280
    # Set a plot title that includes the frame number:
281
    $plot-&gt;SetTitle(sprintf("Moving Plot Test (Frame %4d)", $frame));
282
    # Reload the data array:
283
    $plot-&gt;SetDataValues($data);
284
    # Draw and output the plot:
285
    $plot-&gt;DrawGraph();
286
    $plot-&gt;PrintImageFrame();
287
    # Sleep until it is time to start the next frame:
288
    time_sleep_until($timestamp += $frame_time);
289
}
290
# End the stream:
291
$plot-&gt;EndStream();
292
</pre><p>
293
</p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="adv-multiplot.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="advanced.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="adv-imgmap.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4.8. Multiple Plots Per Image </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 4.10. Image Maps for Plot Data</td></tr></table></div></body></html>