Plot a Horizontal Bar Graph using MPAndroidChart Library in SUSI.AI Android App

Graphs and charts provide a visual representation of the data. They provide a clearer and quicker understanding of the impact of certain statistics. Thus, SUSI.AI Android app makes use of bar charts to display statistics related to user ratings for SUSI skills. This blog guides through the steps to create a Horizontal Bar Chart, using MPAndroidChart library, that has been used in the SUSI.AI Android app skill details page to display the five star skill rating by the users.

On vertical axis : Labels of the rating shown
On horizontal axis : Percentage of total number
of users who rated the skill with the corresponding
number of stars on the vertical axis

Step – 1 : Add the required dependencies to your build.gradle.

(a) Project level build.gradle

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

(b) App level build.gradle

dependencies {
    implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
}

 

Step – 2 : Create an XML layout.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
   xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
   android:layout_height="match_parent">

    <!-- Add a Horizontal Bar Chart using MPAndroidChart library -->
    <com.github.mikephil.charting.charts.HorizontalBarChart
       android:id="@+id/skill_rating_chart"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>

 

Step – 3 : Create an Activity and initialize the Horizontal Bar Chart.

class MainActivity : Activity {

   lateinit var skillRatingChart : HorizontalBarChart

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.chart)

       setSkillGraph( )

   }
}

 

Step – 4 : Create a method in your MainActivity to set up the basic properties and the axes.

/**
* Set up the axes along with other necessary details for the horizontal bar chart.
*/
fun setSkillGraph(){
   skillRatingChart = skill_rating_chart              //skill_rating_chart is the id of the XML layout

   skillRatingChart.setDrawBarShadow(false)
   val description = Description()
   description.text = ""
   skillRatingChart.description = description
   skillRatingChart.legend.setEnabled(false)
   skillRatingChart.setPinchZoom(false)
   skillRatingChart.setDrawValueAboveBar(false)

   //Display the axis on the left (contains the labels 1*, 2* and so on)
   val xAxis = skillRatingChart.getXAxis()
   xAxis.setDrawGridLines(false)
   xAxis.setPosition(XAxis.XAxisPosition.BOTTOM)
   xAxis.setEnabled(true)
   xAxis.setDrawAxisLine(false)


   val yLeft = skillRatingChart.axisLeft

//Set the minimum and maximum bar lengths as per the values that they represent
   yLeft.axisMaximum = 100f
   yLeft.axisMinimum = 0f
   yLeft.isEnabled = false

   //Set label count to 5 as we are displaying 5 star rating
   xAxis.setLabelCount(5)

//Now add the labels to be added on the vertical axis
   val values = arrayOf("1 *", "2 *", "3 *", "4 *", "5 *")
   xAxis.valueFormatter = XAxisValueFormatter(values)        

   val yRight = skillRatingChart.axisRight
   yRight.setDrawAxisLine(true)
   yRight.setDrawGridLines(false)
   yRight.isEnabled = false

   //Set bar entries and add necessary formatting
   setGraphData()

   //Add animation to the graph
   skillRatingChart.animateY(2000)
}


Here is the XAxisValueFormatter class that is used to add the custom labels to the vertical axis :

public class XAxisValueFormatter implements IAxisValueFormatter {

   private String[] values;

   public XAxisValueFormatter(String[] values) {
       this.values = values;
   }

   @Override
   public String getFormattedValue(float value, AxisBase axis) {
       // "value" represents the position of the label on the axis (x or y)
       return this.values[(int) value];
   }

}

 

Step – 5 : Set the bar entries.

/**
* Set the bar entries i.e. the percentage of users who rated the skill with
* a certain number of stars.
*
* Set the colors for different bars and the bar width of the bars.
*/
private fun setGraphData() {

   //Add a list of bar entries
   val entries = ArrayList<BarEntry>()
   entries.add(BarEntry(0f, 27f))
   entries.add(BarEntry(1f, 45f))
   entries.add(BarEntry(2f, 65f))
   entries.add(BarEntry(3f, 77f))
   entries.add(BarEntry(4f, 93f))

  //Note : These entries can be replaced by real-time data, say, from an API

  ......

}

 

Step – 6 : Now create a BarDataSet.

To display the data in a bar chart, you need to initialize a
BarDataSet instance. BarDataSet is the Subclass of DataSet class. Now, initialize the BarDataSet and pass the argument as an ArrayList of BarEntry object.

val barDataSet = BarDataSet(entries, "Bar Data Set")

 

