Inhoudsopgave:

https://github.com/PA3EFR?tab=repositories

 

 

GOOGLE MAPS SCRIPT

Om van een XLS lijst naar een Google Maps iFrame te komen kun je de volgende stappen doorlopen.

Er wordt gebruik gemaakt van een Python programmatje om het XLS lijstje om te zetten naar een CSV-lijst, want alleen met CSV kan een Google Maps kaart gemaakt worden.

Bij twijfel contact Erwin, PA3EFR.

 

Stapnummer Beschrijving Aanvullende informatie
1.

Installeer Pyhton3 op je computer. Deze is te vinden op https://www.python.org/downloads/windows/

Als je dit al een keer hebt gedaan kun je door naar stap 2
2. 

Zorg dat in de Dropbox BOTA-directory een up-to-date XLS lijst van alle BOTA stations staat.

 
3.

Hernoem (rename) deze XLS BOTA lijst naar "PABOTA_lijst.XLSX" als dit nog niet eerder is gebeurd.

Deze benaming wordt later door het Python-script gebruikt om er een CSV-bestand van te maken.
4. 

Zorg dat in de Dropbox BOTA-directory het script "conversie.py" staat. Deze is hier te downloaden.

Dit script zorgt voor een conversie van PABOTA_lijst.XLSX naar PABOTA.CSV in dezelfde directory.
5. 

Installeer de PANDA , de PILLOW en de OPENPYXL modules,  indien dat nog niet eerder is gedaan met je computer (ga anders door naar stap 6): 

- start de DOS command terminal in administrator modus

- in de terminal: navigeer naar de dropbox directory waar de PABOTA_lijst.XLSX te vinden is

- voer in de terminal uit: pip install openpyxl

- voer in de terminal uit: pip install pandas openpyxl 

- voer in de terminal uit: pip install pillow

Deze PANDA module is nodig voor de uitvoering van het conversie script.

Start, zoek, "Opdrachtprompt"

 

 

Als je dit al een keer hebt gedaan kun je door naar stap 6.

6.

Voer de conversie uit om van de XLSX een CSV bestand te maken. Dat doe je door !Conversie.bat uit te voeren

Na het uitvoeren van dit script is er een nieuwe (of geupdate) PABOTA.csv file ontstaan in de directory. 

Na uitvoering geeft de DOS terminal aan dat het CSV-bestand is opgeslagen naar PABOTA.csv.

""""
Erwin van der Haar - PA3EFR - 13 januari 2025
"""

import pandas as pd

def xlsx_to_csv_with_combined_columns(input_file, output_file, columns, combine_columns, additional_column, new_column_name, separator=" "):
"""
Converteert een XLSX-bestand naar een CSV-bestand met samengevoegde kolommen en geselecteerde kolommen.

Parameters:
- input_file: Pad naar het invoer XLSX-bestand.
- output_file: Pad waar het CSV-bestand wordt opgeslagen.
- columns: Lijst van kolomnamen of indexen die in het CSV-bestand moeten worden opgenomen.
- combine_columns: Tuple of lijst met kolomnamen om samen te voegen.
- additional_column: Extra kolomnaam om toe te voegen aan de samengevoegde kolom.
- new_column_name: Naam van de nieuwe kolom na het samenvoegen.
- separator: Scheidingsteken tussen de samengevoegde waarden (standaard is een spatie).
"""
try:
# Lees het Excel-bestand
df = pd.read_excel(input_file)

# Controleer of de kolommen bestaan
all_columns = list(combine_columns) + [additional_column]
if not all(col in df.columns for col in all_columns):
raise ValueError("Een of meer vereiste kolommen bestaan niet in het bestand.")

# Voeg leading zeroes toe aan de 'Index'-kolom
df[combine_columns[1]] = df[combine_columns[1]].apply(lambda x: str(x).zfill(4))

# Voeg de kolommen samen met de opgegeven separator
df[new_column_name] = (
df[combine_columns[0]].astype(str)
+ df[combine_columns[1]].astype(str)
+ separator + df[additional_column].astype(str)
)

# Selecteer de gewenste kolommen inclusief de nieuwe kolom
selected_columns = df[columns]

# Schrijf naar CSV
selected_columns.to_csv(output_file, index=False)

print(f"CSV-bestand succesvol opgeslagen naar: {output_file}")
except Exception as e:
print(f"Er is een fout opgetreden: {e}")

