At the most foundational level, Apps are comprised of Steps, which can be thought of as the primary components that enable a flow to run within an App.
For example, in an App, if a user runs a flow that consists of (1) connecting to a database to retrieve a dataset, (2) performing a series of operations on the dataset, and (3) generating a report with the processed data, that App will have been written to include three Steps.
Steps (operations run on the backend) map directly to Pages (what a user sees) in the Virtualitics AI Platform (VAIP). On the technical side, Steps are defined by their run() method.
The run() method is called to prepare Elements that will be used to populate the Page associated with a given Step.
Refer to the Virtualitics SDK for more information on run().
Related Article:
Exploring Steps
Analytic workflows are often logically deconstructed into multiple steps. In the same way, Apps may be logically deconstructed and organized into Steps in the VAIP.
Here are a few things to keep in mind:
- It is not possible to write an App without Steps. An App must contain at least one Step.
- Both backend and frontend operations may be included in Steps.
- Steps add interactivity and allow users to run Apps without staring at a blank screen wondering what is happening in the background.
- Steps can simplify debugging during the App-writing process.
- It is common practice in software development to break code into smaller units (classes, functions) that are easier to test (e.g., with unit testing).
- In the same way, it’s easier to identify where errors are coming from if an App is split into multiple aptly-named Steps.
Here is an example of how Steps may be used in an App:
- You are a machine learning (ML) engineer working for a company that provides a subscription service.
- You have been tasked with developing an App in which you predict the likelihood that a subscriber will churn (i.e., cancel their membership).
- Your App will be used by those with ML expertise (data scientists, machine learning engineers, etc.) and without (customer retention specialists, business analysts, etc.)
- In this App, you must:
- Connect to multiple databases (and allow a user to specify query parameters),
- Merge data from each database (and allow a user to inspect the merged dataset),
- Train a machine learning model to predict churn likelihood (but allow a user to specify what hyperparameters to use in the ML model),
- Generate a report highlighting the performance of your model on historical data (and allow a user to download the report with a single click),
- Generate a list of subscribers who are most at risk to churn (also downloadable with a single click), and
- Provide interactive tools to allow customer retention specialists to probe your ML model (which requires access to your trained model and embedded AI tools).
- Each bullet in the preceding section should be implemented as a Step within the App.
- Both backend and frontend operations can be contained in each Step.
- Without Steps, it would not be possible to present steps within the workflow in consumable parts. Presumably, implementing the workflow in a single step would be challenging to develop and test.
Create a Step
In these articles, the Hello World tutorial App is used to provide context for the code being used. For a more high-level runthrough of the code in Hello World, see this article. For more detailed technical documentation, see the Virtualitics SDK.
To Create a Step in an App, ensure you have first imported all of the necessary classes. Then, for this example, we’ll create a Data Upload Step, for your users to upload relevant data from a local source. This will be the first Step that a user experiences as part of going through a flow when running this App.
After your imports, begin your Data Upload Step by creating a Class:
# This step has the user upload the dataset we'll be using
class DataUpload(Step):
dataset_name = "SP 500 Dataset"
def run(self, flow_metadata):
# Get store_interface and then current page and section
store_interface = StoreInterface(**flow_metadata)
page = store_interface.get_page()
section = page.get_section_by_title("")
Within the Step class, you'll create layouts using Sections and Cards and define all of the key elements that a user will interact with.
Step Types
When creating Steps, you will also need to select a StepType. There are four different types of Steps for users to choose from:
- INPUT: A Step should be of type Input if it contains Input Elements.
- DASHBOARD: Marking steps as Dashboard Steps helps them be easily found in the Dashboards section in the Navigation Bar.
- RESULTS: If a Step contains neither Inputs or Dashboards, it should be a Results Step.
- DATA_LAB: A Step for data manipulation.
For example, if you have two Cards titled “Executive Dashboard Plots” and “Operational Dashboard Plots” on the same Step with StepType set to DASHBOARD, that Step will appear as two tabs at the top of the Page, as shown below:
Adding Multiple Steps
To add multiple Steps to an App, once you’ve built out the Page, Sections, Cards, and Elements of your first Step, simply create a new Class with your new Step as the next part of your code.
In the Hello World App, the second Step begins with:
# This step allows the user to specify query parameters for our data before analysis
# It references the data uploaded in the previous step to set selection boundaries for the query parameters
class DataQuery(Step):
def run(self, flow_metadata):
# Get store_interface and current page
store_interface = StoreInterface(**flow_metadata)
page = store_interface.get_page()
From here, the Page, Section, Card, and Elements are added in the code to complete the second Step.
Building Your Steps
Once you have finished building your Step classes for each of the Steps in your App, including any associated Pages, Sections, Cards, and Elements, you’ll need to actually build the Steps themselves. To do so, you’ll add this code (taken from the Hello World tutorial App):
# Build data upload step
data_upload_section = Section("", [])
data_upload_page = Page(
"Getting Data Into the Platform", [data_upload_section]
)
data_upload_step = DataUpload(
title="Data Upload",
description="Upload the S&P 500 data.",
parent="Inputs",
type=StepType.INPUT,
page=data_upload_page,
)
# Build query step
data_query_section = Section("", [])
data_query_page = Page(
"Additional Inputs and Parameters", [data_query_section]
)
data_query_step = DataQuery(
title="Additional Inputs",
description="Build data query.",
parent="Inputs",
type=StepType.INPUT,
page=data_query_page,
)
# Build data visualization step
data_visualization_content = Section("", [])
data_visualization_page = Page(
"Displaying Analytics through Page Elements",
[data_visualization_content],
)
data_visualization_step = DataVisualization(
title="Displaying Analytics through Page Elements",
description="Show time-series of Dataset and perform preprocessing steps.",
parent="Analytics and Page Elements",
type=StepType.RESULTS,
page=data_visualization_page,
)
# Build additional elements step
additional_elements_content = Section("", [])
additional_elements_page = Page(
"Displaying Analytics through Page Elements",
[data_visualization_content],
)
additional_elements_step = CreateAdditionalElements(
title="Additional Elements and Events",
description="Create additional elements for demonstration.",
parent="Analytics and Page Elements",
type=StepType.RESULTS,
page=additional_elements_page,
)
# Build asset saving step
save_assets_content = Section("", [])
save_assets_page = Page("Saving Assets", [save_assets_content])
save_assets_step = SaveAssets(
title="Saving Assets",
description="Read data from prior step and save as asset.",
parent="Analytics and Page Elements",
type=StepType.INPUT,
page=save_assets_page,
)