Hiding Intelligence of Susper When a Query is Empty or Erased with Angular

Recently, we have implemented intelligence feature in Susper using SUSI chat API to provide users answer a question without going deeper in search results. When a user types “height of Trump”, it shows answer like this:

Problem which we faced after implementing the feature:

When a user was erasing a query or query field was empty, Susper was still showing the answer of the intelligence component like this:

The answer should not be displayed when a query is empty because the user is not asking any question. The answer was still displayed because it had received a response from SUSI API.

How did we solve the problem?

The problem was solved in two ways.

  1. By using if/else condition: We checked if the statement shown inside the component is similar to the if-and-else condition. If the condition is true, it should hide the component.
  2. Using [hidden] attribute method: The Angular 4 supports [hidden] attribute which acts as { display:none; } . [hidden] attribute generally works as ngShow and ngHide which was earlier supported by Angular 2.

We preferred both the methods to solve the problem. The intelligence component is being loaded inside results component using <app-intelligence> element. Further, we added [hidden] attribute to this element like this :

<appintelligence [hidden]=“hideIntelligence”></app-intelligence>
We created hideIntelligence as variable and assign it as boolean. To check if a query is empty, searchdata variable was used.
searchdata: any = {
  query: ‘ ‘,
  rows: 10,
  start: 0
};
And then checked if a query is empty using if-else condition :
// checks if query is empty or erased
if (this.searchdata.query === ‘ ‘) {// display: none; is true
  this.hideIntelligence = true;

} else {
// display: none; is false
  this.hideIntelligence = false;
}

 

Applying this solution, we succeeded in hiding the intelligence component. We would also had used *ngIf statement but we preferred using [hidden]. [hidden] modifies the display property.  *ngIf is a structural directive which creates or destroys content inside DOM.

The source code for the implementation can be found here: https://github.com/fossasia/susper.com/pull/613

Resources:

 

Continue ReadingHiding Intelligence of Susper When a Query is Empty or Erased with Angular

Customizing Serializers in Open Event Front-end

Open Event Front-end project primarily uses Ember Data for API requests, which handles sending the request to correct endpoint, serializing and deserializing the request/response. The Open Event API project uses JSON API specs for implementation of the API, supported by Ember data.

While sending request we might want to customize the payload using a custom serializer. While implementing the Users API in the project, we faced a similiar problem. Let’s see how we solved it.

Creating a serializer for model

A serializer is created for a model, in this example we will create a user serializer for the user model. One important thing that we must keep in mind while creating a serializer is to use same name as that of model, so that ember can map the model with the serializer. We can create a serializer using ember-cli command:

ember g serializer user

 
Customizing serializer

In Open Event Front-end project every serializer extends the base serializer application.js which defines basic serialization like omitting readOnly attributes from the payload.

The user serializer provides more customization for the user model on top of application model. We override the serialize function, which lets us manipulate the payload of the request. We use `snapshot.id` to differentiate between a create request & an update request. If `snapshot.id` exists then it is an update request else it is a create request.

While manipulation user properties like email, contact etc we do not need to pass ‘password’ in the payload. We make use of ‘adapterOptions’ property associated with the ‘save()’ method. If the adapterOptions are associated and the ‘includePassword’ is set then we add ‘password’ attribute to the payload.

import ApplicationSerializer from 'open-event-frontend/serializers/application';
import { pick, omit } from 'lodash';

export default ApplicationSerializer.extend({
  serialize(snapshot, options) {
    const json = this._super(...arguments);
    if (snapshot.id) {
      let attributesToOmit = [];
      if (!snapshot.adapterOptions || !snapshot.adapterOptions.includePassword) {
        attributesToOmit.push('password');
      }
      json.data.attributes = omit(json.data.attributes, attributesToOmit);
    } else if (options && options.includeId) {
      json.data.attributes = pick(json.data.attributes, ['email', 'password']);
    }
    return json;
  }
});

If we want to add the password in the payload we can simply add ‘includePassword’ property to the ‘adapterOptions’ and pass it in the save method for operations like changing the password of the user.

user.save({
  adapterOptions: {
    includePassword: true
  }
})

Thank you for reading the blog, you can check the source code for the example here.
Resources

Learn more about how to customize serializers in ember data here

Continue ReadingCustomizing Serializers in Open Event Front-end

Adding Manual ISO Controls in Phimpme Android

The Phimpme Android application comes with a well-featured camera to take high resolution photographs. It features an auto mode in the camera as well as a manual mode for users who likes to customise the camera experience according to their own liking. It provides the users to select from the range of ISO values supported by their devices with a manual mode to enhance the images in case the auto mode fails on certain circumstances such as low lighting conditions.

In this tutorial, I will be discussing how we achieved this in Phimpme Android with some code snippets and screenshots.

To provide the users with an option to select from the range of ISO values, the first thing we need to do is scan the phone for all the supported values of ISO and store it in an arraylist to be used to display later on. This can be done by the snippet provided below:

String iso_values = parameters.get("iso-values");
if( iso_values == null ) {
 iso_values = parameters.get("iso-mode-values"); // Galaxy Nexus
 if( iso_values == null ) {
    iso_values = parameters.get("iso-speed-values"); // Micromax A101
    if( iso_values == null )
       iso_values = parameters.get("nv-picture-iso-values"); // LG dual P990

Every device supports a different set of keyword to provide the list of ISO values. Hence, we have tried to add every possible keywords to extract the values. Some of the keywords used above covers almost 90% of the android devices and gets the set of ISO values successfully.

For the devices which supports the ISO values but doesn’t provide the keyword to extract the ISO values, we can provide the standard list of ISO values manually using the code snippet provided below:

values.add("200");
values.add("400");
values.add("800");
values.add("1600");

After extracting the set of ISO values, we need to create a list to display to the user and upon selection of the particular ISO value as depicted in the Phimpme camera screenshot below

Now to set the selected ISO value, we first need to get the ISO key to set the ISO values as depicted in the code snippet provided below:

if( parameters.get(iso_key) == null ) {
 iso_key = "iso-speed"; // Micromax A101
 if( parameters.get(iso_key) == null ) {
    iso_key = "nv-picture-iso"; // LG dual P990
    if( parameters.get(iso_key) == null ) {
       if ( Build.MODEL.contains("Z00") )
          iso_key = "iso"; // Asus Zenfone 2 Z00A and Z008

Getting the key to set the ISO values is similar to getting the key to extract the ISO values from the device. The above listed ISO keys to set the values covers most of the devices.

Now after we have got the ISO key, we need to change the camera parameter to reflect the selected change.

parameters.set(iso_key, supported_values.selected_value);
setCameraParameters(parameters);

To get the full source code on how to set the ISO values manually, please refer to the Phimpme Android repository.

Resources

  1. Stackoverflow – Keywords to extract ISO values from the device: http://stackoverflow.com/questions/2978095/android-camera-api-iso-setting
  2. Open camera Android source code: https://sourceforge.net/p/opencamera/code/ci/master/tree/
  3. Blog – Learn more about ISO values in photography: https://photographylife.com/what-is-iso-in-photography
Continue ReadingAdding Manual ISO Controls in Phimpme Android

Handling High Resolution Images in Phimpme Android

In Android, loading heavy and high resolution images is a difficult task. For instance, if we try to load a photo clicked at a resolution four times that of the screen and try to load it in an imageview, it may result in an app’s crash due to the OutOFMemory exception. It happens because at the run time of our application some limited memory is allocated to our application and if we exceed that by loading a high quality images. To make a perfect gallery application, one must take care of all the possible causes for application crashes. In Phimpme Android, we have done this with the help of Glide library with some other tweaks to help catch all possible causes for the OutOfMemory exceptions. In this tutorial, I will be discussing how we have displayed heavy images with the help of Glide library and other tweaks to avoid the above mentioned exception.

Step 1:

To avoid the OutOFMemory exception, first we have to add the below line of code in the AndroidManifest.xml file.

android:largeHeap=”true”

What this piece of code does is that it increases the amount of heap memory that is allocated at the time of run time of the application. Hence, more heap memory, less chance of running out of memory.

Step 2:

To load the images into the image view we can make use of the Glide library as it is the most recommended way to do it according to the Google’s  Android developer page to cache bitmaps. The below code helps us to load the image in the imageView using a pager adapter.

Glide.with(getContext())
          .load(img.getUri())
          .asBitmap().format(DecodeFormat.PREFER_RGB_565)
          .signature(useCache ? img.getSignature(): new StringSignature(new Date().getTime()+""))
          .diskCacheStrategy(DiskCacheStrategy.SOURCE)
          .thumbnail(0.5f)
          .transform(new RotateTransformation(getContext(), img.getOrientation(), false))
          .animate(R.anim.fade_in)
          .into(new SimpleTarget<Bitmap>() {
              @Override
              public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {
                  photoView.setImageBitmap(bitmap);
              }
          });

This is the way we have done it in the Phimpme Android application using the Glide library. We are loading the image as a bitmap and by preferring the bitmap RGB565 as it consumes 50% less memory than the RGB8888 model which may be the type of the original image. Of course the image quality will seem bit less but it is not noticeable until we zoom in to full extent.

The next thing we are doing is caching the image in the memory using the below line of code using Glide library.

.diskCacheStrategy(DiskCacheStrategy.SOURCE)

As caching images offers faster access to the images. It also helps in avoiding the OutOfMemory crashes when we are using a large list of images. Link to cache images without using the Glide library is mentioned in the resources section below. After this, we are loading the image in the PhotoView which is a module we are using in the Phimpme Android application, which extends to the imageView and comes with many zooming images functionalities.

This is how we have implemented the loading of images in the gallery view in Phimpme Android application so that it can handle resolution of any sizes without running out of memory. To get the full source code on how to load high resolution images, please refer to the Phimpme Android repository.

Resource

  1. Introduction to glide image loader: https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
  2. Google developer guide to cache bitmaps without using glide library : https://developer.android.com/topic/performance/graphics/cache-bitmap.html.
  3. Google developer guide to OutOfMemory Exceptions: https://developer.android.com/reference/java/lang/OutOfMemoryError.html
  4. LeafPic GitHub repository: https://github.com/HoraApps/LeafPic
Continue ReadingHandling High Resolution Images in Phimpme Android

Adding Event Overview Route in Open Event Frontend

In Open Event Frontend we have an event overview route which is like a mini dashboard for an event where information regarding event sponsors, general info, roles, tickets, event setup etc. is present. All of the information is present in their corresponding components and this dashboard is made up of those components. To create this dashboard we will first create its components.

To create a component we will use following ember command-

ember -g component <component-name>

This command will give us three files: a template, a component and a test file corresponding to that component. We will use this command to generate all our components.

Now let’s discuss each component separately and see how many of them are combined to form this route-

The event-setup-checklist component contains semantic ui’s steps to maintain checklist of basic-details, sponsors, session & microlocation, call for speakers, session and speakers form customization so that it becomes easy to identify which step is complete and which is not.

Next is general-info component which shows basic information about an event like start-time, end-time, location, number of speakers, number of sponsors etc. It also shows whether the event is live or not.

In manage-roles component, manage the role for a given person, add people and assign different roles to them, edit roles for different people. Also we can see who are invited for a given role and who accepted them.

In event-sponsors component we manage the sponsors for the event, edit an existing sponsor, add a new sponsor with their logo, name, type and level. Also we can delete an existing sponsor.

Next is the ticket component which displays the details of number of orders, number of tickets sold, and total sales. Also it displays the number of types of tickets are sold.

Next is our app-component which has two choices. First is to generate android app for the event and second is to generate webapp of the event.

And finally in our view.index template, we add these components using ui stackable grid layout. Whenever we want to conditionally show or hide a component, we can do that in our event.index template and hence it becomes very easy to manage huge amounts content on a single page.

Resources

Continue ReadingAdding Event Overview Route in Open Event Frontend

Displaying Upcoming Sessions at a Microlocation Open Event Android

When I am attending a session in a room, I don’t get information on what is coming up.”

The issue that the user expressed was that he wanted to know what were the upcoming sessions at a microlocation. While I took up this issue in Open Event Android a few days back, I was thinking of ways about how this can be implemented. The app should be easy-to-use even for non-developers and thus, any new feature shouldn’t be too complex in its implementation. We decided upon doing the following:

  • Adding an “upcoming” option in the options menu of the Location activity.
  • This option’s purpose was to trigger the app to show information about the upcoming session in that microlocation.

Initial changes in LocationActivity.java

First of all, we added a new icon in the options menu of LocationActivity.java. One of the things that we learnt there was to use ifRoom|collapseActionView option for the app:showAsAction  

attribute as frequently as possible. This option ensures that the title in the option’s menu is visible at all times irrespective of the options being visible along with their icons.

So in case, the title is too big and there is very little room for the options to appear individually, then instead of squeezing down the title, the “ifRoom” attribute will collapse the option icons and insert a 3-dotted drop-down option list with all the options appearing in the drop-down.

Something like this:

The icon’s XML element and UI looked something like this:

<item
       android:id="@+id/upcoming_sessions"
       android:icon="@drawable/ic_timeline_white_24dp"
       android:title="@string/upcoming"
       app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.support.v7.widget.Button"/>

About the drawable icon that you see in the screenshot above, it was a tough find. Before I talk about how I came across this icon, I will talk about adding an icon in Android Studio.

How to add an icon in Android Studio?

Adding an item in Android studio means adding a drawable at a basic level. You can find all drawables under the app/src/main/res/drawable folder.

To add a new drawable, right-click on the drawable folder and go to new –>Vector asset. A window similar to what is shown below will appear.

Now, on selecting the “icon” option you will be taken to a huge list of icons that you can add in your app and then use them subsequently. But the problem here is that it is tough at times to find the icon that will be fit for your purpose. Like in my case, there was no direct icon for “upcoming”. This is when we had to do something more. We had to browse to this amazing site by Google: https://material.io/icons/ This site shows all the available icons in a much more interactive way and it was a lot more easier for me to come across the icon we wanted using this site.

The vector drawable file for the icon we chose looks like this:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
       android:width="24dp"
       android:height="24dp"
       android:viewportWidth="24.0"
       android:viewportHeight="24.0">
   <path
       android:fillColor="#FFFFFF"
       android:pathData="M23,8c0,1.1 -0.9,2 -2,2 -0.18,0 -0.35,-0.02 -0.51,-0.07l-3.56,3.55c0.05,0.16 0.07,0.34 0.07,0.52 0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2c0,-0.18 0.02,-0.36 0.07,-0.52l-2.55,-2.55c-0.16,0.05 -0.34,0.07 -0.52,0.07s-0.36,-0.02 -0.52,-0.07l-4.55,4.56c0.05,0.16 0.07,0.33 0.07,0.51 0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2 0.9,-2 2,-2c0.18,0 0.35,0.02 0.51,0.07l4.56,-4.55C8.02,9.36 8,9.18 8,9c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,0.18 -0.02,0.36 -0.07,0.52l2.55,2.55c0.16,-0.05 0.34,-0.07 0.52,-0.07s0.36,0.02 0.52,0.07l3.55,-3.56C19.02,8.35 19,8.18 19,8c0,-1.1 0.9,-2 2,-2s2,0.9 2,2z"/>
</vector>

What would the upcoming icon do?

Keeping in mind the necessity for the feature to be less complex, I decided that the upcoming icon will lead the user to a dialog box that shows the status of upcoming sessions in that micro location. The implementation for this feature involved 2 main things:

  1. Finding out the upcoming session from the list of sessions in the microlocation.
  2. Generate a dialog box that shows information about that session.

Finding position of upcoming session in Recycler View

Upcoming session will be a session whose starting time comes after the current time. So the approach was simple.

  1. Run a loop on a sorted list of all sessions in a microlocation.
  2. Find out every session’s start time.
  3. Compare the start time of every session with the current time.
  4. Find the first session whose start time comes after the current time.
  5. Store that session’s position, name, ID and other stuff like track name and track color.
  6. Break out of the loop.

This was the basic logic or algorithm, so to say. Here’s the implementation in the upcomingSession() function:

public void upcomingSession(){
   String upcomingTitle = "";
   String track = "";
   String color = null;
   Date current = new Date();
   for (Session sess:sortedSessions){
       try {
           Date start = DateUtils.getDate(sess.getStartsAt());
           if (start.after(current)){
               upcomingTitle = sess.getTitle();
               track = sess.getTrack().getName();
               color = sess.getTrack().getColor();
               break;
           }
       } catch (ParseException e) {
           e.printStackTrace();
       }
   }

Now, displaying a dialog box consisting of all the necessary information is an easy thing to do once you have the required information. So, I’ll just provide some code for it here without explaining much about it.

The initialisations:

public void upcomingSessionsInitial(){
   upcomingDialogBox = new Dialog(this);
           upcomingDialogBox.setContentView(R.layout.upcoming_dialogbox);
           trackImageIcon = (ImageView)upcomingDialogBox.findViewById(R.id.track_image_drawable);
           upcomingSessionText = (TextView) upcomingDialogBox.findViewById(R.id.upcoming_session_textview);
           upcomingSessionTitle = (TextView) upcomingDialogBox.findViewById(R.id.upcoming_Session_title);
           Button dialogButton = (Button) upcomingDialogBox.findViewById(R.id.upcoming_button);
           dialogButton.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View view) {
                   upcomingDialogBox.dismiss();
               }
           });
}

The calling:

switch (item.getItemId()){
       case R.id.action_map_location:
           FragmentManager fragmentManager = getSupportFragmentManager();
           FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

           Bundle bundle = new Bundle();
           bundle.putBoolean(ConstantStrings.IS_MAP_FRAGMENT_FROM_MAIN_ACTIVITY, false);
           bundle.putString(ConstantStrings.LOCATION_NAME, location);

           Fragment mapFragment = ((OpenEventApp)getApplication())
                   .getMapModuleFactory()
                   .provideMapModule()
                   .provideMapFragment();
           mapFragment.setArguments(bundle);
           fragmentTransaction.replace(R.id.content_frame_location, mapFragment, FRAGMENT_TAG_LOCATION).addToBackStack(null).commit();

           sessionRecyclerView.setVisibility(View.GONE);
           noSessionsView.setVisibility(View.GONE);
           menu.setGroupVisible(R.id.menu_group_location_activity, false);
           return true;
       case android.R.id.home:
           onBackPressed();
           getSupportFragmentManager().popBackStack();
           sessionRecyclerView.setVisibility(View.VISIBLE);
           return true;
       case R.id.upcoming_sessions:
           upcomingDialogBox.show();
           return true;
       default:
           return true;
   }
}

Final result:

This is the final result or solution that we generated for the issue that was addressed by one of the users:

Some useful links are:

Continue ReadingDisplaying Upcoming Sessions at a Microlocation Open Event Android

File Upload Validations on Open Event Frontend

In Open Event Frontend we have used semantics ui’s form validations to validate different fields of a form. There are certain instances in our app where the user has to upload a file and it is to be validated against the suggested format before uploading it to the server. Here we will discuss how to perform the validation.

Semantics ui allows us to validate by facilitating pass of an object along with rules for its validation. For fields like email and contact number we can pass type as email and number respectively but for validation of file we have to pass a regular expression with allowed extension.The following walks one through the process.

fields : {
  file: {
    identifier : 'file',
    rules      : [
      {
        type   : 'empty',
        prompt : this.l10n.t('Please upload a file')
      },
      {
        type   : 'regExp',
        value  : '/^(.*.((zip|xml|ical|ics|xcal)$))?[^.]*$/i',
        prompt : this.l10n.t('Please upload a file in suggested format')
      }
    ]
  }
}

Here we have passed file element (which is to be validated) inside our fields object identifier, which for this field is ‘file’, and can be identified by its id, name or data-validate property of the field element. After that we have passed an array of rules against which the field element is validated. First rule gives an error message in the prompt field in case of an empty field.

The next rule checks for allowed file extensions for the file. The type of the rule will be regExp as we are passing a regular expression which is as follows-

/^(.*.((zip|xml|ical|ics|xcal)$))?[^.]*$/i

It is little complex to explain it from the beginning so let us breakdown it from end-

 

$ Matches end of the string
[^.]* Negated set. Match any character not in this set. * represents 0 or more preceding token
( … )? Represents if there is something before (the last ?)
.*.((zip|xml|ical|ics|xcal)$) This is first capturing group ,it contains tocken which are combined to create a capture group ( zip|xml|ical|ics|xcal ) to extract a substring
^ the beginning of the string

Above regular expression filters all the files with zip/xml/ical/xcal extensions which are the allowed format for the event source file.

References

  • Ivaylo Gerchev blog on form validation in semantic ui
  • Drmsite blog on semantic ui form validation
  • Semantic ui form validation docs
  • Stackoverflow regex for file extension
Continue ReadingFile Upload Validations on Open Event Frontend

Custom SeekBar in PSLab Android

By default Seekbar in Android only return integer values greater than zero. But there can be some situation where we need the SeekBar to return a float and negative values. To implement trigger functionality in the Oscilloscope activity of PSLab Android app, we require a SeekBar that sets a voltage level that should trigger the capture sequence. Since this voltage value ranges between -16.5 V to 16.5 V, default Seekbar don’t serve the purpose.

The solution is to create a custom SeekBar that returns float values. Let’s understand how to implement it.

Create a FloatSeekBar class which extends AppCompatSeekBar. Create a constructor for the class with Context, AttributeSet and defStyle as parameters. AttributeSet is the set of properties specified in an XML resource file whereas defStyle is default style to apply to this view.

public class FloatSeekBar extends android.support.v7.widget.AppCompatSeekBar {
   private double max = 0.0;
   private double min = 0.0;

   public FloatSeekBar(Context context, AttributeSet attrs, int defStyle) {
       super(context, attrs, defStyle);
       applyAttrs(attrs);
   }

 

Then define setters method which set the max and min values of the SeekBar. This method basically sets the range of the SeekBar.

public void setters(double a, double b)
{
   min = a;
   max = b;
}

 

getValue is a method that manipulates current progress of the SeekBar and returns the value. Here the equation used to determine the value is (max – min) * (getProgress() / getMax()) + min.

public double getValue() {
   DecimalFormat df = new DecimalFormat("#.##");
   Double value = (max - min) * ((float) getProgress() / (float) getMax()) + min;
   value = Double.valueOf(df.format(value));
   return value;
}

 

setValue method takes the double value, and accordingly set the progress of the SeekBar.

public void setValue(double value) {
   setProgress((int) ((value - min) / (max - min) * getMax()));
}

This creates a custom SeekBar, it can be used just like a normal SeekBar.

Now, set the range of custom SeekBar between -16.5 and 16.5.

seekBarTrigger = (FloatSeekBar) v.findViewById(R.id.seekBar_trigger);
seekBarTrigger.setters(-16.5, 16.5);

 

In order to get value of the custom SeekBar call getValue method.

seekBarTrigger.getValue();

In order to follow the entire code for custom SeekBar implementation in PSLab refer FloatSeekBar.java, Attr.xml and TimebaseTrigger.java.

A glimpse of custom SeekBar in PSLab Android.

Resources

 

Continue ReadingCustom SeekBar in PSLab Android

Comparing Different Graph View Libraries and Integrating Them in PSLab Android Application

There is a significant role of graphs in PSLab, they’re used for the following purpose:

For this, we need to implement real time graphs that stimulate real time data from the PSLab device efficiently. It is necessary to analyze each and every Graph View Library, compare them and integrate the best one in PSLab Android app.

Available Graph Libraries

The available Graph View libraries of Android are:

  1. MPAndroidChart
  2. Graph-View
  3. SciChart

Which one is the best with respect to the PSLab project?

MPAndroidChart

Line Graph plotted using MPAndroidChart (image source)

It is an open source graph view library by Philipp Jahoda. The following are the features of MPAndroidChart

  • There are 8 different chart types
  • Scaling on both axes. Scaling can be done using pinch zoom gesture.
  • Dual Axes, we can have 2 Y-axis.
  • Real time support
  • Customizable axis ie we can define different labels to the axis
  • Save chart to SD-Card
  • Predefined color templates
  • Legends which are used to define which line depicts what.
  • Animations
  • Fully customizable, from background color to color of the lines and grids.

On trying MPAndroidChart, I found it to be a slightly difficult to implement.

Graph-View

Line Graph plotted using GraphView Library (image source)

It is also an open source graph view library by Jonas Gehring. The following are features of the Graph-View

  • Supports Line Chart, Bar Chart and Points.
  • Scrolling vertical and horizontal
  • Scaling on both axes.
  • Realtime Graph support
  • Draw multiple series of data. Let the diagram show more that one series in a graph. You can set a color and a description for every series.
  • Legends (as discussed in MPAndroidChart)
  • Custom labels
  • Manual Y axis limits can be set.

SciChart

It is rich APIs for Axis Ranging, Label Formatting, Chart Modifiers (interaction) and Renderable Series. It is packed with features but unfortunately, it is not open sourced.

The Verdict

Both MPAndroidChart and Graph-View are good libraries, packed with a lot of features. GraphView is easier to implement as compared to MPAndroidChat (not that difficult either). Both of them have the features like pinch zoom. MPAndroidChart had the feature of scale adjustment even when the graph is being plotted. The rate of plotting was comparable in both but it was slightly faster in MPAndroidChart. So, finally GraphView is easier to implement but MPAndroidChart has slightly better performance. So, we integrated MPAndroidChart in PSLab Android application.

Integrating MPAndroidChart in PSLab Android App

In order to integrate MPAndroidChart in the Android project add the following code in the build.gradle of your project.

 

compile 'com.github.PhilJay:MPAndroidChart:v3.0.1'

Creating Oscilloscope like graph

If we observe an Oscilloscope, it has a black/blue screen with grid lines. An oscilloscope is a voltage vs time graph hence the x axis represents the time elapsed and y axis the voltage of the signal at the instant of time. There are left and right y axis for different channels.

An Oscilloscope

In order to implement a graph similar to that of Oscilloscope in PSLab Android App using MPAndroidChart library, the graph needed to be customized.

The following step was taken to customized the graph in Oscilloscope Activity.

Background Color

mChart.setBackgroundColor(Color.BLACK);

This sets the background color of the graph as black. mChart is an object of the Line graph.

Legend

Legend l = mChart.getLegend();
l.setForm(Legend.LegendForm.LINE);
l.setTextColor(Color.WHITE);

Here we are setting the Legend form. There are many options available for the same like SQUARE, CIRCLE, and LINE. We are using LINE Legend form.  Also, we set the white color for the legend text.

X Axis Customization

x = mChart.getXAxis();
x.setTextColor(Color.WHITE);

First, we create an object of XAxis and set the textcolor as white.

x.setDrawGridLines(true);

The above method draws the grid lines along the x axis.

x.setAxisMinimum(0f);
x.setAxisMaximum(875f);

Now we will set the range of x axis by setting minimum value as 0 and the maximum value is 875.

Y Axis  Customization

y1 = mChart.getAxisLeft();
y1.setTextColor(Color.WHITE);
y1.setAxisMaximum(16f);
y1.setAxisMinimum(-16f);
y1.setDrawGridLines(true);

This is similar to what we did in x axis formatting.

After performing the above steps we got the following results.

To follow the entire code for graph customization refer chartinit method in Oscilloscope Activity, PSLab Android repository.

Resources

Continue ReadingComparing Different Graph View Libraries and Integrating Them in PSLab Android Application

Plotting Digital Logic Lines In PSLab Android App

The PSLab device offers the Logic Analyzer functionality. A Logic Analyzer is a laboratory instrument that can capture and display digital signals from a digital system or circuit. It is similar to what an oscilloscope is for analog signals and is used to study timing relationship between different logic lines. It plots the logic lines/timing diagram which tells us the information about the state of the Digital System at any instant of time. For example, in the image below we can study the states of digital signals from channels ID1, ID2, ID3 at different times and find parameters like the propagation delay. It’s also used to find errors in Integrated Circuits (ICs) and debug logic circuits.

How I plotted ideal logic lines using MPAndroid Chart library?

Conventional method of adding data points results in the plot as illustrated in the image below. By conventional method I mean basically adding Y-axis (logic state) values corresponding to X-axis values (timestamp).

Result with normal adding and plotting data-points

In the above plot, logic lines follow non-ideal behaviour i.e they take some time in changing their state from high to low. This non-ideal behaviour of these lines increases when the user zooms in graph to analyse timestamps.

Solution to how we can achieve ideal behaviour of logic lines:

A better solution is to make use of timestamps for generating logic lines i.e time instants at which logic made a transition from HIGH -> LOW or LOW -> HIGH. Lets try to figure out with an example:

Timestamps = { 1, 3, 5, 8, 12 } and initial state is HIGH ( i.e at t = 0, it’s HIGH ). This implies that at t = 1, transition from HIGH to LOW took place so at t = 0, it’s HIGH, t = 1 it’s both HIGH and LOW,  at t = 2 it’s LOW.
Now at t = 0 & t = 2, you can simple put y = 1 and 0 respectively. But how do you add data-point for t = 1. Trick is to see how transition is taking place, if it’s HIGH to LOW then add first 1 for t = 1 and then 0 for t = 1.
So the set of points look something like this:

( Y, X ) ( LOGIC , TIME ) -> ( 1, 0 ) ( 1, 1 ) ( 0, 1) ( 0, 2 ) ( 0, 3 ) ( 1, 3 )  ( 1, 4 ) …

Code snippet for adding coordinates in this fashion:

int[] time = timeStamps.get(j);
for (int i = 0; i < time.length; i++) {
   if (initialState) {
       // Transition from HIGH -> LOW
       tempInput.add(new Entry(time[i], 1));
       tempInput.add(new Entry(time[i], 0));
   } else {
       // Transition from LOW -> HIGH
       tempInput.add(new Entry(time[i], 0));
       tempInput.add(new Entry(time[i], 1));
   }

   // changing state variable
   initialState = !initialState;
}

After adding data-points in above mentioned way, we obtained ideal logic lines successfully as illustrated in the image given below

Resources

Continue ReadingPlotting Digital Logic Lines In PSLab Android App