Analysis Classes - Unified Interface to Analysis Results
MVG comes with a set of analysis classes which provide a unified interface to analysis results irrespective of the specific feature. Note that the analysis classes are helper classes, as such the mvg class does not depend on them.
Except for step (1) requesting the specific feature analysis, the following generic workflow holds:
Request a specific analysis
Retrieve results and parse them into an analysis_class object
Use generic methods like plot(), summary() or to_df()
One application is to use the analysis classes interactively from a Python REPL session.
Or in (pseudo) code
result = parse_results(session.get_analysis_results(request_id)) # call API to get results
result.plot() # plot results
result.summary() # print summary table
df = result.to_df() # convert to DataFrame
result.save_pkl() # save to pickle file
Prerequisites
For running the examples in this notebook:
Installed mvg package
A token for API access from Viking Analytics
The database needs to be populated with our example assets. This can be achieved by running the “Sources and Measurement” example.
Importing the required packages, classes and functions
[1]:
import os
from mvg import MVG, analysis_classes # mvg library with python bindings to mvg-API
from mvg.analysis_classes import parse_results # analysis classes
Create a Session and test API access
Note
Each token is used for Authorization AND Authentication. Thus, each unique token represents a unique user, each user has it own, unique database on the VA-MVG’ service.
You need to insert your token received from Viking Analytics here: Just replace "os.environ['TEST_TOKEN']"
by your token as a string.
[2]:
# Replace by your own Token
TOKEN = os.environ["TEST_TOKEN"] # use our own token
ENDPOINT = "https://api.beta.multiviz.com"
[3]:
session = MVG(ENDPOINT, TOKEN)
session.check_version() # Check if API is accessible
[3]:
{'api_version': '0.3.3',
'mvg_highest_tested_version': '0.3.3',
'mvg_version': '0.12.2'}
Request an analysis
Once the API session is live, we start by checking if the source u0001 we will use is available in the database:
[4]:
SOURCE_ID = "u0001"
session.get_source(SOURCE_ID)
[4]:
{'source_id': 'u0001',
'meta': {'assetId': 'assetJ',
'measPoint': 'mloc01',
'location': 'cancun',
'timezone': 'Europe/Stockholm'},
'properties': {'data_class': 'waveform', 'channels': ['acc']}}
We will now request an analysis (first two lines, uncomment one of them) and wait for the results to become available.
The results as returned will be stored in a dictionary named raw_result
. The raw results are shown in the results cell, mainly to show that they are not optimized for readability or interpretation.
[5]:
# Specifc part : Select one of two analysis here by un/commenting
selected_feature = "KPIDemo"
# selected_feature = "ModeId"
# Generic Part: request analysis and wait for results
analysis_request = session.request_analysis(SOURCE_ID, selected_feature)
print(f"Waiting for {analysis_request}")
session.wait_for_analyses([analysis_request["request_id"]])
# Generic Part: Retrieve unparsed results
raw_result = session.get_analysis_results(analysis_request["request_id"])
Waiting for {'request_id': '9fa506fd651f10b05401840edf9f33cb', 'request_status': 'queued'}
Parse Results
Showing and Browsing the results using analysis_classes
To make the results more accessible, we’ll use the analysis_classes. The parse_results function will take the raw_results of (any) analysis and represent them in a python object with a number of convenience methods for summarising, plotting and exporting. For the full list of provided methods check the documentation.
The parse function will automatically determine the kind (feature) of analysis based on the raw_results. Once the results are parsed, we can summarize them using the summary() method irrespective of which analysis they stem from. To verify this you can rerun the cell above by selecting another feature for the analysis.
Timestamps
The Vibration API requires timestamps to be represented in EPOCH time. To display human interpertable timestamps, one needs a timezone and a time unit (specifying if the timestamps are seconds ‘s’ or milliseconds ‘ms’ from EPOCH). This information can be given in the parse_results calls (2nd and 3rd argument). If they are left blank EPOCH times are kept. When exporting the results to a DataFrame, a column called “datetime” will be appended to show the human interpretable times.
[6]:
# Parse
result = parse_results(raw_result, "Europe/Stockholm", "s")
# result = parse_results(raw_result) # show only raw timestamps
# Show summary
summary = result.summary()
=== KPIDemo ===
request_id 9fa506fd651f10b05401840edf9f33cb
from 20191004-13:01.00 to 20191122-13:01.00
+-------+--------------+------------+------------+-----------------+----------------+--------------------+-------------------+--------------------+
| | timestamps | rms_acc | peak_acc | peak2peak_acc | variance_acc | crest_factor_acc | utilization_acc | dc_component_acc |
|-------+--------------+------------+------------+-----------------+----------------+--------------------+-------------------+--------------------|
| count | 50 | 50 | 50 | 50 | 50 | 50 | 50 | 50 |
| mean | 1.57231e+09 | 0.611691 | 2.81764 | 5.40059 | 0.377299 | 4.62976 | 1 | -0.120874 |
| std | 1.26105e+06 | 0.0565414 | 0.278079 | 0.378225 | 0.0636172 | 0.333367 | 0 | 0.0141936 |
| min | 1.57019e+09 | 0.484564 | 2.26056 | 4.55438 | 0.234802 | 4.12339 | 1 | -0.140524 |
| 25% | 1.57125e+09 | 0.627912 | 2.68338 | 5.31364 | 0.394273 | 4.20402 | 1 | -0.140196 |
| 50% | 1.57231e+09 | 0.628307 | 2.84999 | 5.52634 | 0.39477 | 4.80641 | 1 | -0.112316 |
| 75% | 1.57337e+09 | 0.64684 | 3.06661 | 5.69377 | 0.418402 | 4.89065 | 1 | -0.10966 |
| max | 1.57442e+09 | 0.647694 | 3.13609 | 5.79639 | 0.419507 | 4.99256 | 1 | -0.109065 |
+-------+--------------+------------+------------+-----------------+----------------+--------------------+-------------------+--------------------+
Use Generic Methods
Plotting
For visual representation of the results, there is the ‘plot’ method.
Please not that when plotting the results for the KPIDemo feature, one selects the KPI to be displayed by passing the parameter "kpi"
. If this parameter is not included, the plot function will display the results of the first column after the timestamps, which is the RMS value of the first channel.
[7]:
result.plot()
[7]:
''
Export results to DataFrame
The to_df() method will export results to a DataFrame. Note that the format of the DataFrame depends on the specific analysis and that not all of the results can be represented as a data frame.
[8]:
result.to_df()
[8]:
timestamps | rms_acc | peak_acc | peak2peak_acc | variance_acc | crest_factor_acc | utilization_acc | dc_component_acc | datetime | |
---|---|---|---|---|---|---|---|---|---|
0 | 1570186860 | 0.647086 | 2.686563 | 5.313293 | 0.418720 | 4.151786 | 1 | -0.140237 | 2019-10-04 13:01:00+02:00 |
1 | 1570273260 | 0.647123 | 2.691750 | 5.367004 | 0.418769 | 4.159563 | 1 | -0.140420 | 2019-10-05 13:01:00+02:00 |
2 | 1570359660 | 0.646619 | 2.715251 | 5.414856 | 0.418116 | 4.199152 | 1 | -0.140239 | 2019-10-06 13:01:00+02:00 |
3 | 1570446060 | 0.646873 | 2.685147 | 5.351562 | 0.418445 | 4.150966 | 1 | -0.140347 | 2019-10-07 13:01:00+02:00 |
4 | 1570532460 | 0.646643 | 2.726605 | 5.395325 | 0.418147 | 4.216556 | 1 | -0.140423 | 2019-10-08 13:01:00+02:00 |
5 | 1570618860 | 0.646717 | 2.697001 | 5.310974 | 0.418243 | 4.170294 | 1 | -0.140055 | 2019-10-09 13:01:00+02:00 |
6 | 1570705260 | 0.647093 | 2.711733 | 5.314697 | 0.418729 | 4.190640 | 1 | -0.140505 | 2019-10-10 13:01:00+02:00 |
7 | 1570791660 | 0.647422 | 2.681256 | 5.325928 | 0.419155 | 4.141435 | 1 | -0.140363 | 2019-10-11 13:01:00+02:00 |
8 | 1570878060 | 0.646890 | 2.667379 | 5.271362 | 0.418467 | 4.123387 | 1 | -0.140524 | 2019-10-12 13:01:00+02:00 |
9 | 1570964460 | 0.647694 | 2.678755 | 5.379150 | 0.419507 | 4.169247 | 1 | -0.140486 | 2019-10-13 13:01:00+02:00 |
10 | 1571050860 | 0.647081 | 2.722979 | 5.499878 | 0.418714 | 4.291424 | 1 | -0.139850 | 2019-10-14 13:01:00+02:00 |
11 | 1571137260 | 0.647205 | 2.682736 | 5.299072 | 0.418874 | 4.145110 | 1 | -0.140317 | 2019-10-15 13:01:00+02:00 |
12 | 1571223660 | 0.646743 | 2.682785 | 5.278564 | 0.418276 | 4.148148 | 1 | -0.140365 | 2019-10-16 13:01:00+02:00 |
13 | 1571310060 | 0.647322 | 2.700798 | 5.424622 | 0.419026 | 4.207834 | 1 | -0.140312 | 2019-10-17 13:01:00+02:00 |
14 | 1571396460 | 0.647434 | 2.721002 | 5.374634 | 0.419170 | 4.202750 | 1 | -0.140069 | 2019-10-18 13:01:00+02:00 |
15 | 1571482860 | 0.647621 | 2.738182 | 5.366699 | 0.419413 | 4.228060 | 1 | -0.140403 | 2019-10-19 13:01:00+02:00 |
16 | 1571569260 | 0.647111 | 2.692440 | 5.362610 | 0.418753 | 4.160706 | 1 | -0.140071 | 2019-10-20 13:01:00+02:00 |
17 | 1571655660 | 0.484892 | 2.372010 | 4.607971 | 0.235120 | 4.891831 | 1 | -0.114442 | 2019-10-21 13:01:00+02:00 |
18 | 1571742060 | 0.484841 | 2.273428 | 4.554382 | 0.235071 | 4.704542 | 1 | -0.114736 | 2019-10-22 13:01:00+02:00 |
19 | 1571828460 | 0.484752 | 2.356562 | 4.664490 | 0.234984 | 4.861379 | 1 | -0.114924 | 2019-10-23 13:01:00+02:00 |
20 | 1571914860 | 0.484564 | 2.367471 | 4.701599 | 0.234802 | 4.885779 | 1 | -0.114846 | 2019-10-24 13:01:00+02:00 |
21 | 1572001260 | 0.485001 | 2.260560 | 4.652771 | 0.235226 | 4.932384 | 1 | -0.114624 | 2019-10-25 13:01:00+02:00 |
22 | 1572087660 | 0.485013 | 2.301963 | 4.591980 | 0.235237 | 4.746192 | 1 | -0.114586 | 2019-10-26 13:01:00+02:00 |
23 | 1572177660 | 0.485254 | 2.260858 | 4.618774 | 0.235472 | 4.859134 | 1 | -0.114862 | 2019-10-27 13:01:00+01:00 |
24 | 1572264060 | 0.485157 | 2.336525 | 4.584412 | 0.235377 | 4.816021 | 1 | -0.114540 | 2019-10-28 13:01:00+01:00 |
25 | 1572350460 | 0.627895 | 3.037107 | 5.601013 | 0.394252 | 4.836969 | 1 | -0.109921 | 2019-10-29 13:01:00+01:00 |
26 | 1572436860 | 0.628139 | 3.069790 | 5.720886 | 0.394559 | 4.887119 | 1 | -0.110074 | 2019-10-30 13:01:00+01:00 |
27 | 1572523260 | 0.628308 | 3.103501 | 5.754272 | 0.394771 | 4.939456 | 1 | -0.109604 | 2019-10-31 13:01:00+01:00 |
28 | 1572609660 | 0.628020 | 3.032668 | 5.694519 | 0.394409 | 4.828938 | 1 | -0.109878 | 2019-11-01 13:01:00+01:00 |
29 | 1572696060 | 0.628019 | 2.969318 | 5.649292 | 0.394408 | 4.728068 | 1 | -0.109149 | 2019-11-02 13:01:00+01:00 |
30 | 1572782460 | 0.628283 | 3.029716 | 5.675476 | 0.394740 | 4.822214 | 1 | -0.109794 | 2019-11-03 13:01:00+01:00 |
31 | 1572868860 | 0.628152 | 3.136087 | 5.711792 | 0.394575 | 4.992559 | 1 | -0.109659 | 2019-11-04 13:01:00+01:00 |
32 | 1572955260 | 0.627966 | 3.123363 | 5.723633 | 0.394341 | 4.973780 | 1 | -0.109508 | 2019-11-05 13:01:00+01:00 |
33 | 1573041660 | 0.627735 | 3.047385 | 5.654846 | 0.394052 | 4.854570 | 1 | -0.110191 | 2019-11-06 13:01:00+01:00 |
34 | 1573128060 | 0.627870 | 3.134621 | 5.796387 | 0.394221 | 4.992468 | 1 | -0.109597 | 2019-11-07 13:01:00+01:00 |
35 | 1573214460 | 0.628681 | 3.098128 | 5.695251 | 0.395239 | 4.927984 | 1 | -0.109786 | 2019-11-08 13:01:00+01:00 |
36 | 1573300860 | 0.628127 | 3.069387 | 5.691528 | 0.394543 | 4.886571 | 1 | -0.109670 | 2019-11-09 13:01:00+01:00 |
37 | 1573387260 | 0.628122 | 2.961798 | 5.575195 | 0.394537 | 4.715324 | 1 | -0.110052 | 2019-11-10 13:01:00+01:00 |
38 | 1573473660 | 0.627780 | 3.072126 | 5.696533 | 0.394108 | 4.893636 | 1 | -0.109663 | 2019-11-11 13:01:00+01:00 |
39 | 1573560060 | 0.627846 | 3.011650 | 5.716858 | 0.394191 | 4.796795 | 1 | -0.109611 | 2019-11-12 13:01:00+01:00 |
40 | 1573646460 | 0.628536 | 2.978442 | 5.552795 | 0.395058 | 4.738696 | 1 | -0.109851 | 2019-11-13 13:01:00+01:00 |
41 | 1573732860 | 0.628397 | 3.106778 | 5.705566 | 0.394883 | 4.943972 | 1 | -0.109341 | 2019-11-14 13:01:00+01:00 |
42 | 1573819260 | 0.628307 | 3.093943 | 5.683105 | 0.394769 | 4.924257 | 1 | -0.109263 | 2019-11-15 13:01:00+01:00 |
43 | 1573905660 | 0.628142 | 2.996528 | 5.589905 | 0.394563 | 4.770460 | 1 | -0.109992 | 2019-11-16 13:01:00+01:00 |
44 | 1573992060 | 0.628540 | 3.012680 | 5.602417 | 0.395063 | 4.793137 | 1 | -0.110092 | 2019-11-17 13:01:00+01:00 |
45 | 1574078460 | 0.628118 | 3.103921 | 5.717590 | 0.394532 | 4.941623 | 1 | -0.109658 | 2019-11-18 13:01:00+01:00 |
46 | 1574164860 | 0.628429 | 3.058288 | 5.590271 | 0.394922 | 4.866564 | 1 | -0.109374 | 2019-11-19 13:01:00+01:00 |
47 | 1574251260 | 0.628441 | 3.085465 | 5.767273 | 0.394938 | 4.909715 | 1 | -0.109269 | 2019-11-20 13:01:00+01:00 |
48 | 1574337660 | 0.628601 | 3.049571 | 5.659180 | 0.395139 | 4.851366 | 1 | -0.109081 | 2019-11-21 13:01:00+01:00 |
49 | 1574424060 | 0.627963 | 3.088068 | 5.777344 | 0.394337 | 4.917596 | 1 | -0.109065 | 2019-11-22 13:01:00+01:00 |
Full results
In case the full server results are needed in the raw form they were returned, we can obtain them with the results() method:
[9]:
result.results();
Black Sheep Analysis example
The BlackSheep is a population analysis and has a somewhat different call signature as it requires a number of assets to be submitted to analysis.
[ ]:
# Specific signature for BlackSheep
POPULATION_SOURCES = ["u0001","u0002","u0003","u0004"]
analysis_request = session.request_population_analysis(POPULATION_SOURCES, "BlackSheep", parameters={"atypical_threshold": 0.15})
# Generic part to request analysis, same as above
print(f"Waiting for {analysis_request}")
session.wait_for_analyses([analysis_request["request_id"]])
raw_result = session.get_analysis_results(analysis_request["request_id"])
Waiting for {'request_id': 'e6a0938e5dd9128550f710ad0180d015', 'request_status': 'queued'}
Using the analysis classes
We use exactly the same code as above to inspect the results:
[ ]:
# Parse
blacksheep_result = analysis_classes.parse_results(raw_result, "Europe/Stockholm", "s")
# Show summary
blacksheep_result.summary()
blacksheep_result.plot()
Serializing
Finally, we can save the object including the results to pickle. If no name is given it is saved under the name "<request_id>.pkl"
.
[13]:
blacksheep_result.save_pkl()
Saving BlackSheep object to 9895be09684f27257096bd9d517a9680.pkl
[13]:
'9895be09684f27257096bd9d517a9680.pkl'