Creating an Elementary Oscilloscope in PSLab’s Remote Framework

The last couple of blog posts explained how we could put together the versatility of ember components, the visual appeal of jqplot, the flexibility of Python Flask, and the simplicity of Python itself in order to make simple scripts for PSLab that would could be run on a server by a remote client anywhere on the web. We have also seen how callbacks could be assigned to widgets created in these scripts in order to make object oriented applications. In this blog post, we shall see how to assign a capture method to a button, and update a plot with the received data. It will also demonstrate how to use ember-lodash to perform array manipulations. Specifying the return data type in the callback success routine For a more instructive write-up on assigning callbacks, please refer to these posts . Whenever the callback assigned to a button is a function that returns an array of elements, and the target for the resultant data is a plot, the stacking order of the returned array must be specified in order to change its shape to suit the plotting library. The default return data from a capture routine (oscilloscope) is made up of separate arrays for X coordinate and Y coordinate values. Since JQplot requires [X,Y] pairs , we must specify a stacking order of ‘xy’ so that the application knows that it must convert them to pairs (using lodash/zip)  before passing the result to the plot widget. Similarly, different stacking orders for capture2, and capture4 must also be defined. Creating an action that performs necessary array manipulations and plots the received data It can be seen from the excerpt below, that if the onSuccess target for a callback is specified to be a plot in the actionDefinition object, then the stacking order is checked, and the returned data is modified accordingly Relevant excerpt from controllers/user-home.js/runButtonAction if (actionDefinition.success.type === 'update-plot') { if (actionDefinition.success.stacking === 'xy') { $.jqplot(actionDefinition.success.target, [zip(...resultValue)]).replot(); } else if (actionDefinition.success.stacking === 'xyy') { $.jqplot(actionDefinition.success.target, [zip(...[resultValue[0], resultValue[1]]), zip(...[resultValue[0], resultValue[2]])]).replot(); } else if (actionDefinition.success.stacking === 'xyyyy') { $.jqplot(actionDefinition.success.target, [zip(...[resultValue[0], resultValue[1]]), zip(...[resultValue[0], resultValue[2]]), zip(...[resultValue[0], resultValue[3]]), zip(...[resultValue[0], resultValue[4]])]).replot(); } else { $.jqplot(actionDefinition.success.target, resultValue).replot(); } }   With the above framework in place, we can add a plot with the line plt = plot(x, np.sin(x)) , and associate a button with a capture routine that will update its contents with a single line of code: button('capture1',"capture1('CH1',100,10)","update-plot",target=plt) Final Result The following script created on the pslab-remote platform makes three buttons and plots, and sets the buttons to invoke capture1, capture2, and capture4 respectively when clicked. import numpy as np x=np.linspace(0,2*np.pi,30) plt = plot(x, np.sin(x)) button('capture 1',"capture1('CH1',100,10)","update-plot",target=plt) plt2 = plot(x, np.sin(x)) button('capture 2',"capture2(50,10)","update-plot",target=plt2,stacking='xyy') plt3 = plot(x, np.sin(x)) button('capture 4',"capture4(50,10)","update-plot",target=plt3,stacking='xyyyy')                         Resources Ember components documentation : https://www.emberjs.com/api/ember/2.14/classes/Ember.Component Jqplot homepage : http://www.jqplot.com/ JQplot examples : http://www.jqplot.com/examples/line-charts.php Designing A Virtual Laboratory With PSLab Designing a Remote Laboratory with PSLab using Python Flask Framework Designing A Remote Laboratory With PSLab: execution of function…

Continue ReadingCreating an Elementary Oscilloscope in PSLab’s Remote Framework

Including a Graph Component in the Remote Access Framework for PSLab

