How to convert a Python Project to a VIKTOR app
Level: Beginners
Time: 30 min
Prerequisites:
- You have some experience with reading Python code
- You have completed the installation and onboarding process of the VIKTOR platform
- You have a Python project or script that you would like to convert to a VIKTOR app
Introduction
Most Python projects start off with a simple script to help with a task, whether it is for automating or calculation purposes. These scripts can evolve into valuable tools that can have value far beyond your own use.
In general, what keeps these scripts from being utilized by others is that it often does not have a user-friendly way of being operated (for example an intuitive interface), it generally requires an extensive user manual, and that distribution is nearly impossible, as these scripts almost always require a set of dependencies that need to be installed, not mentioning the rights that need to be allocated to the user to be able to install these programs and packages.
The VIKTOR platform allows one to overcome these challenges by providing a platform, SDK and integration possibilities. In this piece we will provide a guide to easily convert your script into a VIKTOR web application, which will allow others to also share the value that you created, without the bottlenecks usually encountered.
In this guide, we will explore how to convert your Python project to a VIKTOR app. We will cover:
By the end of this guide, you will have a clear understanding how to convert your Python project to a VIKTOR app.
If you do not have a suitable Python script, consider writing something that you are familiar with such as a basic plot. This will remove the chance of knowledge gaps that you would have if you are given a script and allows you to focus on the VIKTOR elements.
Throughout the guide, we added some links with additional information; but don't let them distract you too much. Stay focused on understanding the content. After this, you will know everything you need to convert your Python project to an app.
Where to start
For the sake of this guide it is important to understand the fundamentals and typical layout of a VIKTOR app. These fundamentals are, however, elaborated upon earlier during the VIKTOR onboarding. So, if you want to directly get started in the steps to convert your script to an app, skip to the Let’s convert your script!!
VIKTOR framework fundamentals
As the goal with this guide is to help you convert your script to a VIKTOR app, it is helpful to understand the fundamentals that make up the VIKTOR framework. In an attempt to give the clearest overview of the fundamentals, without oversimplifying, let us start with what we believe a good starting point is in understanding the VIKTOR framework. There are three aspects that are important to keep in mind when converting your script to an app, which are:
- Input: The variables that can be adjusted for a calculation
- Results: Results can either be presented visually or downloaded in a given file format.
- Stateless and containerized calculation: A stateless calculation’s outcomes are not influenced by previous events, except if part of the calculation’s outcome is to alter the input (which will then alter the outcome of the next calculation). A deployed app also runs in isolation, which is what is meant by being containerized.
These three points are important to remember when considering converting a script to a VIKTOR application.
VIKTOR code layout
Now that we know how VIKTOR’s framework fundamentally works, let us look at an example of a VIKTOR app to explain a typical VIKTOR app code layout:
Be aware that this is just an example to explain the fundamentals from a code’s perspective, and that the VIKTOR platform provides an endless number of possibilities.
Noting above’s example, let us try to connect the fundamentals to this example.
Input
As a fundamental, the VIKTOR platform forces the developer to determine what the input variables of the calculation
should be. This is done by defining all input parameters in the Parametrization
class. There is an extensive amount of
input, so this should not limit the developer. Refer to the User input, fields and buttons
section in the documentation for a clear overview of the possibilities.
Results
Whether the result of the calculation is a visualization of sorts or a download, this is a result of a method that is
defined in the Controller
class. A download is simply a file of bytes or strings, so any format can be downloaded. For
visualizations, the following is possible:
- Images (PNG, JPEG, SVG, GIF): these formats need to be saved to memory by using
BytesIO
,StringIO
or VIKTOR’sFile
- Maps
- 3D geometries (any object that can be converted to a glb/gltf format, or by using the primitive geometries available in the VIKTOR SDK)
- PDFs
- Any result in HTML
- Plotly
Refer to the Results and visualizations section in the documentation to read up more on this.
Stateless calculation
Any method that produces a result, presents a visualization, or produces a download must contain some logic. This logic
can be defined directly in the method, split up into different methods, or defined in functions or classes in other
files or directories within the app project. The requirement is that the code is written in such a way that the input
provided (which can be retrieved from the params
argument of the Controller
class) always produces the same result
when the input remains unchanged.
In the event where a stateful event is wanted, the VIKTOR platform provides a Storage
capability that allows developers
to write data to a storage database that can be retrieved for the next calculation.
Containerized calculation
As the intent of building a web app is to run it on a server rather than locally, the app with all its logic and files needs to be able to run in an isolated environment. Therefore, one needs to make sure that the entire development is done within the project folder, and that, when referring to files and folders, that these paths are referenced relatively.
Other things to consider…
- If your code is written such that files are written to your local drive, it is suggested to convert this to saving the
file to memory, or to use the VIKTOR SDK
Storage
functionality to store the file to a database. - If the Python code uses system dependencies or software that cannot be installed using
pip install
, we suggest using the integrations we provide. Or rewrite your code to use code that does not require these dependencies.
Let’s convert your script!
Now that we know the VIKTOR platform from fundamentals, and we have an idea how the code structure works for a VIKTOR application, let’s take that knowledge to convert a script to a VIKTOR application.
Take the following steps:
1. Create a VIKTOR app project.
To create a new VIKTOR application project, use the viktor-cli
to generate a project file structure automatically.
The command to use is:
viktor-cli create-app –-app-type editor <name-of-your-project>
2. Collect all requirements of the python script.
A good place to start would be to collect a list of all the python packages that are being used in the script. Some examples of frequently used Python packages are:
- Numpy
- Scipy
- Matplotlib
- Pandas
- Etc.
Add these packages to the requirements.txt
file.
If the Python script only works for a given Python version, make sure to indicate this in the viktor.config.toml
file.
3. Convert script to a function.
A script can be converted to a VIKTOR app in many ways. One of the simpler ways of converting a script would be to
rewrite the code such that it can run by calling a single function. This would entail you only need to consider what
should be the result of the calculation, and then make sure that the result that you want to produce is returned by the
function. E.g. if the result of the code is to produce a matplotlib plot, return a matplotlib figure, or if the result
is a pandas dataframe, return that. If your code writes a file to a local drive, rewrite the code such that it returns
the file as an object saved to memory, e.g. BytesIO
, StringIO
or File
.
4. Create a view/download in the VIKTOR Controller
In this step we will create a view or download functionality that can be seen in the interface of the VIKTOR app. Here are the steps:
To use the newly created function in your VIKTOR app, import the function into the app.py
file where the bare-bones
VIKTOR app code structure resides.
Depending on whether you would like to create a download functionality or visualization, follow the steps described in the subsection:
4.1 Download
Here are the steps for a download functionality:
- Create a download button: In the
Parametrization
, create a field with aDownloadButton
, similar to the code snippet presented below:
import viktor as vkt
class Parametrization(vkt.Parametrization):
download_btn = vkt.DownloadButton('Download file', method='download_file')
- In the
Controller
, create a method with the same name as defined in themethod
argument (in the given example,download_file
). Here is an example how this would look like:
import viktor as vkt
class Controller(vkt.Controller):
parametrization = Parametrization
def download_file(self, params, **kwargs):
return vkt.DownloadResult(file_content='', file_name='my_file.txt')
- Add your function to the method. The
file_content
that the VIKTOR platform expects is either string, bytes,File
orBytesIO
. Therefore, make sure to convert the type produced by the function if it does not suit any of the given types.
import viktor as vkt
from .my_project import my_function # assuming that your function is within another file
# Assuming that your function is within this project
def my_function():
...
return
class Controller(vkt.Controller):
parametrization = Parametrization
def download_file(self, params, **kwargs):
result = my_function()
return vkt.DownloadResult(file_content=result, file_name='my_file.txt')
4.2 Visualization
Here are the steps for a visualization:
- Determine what type of visualization you want to create from the result of your function.
- In the
Controller
, create a method with your name of choice. The result to be returned by the method is dependent on the type of visualization. - Add a decorator to your method that suits your visualization.
- Add your function to the method. Depending on the View, the result may differ. Therefore, make sure to check the documentation for that given view, and convert the type produced by the function to the format that is expected.
Here is an example of the result of the four steps:
import viktor as vkt
from .my_project import my_function # assuming that your function is within another file
# Assuming that your function is within this project
def my_function():
...
return
class Controller(vkt.Controller):
parametrization = Parametrization
@vkt.WebView("My View")
def create_plot(self, params, **kwargs):
my_result = my_function()
return vkt.WebResult(my_result)
Here is a table overview of the steps, with the possible options:
Steps | Image | Map | 3D Geometry | HTML | Plotly | |
---|---|---|---|---|---|---|
1. Determine type of visualization | This could be static plots such as Matplotlib, Seaborn, etc. or other type of images. | GeoJSONs or locations that can be visualized on a map | Any type of geometry that can be converted to glb/gltf, or some simple parameters that can be converted to simple VIKTOR geometries. | Word and Excel files can be converted to PDFs within VIKTOR! | HTML or URLs can be imbedded. | Plotly is a Python package with which you can create dynamic plots. |
2. Create method with correct return type | ImageResult | MapResult or GeoJSONResult | GeometryResult | PDFResult | WebResult | PlotlyResult |
3. Add decorator to your method | ImageView | MapView or GeoJSONView | GeometryView | PDFView | WebView | PlotlyView |
4. Add your function to the method. | BytesIO for PNG, JPG/JPEG and GIF, StringIO for SVG | MapView : a list of VIKTOR map objects GeoJSONView : a GeoJSON dict | This could either be a VIKTOR Group object, consisting of VIKTOR primitive Geometry objects, or... a glTF/GLB or 3DM file as a VIKTOR File ojbect | You could reference a PDF from a URL, a path, or, probably the most common one, as a VIKTOR File | The HTML could be retrieved from a URL, static file as a path, or as an HTML string | A Plotly JSON using the .to_json method on the Plotly Figure object |
If all went well, you will now have an application that displays the result of your function.
5. Create fields as input for calculation.
We’ve created a visualization, but ideally, we would like to make the app dynamic based on input. To do this, the following steps can be followed:
- Start by determining which variables you would like the user of the app to change. Add these variables as input to the function you’ve created from your script.
- Add fields to the parametrization that correspond with these variables. For example, if there are three variables
named
a
,b
andc
that can be adjusted, we can add these fields to theParametrization
as well:
Variable | Type | Field |
---|---|---|
a | Float | NumberField |
b | Options of strings | OptionField |
c | File | FileField |
Etc. |
class Parametrization(vkt.Parametrization):
a = vkt.NumberField('a')
b = vkt.OptionField('b', options=['apple', 'pear', 'lemon'])
c = vkt.FileField('Upload file')
- Add the parameters to the function. You may have noticed that the methods defined in the
Controller
have aparams
argument. You can access the parameters from that variable. Here is an example:
import viktor as vkt
from .my_project import my_function # assuming that your function is within another file
# Assuming that your function is within this project
def my_function(a, b, c):
...
return
class Controller(vkt.Controller):
parametrization = Parametrization
@vkt.WebView("My View")
def create_plot(self, params, **kwargs):
result = my_function(
a=params.a,
b=params.b,
c=params.c
)
return vkt.WebResult(result)
What's next?
And that's it! By following these steps, one should be able to convert a Python script to a VIKTOR app in no time.
The VIKTOR platform provides much, much more in terms of functionalities and features. Therefore, if you want to explore the possibilities to improve your app, consider consulting the documentation. Topics that are of great interest to developers are:
There are also resources other than the documentation available that could help in the app development journey, such as: