├── AirQual ├── for_testing │ ├── includedSupportPackages.txt │ ├── unresolvedSymbols.txt │ ├── matlabruntimeforpython.egg-info │ │ ├── dependency_links.txt │ │ ├── top_level.txt │ │ ├── PKG-INFO │ │ └── SOURCES.txt │ ├── requiredMCRProducts.txt │ ├── AirQual │ │ ├── AirQual.ctf │ │ └── __init__.py │ ├── mccExcludedFiles.log │ ├── setup.py │ └── readme.txt ├── for_redistribution │ └── MyAppInstaller_web.exe ├── for_redistribution_files_only │ ├── AirQual │ │ ├── AirQual.ctf │ │ └── __init__.py │ ├── setup.py │ └── GettingStarted.html └── PackagingLog.html ├── cities.mat ├── airQualModel.mat ├── CallPythonFromMATLAB.mlx ├── README.md ├── predictAirQual.m ├── prepData.m ├── CallMATLABCompiledLibraryFromPython.ipynb ├── weather.py ├── AirQual.prj └── CallMATLABfromPython.ipynb /AirQual/for_testing/includedSupportPackages.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AirQual/for_testing/unresolvedSymbols.txt: -------------------------------------------------------------------------------- 1 | Path Symbol Reason 2 | -------------------------------------------------------------------------------- /AirQual/for_testing/matlabruntimeforpython.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /AirQual/for_testing/matlabruntimeforpython.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | AirQual 2 | -------------------------------------------------------------------------------- /cities.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hgorr/weather-matlab-python/HEAD/cities.mat -------------------------------------------------------------------------------- /airQualModel.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hgorr/weather-matlab-python/HEAD/airQualModel.mat -------------------------------------------------------------------------------- /AirQual/for_testing/requiredMCRProducts.txt: -------------------------------------------------------------------------------- 1 | 35000 35003 35010 35103 35104 35106 35119 35180 35274 35055 -------------------------------------------------------------------------------- /CallPythonFromMATLAB.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hgorr/weather-matlab-python/HEAD/CallPythonFromMATLAB.mlx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # weather-matlab-python 2 | Example illustrating coexecution between MATLAB and Python for a weather prediction app 3 | -------------------------------------------------------------------------------- /AirQual/for_testing/AirQual/AirQual.ctf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hgorr/weather-matlab-python/HEAD/AirQual/for_testing/AirQual/AirQual.ctf -------------------------------------------------------------------------------- /AirQual/for_testing/mccExcludedFiles.log: -------------------------------------------------------------------------------- 1 | The List of Excluded Files 2 | Excluded files Exclusion Message ID Reason For Exclusion Exclusion Rule 3 | -------------------------------------------------------------------------------- /AirQual/for_redistribution/MyAppInstaller_web.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hgorr/weather-matlab-python/HEAD/AirQual/for_redistribution/MyAppInstaller_web.exe -------------------------------------------------------------------------------- /AirQual/for_redistribution_files_only/AirQual/AirQual.ctf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hgorr/weather-matlab-python/HEAD/AirQual/for_redistribution_files_only/AirQual/AirQual.ctf -------------------------------------------------------------------------------- /AirQual/for_testing/matlabruntimeforpython.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: matlabruntimeforpython 3 | Version: R2022a 4 | Summary: A module to call MATLAB from Python 5 | Home-page: https://www.mathworks.com/ 6 | Author: MathWorks 7 | License: UNKNOWN 8 | Platform: Linux 9 | Platform: Windows 10 | Platform: MacOS 11 | 12 | UNKNOWN 13 | 14 | -------------------------------------------------------------------------------- /AirQual/for_testing/matlabruntimeforpython.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | setup.py 2 | AirQual/AirQual.ctf 3 | AirQual/__init__.py 4 | matlabruntimeforpython.egg-info/.MATLABDriveTag 5 | matlabruntimeforpython.egg-info/PKG-INFO 6 | matlabruntimeforpython.egg-info/SOURCES.txt 7 | matlabruntimeforpython.egg-info/dependency_links.txt 8 | matlabruntimeforpython.egg-info/top_level.txt 9 | predictAirQual/__init__.py 10 | predictAirQual/predictAirQual.ctf -------------------------------------------------------------------------------- /predictAirQual.m: -------------------------------------------------------------------------------- 1 | function airQual = predictAirQual(data) 2 | % PREDICTAIRQUAL Predict air quality, based on machine learning model 3 | % 4 | %#function CompactClassificationEnsemble 5 | 6 | % Convert data types 7 | currentData = prepData(data); 8 | 9 | % Load model 10 | mdl = load("airQualModel.mat"); 11 | model = mdl.model; 12 | 13 | % Determine air quality 14 | airQual = predict(model,currentData); 15 | 16 | % Convert data type for use in Python 17 | airQual = char(airQual); 18 | 19 | end 20 | 21 | -------------------------------------------------------------------------------- /AirQual/PackagingLog.html: -------------------------------------------------------------------------------- 1 |
2 | mcc -W python:AirQual -T link:lib -d 'C:\Users\ydebray\MATLAB Drive\PythonMunichWebinar\AirQual\for_testing' -v 'C:\Users\ydebray\MATLAB Drive\PythonMunichWebinar\predictAirQual.m' 3 | Compiler version: 8.4 (R2022a) 4 | 5 | Analyzing file dependencies. 6 | 7 | Parsing file "C:\Users\ydebray\MATLAB Drive\PythonMunichWebinar\predictAirQual.m" 8 | (referenced from command line). 9 | Generating file "C:\Users\ydebray\MATLAB Drive\PythonMunichWebinar\AirQual\for_testing\AirQual\__init__.py". 10 | Generating file "C:\Users\ydebray\MATLAB Drive\PythonMunichWebinar\AirQual\for_testing\setup.py". 11 | Generating file "C:\Users\ydebray\MATLAB Drive\PythonMunichWebinar\AirQual\for_testing\readme.txt". 12 | Packaging... 13 | Creating the bundle... 14 | Creating the install agent URL file... 15 | Web based installer created at C:\Users\ydebray\MATLAB Drive\PythonMunichWebinar\AirQual\for_redistribution\MyAppInstaller_web.exe. 16 | Packaging complete. 17 | Elapsed packaging time was: 8 seconds. 18 |19 | -------------------------------------------------------------------------------- /AirQual/for_testing/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015-2018 The MathWorks, Inc. 2 | 3 | from distutils.core import setup 4 | from distutils.command.clean import clean 5 | from distutils.command.install import install 6 | 7 | class InstallRuntime(install): 8 | # Calls the default run command, then deletes the build area 9 | # (equivalent to "setup clean --all"). 10 | def run(self): 11 | install.run(self) 12 | c = clean(self.distribution) 13 | c.all = True 14 | c.finalize_options() 15 | c.run() 16 | 17 | if __name__ == '__main__': 18 | 19 | setup( 20 | name="matlabruntimeforpython", 21 | version="R2022a", 22 | description='A module to call MATLAB from Python', 23 | author='MathWorks', 24 | url='https://www.mathworks.com/', 25 | platforms=['Linux', 'Windows', 'MacOS'], 26 | packages=[ 27 | 'AirQual' 28 | ], 29 | package_data={'AirQual': ['*.ctf']}, 30 | # Executes the custom code above in order to delete the build area. 31 | cmdclass={'install': InstallRuntime} 32 | ) 33 | 34 | 35 | -------------------------------------------------------------------------------- /AirQual/for_redistribution_files_only/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015-2018 The MathWorks, Inc. 2 | 3 | from distutils.core import setup 4 | from distutils.command.clean import clean 5 | from distutils.command.install import install 6 | 7 | class InstallRuntime(install): 8 | # Calls the default run command, then deletes the build area 9 | # (equivalent to "setup clean --all"). 10 | def run(self): 11 | install.run(self) 12 | c = clean(self.distribution) 13 | c.all = True 14 | c.finalize_options() 15 | c.run() 16 | 17 | if __name__ == '__main__': 18 | 19 | setup( 20 | name="matlabruntimeforpython", 21 | version="R2022a", 22 | description='A module to call MATLAB from Python', 23 | author='MathWorks', 24 | url='https://www.mathworks.com/', 25 | platforms=['Linux', 'Windows', 'MacOS'], 26 | packages=[ 27 | 'AirQual' 28 | ], 29 | package_data={'AirQual': ['*.ctf']}, 30 | # Executes the custom code above in order to delete the build area. 31 | cmdclass={'install': InstallRuntime} 32 | ) 33 | 34 | 35 | -------------------------------------------------------------------------------- /AirQual/for_testing/readme.txt: -------------------------------------------------------------------------------- 1 | AirQual MATLAB Python Package 2 | 3 | 1. Prerequisites for Deployment 4 | 5 | Verify that version 9.12 (R2022a) of the MATLAB Runtime is installed. 6 | If not, you can run the MATLAB Runtime installer. 7 | To find its location, enter 8 | 9 | >>mcrinstaller 10 | 11 | at the MATLAB prompt. 12 | NOTE: You will need administrator rights to run the MATLAB Runtime installer. 13 | 14 | Alternatively, download and install the Windows version of the MATLAB Runtime for R2022a 15 | from the following link on the MathWorks website: 16 | 17 | https://www.mathworks.com/products/compiler/mcr/index.html 18 | 19 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see 20 | "Distribute Applications" in the MATLAB Compiler SDK documentation 21 | in the MathWorks Documentation Center. 22 | 23 | Verify that a Windows version of Python 2.7, 3.8, and/or 3.9 is installed. 24 | 25 | 2. Installing the AirQual Package 26 | 27 | A. Change to the directory that contains the file setup.py and the subdirectory AirQual. 28 | If you do not have write permissions, copy all its contents to a temporary location and 29 | change to that directory. 30 | 31 | B. Execute the command: 32 | 33 | python setup.py install [options] 34 | 35 | If you have full administrator privileges, and install to the default location, you do 36 | not need to specify any options. Otherwise, use --user to install to your home folder, or 37 | --prefix="installdir" to install to "installdir". In the latter case, add "installdir" to 38 | the PYTHONPATH environment variable. For details, refer to: 39 | 40 | https://docs.python.org/2/install/index.html 41 | 42 | 43 | 3. Using the AirQual Package 44 | 45 | The AirQual package is on your Python path. To import it into a Python script or session, 46 | execute: 47 | 48 | import AirQual 49 | 50 | If a namespace must be specified for the package, modify the import statement accordingly. 51 | -------------------------------------------------------------------------------- /prepData.m: -------------------------------------------------------------------------------- 1 | function data = prepData(currentData) 2 | % Convert types, units, and organize data for machine learning 3 | 4 | % Convert data type 5 | data = convertData(currentData); 6 | 7 | % Calculate dew point from temp and relative humidity 8 | data.DP = data.T-(9/25)*(100-data.RH); 9 | 10 | % Convert Kelvin to Celsius 11 | data.T = data.T - 273.15; 12 | 13 | % Convert date 14 | if ~isa(data.DateLocal,"datetime") 15 | if strlength(data.DateLocal) > 20 16 | data.DateLocal = datetime(data.DateLocal,... 17 | "InputFormat","uuuu-MM-dd HH:mm:ss.SSS"); 18 | else 19 | data.DateLocal = datetime(data.DateLocal); 20 | end 21 | end 22 | % Split date into components for machine learning 23 | [data.yy,data.MM,data.dd] = ymd(data.DateLocal); 24 | 25 | % Figure out the US State from the city name and lat/lon using data from: 26 | % https://simplemaps.com/data/us-cities. 27 | switch data.city 28 | case "San Jose" 29 | data.StateName = "California"; 30 | case "Washington DC." 31 | data.StateName = "District of Columbia"; 32 | case "Boston" 33 | data.StateName = "Massachusetts"; 34 | case "Munich" 35 | data.StateName = "Bayern"; 36 | case "London" 37 | data.StateName = "UK"; 38 | otherwise 39 | load cities city 40 | idx = city.city == data.city & ... 41 | round(city.lat) == round(data.lat) & ... 42 | round(city.lng) == round(data.lon); 43 | data.StateName = city.state_name(idx); 44 | end 45 | % Convert state to categorical 46 | data.StateName = categorical(data.StateName); 47 | 48 | % Select data for model prediction 49 | data = data(:,["DateLocal","city","StateName","T","P",... 50 | "DP","RH","WindDir","WindSpd","yy","MM","dd"]); 51 | end 52 | 53 | function data = convertData(data) 54 | % Organize and convert data types 55 | data = struct2table(struct(data)); 56 | % Check for wind direction (deg), sometimes missing 57 | if ~any(data.Properties.VariableNames == "deg") 58 | deg = ""; 59 | data = addvars(data,deg,'After','speed'); 60 | end 61 | data = removevars(data,["temp_min","temp_max"]); 62 | data.Properties.VariableNames([1:5,end]) = ["T","P","RH","WindSpd","WindDir","DateLocal"]; 63 | data = convertvars(data,["T","P","RH","WindSpd","WindDir"],"double"); 64 | data = convertvars(data,["city","DateLocal"],"string"); 65 | 66 | % Convert date 67 | if strlength(data.DateLocal) > 20 68 | data.DateLocal = datetime(data.DateLocal,"InputFormat","uuuu-MM-dd HH:mm:ss.SSS"); 69 | else 70 | data.DateLocal = datetime(data.DateLocal); 71 | end 72 | 73 | end -------------------------------------------------------------------------------- /CallMATLABCompiledLibraryFromPython.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Predict Air Quality: Calling MATLAB from Python Using MATLAB Runtime" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Import the weather data and use the MATLAB code to predict air quality.\n", 15 | "\n", 16 | "Use the MATLAB Runtime to call the model and code, which does not require a MATLAB installation or license to use. More info here: https://www.mathworks.com/help/compiler_sdk/python_packages.html\n", 17 | "\n", 18 | "First, install the Compiled Python library by going in the for_testing folder and execute the install command class (open a terminal with Ctrl+ù from VScode or the good old Windows cmd):\n", 19 | " * `cd AirQual\\for_testing`\n", 20 | " * `python setup.py install`\n" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "#### Read the current weather data" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 1, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "import weather" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 2, 42 | "metadata": {}, 43 | "outputs": [ 44 | { 45 | "name": "stdout", 46 | "output_type": "stream", 47 | "text": [ 48 | "{'temp': 280.32, 'pressure': 1012, 'humidity': 81, 'temp_min': 279.15, 'temp_max': 281.15, 'speed': 4.1, 'deg': 80, 'lon': -0.13, 'lat': 51.51, 'city': 'London', 'current_time': '2022-07-27 14:14:20.500642'}\n" 49 | ] 50 | } 51 | ], 52 | "source": [ 53 | "appid ='b1b15e88fa797225412429c1c50c122a1'\n", 54 | "json_data = weather.get_current_weather(\"London\",\"UK\",appid,api=\"samples\")\n", 55 | "data = weather.parse_current_json(json_data)\n", 56 | "print(data)" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "#### Use MATLAB to predict air quality\n", 64 | "Import the package created from MATLAB" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 1, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "import AirQual" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 3, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "aq = AirQual.initialize()" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 8, 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "name": "stdout", 92 | "output_type": "stream", 93 | "text": [ 94 | "Good\n" 95 | ] 96 | } 97 | ], 98 | "source": [ 99 | "label = aq.predictAirQual(data)\n", 100 | "print(label)" 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "metadata": {}, 106 | "source": [ 107 | "Terminate the MATLAB instance" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 9, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "aq.terminate()" 117 | ] 118 | } 119 | ], 120 | "metadata": { 121 | "kernelspec": { 122 | "display_name": "Python 3.9.13 64-bit", 123 | "language": "python", 124 | "name": "python3" 125 | }, 126 | "language_info": { 127 | "codemirror_mode": { 128 | "name": "ipython", 129 | "version": 3 130 | }, 131 | "file_extension": ".py", 132 | "mimetype": "text/x-python", 133 | "name": "python", 134 | "nbconvert_exporter": "python", 135 | "pygments_lexer": "ipython3", 136 | "version": "3.9.13" 137 | }, 138 | "vscode": { 139 | "interpreter": { 140 | "hash": "81794d4967e6c3204c66dcd87b604927b115b27c00565d3d43f05ba2f3a2cb0d" 141 | } 142 | } 143 | }, 144 | "nbformat": 4, 145 | "nbformat_minor": 4 146 | } 147 | -------------------------------------------------------------------------------- /weather.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Created on Thu Jan 4 20:41:45 2018 4 | Modified Jan 29 2019 5 | Simplified June 16 2022 6 | 7 | ''' 8 | 9 | # weather.py 10 | import datetime 11 | import json 12 | import urllib.request 13 | 14 | BASE_URL = '/data/2.5/{}?q={},{}&appid={}' 15 | 16 | def get_current_weather(city, country, apikey,**kwargs): 17 | '''get current conditions in specified location 18 | appid='b1b15e88fa797225412429c1c50c122a1' 19 | get_current_weather('London','uk',appid,api='samples')''' 20 | 21 | # select between samples or prod api 22 | if 'api' in kwargs: 23 | if kwargs['api'] == 'samples': 24 | DOMAIN = "http://samples.openweathermap.org" 25 | else: 26 | print('not the right api arg') 27 | DOMAIN = "http://api.openweathermap.org" 28 | else: 29 | DOMAIN = "http://api.openweathermap.org" 30 | 31 | # Read current conditions 32 | try: 33 | # url = 'http://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b1b15e88fa797225412429c1c50c122a1' 34 | url = DOMAIN + BASE_URL.format('weather',city,country,apikey) 35 | json_data = json.loads(urllib.request.urlopen(url).read()) 36 | return json_data 37 | except urllib.error.URLError: 38 | # If weather API doesnt work 39 | print("API not available") 40 | 41 | 42 | def parse_current_json(json_data): 43 | '''parse and extract json data from the current weather data''' 44 | 45 | try: 46 | # select data of interest from dictionary 47 | weather_info = json_data['main'] 48 | weather_info.update(json_data['wind']) 49 | weather_info.update(json_data['coord']) 50 | weather_info['city'] = json_data['name'] 51 | # add current date and time 52 | weather_info['current_time'] = str(datetime.datetime.now()) 53 | 54 | except KeyError as e: 55 | # use current dictionary (because it probably came from backup file) 56 | try: 57 | # If this fails then the json_data didn't come from backup file 58 | json_data.pop('City') 59 | weather_info = json_data 60 | except: 61 | # print('Something else went wrong while parsing current json') 62 | raise e 63 | 64 | return weather_info 65 | 66 | 67 | def get_forecast(city, country, apikey, **kwargs): 68 | '''get forecast conditions in specified location 69 | appid='b1b15e88fa797225412429c1c50c122a1' 70 | get_forecast('Muenchen','DE',appid,api='samples')''' 71 | 72 | # select between samples or prod api 73 | if 'api' in kwargs: 74 | if kwargs['api'] == 'samples': 75 | DOMAIN = "http://samples.openweathermap.org" 76 | else: 77 | print('not the right api arg') 78 | DOMAIN = "http://api.openweathermap.org" 79 | else: 80 | DOMAIN = "http://api.openweathermap.org" 81 | # get forecast 82 | try: 83 | url = DOMAIN + BASE_URL.format('forecast',city,country,apikey) 84 | json_data = json.loads(urllib.request.urlopen(url).read()) 85 | return json_data 86 | except: 87 | print("API not available") 88 | 89 | 90 | def parse_forecast_json(json_data): 91 | '''parse and extract json data from the weather forecast data''' 92 | 93 | try: 94 | # parse forecast json data 95 | data = json_data['list'] 96 | wind_keys = ['deg','speed'] 97 | weather_info = {'current_time':[], 'temp':[], 'deg':[], 98 | 'speed':[], 'humidity':[], 'pressure':[]} 99 | for data_point in data[0:40]: 100 | for k in list(weather_info.keys())[1:]: #Taking a slice so we don't add the time 101 | weather_info[k].append(float(data_point['wind' if k in wind_keys else 'main'][k])) 102 | weather_info['current_time'].append(data_point['dt_txt']) 103 | return weather_info 104 | 105 | except: 106 | print('Something went wrong while parsing forecast json') 107 | -------------------------------------------------------------------------------- /AirQual/for_redistribution_files_only/GettingStarted.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
python setup.py install [options]
python driverApplication.py