Skip to main content

Automate your reporting

As we all know, writing reports is boring and updating is a repetitive cycle that nevtheer ends... That is why VIKTOR lets you connect a report template so that every time you change input values, the report can automatically be generated.

Set up the app template

When you start creating a new app the first thing you need to do is to create an app template. The steps depend on the installation method you chose before. Please select the correct tab before you continue.

  1. You will need a code editor to write the code of your app. Download and install a code editor if you don't have one installed on your computer. We recommend using VS Code or PyCharm.

  2. Create a new folder on your computer that you will use to store the code of your app (e.g. C:\Users\<username>\viktor-apps\my-app).

  3. Open your code editor and open the folder you just created in the previous step. Select the correct tab below and see how to do this in the code editor of your choice.

  1. Open a terminal in your code editor:

    Inside that terminal enter the following command to generate the necessary app files and hit enter:

    viktor-cli create-app --app-type editor
    viktor-cli not recognized

    If you activated your account, continued with the starter guide and installed a code editor in the same session you might encounter the following error:

    viktor-cli : The term 'viktor-cli' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path 
    is correct and try again.
    At line:1 char:1
    + viktor-cli
    + ~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (viktor-cli:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    You can solve this error by closing and restarting your code editor. After doing so you can run the command without any problems. The problem is caused because your code editor inherits the environment variables of the process that launched it and because you installed the VIKTOR CLI in the same session it requires a restart to be recognized properly.

  2. Install the app and its dependencies and connect it to the VIKTOR platform by using the following command in the terminal:

    viktor-cli clean-start

    Running this command can take a few minutes. When the installation is complete you will see the following lines printed in the terminal. This means that the app is connected to the VIKTOR platform.

    INFO    :  __      __ __  __  __
    INFO : \ \ / / | | | |/ /
    INFO : \ \ / / | | | ' /
    INFO : \ \/ / | | | <
    INFO : \ / | | | . \
    INFO : \/ |_| |_|\_\
    INFO : _______ ____ _____
    INFO : |__ __| / __ \ | __ \
    INFO : | | | | | | | |__) |
    INFO : | | | | | | | _ /
    INFO : | | | |__| | | | \ \
    INFO : |_| \____/ |_| \_\
    INFO : VIKTOR connector vX.Y.Z
    INFO : VIKTOR SDK vX.Y.Z
    INFO : Connecting to platform...
    INFO : Connection is established: <URL> <---- here you can see your app
    INFO : The connection can be closed using Ctrl+C
    INFO : App is ready

    Do not close the terminal as this will break the connection with your app.

App.py structure explained

Restarting your app
  • The app will update automatically after adding your code and saving the app.py file, as long as you don't close the terminal.
  • Did you close your code editor or the terminal inside your editor? Use viktor-cli start to start the app again. No need to run the install and clear commands.
  • Once your app is started you will be able to interact with it in your Development workspace

Open the app.py file in your code editor. This is where you will write the code of your app. The content should look like this:

from viktor import ViktorController
from viktor.parametrization import ViktorParametrization


class Parametrization(ViktorParametrization):
pass


class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

The app.py file consists of 3 parts:

  1. Imports: this is where you import Python modules you use in your app.
  2. Parametrization: this is where you define the inputs of your app.
  3. Controller: this is where you define the outputs (such as visualizations) and logic of your app.

Add additional imports

To complete this task you will need some additional imports. Copy and paste the imports at the top of the app.py file.

from pathlib import Path

from viktor.external.word import render_word_file, WordFileTag
from viktor.utils import convert_word_to_pdf
from viktor.views import PDFResult, PDFView
from viktor.parametrization import TextField, DateField, Text
Result

The resulting app.py will look like this. You can use the snippet below to check your code.

from pathlib import Path

from viktor.external.word import render_word_file, WordFileTag
from viktor.utils import convert_word_to_pdf
from viktor.views import PDFResult, PDFView
from viktor.parametrization import TextField, DateField, Text
from viktor import ViktorController
from viktor.parametrization import ViktorParametrization



class Parametrization(ViktorParametrization):
pass


class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

Define the input fields

For the sake of this tutorial, we will keep it simple and automate the addition of the name and date to the report from within the VIKTOR app. The possibilities do not end there, with VIKTOR's reporting capabilities you can add schematics, tables, images, and more all from the results of the calculations within your app.

Let's begin by adding some parameters that we want to add to our report. First we will use the Text class to indicate that this part of the input fields is dedicated to automatic reporting. Then we will use a TextField and a DateField for user input. You only need to replace the pass statement with the highlighted lines of code.

class Parametrization(ViktorParametrization):
text_report = Text('## Report inputs')
user_name = TextField('Your name')
project_date = DateField('Choose a project date')
Result

The resulting app.py will look like this. You can use the snippet below to check your code.

from pathlib import Path

from viktor.external.word import render_word_file, WordFileTag
from viktor.utils import convert_word_to_pdf
from viktor.views import PDFResult, PDFView
from viktor.parametrization import TextField, DateField, Text
from viktor import ViktorController
from viktor.parametrization import ViktorParametrization


class Parametrization(ViktorParametrization):
text_report = Text('## Report inputs')
user_name = TextField('Your name')
project_date = DateField('Choose a project date')


class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

Save the app.py file. This action triggers a reload of your app. This reload is shown in the terminal. If you made a mistake any errors will also be printed in the terminal.

