Table of Contents
- Introduction
- What is QWML?
- QWML Syntax
- Syntax Chart
- Input Tags
- Conditional Logic
- Iterative Constructs
- Document Structure
- Initializing a Template
- Layout Customization
-
Document Structure in Templates
- Features
- Conditional Formatting
- Calculations
- Default Values
- Use Cases and Examples
-
Custom Worksheets Overview
- Custom Reports Overview
-
- Advanced Use Cases
-
Batch-Level Summary
-
Regulatory Report
-
-
Combining Layout and Logic
-
Best Practices for QWML Design
- Common Errors and Troubleshooting
- Glossary of Terms
- Conclusion
1. Introduction
QBench Worksheet Markup Language (QWML) is a flexible and powerful tool for creating dynamic, interactive worksheets within QBench. QWML simplifies the process of generating custom worksheets in QBench by offering a templating language with a familiar Python-like syntax. These templates can be created directly in the QBench editor or any external text editor and imported into QBench. It allows labs to transform static data entry processes into intelligent, reusable templates for workflows such as sample management and batch testing.
QBench enables users to design Custom Worksheets and Custom Reports for advanced data handling and presentation. These tools cater to complex requirements that surpass the capabilities of the Visual Editor. Leveraging QBench Worksheet Markup Language (QWML) and Jinja2 templating, users can build sophisticated, reusable templates. This guide provides a structured breakdown of QWML, with clear explanations, practical examples, and best practices to help you harness its potential.
What is QWML?
Purpose:
QWML allows users to configure electronic worksheets by embedding dynamic input fields and logic directly into templates. These worksheets are integrated into assays, enabling efficient data collection and real-time calculations.
Core Features:
- Dynamic Inputs: Fields such as text, dropdowns, and calculations.
- Conditional Logic: Display fields or values based on specific criteria.
- Iteration: Automatically populate fields for multiple related items, such as tests or samples.
2. QWML Syntax
The breakdown includes elements used in QWML templates, including standard HTML tags (like <p>), Jinja-specific constructs, and other formatting or functional elements.
Element |
Type |
Description |
Example Syntax |
Key Attributes/Notes |
<p> |
HTML Tag |
Paragraph tag for adding textual content in templates. |
<p>This is a paragraph</p> |
Supports inline styles like style="color:red;" |
<table> |
HTML Tag |
Creates a table structure. Used for organizing data into rows and columns. |
<table border="1">...</table> |
Combine with <tr> (rows) and <td> (columns). |
<th> |
HTML Tag |
Defines a header cell in a table. |
<th>Header</th> |
Typically styled differently (e.g., bold). |
<tr> |
HTML Tag |
Defines a row in a table. |
<tr><td>Data</td></tr> |
Rows must contain <td> or <th>. |
<td> |
HTML Tag |
Defines a cell in a table row. |
<td>Cell Content</td> |
Supports inline styles for layout. |
<span> |
HTML Tag |
Inline container for styling or grouping text without breaking lines. |
<span style="color:blue;">Text</span> |
Use for lightweight formatting. |
<br> |
HTML Tag |
Inserts a line break. |
<br> |
Self-closing. |
{% for ... %} |
Jinja Loop |
Iterates over a list or dictionary to dynamically generate elements. |
{% for sample in batch.samples %} |
Must end with {% endfor %}. |
{% if ... %} |
Jinja Conditional |
Adds logic-based rendering to templates. |
{% if sample.status == "Approved" %} |
Must end with {% endif %}. |
__() |
QWML Input Tag |
Defines a dynamic input field for data entry. |
__(input, field_name)__ |
Customizable with attributes like default. |
{{ ... }} |
Jinja Variable Tag |
Inserts a variable’s value into the template. |
{{ sample.name }} |
Case-sensitive; supports filters like ` |
Inline Styles |
HTML Attribute |
Adds CSS styling directly to elements for customization. |
<p style="color:red;">Text</p> |
Recommended for small adjustments. |
CSS Classes |
HTML Attribute |
Defines styles for an element via classes defined in a stylesheet. |
<div class="header">Content</div> |
Add reusability to template styling. |
<strong> |
HTML Tag |
Emphasizes text, typically displayed as bold. |
<strong>Bold Text</strong> |
Semantic alternative to <b>. |
<em> |
HTML Tag |
Emphasizes text, typically displayed as italic. |
<em>Italic Text</em> |
Semantic alternative to <i>. |
Comment |
Jinja/HTML Syntax |
Adds a comment that is ignored during rendering. |
{# Comment #} |
Use Jinja {# ... #} or HTML <!-- ... -->. |
Static Data |
QWML Tag |
Displays static data from QBench objects. |
__(static, sample_name)__ |
Read-only. |
Dynamic Input |
QWML Tag |
Creates interactive data entry fields linked to QBench schema. |
__(input, test_value)__ |
Customizable attributes like required. |
Calculations |
QWML Tag |
Computes values dynamically based on formulas. |
__(calculation, total, formula="x+y")__ |
Supports basic mathematical expressions. |
Key Notes:
-
HTML Tags: Provide structure and formatting. Ensure consistent styling by using inline styles or referencing CSS classes.
-
QWML Tags: Focus on dynamic data interaction. Attributes like default, required, or formula add functionality.
-
Jinja Constructs: Allow conditional logic and iteration, making templates dynamic and reusable.
-
Inline Styles vs. CSS Classes: Prefer classes for scalable and reusable designs; use inline styles sparingly for quick adjustments.
Input Tags
Input tags define data entry fields and are customizable with attributes such as required, default_value, and increment_by. Below are the key input types:
Input Type | Description | Example Syntax |
input | Single-line text input | __(input, field_name)__ |
textarea | Multi-line text input | __(textarea, comments)__ |
checkbox | Toggleable checkbox | __(checkbox, approval)__ |
select | Dropdown menu | __(select, options, default="Yes")__ |
calculation | Read-only field for computed values | __(calculation, total_score)__ |
static | Displays data from other QBench fields | __(static, sample_name)__ |
Conditional Logic
QWML supports condition-based rendering and input validation using Jinja2's if statements. For example:
{% if sample.status == "Approved" %}
<span>Status: Approved</span>
{% else %}
<span>Status: Pending</span>
{% endif %}
Iterative Constructs (foreach)
Dynamic generation of input fields for associated data (e.g., samples in a batch) can be achieved using foreach. Example:
{% for test in batch.tests %}
__(input, test.id, default="0")__
{% endfor %}
3. Document Structure
QWML templates are designed using a flexible syntax that supports both layout and logic. Every template should follow a clear structure to ensure usability.
Example: Basic Layout
<h1>Batch Worksheet</h1>
<p>Batch ID: {{ batch.id }}</p>
Breakdown:
- Title: Indicates the worksheet purpose.
- Dynamic Field: {% batch.id %} pulls the batch ID.
Initializing a Template
A basic QWML template starts with Jinja2 variable definitions and structural elements. Example:
{% set batch_id = batch.id %}
<table>
<tr><th>Batch ID</th><td>{{ batch_id }}</td></tr>
</table>
Layout Customization
Layouts can include tables, headers, and styled elements:
<table border="1">
<tr>
<th>Sample Name</th>
<th>Result</th>
</tr>
{% for sample in batch.samples %}
<tr>
<td>{{ sample.name }}</td>
<td>__(input, result_{{ sample.id }})__</td>
</tr>
{% endfor %}
</table>
4. Features
Conditional Formatting
Highlight values based on conditions:
<td style="{% if value > threshold %}background-color:red;{% endif %}">{{ value }}</td>
Calculations
Perform inline calculations:
__(calculation, total, formula="field_1 + field_2")__
a. Conditional Fields
Conditional fields dynamically change values or visibility based on input or system data.
__(condition,pass_condition,result >= 50,true_value='Pass',false_value='Fail')__
Why This Matters:
- Efficiency: Automatically displays "Pass" or "Fail" based on a threshold.
- Readability: Reduces manual interpretation errors.
b. Iterative Fields
Dynamic generation of inputs for related items, like samples in a batch.
__(foreach,sample_input,sample.name,sample.value)__
How It Works:
- foreach iterates over a list (e.g., samples).
- Generates individual inputs for each item dynamically.
Dynamic Input Fields (Worksheets)
Example: Dropdown with Options
__(select,dropdown_1,options=['Pass','Fail','Pending'])__
Explanation:
- Creates a dropdown field for user input.
- options: Defines selectable values.
- Use Case: Standardized selection for QA results.
Automated Calculations (Worksheets)
Example: Total Weight Calculation
__(calculation,total_weight,weight1 + weight2)__
Explanation:
- Calculates the total by summing two input fields.
- Use Case: Summarizing batch weights dynamically.
Conditional Logic (Worksheets and Reports)
Example: Conditional Field Display
{% if test.result > threshold %}
<p style="color:red;">Result exceeds threshold: {{ test.result }}</p>
{% else %}
<p>Result: {{ test.result }}</p>
{% endif %}
Explanation:
- Highlights results exceeding a threshold in red.
- Use Case: QA alerts for out-of-spec results.
Data Aggregation (Reports)
Example: Average Test Result
<p>Average Result: {{ order.tests|map(attribute='result')|sum / order.tests|length }}</p>
Explanation:
- Maps test results, sums them, and divides by count for average.
- Use Case: Consolidated statistics for COAs.
Default Values
Default values streamline workflows by pre-filling fields, reducing user input requirements.
a. Default Text Value
__(input,field_1,default_value="Enter here")__
b. Default Numeric Value
__(input,field_2,default_numeric_value=100)__
Pro Tip: Default values ensure consistency while allowing flexibility for edits.
5. Use Cases and Examples
Custom Worksheets Overview
Purpose
Worksheets are tailored to streamline data collection and calculation:
- Use Case: Labs needing batch-specific input fields or calculations, such as pharmaceutical QC forms or environmental testing logs.
Key Features
- Dynamic input fields for user interaction.
- Automated calculations based on input or external data.
- Integration with QBench objects like tests, samples, and batches.
Worksheets: Basic Example
Purpose: Render interactive fields for sample data collection.
Code:
<h1>Sample Worksheet</h1>
<p>Sample ID: {{ sample.get_display_id(enabled_custom_ids) }}</p>
<table>
<tr>
<th>Analyte</th>
<th>Result</th>
<th>Units</th>
</tr>
{% for test in sample.tests %}
<tr>
<td>{{ test.analyte }}</td>
<td>{{ test.result }}</td>
<td>{{ test.units }}</td>
</tr>
{% endfor %}
</table>
Explanation:
- Header: Displays sample metadata, such as ID.
- Table: Dynamically lists tests associated with the sample.
- sample.tests: Accesses related test objects.
- for loop: Iterates through each test.
- Why Use This? It dynamically adapts to varying sample data sizes.
Example: Sample Entry Form
<table>
<tr>
<td>Sample Name</td>
<td>__(input, sample_name)__</td>
</tr>
<tr>
<td>Result</td>
<td>__(input, result)__</td>
</tr>
</table>
Example 2: Pass/Fail Logic
<table>
<tr>
<th>Analyte</th>
<th>Value</th>
<th>Limit</th>
<th>Pass/Fail</th>
</tr>
{% for analyte, limit in analyte_list.items() %}
<tr>
<td>{{ analyte }}</td>
<td>__(input, {{ analyte }}, default=0)__</td>
<td>{{ limit }}</td>
<td>
{% if value <= limit %}
Pass
{% else %}
Fail
{% endif %}
</td>
</tr>
{% endfor %}
</table>
Custom Reports Overview
Purpose
Reports are designed for presenting data in a professional format:
- Use Case: Certificates of Analysis (COAs), regulatory reports, or multi-sample summaries.
Key Features
- Complex layouts with headers, footers, and CSS styling.
- Data aggregation across multiple QBench objects.
- Conditional logic for dynamic content.
Reports: Advanced Layout Example
Purpose: Present a professional COA with dynamic styling.
Code:
<!DOCTYPE html>
<html>
<head>
<title>Certificate of Analysis</title>
<style>
body { font-family: Arial, sans-serif; }
table { width: 100%; border-collapse: collapse; }
th, td { border: 1px solid black; padding: 8px; text-align: left; }
</style>
</head>
<body>
<h1>Certificate of Analysis</h1>
<p>Order ID: {{ order.get_display_id(enabled_custom_ids) }}</p>
<p>Date: {{ order.date.strftime('%Y-%m-%d') }}</p>
<table>
<tr>
<th>Test</th>
<th>Result</th>
<th>Units</th>
</tr>
{% for test in order.tests %}
<tr>
<td>{{ test.name }}</td>
<td>{{ test.result }}</td>
<td>{{ test.units }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
Explanation:
- HTML Head: Includes styling for consistency across reports.
- Dynamic Fields:
- {{ order.get_display_id }}: Fetches and displays the order ID.
- {{ order.date.strftime('%Y-%m-%d') }}: Formats the order date.
- Iteration: Lists all tests associated with the order.
- Why Use This? For polished, standardized documents that align with branding and regulatory requirements.
6. Advanced Use Cases
Batch-Level Summary
<h2>Batch Overview</h2>
<p>Total Tests: {{ batch.tests|length }}</p>
<p>Average Weight: {{ batch.samples|map(attribute='weight')|sum / batch.samples|length }}</p>
Summarizes batch-level metrics for QA reporting.
Regulatory Report
<h1>Regulatory Compliance Report</h1>
{% for analyte in sample.analytes %}
<p>{{ analyte.name }}: {{ analyte.value }} {{ analyte.unit }}</p>
{% if analyte.value > analyte.limit %}
<p style="color:red;">Non-compliant</p>
{% endif %}
{% endfor %}
a. Batch Quality Control
Objective: Automate entry and evaluation of test results in a batch. Features Used:
- Dropdowns for pass/fail selection.
- Conditional highlighting for thresholds.
b. Certificate of Analysis
Objective: Generate a customer-ready summary of sample results. Features Used:
- Iterative fields to list multiple analytes.
- Pre-filled metadata fields for sample IDs.
7. Combining Layout and Logic
QWML supports combining HTML layout with dynamic logic for enhanced customization.
Example: Summary Table
<table>
<tr>
<th>Sample</th>
<th>Result</th>
</tr>
{% for sample in batch.samples %}
<tr>
<td>{{ sample.name }}</td>
<td>{{ sample.result }}</td>
</tr>
{% endfor %}
</table>
How It Works:
- Static Headers: Define column labels.
- Dynamic Content: Populate rows dynamically for each sample.
8. Best Practices for QWML Design
a. Use Descriptive Field Names
- Ensure field names are meaningful for readability and maintenance.
- Example:
__(input,analyte_concentration)__
b. Modularize Repeated Logic
- Use variables to define reusable elements.
- Example:
{% set header_style = "font-weight: bold;" %}
<h1 style="{{ header_style }}">Worksheet</h1>
c. Test Templates Thoroughly
- Validate input fields and conditional logic for various scenarios.
- Preview templates in QBench to ensure proper rendering.
d. Avoid Overcomplication
- Focus on clarity and simplicity unless complexity is absolutely necessary.
9. Common Errors and Troubleshooting
Error | Cause | Solution |
Missing field | Incorrect or missing field reference | Verify field names in QBench schema |
Syntax errors | Improper Jinja2 syntax | Validate syntax in an IDE |
Incorrect calculations | Formula not aligned with field names | Double-check formula references |
10. Glossary of Terms
- QWML: QBench Worksheet Markup Language.
- Jinja2: A templating engine used for dynamic content generation.
- Batch: A collection of samples processed together.
11. Conclusion
QBench Worksheet Markup Language empowers labs to replace manual processes with dynamic, intelligent templates. By mastering its syntax, logic, and best practices, you can create worksheets that are not only functional but also highly efficient. Keep your designs modular, clear, and user-friendly, leveraging QWML's powerful features for optimal workflows.
Custom templates in QBench provide unparalleled flexibility for labs with complex workflows. By leveraging best practices, detailed planning, and thorough testing, you can design templates that enhance efficiency, meet compliance needs, and present data professionally. Whether you are designing worksheets for streamlined input or reports for client-ready output, QBench’s customization capabilities are a game-changer for modern labs.
Comments
0 comments
Please sign in to leave a comment.