Display Streamed Data in Figure Window
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('<URL>','accountId',<YOUR_ACCOUNT_ID>,'<NAME>','<VALUE>'); 
- Modify - PricesStreamer.putDatato 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
PricesStreamer.m is a subclass of the
                    StringConsumer class, which is a subclass of
                    ContentConsumer. 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 raw
                    uint8 bytes to a JSON string using
                    StringConsumer. 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 the
                    stop 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, where
                    timestamp is a GMT time and bid and
                    ask are numbers.
- {"heartbeat"="timestamp"}
- {"tick"="timestamp", "bid"=bid, "ask"=ask}
To read this specific format, override the putData method. The following statements from the
                    PricesStreamer class use
                    StringConsumer.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 and
                    heartbeat structures. A helper function
                    cvtime 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 pressing
                    Ctrl+C. To inform MATLAB of a user interruption, set the stop argument in
                    putData 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('<URL>','accountId',<YOUR_ACCOUNT_ID>,'<NAME>','<VALUE>'); authInfo = matlab.net.http.AuthInfo(matlab.net.http.AuthenticationScheme.Bearer,... 'Encoded','<YOUR_CREDENTIALS>'); 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 in Map 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"}}