Single-Stage App: Area Calculator¶
Note
Estimated Time: 30 min
Pre-Requisites
- Sucessfully completed the Getting-Started section
- Have an App Collection stored on your machine
- Have a basic understanding of how the Compute platform works
- Basic understanding of Python
Useful Links
Introduction¶
Welcome to the first tutorial of our platform! In this example, you'll learn how to create a simple application that calculates the area of geometric shapes—specifically rectangles and circles. This app will also showcase how you can import external assets, such as images, to make your app more engaging.
This tutorial is divided into the following sections:
- 1. Setting Up the App
- 2. Adding Inputs for a Rectangle
- 3. Implementing the Area Calculation
- 4. Adding Inputs and Calculation for a Circle
- 5. Enhancing the App with Text and Images
What you'll Learn¶
- Create User Inputs: Add input fields where users can enter the dimensions of shapes, such as the length and width for rectangles and the diameter for circles.
- Implement Calculations: Write calculations to compute the area of the selected shape.
- Enhance the User Interface: Incorporate images and text elements to create a user-friendly interface.
- Use Control Flow: Utilize Python control flow statements to make the app dynamic, showing different inputs, equations, and images depending on whether the user selects a rectangle or a circle.
Note
In this tutorial we'll be setting up everything from scratch in order to explain each step more clearly. However, you'll probably want to use the code of an already existing app as a starting point when building new apps.
1. Setting Up the App¶
Create the App Directory¶
By now, you should have an App Collection directory on your machine. If you don't, please follow the steps here to create one.
First, navigate to the apps
directory of your collection:
C:\Users\<your-username>/<name-of-app-collection>/apps
Next, create a new directory named sample_area_calculation
. Inside this directory, create an
empty .py
file named sample_area_calculation.py
— this will be our app file. Create a subdirectory
called resources
to store images used in the app. And finally, create the app_meta.yaml
and README.md
files.
The final directory structure should look like this:
<name-of-app-collection>/
├── apps/
│ ├── training_boilerplate/
│ │ ├── app_meta.yaml
│ │ ├── README.md
│ │ └── training_boilerplate.py
│ └── sample_area_calculation/
│ ├── app_meta.yaml
│ ├── README.md
│ ├── sample_area_calculation.py
│ └── resources/
├── typings/
└── collection_requirements.yaml
Add the App's Metadata¶
Add the following two files to the root directory of the app to set the app's metadata. This information will be available in the App Details section of the app's page. Click here to learn more about these files.
app_meta.yaml
¶
app_title: Area Calculation Rectangle or Circle
discipline: Training
subcategory:
- Generic
app_status: Verified
reviewers:
- None
authors:
- None
is_multi_stage: false
README.md
¶
# Area Calculation Rectangle or Circle
Calculates the area of either a rectangle of a circle.
Tip
Use the README.md
file
to present users of the app with more information - its features, assumptions, how to use the app, etc. It'll then
be rendered nicely in Markdown!
Code the App's Skeleton¶
First, import the stub files from the typings
directory. This step is optional but highly recommended for
code auto-completion in your editor. Add the following line at the top of your sample_area_calculation.py
file:
from v0_0_1.compute_core.app_imports.basic_imports import * # type: ignore
Next, create a class inheriting from AppStageCompute
. In the class's constructor, call the parent class
constructor to initialize internal variables of the app:
class SampleAreaCalculation(AppStageCompute):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Finally, add the three AppStageCompute
(1) execution methods with empty bodies:
- If you want to know more about these execution methods, please check this article
def register_parameters(self):
...
def build_parameters(self):
...
def build_report(self):
...
The complete app's skeleton should look like this:
from v0_0_1.compute_core.app_imports.basic_imports import * # type: ignore
class SampleAreaCalculation(AppStageCompute):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def register_parameters(self):
...
def build_parameters(self):
...
def build_report(self):
...
Understanding App Execution Flow
To learn more about how an app is processed under the hood and the execution order of the different
AppStageCompute
methods, check this article.
Add the App to the Collection Requirements¶
To load the app in the App Builder, you need to add it to the collection_requirements.yaml
file.
Add the following entry to the file:
- app_dir: sample_area_calculation
entry_module: sample_area_calculation
entry_class: SampleAreaCalculation
In the Compute.build Engine, go to the App Building tab and select your app's class name from the
Entry App dropdown menu. If you used the same name as this tutorial, it should appear as SampleAreaCalculation
.
Troubleshooting
If the app's class doesn't appear in the dropdown menu, try clicking on the Refresh Folder button to reload the collection. This is also useful when you change the app's class name.
You can now go to the App Builder in compute.build and start building the app! It should look empty since haven't added anything yet:
Also, check the App Details tab to see the app's metadata:
2. Adding Inputs for a Rectangle¶
Registering the Input Parameters¶
Let's begin by defining the two inputs necessary to compute the area of a rectangle:
- Width of the rectangle
- Length of the rectangle
First, register these inputs within the register_parameters
method. We can add primitive inputs
(basic data types like int
, float
, string
, or bool
) using the input_parameter
method with
appropriate UI elements.
The complete register_parameters
method should look like this:
def register_parameters(self):
self.input_parameter(
var_name='width',
fullname='Width of rectangle',
bind_ui=UiNumberInput(min_val=10, max_val=1000, step=1.0, default=100),
)
self.input_parameter(
var_name='length',
fullname='Length of rectangle',
bind_ui=UiRange(min_val=10, max_val=1000, step=1.0, default=200),
)
In this example, both inputs are numerical, so we use UiNumberInput
and UiRange
UI elements.
We set constraints like minimum and maximum values, step size, and default values.
Registering parameters
The inputs registered within register_parameters
are not immediately rendered in the UI.
Instead, they're mainly used to define the Parameters section of the App Details, which is helpful when
calling this app within another app.
Exposing the Input Parameters¶
To display the registered inputs in the UI, you need to expose them within the build_parameters
method using
expose_parameter
:
def build_parameters(self):
self.expose_parameter(var_name="width")
self.expose_parameter(var_name="length")
Exposing parameters makes them available in the app's memory, allowing you to use them in calculations and retrieve them as Python variables.
After clicking the INIT UI button in the App Builder, the input parameters should appear:
3. Implementing the Area Calculation¶
Now that we have our inputs, let's add the area calculation for our rectangle using the width
and length
parameters.
In the build_report
method, use the add_calc
method to add a calculation. We'll use the equation
argument to
define the calculation, as it renders nicely in mathematical format in the platform and reports.
def build_report(self):
self.add_calc(
var_name='A',
fullname='Area of the shape',
equation="{width} * {length}",
)
Using Equations
When using the equation
argument, you can include parameters by surrounding their var_name
with curly braces,
like {width}
.
To compute the area, press the Compute button in the platform:
4. Adding Inputs and Calculation for a Circle¶
Currently, our app calculates the area of a rectangle. Let's extend it to also calculate the area of a circle.
Inputs for a circle¶
To compute the area of a circle we need one additional input parameter:
- Diameter of the circle
First, register the new input and then expose it in build_parameters
:
def register_parameters(self):
...
self.input_parameter(
var_name='diameter',
fullname='Diameter of Circle',
bind_ui=UiRange(min_val=10, max_val=1000, step=1.0, default=200),
)
def build_parameters(self):
...
self.expose_parameter("diameter")
If you refresh the UI, you'll see all three inputs. However, displaying inputs for both shapes simultaneously may confuse users. Let's make the app dynamic by adding an option for the user to select the shape and then show the appropriate inputs.
Add a boolean UI element to let the user choose between a rectangle and a circle:
def register_parameters(self):
self.input_parameter(
var_name='is_rectangle',
fullname='Is the object rectangle?',
bind_ui=UiBoolean(flavour='checkbox', default=True),
)
...
def build_parameters(self):
self.expose_parameter(var_name="is_rectangle")
...
By retrieving the value of is_rectangle
using get_result
, we can control which parameters to expose to the user.
The updated build_parameters
section should look something like this:
def build_parameters(self):
self.expose_parameter(var_name="is_rectangle")
_is_rectangle = self.get_result("is_rectangle")
if _is_rectangle:
self.expose_parameter(var_name="width")
self.expose_parameter(var_name="length")
else:
self.expose_parameter(var_name="diameter")
The app should now include a toggle that dynamically changes the displayed inputs:
Calculate the Area of a Circle¶
We want a single calculation named A
that adjusts based on the selected shape:
- Rectangle:
is_rectangle=True
rectangle_equation="{width} * {length}"
- Circle:
is_rectangle=False
circle_equation="(math.pi * {diameter}**2) / 4"
Update the build_report
method to include both equations and select the appropriate one based on _is_rectangle
:
def build_report(self):
_is_rectangle = self.get_result('is_rectangle')
square_equation = '{width}*{length}'
circle_equation = '(math.pi * {diameter}**2) / 4'
equation = square_equation if _is_rectangle else circle_equation
self.add_calc(
var_name='A',
fullname='Area of the shape',
equation=equation,
)
Using math
from the standard library
You can use any method from Python's standard math
library in equations, like math.pi
.
Now, when you run the computation, the correct equation will be used based on the selected shape:
Success! We have now a functional version of our app. Let's spice it up with some text and image elements.
5. Enhancing the App with Text and Images¶
Adding Instructions¶
To improve user experience, let's add some instructions using the add_text
method in the build_parameters
method:
def build_parameters(self):
self.add_text('''
# Area calculator instructions
1. please choose whether you want to calculate the area of a rectangle
or a circle by selecting or not the `is the object rectangle` checkbox.
2. choose the values for the shape input parameters.
3. click on "compute" to calculate the area of the chosen shape.
''')
...
Formatting Multi-line Strings
When using multi-line strings, start the content on a new line to avoid formatting issues in Markdown rendering.
After refreshing the UI, the instructions should appear:
Adding Images¶
Let's include diagrams for both shapes to make the app more informative.
- Rectangle Diagram
- Circle diagram
Save both images in the resources
directory of your app.
Next, update the collection_requirements.yaml
file to include these static files:
- app_dir: sample_area_calculation
entry_module: sample_area_calculation
entry_class: SampleAreaCalculation
local_imports:
static_files:
- resources.legend_rectangle.png
- resources.legend_circle.png
Specifying File Paths
In local_imports
, the path to the file must be specified from the app's root folder using dotted notation.
For example, resources.legend_rectangle.png
.
Now, add the images to your app using the add_image
method:
def build_parameters(self):
...
self.expose_parameter(var_name="is_rectangle")
_is_rectangle = self.get_result("is_rectangle")
image_filepath = "resources/legend_rectangle.png" if _is_rectangle else "resources/legend_circle.png"
image_caption = "Rectangle diagram" if _is_rectangle else "Circle diagram"
shape_image = CbImage(filepath=image_filepath,
image_renderer=ImageRenderExpandable(),
var_name="shape_diagram",
image_width=300,
image_caption=image_caption,
visible=False)
self.add_image(shape_image)
...
The images should now be displayed in the User Input section:
Hiding Inputs from the Report¶
To make the Detailed Output section less cluttered, you can hide input elements by setting visible=False
when
registering parameters:
def register_parameters(self):
...
self.input_parameter(
var_name='diameter',
fullname='Diameter of Circle',
bind_ui=UiRange(min_val=10, max_val=1000, step=1.0, default=200),
visible=False
)
Visibility and Print Report
Setting visible=False
will also hide the parameter in the Print Report.
After setting visible=False
for inputs, text, and images, the final app page should look like this:
The complete app code¶
Below is the full code for the app:
from v0_0_1.compute_core.app_imports.basic_imports import * # type: ignore
class SampleAreaCalculation(AppStageCompute):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def register_parameters(self):
self.input_parameter(
var_name='is_rectangle',
fullname='Is the object rectangle?',
bind_ui=UiBoolean(flavour='checkbox', default=True),
visible=False
)
self.input_parameter(
var_name='width',
fullname='Width of rectangle',
bind_ui=UiNumberInput(min_val=10, max_val=1000,
step=1.0, default=100),
visible=False
)
self.input_parameter(
var_name='length',
fullname='Length of rectangle',
bind_ui=UiRange(min_val=10, max_val=1000, step=1.0, default=200),
visible=False
)
self.input_parameter(
var_name='diameter',
fullname='Diameter of Circle',
bind_ui=UiRange(min_val=10, max_val=1000, step=1.0, default=200),
visible=False
)
def build_parameters(self):
self.add_text('''
# Area calculator instructions
1. please choose whether you want to calculate the area of a rectangle
or a circle by selecting or not the `is the object rectangle` checkbox.
2. choose the values for the shape input parameters.
3. click on "compute" to calculate the area of the chosen shape.
''',
visible=False
)
self.expose_parameter(var_name="is_rectangle")
_is_rectangle = self.get_result("is_rectangle")
image_filepath = "resources/legend_rectangle.png" if _is_rectangle else "resources/legend_circle.png"
image_caption = "Rectangle diagram" if _is_rectangle else "Circle diagram"
shape_image = CbImage(filepath=image_filepath,
image_renderer=ImageRenderExpandable(),
var_name="shape_diagram",
image_width=300,
image_caption=image_caption,
visible=False)
self.add_image(shape_image)
if _is_rectangle:
self.expose_parameter(var_name="width")
self.expose_parameter(var_name="length")
else:
self.expose_parameter(var_name="diameter")
def build_report(self):
_is_rectangle = self.get_result('is_rectangle')
square_equation = '{width}*{length}'
circle_equation = '(math.pi * {diameter}**2) / 4'
equation = square_equation if _is_rectangle else circle_equation
self.add_calc(
var_name='A',
fullname='Area of the shape',
equation=equation,
)
Wrapping up¶
Fantastic job! You've learned the essentials of building a Compute.build application, including:
- Adding inputs and calculations
- Retrieving data during execution
- Enhancing the user interface with images and text
You're now ready to create and share powerful applications that automate repetitive tasks.
If you enjoyed this tutorial and want to explore more, we recommend following the Volume of a Box Tutorial, which demonstrates how to execute apps within other apps.
Happy coding!