INFO    : Reloading app...
INFO : App is ready

At this point you must be wondering what the app looks like. The Development workspace is where you can see and use the resulting app. Switch to VIKTOR in your browser. If you continued with this starter guide immediately after activating your account you have been automatically redirected into your Development workspace. In that case simply refresh the browser to see your app. If this is not the case you can open the Development workspace by clicking the open button as you can see in the image below:

After you have entered the development workspace and refresh the page you should see the input fields appear:

Add a PDF preview

The next step is to make sure we can preview the report in the app. For this we will use the PDFView, which can be used to visualize PDFs. Feel free to copy the highlighted lines of code template into your Controller class from below:

class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

@PDFView("Report", duration_guess=10)
def starter_guide_report(self, params, **kwargs):
components = []
return PDFResult()
Result

The resulting app.py will look like this. You can use the snippet below to check your code.

from pathlib import Path

from viktor.external.word import render_word_file, WordFileTag
from viktor.utils import convert_word_to_pdf
from viktor.views import PDFResult, PDFView
from viktor.parametrization import TextField, DateField, Text
from viktor import ViktorController
from viktor.parametrization import ViktorParametrization


class Parametrization(ViktorParametrization):
text_report = Text('## Report inputs')
user_name = TextField('Your name')
project_date = DateField('Choose a project date')


class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

@PDFView("Report", duration_guess=10)
def starter_guide_report(self, params, **kwargs):
components = []
return PDFResult()

Generate the report

The next step is to connect a template which we can fill, to our app. For this tutorial you can download this template and add it to your app folder. The app folder's structure should now look like this:

viktor-demo
├── tests
├── app.py
├── CHANGELOG.md
├── README.md
├── report_template.docx
├── requirements.txt
└── viktor.config.toml

If you open the template, you will notice some parts are placed in double curly brackets. These are the tags that we need to connect to the parameters that we made earlier.

To connect these tags we will make a Python list with WordFileTag components. Here we will need to make sure that the name of each tag is exactly the same as in the Word file. The inputs defined on the Parametrization are passed to the PDFView method with the params argument. For example, to use the name of the user you reference it by its variable name params.user_name. You only need to add or change the highlighted lines of code.

class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

@PDFView("Report", duration_guess=10)
def starter_guide_report(self, params, **kwargs):
components = [
WordFileTag("user_name", params.user_name),
WordFileTag("project_date", str(params.project_date))
]
return PDFResult()
Result

The resulting app.py will look like this. You can use the snippet below to check your code.

from pathlib import Path

from viktor.external.word import render_word_file, WordFileTag
from viktor.utils import convert_word_to_pdf
from viktor.views import PDFResult, PDFView
from viktor.parametrization import TextField, DateField, Text
from viktor import ViktorController
from viktor.parametrization import ViktorParametrization


class Parametrization(ViktorParametrization):
text_report = Text('## Report inputs')
user_name = TextField('Your name')
project_date = DateField('Choose a project date')


class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

@PDFView("Report", duration_guess=10)
def starter_guide_report(self, params, **kwargs):
components = [
WordFileTag("user_name", params.user_name),
WordFileTag("project_date", str(params.project_date))
]
return PDFResult()

Now that we have our report's tags matched with our parameters, let's combine them to automate the reporting process. We will refer to the template using its file path. Then we will render the template together with the components and finally convert it to a PDF file which we can display in our VIKTOR app. The final result should look something like the code snippet below. You only need to add the highlighted lines of code.

class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

@PDFView("Report", duration_guess=10)
def starter_guide_report(self, params, **kwargs):
components = [
WordFileTag("user_name", params.user_name),
WordFileTag("project_date", str(params.project_date))
]

# Get path to template and render word file
template_path = Path(__file__).parent / "report_template.docx"
with open(template_path, 'rb') as template:
word_file = render_word_file(template, components)

# Convert to PDF
with word_file.open_binary() as f:
pdf_file = convert_word_to_pdf(f)

return PDFResult(file=pdf_file)
Result

The resulting app.py will look like this. You can use the snippet below to check your code.

from pathlib import Path

from viktor.external.word import render_word_file, WordFileTag
from viktor.utils import convert_word_to_pdf
from viktor.views import PDFResult, PDFView
from viktor.parametrization import TextField, DateField, Text
from viktor import ViktorController
from viktor.parametrization import ViktorParametrization


class Parametrization(ViktorParametrization):
text_report = Text('## Report inputs')
user_name = TextField('Your name')
project_date = DateField('Choose a project date')


class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

@PDFView("Report", duration_guess=10)
def starter_guide_report(self, params, **kwargs):
components = [
WordFileTag("user_name", params.user_name),
WordFileTag("project_date", str(params.project_date))
]

# Get path to template and render word file
template_path = Path(__file__).parent / "report_template.docx"
with open(template_path, 'rb') as template:
word_file = render_word_file(template, components)

# Convert to PDF
with word_file.open_binary() as f:
pdf_file = convert_word_to_pdf(f)

return PDFResult(file=pdf_file)

Save the app.py file. Go to your Development workspace in the browser and refresh the page. If you fill in the user name and date and click the update button on the bottom right of the PDFView you should see the following:

As you can see the name and date appear in the report. Like we mentioned at the beginning, this is only the basics of reporting and there are so many things you can automate. If you want to start learning more about what you can do with reporting, feel free to try out the full tutorial.

Continue the next section or come back tomorrow to spread the workload!