Step – 7 : Assign different colors to the bars (as required).

private fun setGraphData() {
    .....

   //Set the colors for bars with first color for 1*, second for 2* and so on
      barDataSet.setColors(
              ContextCompat.getColor(skillRatingChart.context, R.color.md_red_500),
              ContextCompat.getColor(skillRatingChart.context, R.color.md_deep_orange_400),
              ContextCompat.getColor(skillRatingChart.context, R.color.md_yellow_A700),
              ContextCompat.getColor(skillRatingChart.context, R.color.md_green_700),
              ContextCompat.getColor(skillRatingChart.context, R.color.md_indigo_700)

   .....
)


Step – 8 : Populate data into Bar Chart.

To load the data into Bar Chart, you need to initialize a
BarData object  with bardataset. This BarData object is then passed into setData() method to load Bar Chart with data.

//Set bar shadows
   skillRatingChart.setDrawBarShadow(true)
   barDataSet.barShadowColor = Color.argb(40, 150, 150, 150)
   val data = BarData(barDataSet)

   //Set the bar width
   //Note : To increase the spacing between the bars set the value of barWidth to < 1f
   data.barWidth = 0.9f

   //Finally set the data and refresh the graph
   skillRatingChart.data = data
   skillRatingChart.invalidate()
}


Your Horizontal Bar Chart is now ready.
Note: You can format the labels as per your need and requirement with the help of XAxisValueFormatter.

Resources

Continue ReadingPlot a Horizontal Bar Graph using MPAndroidChart Library in SUSI.AI Android App

Use Timber for Logging in SUSI.AI Android App

As per the official GitHub repository of Timber : “Timber is a logger with a small, extensible API which provides utility on top of Android’s normal Log class”. It is a flexible logging library for Android which makes logging a lot more convenient. In this blog you will learn how to use Timber in SUSI.AI Android app.

To begin, add Timber to your build.gradle and refresh your gradle dependencies.

implementation 'com.jakewharton.timber:timber:4.7.0’


Two easy steps to use Timber:

  1. Install any Tree instances that you want in the onCreate() of your application class.
  2. Call Timber’s static methods everywhere throughout the app.

You can add the following code to your application class :

@Override
   public void onCreate() {
       super.onCreate();

       …..
        
       if (BuildConfig.DEBUG) {
           Timber.plant(new Timber.DebugTree() {
               //Add the line number to the tag
               @Override
               protected String createStackElementTag(StackTraceElement element) {
                   return super.createStackElementTag(element) + ": " + element.getLineNumber();
               }
           });
       } else {
           //Release mode
           Timber.plant(new ReleaseLogTree());
       }
   }

   private static class ReleaseLogTree extends Timber.Tree {

       @Override
       protected void log(int priority, String tag, @NonNull String message,  
                                     Throwable throwable) {
           if (priority == Log.DEBUG || priority == Log.VERBOSE || priority == Log.INFO) {                           
               return;
           }

           if (priority == Log.ERROR) {
               if (throwable == null) {
                   Timber.e(message);
               } else {
                   Timber.e(throwable, message);
               }
           }
       }
   }


Timber ships with a ‘Debug Tree’ that provides all the basic facilities that you are very used to in the common Android.log framework. Timber has all the logging levels that are used in the normal Android logging framework which are as follows:

        • Log.e: Use this tag in places like inside a catch statement where you are aware that an error has occurred and therefore you’re logging an error.
        • Log.w: Use this to log stuff you didn’t expect to happen but isn’t necessarily an error.
        • Log.i: Use this to post useful information to the log. For instance, a message that you have successfully connected to a server.
        • Log.d: Use this for debugging purposes. For instance, if you want to print out a bunch of messages so that you can log the exact flow of your program or if you want to keep a log of variable values.
        • Log.v: Use this if, for some reason, you need to log every little thing in a particular part of your app.
        • Log.wtf: Use this when you encounter a terrible failure.

       

    • You can use Timber.e, Timber.w, Timber.i, Timber.d and Timber.v respectively for the logging levels mentioned above. However, there is a small difference. In Android logging framework the exception is passed as the last parameter. But, when using Timber, you need to provide the exception as the first parameter. Interestingly, while using Timber you don’t have to provide a TAG in logging calls because it automatically does that for you. It uses the file name, where you are logging from, as the TAG. To log an exception you can simply write:
    • Timber.e(exception, "Message");
      
    • Or a null message if you want:
    • Timber.e(exception, null);
      
    • A simple message can be logged sent via Crashlytics too:
    • Timber.e("An error message");
      