The remote-lab software of the pocket science lab enables users to access their devices remotely via the Internet. It includes an API server designed with Python Flask, and a web-app designed with EmberJS that allows users to access the API and carry out various tasks such as writing and executing Python scripts. In a series of blog posts, various aspects of this framework such as  remote execution of function strings, automatic deployment on various domains, creating and submitting python scripts which will be run on the remote server etc have already been explored.  This blog post deals with the inclusion of a graph component in the webapp that will be invoked when the user utilises the `plot` command in their scripts. The JQPLOT library is being used for this purpose, and has been found to be quite lightweight and has a vast set of example code . Task list for enabling the plotting feature Add a plot method to the codeEvaluator module in the API server and allow access to it by adding it to the evalGlobals dictionary Create an EmberJS component for handling plots Create a named div in the template Invoke the Jqplot initializer from the JS file and pass necessary arguments and data to the jqplot instance Add a conditional statement to include the jqplot component whenever a plot subsection is present in the JSON object returned by the API server after executing a script Adding a plot method to the API server Thus far, in addition to the functions supported by the sciencelab.py instance of PSLab, users had access to print, print_, and button functions. We shall now add a plot function. def plot(self,x,y,**kwargs): self.generatedApp.append({"type":"plot","name":kwargs.get('name','myPlot'),"data":[np.array([x,y]).T.tolist()]})   The X,Y datasets provided by the user are stacked in pairs because jqplot requires [x,y] pairs . not separate datasets. We also need to add this to evalGlobals, so we shall modify the __init__ routine slightly: self.evalGlobals['plot']=self.plot Building an Ember component for handling plots First, well need to install jqplot:   bower install --save jqplot And this must be followed by including the following files using app.import statements in ember-cli-build.js bower_components/jqplot/jquery.jqplot.min.js bower_components/jqplot/plugins/jqplot.cursor.js bower_components/jqplot/plugins/jqplot.highlighter.js bower_components/jqplot/plugins/jqplot.pointLabels.js bower_components/jqplot/jquery.jqplot.min.css In addition to the jqplot js and css files, we have also included a couple of plugins we shall use later. Now we need to set up a new component : ember g component jqplot-graph Our component will accept an object as an input argument. This object will contain the various configuration options for the plot Add the following line in templates/components/jqplot-graph.hbs: style="solid gray 1px;" id="{{data.name}}"> The JS file for this template must invoke the jqplot function in order to insert a complete plot into the previously defined <div> after it has been created. Therefore, the initialization routine must override the didInsertElement routine of the component. components/jqplot-graph.js import Ember from 'ember'; export default Ember.Component.extend({ didInsertElement () { Ember.$.jqplot(this.data.name,this.data.data,{ title: this.title, axes: { xaxis: { tickInterval: 1, rendererOptions: { minorTicks: 4 } }, }, highlighter: { show: true, showLabel: true, tooltipAxes: 'xy', sizeAdjust: 9.5 , tooltipLocation :…

Continue ReadingIncluding a Graph Component in the Remote Access Framework for PSLab

PSLab Remote Lab: Automatically deploying the EmberJS WebApp and Flask API Server to different domains

The remote-lab software of the pocket science lab enables users to access their devices remotely via the internet. Its design involves an API server designed with Python Flask, and a web-app designed with EmberJS that allows users to access the API and carry out various tasks such as writing and executing Python scripts. For testing purposes, the repository needed to be setup to deploy both the backend as well as the webapp automatically when a build passes, and this blog post deals with how this can be achieved. Deploying the API server The Heroku PaaS was chosen due to its ease of use with a wide range of server software, and support for postgresql databases. It can be configured to automatically deploy branches from github repositories, and conditions such as passing of a linked CI can also be included. The following screenshot shows the Heroku configuration page of an app called pslab-test1. Most of the configuration actions can be carried out offline via the Heroku-Cli   In the above page, the pslab-test1 has been set to deploy automatically from the master branch of github.com/jithinbp/pslab-remote . The wait for CI to pass before deploy has been disabled since a CI has not been setup on the repository. Files required for Heroku to deploy automatically Once the Heroku PaaS has copied the latest commit made to the linked repository, it searches the base directory for a configuration file called runtime.txt which contains details about the language of the app and the version of the compiler/interpretor to use, and a Procfile which contains the command to launch the app once it is ready. Since the PSLab’s API server is written in Python, we also have a requirements.txt which is a list of dependencies to be installed before launching the application. Procfile web: gunicorn app:app --log-file - runtime.txt python-3.6.1 requirements.txt gunicorn==19.6.0 flask >= 0.10.1 psycopg2==2.6.2 flask-sqlalchemy SQLAlchemy>=0.8.0 numpy>=1.13 flask-cors>=3.0.0 But wait, our app cannot run yet, because it requires a postgresql database, and we did not do anything to set up one. The following steps will set up a postgres database using the heroku-cli usable from your command prompt. Point Heroku-cli to our app $ heroku git:remote -a pslab-test1 Create a postgres database under the hobby-dev plan available for free users. $ heroku addons:create heroku-postgresql:hobby-dev Creating heroku-postgresql:hobby-dev on ⬢ pslab-test1... free Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pg:copy Created postgresql-slippery-81404 as HEROKU_POSTGRESQL_CHARCOAL_URL Use heroku addons:docs heroku-postgresql to view documentation The previous step created a database along with an environment variable HEROKU_POSTGRESQL_CHARCOAL_URL . As a shorthand, we can also refer to it simply as CHARCOAL . In order to make it our primary database, it must be promoted $ heroku pg:promote HEROKU_POSTGRESQL_CHARCOAL_URL The database will now be available via the environment variable DATABASE_URL Further documentation on creating and modifying postgres databases on Heroku can be found in the articles section . At this point, if the app is…

Continue ReadingPSLab Remote Lab: Automatically deploying the EmberJS WebApp and Flask API Server to different domains