Display Streamed Data in Figure Window - MATLAB & Simulink (original) (raw)
Main Content
This example shows how to customize an HTTP StringConsumer class—PricesStreamer
—to display streamed data from a hypothetical website in a MATLAB® figure window. To create a working example:
- Identify a URL, similar to:
url = matlab.net.URI('','accountId',,'',''); - Modify
PricesStreamer.putData
to read data specific to your web service
The following tasks are described in this topic. For information about displaying table data in a figure window, see uitable.
- PricesStreamer Class
- Map Data to MATLAB uitable Object
- Display Data in JSON Format
- Terminate Data Stream
- Call PricesStreamer
PricesStreamer
Class
PricesStreamer.m
is a subclass of theStringConsumer
class, which is a subclass ofContentConsumer
. PricesStreamer
receives streamed data customized to the data provided by a specific web service. In this example, the structure of the data is:
% Data contains one or more CRLF-separated JSON structures.
% Each structure is one of the format:
% {"heartbeat"="timestamp"}
% {"tick"="timestamp", "bid"=bid, "ask"=ask}
% where timestamp is a GMT time and bid and ask are numbers.
MATLAB calls the PricesStreamer.putData
function for each chunk of data received from the server. The function first converts the rawuint8
bytes to a JSON string usingStringConsumer
. Next, it gets a MATLAB structure from the JSON string using jsondecode
and then displays the data in a table in a figure, adding one line to the top of the table for each increment of data. You can modify the putData
function to do something else with the data, for example, plot a real-time graph or display delta prices. PricesStreamer
sets thestop
return value to stop the operation when the user closes the figure. For more information, see putData.
classdef PricesStreamer < matlab.net.http.io.StringConsumer % PricesStreamer accepts streamed JSON % and displays the result in a uitable in a figure window.
% Copyright 2016-2017 The MathWorks, Inc.
properties
Figure
Table
Endit logical
HaveTick logical
end
methods (Access=protected)
function length = start(obj)
if obj.Response.StatusCode ~= matlab.net.http.StatusCode.OK
length = 0;
else
length = obj.start@matlab.net.http.io.StringConsumer;
obj.Figure = figure('CloseRequestFcn',@obj.endit);
obj.Figure.Position(4) = 550;
obj.Figure.Position(2) = 50;
obj.Table = uitable(obj.Figure,...
'ColumnName',{'Time','Bid','Ask'},...
'ColumnWidth',{130,'auto','auto'});
obj.Table.Position(4) = 500;
obj.Table.Data = cell(0,3);
obj.Endit = false;
obj.HaveTick = false;
end
end
end
methods
function [len,stop] = putData(obj, data)
% Data contains one or more CRLF-separated JSON structures.
% Each structure is one of the format:
% {"heartbeat"="timestamp"}
% {"tick"="timestamp", "bid"=bid, "ask"=ask}
% where timestamp is a GMT time and bid and ask are numbers.
if obj.Endit
data = [];
delete(obj.Figure);
end
first = obj.CurrentLength + 1;
[len,stop] = obj.putData@matlab.net.http.io.StringConsumer(data);
if isempty(data) || stop
if ischar(data) % data == '' means user ctrl/c'ed, so set to
obj.Endit = true; % delete figure on next close
end
stop = true;
else
stop = false;
last = obj.CurrentLength;
newData = obj.Response.Body.Data.extractBetween(first,last);
% split at CRLFs
strings = strsplit(newData, '\r\n');
try
cellfun(@obj.displayJSON, strings);
catch e
fprintf('Error on JSON:\n%s<EOF>\n',data);
obj.Endit = true;
rethrow(e);
end
end
end
function displayJSON(obj, str)
if ~isempty(str)
try
val = jsondecode(str);
catch e
fprintf('Error "%s" on JSON:\n%s<EOF>\n',e.message,str);
rethrow(e);
end
if isfield(val,'tick')
tick = val.tick;
newdata = {cvtime(val.tick.time),tick.bid,tick.ask};
setExtent = ~obj.HaveTick;
obj.HaveTick = true;
elseif isfield(val, 'heartbeat')
newdata = {cvtime(val.heartbeat.time),'',''};
setExtent = false;
end
obj.Table.Data = [newdata;obj.Table.Data];
if setExtent || ~mod(log10(length(obj.Table.Data)),1)
% set extent on first tick and every power of 10
% add 15 for width of scroll bar
obj.Table.Position(3) = obj.Table.Extent(3) + 15;
end
drawnow
end
end
function endit(obj,~,~)
% endit callback from close(obj.Figure)
if exist('obj','var') && isvalid(obj)
if obj.Endit
if isvalid(obj.Figure)
delete(obj.Figure);
end
else
obj.Endit = true;
end
end
end
function delete(obj)
if ~isempty(obj.Figure) && isvalid(obj.Figure)
delete(obj.Figure);
end
end
end
end
function time = cvtime(time) % Format time data for display time = datetime(time,'InputFormat','yyyy-MM-dd''T''HH:mm:ss.S''Z''','TimeZone','GMT'); time.TimeZone = 'local'; time = char(time, 'dd-MMM-yyyy HH:mm:ss.S'); end
Map Data to MATLAB uitable
Object
Identify the data structures for your use case by reading API information from the web service. The data for this example contains one or more CRLF-separated JSON structures. The format for the structures is one of the following, wheretimestamp
is a GMT time and bid
andask
are numbers.
{"heartbeat"="timestamp"}
{"tick"="timestamp", "bid"=bid, "ask"=ask}
To read this specific format, override the putData method. The following statements from thePricesStreamer
class useStringConsumer.putData
to read the next buffer, then select the JSON strings.
first = obj.CurrentLength + 1; [len,stop] = obj.putData@matlab.net.http.io.StringConsumer(data); last = obj.CurrentLength; newData = obj.Response.Body.Data.extractBetween(first,last); % split at CRLFs strings = strsplit(newData, '\r\n');
Display Data in JSON Format
The following statements from the displayJSON
function individually handle the JSON tick
andheartbeat
structures. A helper functioncvtime
formats the time data for display in the table.
function displayJSON(obj, str) ... val = jsondecode(str); if isfield(val,'tick') tick = val.tick; newdata = {cvtime(val.tick.time),tick.bid,tick.ask}; ... elseif isfield(val, 'heartbeat') newdata = {cvtime(val.heartbeat.time),'',''}; ... end obj.Table.Data = [newdata;obj.Table.Data]; ... end
Terminate Data Stream
In this example, MATLAB receives data as long as the web service is active. The user can terminate the stream by closing the figure window or by pressingCtrl+C. To inform MATLAB of a user interruption, set the stop
argument inputData
to false
. Clean-up tasks include closing the figure using the CloseRequestFcn
property and deleting the object using the PricesStreamer.delete
function.
Call PricesStreamer
The following code provides a framework for retrieving data from a web service. To run the code, you must provide values for content within <>
characters. The URL for your web service might include additional parameters, such as login information and other information specified as name, value pair arguments. To utilize the PricesStreamer
, add it to your call to send. For information about creating request messages, see Call Web Services from MATLAB Using HTTP.
url = matlab.net.URI('','accountId',,'',''); authInfo = matlab.net.http.AuthInfo(matlab.net.http.AuthenticationScheme.Bearer,... 'Encoded',''); af = matlab.net.http.field.AuthorizationField('Authorization',authInfo); r = matlab.net.http.RequestMessage('get',af); consumer = PricesStreamer; % SavePayload set to retain all results - useful for debugging [resp,req,hist] = r.send(url,matlab.net.http.HTTPOptions('SavePayload',true),consumer); % Show the results for debugging show(resp)
The following is an example of data from a web service sending data described inMap Data to MATLAB uitable Object.
HTTP/1.1 200 Ok Server: openresty/1.9.15.1 Date: Wed, 06 Sep 2017 19:26:56 GMT Content-Type: application/json Transfer-Encoding: chunked Connection: close Access-Control-Allow-Origin: *
{"tick":{"instrument":"AUD_CAD","time":"2017-09-06T19:26:54.304054Z","bid":0.97679,"ask":0.97703}} {"heartbeat":{"time":"2017-09-06T19:26:56.253091Z"}} {"tick":{"instrument":"AUD_CAD","time":"2017-09-06T19:26:57.226918Z","bid":0.97678,"ask":0.97703}} {"tick":{"instrument":"AUD_CAD","time":"2017-09-06T19:26:58.226909Z","bid":0.97678,"ask":0.97705}} {"heartbeat":{"time":"2017-09-06T19:26:58.720409Z"}} {"tick":{"instrument":"AUD_CAD","time":"2017-09-06T19:27:00.733194Z","bid":0.97679,"ask":0.97704}} {"heartbeat":{"time":"2017-09-06T19:27:01.251202Z"}} {"tick":{"instrument":"AUD_CAD","time":"2017-09-06T19:27:01.757501Z","bid":0.9768,"ask":0.97706}} {"heartbeat":{"time":"2017-09-06T19:27:03.720469Z"}}