For our water utility project we have a large number of historized tags (flow, level, pressure, valves, pumps) spread across many UDT instances. The stock Tag Browser next to the Power Chart works, but for our operators it's not great: tags are grouped by UDT/folder structure rather than by measurement type, the labels are raw tag names instead of something readable, and there's no way to show "already selected" state at a glance.
So I built a custom navigation tree (Perspective Tree component) driven by a script transform that browses [default] with system.tag.browse, groups tags into categories (Portata, Livello, Pressione, Valvole, Pompe, etc.) based on tag name/path patterns, and labels each leaf as <assetID> - <Component_Desc>. Clicking a leaf toggles a pen on/off on a PowerChart_1 component sitting next to the tree, instead of dragging tags manually.
The pen add/remove logic (below) dynamically manages props.pens, props.plots and props.axes on the Power Chart so that:
- each distinct axis gets its own plot row
- pens sharing the same axis (e.g. two flow meters both using
Flow_Axis) share the same row - rows are always compacted (no gaps) after a pen is removed
When I remove a pen whose axis is used by no other pen (so an entire row needs to disappear and everything below it needs to shift up by one), the row disappears correctly, but the axis label of pens that had to change their plot index does not move to its new row — it stays visually merged with a different row, even though props.pens[].plot, props.plots and props.axes are all provably correct at the moment of the write.
I tried this
- Add 4 pens, each on its own axis:
Flow_Axis→plot 0,Level_Axis→plot 1,Valve_Axis→plot 2 (only pen on this axis),Pump_Axis→plot 3. - Remove the pen on
Valve_Axis(the only one using that axis). - Recompute plots so that:
Flow_Axis→0,Level_Axis→1,Pump_Axis→2 (was 3), and writeprops.plots(3 rows) /props.axes(3 axes) /props.pensin one consolidated write. - Expected: 3 rows,
Pump_Axisnow occupies row 2. - Actual:
Pump_Axisrenders squeezed together with plot #0.
Relevant code (TOGGLE OFF branch — pen removal)
if already_exists:
del current_pens[existing_pen_index]
if tag_path in selected_curves:
selected_curves.remove(tag_path)
self.view.getChild("root").custom.selectedCurves = selected_curves
plot_ancora_usati = sorted(set(p.get('plot', 0) for p in current_pens))
remap = {old: new for new, old in enumerate(plot_ancora_usati)}
for p in current_pens:
p['plot'] = remap[p.get('plot', 0)]
distinct_plots_count = len(set(p.get('plot', 0) for p in current_pens))
nuovi_plots = costruisci_plots(distinct_plots_count) # rebuilds plots array from scratch, 1 row per distinct plot value
nuovi_axes = ricalcola_axes_attivi(current_pens, master_axes) # filters master axis list by name still in use
chart.props.pens = current_pens
chart.props.plots = nuovi_plots
chart.props.axes = nuovi_axes
def costruisci_plots(numero_pen):
if numero_pen <= 0:
return [{"color": "#ffffff00", "relativeWeight": 1, "style": {"classes": ""}, "markers": []}]
return [{"color": "#ffffff00", "relativeWeight": 1, "style": {"classes": ""}, "markers": []} for _ in range(numero_pen)]
def ricalcola_axes_attivi(pens_correnti, master_axes_list):
assi_usati = set(p.get('axis') for p in pens_correnti if p.get('axis'))
return [ax for ax in master_axes_list if ax.get('name') in assi_usati]
Debug log
[DEBUG] plot_ancora_usati = [0, 1, 2, 4]
[DEBUG] remap dict = {0: 0, 1: 1, 2: 2, 4: 3}
[DEBUG] PRIMA - Pump pen plot=4
[DEBUG] DOPO - Pump pen old=4 new=3
[DEBUG] distinct_plots_count = 4
[DEBUG] nuovi_plots lunghezza = 4
[REMOVE] axes che verranno scritti: ["Flow_Axis","Level_Axis","Pressure_Axis","Pump_Axis"]
Is there a known limitation in how Power Chart associates an axis entry with the correct row when a pen's plot index changes after the pen (and its axis) were already rendered once? I notice the axis objects themselves (props.axes[]) have no plot/row reference at all — the only link is via pens[].plot + pens[].axis. Is there an internal caching/diffing step on the component's frontend that doesn't fully recompute axis layout when only plot values change on existing pens (as opposed to adding a brand-new pen, which always renders correctly in my testing)?
Happy to share the full script. Thanks in advance for any pointers.