🐬Spotfire 為什麼突然沒有 BIN 值與圖表不顯示?工程師用「縮排、欄位來源、過濾條件」三招快速定位(含 IronPython 範例)
在 Tibco Spotfire 裡做良率(Yield)或 BIN 分佈分析時,最常見也最讓人抓狂的狀況之一,就是:
-
表格(TablePlot)突然看不到 BIN 欄位
-
圖表(Chart)突然空白
-
你明明知道資料有回來,但畫面就是不出來
-
腳本還可能報
unexpected indent、或是印出一堆 debug 訊息卻看不出問題在哪
這篇文章用「軟體工程師的除錯方式」,用簡單白話把問題拆成 3 類,並用可套用在任何 Spotfire 專案的方式,教你快速定位「BIN 不見」的真正原因。
一、Spotfire 的 BIN 不見,其實通常不是「沒資料」,而是「你拿錯地方的欄位」
很多人直覺以為:
圖表不顯示 = 資料表沒資料
但在 Spotfire 的腳本世界裡,另一個超常見真相是:
只是你從「視覺物件的參照」去拿欄位,而不是從「真正的資料表」去拿欄位
什麼是「視覺物件的參照」?
Spotfire 的 TablePlot / Chart 會有一種像「指向資料的指標」的東西(概念上類似捷徑),它可能還停留在舊的 view、舊的欄位集合,或欄位字串格式跟你想像的不一樣。
工程師的做法是:
-
用「資料表」做欄位判斷
-
用「視覺物件參照」做欄位加入(AddColumn)
二、為什麼你「明明印得出 BIN 欄位清單」,最後卻又變成空?
你可能會遇到這種除錯輸出:
-
你先印出:有
BIN1, BIN2, BIN3... -
但你最後算出來要顯示的
binColumns卻是空的
這常見原因不是資料突然消失,而是你的判斷式像這樣:
-
把欄位物件轉成字串
str(col)去判斷是否startswith("BIN") -
但
str(col)根本不是欄位名(可能是ColumnRef(...)這類描述字串)
三、第二個大地雷:過濾條件把資料「全部清光」但你沒發現
另一種超常見的 BIN 消失原因,是你後面加了某種過濾:
-
只保留「Rate% > 0.01」
-
只保留「選到的 BIN」
-
只保留「某個欄位不是空」
如果你寫得太嚴格、或欄位名稱對不上、或格式是百分比字串(例如 "0.00%"),結果就是:
實際上你把所有資料都刪了
→ 表格剩 0 筆
工程師會在每個關鍵步驟都印出 RowCount,像這樣:
四、最實用的工程師除錯流程(通用版)
下面的程式碼示範 Spotfire 腳本中「一步一步定位」的做法。
1)每一步都要印 RowCount(超重要)
# ✅ 通用除錯:每個重要處理後都看一下資料剩多少筆
def log_count(table_name):
t = Document.Data.Tables[table_name]
print("[COUNT]", table_name, "=", t.RowCount)
log_count("SourceTable")
log_count("IntermediateTable")
log_count("FinalTable")
只要你發現某一步後 RowCount 變成 0,就知道問題在哪一段。
2)用「真正資料表」判斷 BIN 欄位名稱
def get_bin_columns_from_table(table_name, prefix="BIN"):
t = Document.Data.Tables[table_name]
bins = []
for c in t.Columns:
name = c.Name
if name.startswith(prefix):
bins.append(name)
return bins
3)加入欄位到 TablePlot,要用視覺參照(Reference)
def apply_columns_to_tableplot(page_title, visual_title, column_names):
# 找到 TablePlot
page = next(p for p in Document.Pages if p.Title == page_title)
table_vis = next(v for v in page.Visuals if v.Title == visual_title).As[TablePlot]()
# 取得視覺資料參照
ref = table_vis.Data.DataTableReference
# 清除 + 加回欄位
table_vis.TableColumns.Clear()
for n in column_names:
table_vis.TableColumns.Add(ref.Columns.Item[n])
4)避免「過濾清光」:先算再刪,刪前印出會刪多少
def filter_rows_by_threshold(table_name, col_name, threshold):
t = Document.Data.Tables[table_name]
cur = DataValueCursor.CreateFormatted(t.Columns[col_name])
to_remove = IndexSet(t.RowCount, False)
for r in t.GetRows(cur):
raw = cur.CurrentValue
if raw is None:
to_remove.AddIndex(r.Index)
continue
s = str(raw).replace("%", "").replace(",", "").strip()
if s == "":
to_remove.AddIndex(r.Index)
continue
try:
v = float(s)
except:
to_remove.AddIndex(r.Index)
continue
if v <= threshold:
to_remove.AddIndex(r.Index)
print("[FILTER]", table_name, "remove =", to_remove.Count, "remain =", t.RowCount - to_remove.Count)
t.RemoveRows(RowSelection(to_remove))
五、unexpected indent 是什麼?為什麼 Spotfire/IronPython 特別容易中招?
很多 Spotfire 腳本的第一個錯誤不是邏輯,而是:
SyntaxError: unexpected indent
這幾乎都跟「縮排」有關,常見原因:
-
Tab 跟空白混用(你以為對齊,IronPython 覺得不對)
-
if / for / def少了冒號: -
該在外層的
print()卻縮排進去
工程師建議:
-
全部統一用 4 個空白
-
不用 Tab
-
程式先貼到 VSCode / Notepad++ 做「Convert Tabs to Spaces」再貼回 Spotfire
六、真正能快速解決 BIN 不顯示的三個結論
✅ 結論 1:欄位判斷要用 DataTable(資料表),不是視覺參照
-
用
Document.Data.Tables["..."].Columns做欄位判斷 -
用
TablePlot.Data.DataTableReference做欄位加入
✅ 結論 2:不要用 str(column) 當欄位名
-
一律用
column.Name
✅ 結論 3:任何會刪資料的過濾,都必須印 RowCount
-
過濾前後都要印
-
刪除前先計算「會刪幾筆、會剩幾筆」
七、常見 FAQ
Q1:為什麼我印得出 BIN 欄位,但表格就是不顯示?
因為你印的是「資料表的欄位」,但你加欄位用的是「視覺物件參照」,兩者欄位集合可能不同步或名稱格式不同。
Q2:為什麼一加上 Rate% 過濾,圖表就全空?
通常是欄位名不一致、格式是 % 字串、或你把 Null/空值都當作要刪除,最後刪到 0 筆。
Q3:Spotfire 腳本除錯最有效的方法是什麼?
RowCount。把每段處理後的資料筆數印出來,最能立刻定位是哪一步把資料弄沒。
結尾:用工程師方式除錯,Spotfire 問題會變得很可控
Spotfire 的腳本除錯其實跟一般程式一樣:
不是靠猜,而是靠「可觀測性」:RowCount、欄位名、每一步的輸出。
只要你掌握:
-
正確使用 DataTable vs DataTableReference
-
欄位名用
.Name不用str() -
過濾前後都印 RowCount
「BIN 不見」與「圖表空白」就會從玄學變成可快速定位的工程問題。
留言
張貼留言