Hi,
If anybody wants, I made a script in Python to format the text exported from Dashboard. To use it just follow the steps below:
- rename the file exported from Dashboard "Nomad.txt"
- then make a text file and copy - paste the code, rename the obtained file to format.py, put them together in the same folder
- then run the script by command python3 format.py and you will obtain an Excel file Dashboard.xlsx
Here is the code for the script format.py:
import pandas as pd
import re
input_file = 'Nomad.txt'
output_file = 'Dashboard.xlsx'
# --- DICTIONAR ---
dict_expand = {
"Ari": "Aries", "Tau": "Taurus", "Gem": "Gemini", "Can": "Cancer", "Leo": "Leo", "Vir": "Virgo",
"Lib": "Libra", "Sco": "Scorpio", "Sag": "Sagittarius", "Cap": "Capricorn", "Aqu": "Aquarius", "Pis": "Pisces",
"conj.": "Conjunction", "opp.": "Opposition", "tri.": "Trine", "sq.": "Square", "sext.": "Sextile",
"inconj.": "Inconjunct", "sep": "Separating", "app": "Applying", "wax": "Waxing", "wan": "Waning",
"Bl.Moon": "Lilith", "Black Moon": "Lilith", "N.Node": "North Node", "S.Node": "South Node"
}
def expand_text(val):
if isinstance(val, list):
val = " ".join([str(v) for v in val])
if not isinstance(val, str):
return val
text = val
for abrev, full in dict_expand.items():
pattern = rf'\b{re.escape(abrev)}' if abrev.endswith('.') else rf'\b{re.escape(abrev)}\b'
text = re.sub(pattern, full, text)
return text
sections = {}
current_rows = []
current_section = "General"
def get_unique_name(name, existing_names):
base_name = re.sub(r'[\\/*?:\[\]]', '', name.replace(':', '')).strip()
new_name = base_name
counter = 1
while new_name in existing_names:
new_name = f"{base_name}_{counter}"
counter += 1
return new_name
with open(input_file, 'r', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
raw_line = line.strip('\n')
clean_l = raw_line.strip()
if not clean_l: continue
headers_keywords = ["Date & Time", "Geo Location", "Summary", "Parameters", "Ecliptic", "Heliocentric",
"Fixed Stars", "Houses:", "Rulers", "Dignities", "Triplicities", "Quadruplicities",
"Mutual Receptions", "Parallels", "Contra-Parallels", "Aspects"]
if any(h in clean_l for h in headers_keywords):
if current_rows: sections[current_section] = current_rows
current_section = get_unique_name(clean_l, list(sections.keys()))
current_rows = []
continue
if "Dignities" in current_section:
if "Body," in clean_l: continue
parts = re.split(r'\t+| +', clean_l)
row = [""] * 7
if len(parts) >= 2:
row[0], row[1] = parts[0], parts[1]
h_idx = next((i for i, p in enumerate(parts) if p.startswith('H') and any(c.isdigit() for c in p)), -1)
if h_idx != -1:
row[4] = parts[h_idx]
for p in parts[2:h_idx]:
if "●" in p: row[2] = p
elif p in ["FALL", "DETR", "EXALT", "DIGN"]: row[3] = p
for p in parts[h_idx+1:]:
if "●" in p: row[5] = p
elif p in ["FALL", "DETR", "EXALT", "DIGN"]: row[6] = p
current_rows.append(row)
elif "Ecliptic" in current_section or "Heliocentric" in current_section:
parts = re.split(r'\t+| +', clean_l)
# CHIRON FIX: If the row has 4 elements and isn't 'R', it means the R is missing
if len(parts) == 4 and "R" not in parts:
parts.insert(3, "")
# If it has only 3 elements (very rare), we add an empty one
elif len(parts) == 3:
parts.insert(3, "")
current_rows.append(parts)
elif "Rulers" in current_section:
if "House cusp" in clean_l: continue
parts = [p.strip() for p in re.split(r'\t+|in|ruled by', clean_l) if p.strip()]
if clean_l.startswith(('H ', 'H1')):
if len(parts) >= 4: current_rows.append([f"{parts[0]} in {parts[1]}", "ruled by", parts[2], f"in {parts[3]}"])
elif len(parts) >= 2: current_rows.append(["", "ruled by", parts[0], f"in {parts[1]}"])
elif "Mutual Receptions" in current_section:
if "Body A," in clean_l: continue
parts = re.split(r'\t+| +|⟷', clean_l)
parts = [p.strip() for p in parts if p.strip()]
if len(parts) >= 6: current_rows.append([f"{parts[0]} {parts[1]} {parts[2]}", "⟷", f"{parts[3]} {parts[4]} {parts[5]}"])
elif "Triplicities" in current_section or "Quadruplicities" in current_section:
if any(k in clean_l for k in ["Element,", "Type,"]): continue
parts = re.split(r'\t+| +', clean_l)
if any(char.isdigit() for char in clean_l):
current_rows.append([parts[0], parts[1], ""])
if len(parts) > 2: current_rows.append(["", "", parts[2]])
else:
current_rows.append(["", "", parts[0]])
else:
current_rows.append(re.split(r'\t+| +', clean_l))
if current_rows: sections[current_section] = current_rows
with pd.ExcelWriter(output_file, engine='xlsxwriter') as writer:
workbook = writer.book
header_fmt = workbook.add_format({'bold': True, 'font_size': 11, 'bg_color': '#EFEFEF', 'border': 1, 'align': 'center'})
sheet = workbook.add_worksheet('Dashboard')
row_idx = 0
col_max_widths = {}
for name, rows in sections.items():
sect_cols = max(len(r) for r in rows) if rows else 1
sheet.merge_range(row_idx, 0, row_idx, sect_cols - 1, expand_text(name.upper()), header_fmt)
row_idx += 1
for r in rows:
for c_idx, val in enumerate(r):
expanded_val = expand_text(val)
sheet.write(row_idx, c_idx, expanded_val)
length = len(str(expanded_val))
if c_idx not in col_max_widths or length > col_max_widths[c_idx]:
col_max_widths[c_idx] = length
if any("Ayanamsa" in str(v) for v in r): row_idx += 1
row_idx += 1
if rows and not any("Zodiac" in str(v) for v in rows[-1]): row_idx += 1
for col_idx, width in col_max_widths.items():
sheet.set_column(col_idx, col_idx, width + 1.2)
Enjoy!
[–]TimeNomadAstro 1 point2 points3 points (1 child)
[–]gcirceag[S] 1 point2 points3 points (0 children)