# Voorbeeldgebruik
# Vervang deze waarden door je eigen bestandsnamen en kolomnamen
input_file = "PABOTA_lijst.xlsx"
output_file = "PABOTA.csv"
combine_columns = ("Ref", "Index") # Kolommen om samen te voegen
additional_column = "Name" # Extra kolom om toe te voegen
new_column_name = "Object" # Naam van de nieuwe kolom als string
columns = ["Object", "Latitude", "Longitude"] # Pas deze aan met de kolomnamen in je Excel-bestand
separator = ": " # Separator tussen de samengevoegde waarden

xlsx_to_csv_with_combined_columns(input_file, output_file, columns, combine_columns, additional_column, new_column_name, separator)
print ("\nErwin van der Haar - PA3EFR - 19 februari 2025")
7. 

Login bij Google met het PABOTA account

(This email address is being protected from spambots. You need JavaScript enabled to view it.  /  ssssss<####>)

   pabota<##25>
8. 

Ga naar de Google Drive van het PABOTA account en kopieer de PABOTA.CSV file daar naar toe (in de map PABOTA).

Alleen vanuit de Google Drive worden kaarten op Google Maps mogelijk gemaakt.
9. 

Open een browser-window en navigeer naar google.com/maps/d/

We gaan er nu vanuit dat er nog geen kaart staat met reeds aangegeven Bunkers. Indien dat wel het geval is ga je naar stap 12.

 
10. 

Klik linksboven op NIEUWE KAART MAKEN. Er komt een nieuwe kaart in zicht en linksboven een venster waarin we lagen kunnen toevoegen en de Naamloze kaart kunnen hernoemen.

 
11. 

Klik op NAAMLOZE KAART en vul in de pop-up een nieuwe naam in (Dutch Bunkers On The Air <datum van creatie>)

 
12. 

Klik op LAAG TOEVOEGEN en selecteer bij die nieuwe laag de drie puntjes voor de optie IMPORTEREN. In de pop-up navigeer naar het Google Drive bestand PABOTA.csv (van stap 8).

 
13. 

In de pop-up Kolommen Kiezen selecteer je de Latitude en Longitude voor de plaatsbepaling. Klik op Doorgaan.

In het volgende scherm selecteer je Object voor de benaming van de Bunkers. Klik op Voltooien. 

 

 

De kaart laat nu alle bunkers zien die in de PABOTA.csv stonden opgenomen.

14.

Verwijder de lagen met de oude informatie via de drie puntjes bij die laag (en Verwijderen).

De kaart is nu eigenlijk gereed voor publicatie, maar we gaan hem wel even opleuken. 
15. 

We laten in deze laag de optie UNIFORME STIJL onaangeroerd. We richten ons nu op ALLE ITEMS en klikken het vulbekertje rechts van de tekst.

- selecteer de kleur rood

- selecteer Meer Pictogrammen

- onder de kop Plaatsen, voorlaatste regel, schuin rechtsboven de alien, selecteer de cirkels. Klik op OK.

 
16. 

De kaart kan nu gedeeld worden en als iFrame worden gepost op een internet pagina.

- Linksboven klik op Delen. In de pop-up selecteer de bovenste schuif (iedereen met deze link kan de kaart bekijken)

- Naast de nieuwe kaartnaam (van stap 10) klik op de drie puntjes en selecteer Insluiten in mijn site. Er komt een nieuwe pop-up die je kunt insluiten in een website. Daarbij het schuifje aanzetten.

 

 

 

 

Met deze iFrame kun je je website voorzien van de nieuwe kaart.

<iframe src="https://www.google.com/maps/d/u/0/embed?mid=1OxaX3mg1UevLOT90LIfErrlMGj6U5X8&ehbc=2E312F" width="1040" height="880"></iframe>

 

Daarmee is het proces rond en is de kaart weer up-to-date.

 

 

 

AWARD SCRIPT

Voor de aanvragen van de verschillende awards met kleuren (Bronze, SIlver, Gold; de verschillende typen (Activator, Hunter) en juiste volgnummers heb ik een Python script gemaakt. Ik ga er in beginsel vanuit dat Python is geinstalleerd.

Hierbij de stappen en de code. De scripts zijn deels in het Engels, deels in hetNederlands. Naar eigen behoefte is dat aan te passen. Mij ging het om de functionaliteiten.

 

1. Start Python op zodat er een nieuw scherm zichtbaar is met een prompt ">>>"  

2. Installeer met het commande "pip"de volgende lybraries:

  • pip install openpyxl
  • pip install pandas openpyxl
  • pip install tabulate
Als je dit al een keer hebt gedaan kun je door naar stap 3

3. Terug naar Windows. Maak submapjes met de kleuren van de awards. Dus mapje Bronze, Mapje Silver en mapje Gold.

Als je dit al een keer hebt gedaan kun je door naar stap 5

4. Zorg dat in elk mapje een JPG bestand staat dat uiteindelijk het award laat zien. De naam van de JPG is een combinatie van kleur en type award. Dus voor een Silver - Activator award zorg je dat de filenaam SilverActivator.jpg is. Let ook op de hoofdletters.

 

5. Maak in de hoofdmap een file met naam AwardGrantsOvervieuw.xlsx. Hier worden de awards bijgehouden.

Als je dit al een keer hebt gedaan kun je door naar stap 6, 7 of 8

6. Kopieer naastafgebeeld programma naar de hoofdmap en noem het "Award.py".

  • De awards worden als PDF weggeschreven in de verschillende kleuren awards. De naam van elk award is een combinatie van 
    • Volgnummer-Kleur-Type-Operatorname.pdf
  • De file AwardGrantsOverwiew wordt aangevuld met deze informatie.

 

Bekijk de PDF's en schuif met de texten indien nodig. 

Er valt ook te expirementeren met font-type (TTF-only) en font-kleuren.

from PIL import Image, ImageDraw, ImageFont
import os
from datetime import datetime
from openpyxl import load_workbook


# Function to validate input with repeated prompts
def get_valid_input(prompt, valid_options):
while True:
value = input(prompt).strip().lower()
if value in valid_options:
return value
print(f"Invalid input. Choose from {', '.join(valid_options)}.")


# Function to draw text with a border (outline)
def draw_text_with_border(draw, text, position, font, text_color, border_color, border_thickness):
# Draw border by rendering text multiple times around the original position
x, y = position
for offset_x in range(-border_thickness, border_thickness + 1):
for offset_y in range(-border_thickness, border_thickness + 1):
# Skip the center position (to avoid drawing the text multiple times in the exact same spot)
if offset_x == 0 and offset_y == 0:
continue
# Draw the border (outline)
draw.text((x + offset_x, y + offset_y), text, font=font, fill=border_color)

# Draw the main text over the border (in the desired text color)
draw.text(position, text, font=font, fill=text_color)


# Ask for input details
color_input = get_valid_input("\nEnter the color (options: b for Bronze, s for Silver, g for Gold): ", ["b", "s", "g"])

# Map the color input to the full color name
if color_input == "b":
color = "bronze"
elif color_input == "s":
color = "silver"
elif color_input == "g":
color = "gold"

# Ask for the activator/hunter option
type_option = get_valid_input("\n\t Is it an activator (a) or a hunter (h)? (options: a, h): ", ["a", "h"])

# Map single-letter input to full words
type_option = "activator" if type_option == "a" else "hunter"

name = input("\n\t Enter the name to be added (e.g., 'Erwin - PA3EFR'): ").strip()
serial_number = input("\n\t\t\t\t\t Enter the serial number: ").strip()

# Get today's date
today_date = datetime.now().strftime("%Y-%m-%d")

# Construct the correct input file path based on color and activator/hunter
input_directory = color.capitalize() # Directory name: Bronze, Silver, Gold
input_image_name = f"{color.capitalize()}{type_option.capitalize()}.jpg"
input_image_path = os.path.join(input_directory, input_image_name)

# Check if the file exists
if not os.path.exists(input_image_path):
print(f"The file '{input_image_path}' does not exist. Please check the name and try again.")
exit()

# Create the output file name
sanitized_name = name.replace(" ", "-").replace("/", "-")
output_pdf_name = f"{serial_number}_{color}_{type_option}_{sanitized_name}.pdf"
output_pdf_path = os.path.join(input_directory, output_pdf_name)

try:
# Open the image
img = Image.open(input_image_path)

# Create a drawing object
draw = ImageDraw.Draw(img)

# Choose a font and size (adjust the path if necessary)
font_size_name = int(150) # Fixed font size
font_size_number = int(150) # Fixed font size
font_size_date = int(150) # Fixed font size

try:
font_name = ImageFont.truetype("Bodoni Bd BT Bold.ttf", font_size_name)
font_number = ImageFont.truetype("arial.ttf", font_size_number)
font_date = ImageFont.truetype("arial.ttf", font_size_date)
except IOError:
# Fallback to a default font if arial.ttf is not available
font_name = ImageFont.load_default()
font_number = ImageFont.load_default()
font_date = ImageFont.load_default()

# Calculate the position of the name
text_name_bbox = draw.textbbox((0, 0), name, font=font_name) # (left, top, right, bottom)
text_name_width = text_name_bbox[2] - text_name_bbox[0]
name_position = (
1500, # 1500 pix from left
200 # 140 pix from the top (140 pixels at 300 DPI)
)

# Calculate the position of the serial number
text_number_bbox = draw.textbbox((0, 0), serial_number, font=font_number) # (left, top, right, bottom)
text_number_width = text_number_bbox[2] - text_number_bbox[0]
number_position = (
img.size[0] - text_number_width - 10, # 10 pix from the right edge
img.size[1] - text_number_bbox[3] - 10 # 10 pix above the bottom
)

# Calculate the position of the date
text_date_bbox = draw.textbbox((0, 0), today_date, font=font_date) # (left, top, right, bottom)
date_position = (
100, # 100 pixels from the left edge
img.size[1] - text_date_bbox[3] - 100 # 100 pixels from the bottom edge
)

# Add the name with a white border and black text
draw_text_with_border(draw, name, name_position, font_name, (0, 0, 0), (255, 255, 255), 5) # Border thickness = 5

# Add the serial number with a white border and black text
draw_text_with_border(draw, serial_number, number_position, font_number, (0, 0, 0), (255, 255, 255), 5)

# Add the date with a white border and red text
draw_text_with_border(draw, today_date, date_position, font_date, (255, 0, 0), (255, 255, 255), 5)

# Convert the image to RGB (necessary for PDF export)
if img.mode in ("RGBA", "P"): # Check if conversion is needed
img = img.convert("RGB")

# Save the image as a PDF in the correct directory
img.save(output_pdf_path, "PDF")
print(f"\n\n> The image with added text has been saved as '{output_pdf_path}'.")

# Now add the information to the Excel file
try:
# Load the existing workbook
workbook = load_workbook("AwardGrantsOverview.xlsx")
sheet = workbook.active

# Add a new row with the data
sheet.append([color.capitalize(), type_option.capitalize(), name, serial_number, output_pdf_name, today_date])

# Save the changes to the Excel file
workbook.save("AwardGrantsOverview.xlsx")
print("> The data has been added to 'AwardGrantsOverview.xlsx'.")

except Exception as e:
print(f"An error occurred while updating the Excel file: {e}")

except Exception as e:
print(f"An error occurred: {e}")

7. Om te weten wat het volgende volgnummer is van een volgend award heb ik een sorteer script geschreven die ook het AwardGrantsOVerview.xlsx bestand sorteert op kleur-type-volgnummer. Het script staat hiernaast. 

Schrijf dit bestand in de hoofdmap weg als Sort.py

import pandas as pd

# Bestandspad
file_name = "AwardGrantsOverview.xlsx"

# Inlezen van de Excel-bestand
data = pd.read_excel(file_name)

# Controleren of de benodigde kolommen bestaan
required_columns = ['Color', 'Type', 'Number']
if not all(col in data.columns for col in required_columns):
raise ValueError(f"De Excel file moet de volgende kolommen bevatten: {', '.join(required_columns)}")

# Sorteren op Color, Type en Number
data_sorted = data.sort_values(by=['Color', 'Type', 'Number'], ascending=[True, True, True])

# Groeperen op Color en Type en het hoogste nummer vinden
grouped = data_sorted.groupby(['Color', 'Type'])
highest_numbers = grouped['Number'].max()

# Printen van de resultaten
print("Hoogste nummers voor elke Color-Type combinatie:\n")
for (color, type_), number in highest_numbers.items():
print(f"\t{color}, {type_}, Hoogste Number: {number}")

# Optioneel: opslaan van de gesorteerde data in een nieuw Excel-bestand
data_sorted.to_excel("AwardGrantsOverview.xlsx", index=False)
print("\n\n> Gesorteerde data is opgeslagen in 'AwardGrantsOverview.xlsx'.")

8. Activeer nu het bestand !Award.bat om de nieuwe awards aan te maken en terug te vinden in de map van de kleur én in het overzicht AwardGrantsOverview.xlsx.

 

 

 

 

 

Nieuw object toevoegen

In deze module wordt een nieuw object toegevoegd aan een bestaande XLSX BOTA lijst.

Het vorige (laatste) record wordt weergegeven als geheugensteuntje voor de invoer van het nieuwe object. De nieuwe data wordt toegevoegd aan de bestaande XLSX.

   
""""
Erwin van der Haar - PA3EFR - 18 februari 2025
"""

import openpyxl
import os

def main():
# Laad het bestaande Excel-bestand
file_path = "PABOTA_lijst.xlsx"
wb = openpyxl.load_workbook(file_path)
sheet = wb.active

# Bepaal de laatste gebruikte rij
last_row = sheet.max_row
last_ref = sheet[f"A{last_row}"].value # Ref (kolom A)
last_index = sheet[f"B{last_row}"].value # Index (kolom B)

# Toon de relevante kolomnamen en laatste regel ter referentie
headers_filtered = [sheet.cell(row=1, column=col).value for col in
range(3, sheet.max_column + 1)] # Exclude Ref, Index
last_record = [sheet.cell(row=last_row, column=col).value for col in range(3, sheet.max_column + 1)]

print("Laatste record:")
for header, value in zip(headers_filtered, last_record):
print(f"{header}: {value}")

# Bepaal de nieuwe index
new_index = str(int(last_index) + 1).zfill(4)
print ("\nEn dan nu de gegevens invullen voor de het nieuwe object:")
# Vraag de gebruiker om nieuwe invoer voor de resterende kolommen
new_data = [input(f"Voer waarde in voor {header}: ") for header in headers_filtered]

# Schrijf de nieuwe gegevens naar het volgende lege rij
new_row = [last_ref, new_index] + new_data
sheet.append(new_row)

# Opslaan en afsluiten
wb.save(file_path)
print(f"\nNieuwe rij toegevoegd: {new_row}")
print(f"\nBestand opgeslagen als: {file_path}")

def ask_to_run_again():
# Vraag of het script opnieuw uitgevoerd moet worden
while True:
choice = input("\nWil je het script nog een bunker toevoegen? (j/n): ").strip().lower()
if choice == "j":
os.system('cls')
main() # Voer het script opnieuw uit
elif choice == "n":
print("Het script wordt afgesloten.")
break # Stop het script
else:
print("Ongeldige keuze. Typ 'j' (voor ja) of 'n' (voor nee).")

if __name__ == "__main__":
main() # Voer het script eerst uit
ask_to_run_again() # Vraag of het script opnieuw uitgevoerd moet worden

 

XLSX to DOCX

Maak van een PABOTA lijst een nieuw Word document met op elke pagina een enkele beschrijving (regel uit het XLSX bestand) om daarna beschrijvingen en fotos te kunnen toevoegen.

Zorg vooraf de er een installatie wordt uitgevoerd: pip install openpyxl python-docx

 
""""
Erwin van der Haar - PA3EFR - 3 februari 2025
"""

from openpyxl import load_workbook
from docx import Document
from docx.shared import Pt

# Functie om een pagina-einde toe te voegen
def add_page_break(doc):
    doc.add_page_break()

# Excel bestand lezen
def read_xlsx(file_path):
    wb = load_workbook(file_path)
    sheet = wb.active
    rows = list(sheet.iter_rows(values_only=True))
    return rows

# Word-document maken
def create_word_from_xlsx(excel_file, word_file):
    rows = read_xlsx(excel_file)
    doc = Document()
    
    for row in rows:
        # Voeg rijgegevens toe als koptekst op de pagina
        header = doc.add_paragraph()
        header.alignment = 1  # Centreren
        run = header.add_run(" | ".join(str(cell) for cell in row if cell is not None))
        run.bold = True
        run.font.size = Pt(14)
        
        # Pagina-einde als er meer rijen zijn
        add_page_break(doc)
    
    # Opslaan van het Word-document
    doc.save(word_file)

# Bestanden instellen
excel_bestand = input("Geef het pad van het Excel-bestand op: ")
word_bestand = input("Geef de naam van het uitvoerbestand op (met .docx): ")

# Uitvoeren
create_word_from_xlsx(excel_bestand, word_bestand)
print(f"Word-document '{word_bestand}' is succesvol aangemaakt.")