Visualizing time series data in Vue.js

Demonstrates the use of Vue.js, vue-chartjs and Chart.js to plot the simple moving average data I am pulling from AWS AppSync.

Introduction

This is the fifth of a series of posts describing my experimentation with Vue.js, AWS AppSync, Lambda and other technologies. A public GitHub repository exists with this experiment so others can learn from my efforts. For this post, I will be describing the code that resides on the v3 tag, so feel free to checkout to this point in time: git checkout v3. Links to the other posts in this series can be found in the first post.

In the first three posts for this Invest Guru endeavor, I built up a simple GraphQL API that uses AWS AppSync to host a GraphQL API and AWS Lambda and the Python 3.7 runtime to implement a simple resolver for handling a simple moving average query. I use the excellent Alpha Vantage API to source the simple moving average data for a specific company. I have demonstrated that the GraphQL query works by exercising it from Prisma’s GraphQL Playground.

In the fourth post, I started working on the front-end, building out a Vue.js web application that will consume the GraphQL API and present the data to the user in various presentations. I will continue to build out this Vue.js-based web application in this post. I’ll be enlisting the help of Chart.js and vue-chartjs to help me plot the simple moving average data that we are consuming from the back-end. So let’s get to it!

Implementation

Add chart.js and vue-chartjs dependencies

I’ll be using Chart.js and vue.chartjs to plot datasets in the browser. Chart.js is a simple charting library that uses the Canvas API in HTML5. Chart.js has good animation support and is fairly easy to get up and running with. I will also be using vue-chartjs to facilitate the hassle-free integration of Chart.js into Vue.js. The vue-chartjs library abstracts the basic functionality of Chart.js so you can get up and running quickly, but also exposes the Chart.js object to give you maximal flexibility as you grow into more advanced uses of Chart.js. Execute the following to add the two dependencies to the Vue.js project:yarn add chart.js vue-chartjs

SimpleMovingAverageChart.js

Now to create our first chart component, the SimpleMovingAverageChart. I created this component in the src/components/charts/SimpleMovingAverageChart.js file.

You will notice that I am not using a Single File Component here for the Vue.js component. The integration between Vue.js and Chart.js is much more low-level. The DOM template that would typically be included in a Single File Component cannot be used with these Vue.js/Chart.js components. The vue-chartjs documentation talks a little bit about this here. I just avoided Single File Components here so that I would not be lulled into trying to use a template with one of these types of components.

The vue-chartjs integration provides a base chart, Line, that I am extending. The renderChart function is provided by the Line chart component. It accepts two object parameters, which are detailed in the Chart.js documentation. The first parameter is the chart datasets, and the second parameter is the general options for the chart. I’m also using the reactiveProp mixin to provide live updating of the chart when the dataset changes. This is something that the vue-chartjs integration provides and is documented here.

SimpleMovingAverageChartContainer.vue

Next up is our chart container component, the SimpleMovingAverageChartContainer. I created this component in the src/components/charts/SimpleMovingAverageChartContainer.js file.

The chart container is a bit more involved — it has the responsibility of querying AWS AppSync for the simple moving average analytic data and transforming that data into datasets that Chart.js will render. Let’s run through this source code listing and highlight some of the interesting things happening here.

In the <template> section of the Single File Component, I am rendering the chart if, and only if, the data has been loaded. Otherwise I’ll render a loading message. I should probably also render errors up there, but I’ll save that for another day.

Dropping down into the <script> section, I have a single required prop (lines 22–27) that I expose for obtaining the company symbol that I will use to make the GraphQL query.

The data object (lines 28–35) contains data for managing the chart container and the chart datasets. You can see the chartData and options properties here will be used as prop values for the chart itself. The chartData property is interesting here, as it is initially set to null and will be generated once Apollo Client/AppSync Client return the results of the GraphQL query.

In the methods object, I have a single method, buildChartDataSets, that I am using in the Apollo result callback to transform the GraphQL response into something that Chart.js can render. I’m taking the last 30 observations of the 50 day and 300 day simple moving average observations lists and determining that they match the date of the observation (there is a chance that a 50 day observation does not have a matching 300 day observation). If they match, I add the observations to the appropriate dataset array and add the date of the observation to the labels array. Lines 64–88 is creating a Chart.js chartData object that contains the datasets, label, and rendering options for the line charts. The rendering options for the Line chart can be found here in the Chart.js documentation.

Lines 91–110 are the Apollo Client/AppSync Client apollo object. This object effectively wires up the GraphQL query, simpleMovingAverageAnalyticQuery, to this container component. We are binding the symbol property value from the container component to the variables object for Apollo (lines 94–98). I’m setting the fetch-policy here to cache-and-network, which you can read more about fetch policies here. Apollo Client will check the cache first to determine if the result of the query is cached and will only go across the network when the cache does not contain a result for that particular query (including variables).

I have an error property function here, but it’s just logging any errors to the JavaScript console. This property function could set data on the component and display some user-friendly message to the user in the <template> section.

Home.vue

The Home view component changes to the following:

Most of this is self-explanatory. The symbol property in the data object hard-codes a value. This will change in subsequent posts, but it works for our straw man implementation for now. The apollo object that was here in the fourth post has migrated to the SimpleMovingAverageChartContainer component that we previous saw.

Results

The resultant line chart for the 50-day and 300-day simple moving averages analytic for Microsoft (MSFT) is below:

Line chart rendering the past 30 days of observation of 50-day and 300-day simple moving averages

Conclusion

This concludes our straw man implementation of a serverless GraphQL back-end using AWS AppSync and Lambda and a front-end using Vue.js. I will continue to add new features and posts, so I hope that you continue to follow on with my journey. I have added a GitHub Project to this repository to collect potential features that I will be building out to evolve Invest Guru into something that is usable.