- [Instructor] For our last application
demonstrating IoT pub/sub capabilities,
we're going to go back to working with the PubNub service.
And in this case we're going to take advantage
of their pubnub module, which is a Python module
for interacting with the PubNub service.
And we're going to be using that
to visualize data from their simulated Market Orders stream.
And that Market Orders stream has fake stock information
for several different companies.
Now, you can also use the pubnub module to publish messages
through the PubNub service.
We don't cover that here,
but this link shows you the documentation
for the pubnub Python SDK.
And it describes both, subscribing to existing streams,
and creating your owns streams to publish messages as well.
In order to use the pubnub module
you will need to install it.
So, this is the installation command.
And we've provided a stocklistener.py file, or script,
that is going to subscribe
to that simulated Market Orders stream,
and visualize the stock prices as they change in a bar plot.
Now, the PubNub client that we're going to be working with
is going to give us back JSON objects
in the form of Python dictionaries,
and we'll extract the information we need from that,
and then go ahead and visualize that data.
Now, before we actually get into
the source code for this application,
let's run our script and demonstrate it in action.
So, we set up this script
with the command-line argument that specifies
the total number of messages you wish to receive
from the PubNub service.
So we'll just do 1,000 for demonstration purposes here.
And as you'll see in a moment,
it will pop open a matplotlib window
with a seaborn bar plot.
And as the stock prices are coming in,
we're displaying the name of the company
and the current stock price at the command line,
but we're also updating a dictionary in memory,
and that dictionary's data is being used
to visualize the stock prices here
in the context of the bar plot.
So, the coloring of the bar plot
is not important in this case,
it's just for visual effect.
But the nice thing that we're getting here
is the dynamic, animated presentation of how those values
are changing with respect to one another.
And notice, by the way, that the y-axis is auto-scaling
based on the current values of all the different stocks.
So, the top end of the y-axis is always going to have to do
with the value of the stock
that has the current highest price.
This is the PubNub webpage
for their simulated Market Orders stream.
And as you can see when you go to this webpage,
it is going to show you
simulated prices changing over time here.
And if we go and scroll down further on the page,
you'll see that it tells you the name
of the channel that you need to use,
and the subscription key that you need to use.
And we'll need both of those in our source code in a moment.
And it also shows you the format
of the JavaScript Object Notation objects
that represent each message.
So, every message we receive has these five keys in it,
but we're actually only going to take advantage,
in this app, of the symbol, and the bid price
so that we can visualize the stock price changes
as they occur.
So now that we've seen the animation,
let's take a look at the script
that implements the animation.
Now, we've seen these imports
in lines three through seven previously.
Lines nine through 12 import the various types
that we're going to need from the pubnub module.
The first type here is a class
that we'll be creating a subclass of
to listen for messages from PubNub.
We'll get two different kinds of messages from PubNub
in this example.
Administrative messages that have a constant
in this PNStatusCategory type,
and also messages from the live stream itself.
We'll use the PNConfiguration object
to specify the subscription key
that's required for connecting to a stream
in the context of PubNub.
And the PubNub client will not only be used
to register a listener
for all the different messages that we'll receive,
but also to subscribe to the stream
to start the flow of messages into our app.
Now, this list right here
contains the names of the five different companies
we'll be receiving from the simulated Market Orders stream.
And we use that list to help create a data-frame here,
where we'll store the names of the companies,
and their most recent stock price in each case.
So, we're using a dictionary to initialize this data frame.
And remember, when you use a dictionary
the keys become the column names,
and the values associated with those keys
are used to populate the rows within a given column.
So, the company column will have the names
of all the companies that we defined up above.
And the price column will initially have zeros
for each of those companies.
Now, the most important piece in this example
is our subclass of SubscribeCallback.
In that subclass, we've defined an __init__ method,
which is going to receive the data frame
containing the names of the companies
and their current stock prices.
And we'll keep updating that as we receive messages.
And limit=1000, this is the total number of messages
we wish to receive before we unsubscribe from the stream
in this demonstration example.
We store the data frame and keep track of the order count,
because we need to be able to check
whether we've reached the maximum number of orders as well.
Now, we've overwritten two different methods
in our subclass.
One is the status method,
which will receive administrative messages
from the PubNub service.
And we're looking in this example
for two different status messages.
You'll notice that the status object
we receive as a parameter has a category attribute.
And that category attribute will be one of the constants
in the PNStatusCategory type.
So if we get this type of category,
that means we've subscribed to a stream.
And if we get this one it means that we've unsubscribed.
And in each case, we'll display a message
at the command line.
This is the key method for receiving messages
from the live stream itself.
It receives the client object, the pubnub client object,
and the the particular message from the stream.
Within that message parameter
there is a dictionary called message
that has the dictionary representation
of the JSON object that was sent to us.
And within that JSON object there's a symbol key
and a bid_price key, as well as several other keys.
We only need these two in this example.
So, the symbol and bid_price are captured
and then displayed at the command line.
Then we update at the particular row and column
within our data frame, the bid_price.
So, you'll notice we figure out the symbol's row
by passing it to the data frame's index method,
which looks for that symbol in the index,
and then figures out the current row,
or the appropriate row.
And based on that, we update the corresponding column
with that bid_price.
We also add one to the order count.
And if we've reached the maximum number of orders,
we tell the PubNub client to unsubscribe
from all the different streams that we subscribed to.
In this example, there's only one channel
that we will subscribe to, the Market Orders live stream.
So, if we had multiples,
this would unsubscribe from all of them.
And of course, they also give you the ability
to unsubscribe from one as well.
Our update method just defines
what's going to be displayed
in every frame of the animation.
And we've done similar things to this multiple times now.
But just as a reminder, this clears the current bar plot
from the figure object, from the axes.
cla stands for clear axes.
This creates a new bar plot
with the current data from the companies data frame,
using the x-axis to plot the companies,
and the y-axis to plot the prices.
Then we set the x and y labels.
And we use a tight_layout
to make sure that everything fits nicely
within the figure window.
And then finally, we have the main part of our application,
in which we set the background of our seaborn plot.
We create the window
in which the animation will be displayed.
We configure the animation,
which we've done a number of times previously,
but again, remember, it requires the figure object
that specifies where to display the animation frames,
and the method to call
to create those animation frames as well.
This version of plt.show, with the block=False argument,
says to display the window,
but don't block and wait for that window to be closed.
Move on to the next statement in the example, in this case.
And we'll call plt.show again later
to keep the window on the screen.
config, we create the PNConfiguration object.
That's where we store the subscription key.
And in this case,
we did put the subscription key directly into our code,
but that's not normally what we would do.
The only reason we chose to do that here
is because this is a public key
that they publish on their website
for you to play around with
and learn about streaming with PubNub.
We,
can create, excuse me, the PubNub client object,
by passing the configuration
into the constructor for the PubNub client.
Once we have the pubnub object,
we register a listener of our StockListener type,
giving it the data frame that specifies
the location in which we'll update the stock prices.
And separately, the total number of orders to listen to,
and we get that as a command line argument.
And if it's not a correct command line argument,
we'll use the number 1,000 by default.
So, the last step is to actually subscribe to the channel.
And as you can see here,
we call the pubnub client's subscribe method,
and then we access the resulting object's channels method
to specify the name of the channel we wish to subscribe to.
And this, again, was published on the PubNub page.
And then we call execute,
at which point we now subscribe to the channel
and begin receiving messages.
Now, if we did not have this last call to plt.show,
the program would actually terminate
and the window would simply go away.
In this case, calling show with no arguments
keeps that window on the screen,
and that's what enables you to see the animation.