44
55import inspect
66import os
7+ import re
78import sys
89import threading
910import time
1314from collections .abc import Mapping
1415
1516import ipywidgets as ipw
16- import pandas as pd
1717import traitlets as tl
1818
1919# AiiDA imports
2727from aiida .common .links import LinkType
2828from aiida .tools .query .calculation import CalculationQueryBuilder
2929from IPython .display import HTML , Javascript , clear_output , display
30+ from jinja2 import Template
3031
3132
3233class CantRegisterCallbackError (Exception ):
@@ -38,6 +39,85 @@ def __init__(self, function):
3839 )
3940
4041
42+ PROCESS_TABLE_TEMPLATE = Template (
43+ """
44+ <style>
45+ .df { border: none; }
46+ .df tbody tr:nth-child(odd) { background-color: #e5e7e9; }
47+ .df tbody tr:nth-child(odd):hover { background-color: #f5b7b1; }
48+ .df tbody tr:nth-child(even):hover { background-color: #f5b7b1; }
49+ .df tbody td { min-width: 150px; text-align: center; border: none; }
50+ .df th { text-align: center; border: none; border-bottom: 1px solid black; }
51+ </style>
52+ <table class="df">
53+ <thead>
54+ <tr>
55+ {% for header in headers %}
56+ <th>{{ header }}</th>
57+ {% endfor %}
58+ </tr>
59+ </thead>
60+ <tbody>
61+ {% for row in rows %}
62+ <tr>
63+ {% for header in headers %}
64+ <td>{{ row[header] }}</td>
65+ {% endfor %}
66+ </tr>
67+ {% endfor %}
68+ </tbody>
69+ </table>
70+ """
71+ )
72+
73+
74+ def _stringify_process_cell (value ):
75+ if value is None :
76+ return ""
77+ return str (value )
78+
79+
80+ def _normalize_process_rows (projected ):
81+ if not projected :
82+ return [], []
83+
84+ headers = list (projected [0 ])
85+ rows = [
86+ {
87+ header : _stringify_process_cell (value )
88+ for header , value in zip (headers , entry )
89+ }
90+ for entry in projected [1 :]
91+ ]
92+ return headers , rows
93+
94+
95+ def _filter_process_rows (rows , description_contains ):
96+ if not description_contains :
97+ return rows
98+
99+ pattern = re .compile (description_contains )
100+ return [row for row in rows if pattern .search (row .get ("Description" , "" ))]
101+
102+
103+ def _add_process_links (rows , path_to_root ):
104+ linked_rows = []
105+ for row in rows :
106+ linked_row = dict (row )
107+ pk = linked_row .get ("PK" , "" )
108+ linked_row ["PK" ] = (
109+ f"""<a href={ path_to_root } home/process.ipynb?id={ pk } target="_blank">{ pk } </a>"""
110+ if pk
111+ else ""
112+ )
113+ linked_rows .append (linked_row )
114+ return linked_rows
115+
116+
117+ def _render_process_table (headers , rows ):
118+ return PROCESS_TABLE_TEMPLATE .render (headers = headers , rows = rows )
119+
120+
41121def get_running_calcs (process ):
42122 """Takes a process and yeilds running children calculations."""
43123
@@ -576,22 +656,6 @@ def __init__(self, path_to_root="../", **kwargs):
576656
577657 def update (self , _ = None ):
578658 """Perform the query."""
579- pd .set_option ("max_colwidth" , 40 )
580- # Here we are defining properties of 'df' class (specified while exporting pandas table into html).
581- # Since the exported object is nothing more than HTML table, all 'standard' HTML table settings
582- # can be applied to it as well.
583- # For more information on how to controle the table appearance please visit:
584- # https://css-tricks.com/complete-guide-table-element/
585- self .table .value = """
586- <style>
587- .df { border: none; }
588- .df tbody tr:nth-child(odd) { background-color: #e5e7e9; }
589- .df tbody tr:nth-child(odd):hover { background-color: #f5b7b1; }
590- .df tbody tr:nth-child(even):hover { background-color: #f5b7b1; }
591- .df tbody td { min-width: 150px; text-align: center; border: none }
592- .df th { text-align: center; border: none; border-bottom: 1px solid black;}
593- </style>
594- """
595659 builder = CalculationQueryBuilder ()
596660 filters = builder .get_filters (
597661 all_entries = False ,
@@ -630,19 +694,16 @@ def update(self, _=None):
630694 "description" ,
631695 ],
632696 )
633- dataf = pd . DataFrame (projected [ 1 :], columns = projected [ 0 ] )
697+ headers , rows = _normalize_process_rows (projected )
634698
635699 # Keep only process that contain the requested string in the description.
636- if self .description_contains :
637- dataf = dataf [dataf .Description .str .contains (self .description_contains )]
700+ rows = _filter_process_rows (rows , self .description_contains )
638701
639- self .output .value = f"{ len (dataf )} processes shown"
702+ self .output .value = f"{ len (rows )} processes shown"
640703
641704 # Add HTML links.
642- dataf ["PK" ] = dataf ["PK" ].apply (
643- lambda x : f"""<a href={ self .path_to_root } home/process.ipynb?id={ x } target="_blank">{ x } </a>"""
644- )
645- self .table .value += dataf .to_html (classes = "df" , escape = False , index = False )
705+ rows = _add_process_links (rows , self .path_to_root )
706+ self .table .value = _render_process_table (headers , rows )
646707
647708 @tl .validate ("incoming_node" )
648709 def _validate_incoming_node (self , provided ):
0 commit comments