File Exchange Pick of the Week

Our best user submissions

Py_Addpath

Sean‘s pick this week is py_addpath directory matlab_too by Eric Fields.

Using Python with MATLAB

Do you have some Python code from a colleague or a snippet from GitHub that you’d like to use in MATLAB and not have to rewrite it? You can do that through the Python Interface for MATLAB.

A simple “hello world” example is as follows:

s = py.str("hello world") % Convert MATLAB string to py.str
whos s
sc = string(capitalize(s)) % Convert capitalized str back to MATLAB string
s = 
  Python str with no properties.

    hello world
  Name      Size            Bytes  Class     Attributes

  s         1x11                8  py.str              

sc = 
    "Hello world"

Now what if you want to call your custom Python code? Well the Python interpreter current working directory is the current MATLAB directory:

cwd = py.os.getcwd
cwd = 
  Python str with no properties.

    C:\Documents\MATLAB\potw\PyAddPath

So if your code lives here, you’re all set. However, you may (probably!) have your Python code somewhere else. So this is where this week’s submission comes in. You can use py_addpath to add another directory to the Python interpreter’s path. Optionally, it can also add the directory to the MATLAB path.

Personally, I’m no longer modifying the MATLAB path myself and using (and recommending!) Projects for anything where path or other setup needs to be configured. Because Projects afford us a “Run at Startup” option, I can have it run MATLAB code that takes care of the Python path as well using Eric’s py_addpath.

Let’s take a look at an example. NOTE: Everything we’re doing with Python here could also be done with MATLAB’s webread but we’ll pretend we’re obligated to use this Python function.

Here’s the Python function:

"""
dataLib.py imports 1-minute bars from GDAX 
built with Python 3.5 on 4/3/2018

Example: getPriceData('ETH', '2018-03-16T17:41:26Z', '2018-03-16T18:14:46Z')

To call from Python:
>>import dataLib
>>dataLib.getPriceData('ETH', '2018-03-16T17:41:26Z', '2018-03-16T18:14:46Z')

"""

def getPriceData(product, start, stop):
	import urllib.request
	import json

	# all cryptocurrency products returned in USD
	product = product + '-USD'
	
	# granularity is in seconds, so we are getting 1-minute bars
	granularity = '60'

	# returns back: [time, low, high, open, close, volume]
	url = 'https://api.pro.coinbase.com/products/' + product + '/candles?start=' + start + '&end=' + stop + '&granularity=' + granularity

	# execute call to the website
	urlRequest = urllib.request.Request(url, data=None, headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'})
	response = urllib.request.urlopen(urlRequest)
	html = response.read()

	# python 3.x requires decoding from bytes to string 
	jsonData = json.loads(html.decode())
	return jsonData

###########################################################################################	
	
def parseJson(json_data):
	from array import array

	# return back time and close data
	dates = [row[0] for row in json_data]
	data = [row[4] for row in json_data]

	# convert to 1D array 
	dateArray = array('d')
	dataArray = array('d')
	dateArray.fromlist(dates)
	dataArray.fromlist(data)
	
	# wrap both time series in a dictionary
	closeTimeSeries = {'Date': dateArray, 'Close': dataArray}
	return closeTimeSeries

And here’s the function I would add to the project startup to add the Python folder at project startup.

function addPythonDataLib()
prj = currentProject;
py_addpath(fullfile(prj.RootFolder, 'Python'));
end

Now after opening the project, we can use the dataLib.py functionality.

% Query for Ethereum prices
startDate = '2018-03-16T12:00:00Z';
stopDate = '2018-03-16T17:00:00Z';
jsonData = py.dataLib.getPriceData('ETH', startDate, stopDate);
data = py.dataLib.parseJson(jsonData);

% Convert to MATLAB Data Types
data = struct(data);
data.Date = double(data.Date)';
data.Date = datetime(data.Date, 'ConvertFrom', 'posixtime', 'TimeZone', 'America/New_York');
data.Close = double(data.Close)';
data = table2timetable(struct2table(data));
disp(head(data))
stackedplot(data);
            Date            Close 
    ____________________    ______
    16-Mar-2018 13:00:00     621.1
    16-Mar-2018 12:59:00     621.1
    16-Mar-2018 12:58:00     621.1
    16-Mar-2018 12:57:00    621.09
    16-Mar-2018 12:56:00    621.09
    16-Mar-2018 12:55:00    621.09
    16-Mar-2018 12:54:00    621.06
    16-Mar-2018 12:53:00    621.87

One suggestion for Eric, is that the function could use convertStringsToChars to allow for MATLAB string inputs to be passed in as well without needing to change any algorithmic parts. I.e.

directory = convertStringsToChars(directory);

Comments

Give it a try and let us know what you think here or leave a comment for Eric.

Published with MATLAB® R2019b

|

Comments

To leave a comment, please click here to sign in to your MathWorks Account or create a new one.