Did you notice? There is no TAG parameter. It is automatically assigned as the caller class’ name. Now, you can use Timber for logging in SUSI Android app.

Resources

 

Continue ReadingUse Timber for Logging in SUSI.AI Android App

Hosting SUSI.AI Web Chat on Firebase

“I often wonder if my smartphone or laptop could become a bit smarter… And, I could talk to it the way I talk to my best friend… Wouldn’t that be cool if I could customise my phone’s assistant and enhance its ‘personality’ whenever I want? Or maybe ‘teach it a little more than others to make its intelligence outshine other students in its class?’ Well, that’s what we aim to achieve in the name of SUSI.AI”

Currently, SUSI.AI is in its growing stage and a number of dedicated developers have been working hard to achieve an open source alternative to existing personal assistants like Google Assistant, Alexa and so on. Each one of them has been focussing on improving existing features or introducing new ones.

This blog focuses on hosting the SUSI Webchat using Firebase Hosting. It presents the proper sequence of steps that need to be followed to deploy the web chat on Firebase Hosting.

What is Firebase Hosting?

Firebase Hosting provides fast and secure static hosting for web app. It is a  production-grade web content hosting for developers. With Hosting, one can quickly and easily deploy web apps and static content to a global content-delivery network (CDN) with a single command.

Hosting gives a project a subdomain on the ‘firebaseapp.com’ domain. Using the Firebase CLI, the files can be deployed from local directories on a computer to the Hosting server. Files are served over an SSL connection from the closest edge server on the global CDN.

Steps :

  • Install the Firebase CLI

    The Firebase CLI (Command Line Interface) requires Node.js and npm, which can both be installed by following the instructions on https://nodejs.org/. Installing Node.js also installs npm.

    Note : The Firebase CLI requires Node.js version 5.10.0 or greater.

Once Node.js and npm have been installed, install the Firebase CLI via npm:

$ npm install -g firebase-tools


This installs the globally available
firebase command. To update to the latest version, simply re-run the same command.

Now login to the Firebase console using

$ firebase login

 

  • Initialize the app

Choose the Firebase app that you would like to deploy and then cd into the project directory and run the command:

$ firebase init


Once this command runs, you would be prompted to choose from the following options :

Database: Deploy Firebase Realtime Database Rules
Firestore: Deploy rules and create indexes for Firestore
Functions: Configure and deploy Cloud Functions
Hosting: Configure and deploy Firebase Hosting sites
Storage: Deploy Cloud Storage security rules

Choose Hosting (use the cursor keys to move the pointer to ‘Hosting’ and then select it by pressing Spacebar key followed by the Enter key).

Now, you would be prompted to select a project from the Firebase console that you would like to associate with the web chat. You can create a new project by logging into the Firebase console from a web browser and then follow the steps below :

1) If you don’t have an existing Firebase project, click ‘Add Project’ and enter either an existing Google Cloud Platform project name or a new project name.

2) If you already have apps in your project, click ‘Add Another App’ from the project overview page.

Running the $ firebase init command creates a firebase.json settings file in the root of your project directory.

  • Add a file

    When you initialise the app, you will be prompted for a directory to use as the public root (default is “public”). You can choose to give it some other name as well, say “build”. This is the directory in which the static content would be hosted. If you don’t already have a valid index.html file in your public root directory, one is created for you.

Note : When a new index.html file is created, it contains the default content. You need to run the following commands to customise it according to your requirements and to display the content that you want to.

$ npm install
$ npm run build


If you skip running these commands, on deploying you will see a dialog box, by default, that would direct you to the Firebase Hosting Documentation.

Test on Local Server

Now you can run the $ firebase serve command to test your web app on a local server. Once, everything looks fine, you can proceed to the next step.

  • Deploy the web app on Firebase

    To deploy the web app, simply run:
$ firebase deploy

 

Your app will be deployed to the domain
<OUR-FIREBASE-APP>.firebaseapp.com

Manage and Rollback Deploys

From the Hosting panel in the Firebase Console you can see a full history of your deploys. To rollback to a previous deploy, hover over its entry in the list, click the overflow menu icon, then click “Rollback”.
Now your app is ready to share with the world! 😀

Check out a video created by me, showing the above mentioned steps : Click here

Resources

Continue ReadingHosting SUSI.AI Web Chat on Firebase