De eerste meegeleverde Dynamo nodes om te communiceren met Excel, hebben wat nadelen. Zo moet bijvoorbeeld Office zijn geïnstalleerd (en zeker geen oude versie), anders kan een Excel-bestand niet worden gelezen. Dat is een lastig probleem want niet iedereen heeft een nieuwe Office, of werkt liever met LibreOffice of vergelijkbaar. Daarom is er vorig jaar een nieuwe set nodes toegevoegd: OpenXMLImportExcel en OpenXMLExportExcel. Deze maken gebruik van een open-source module om Excel-bestanden te lezen, zonder dat Office geïnstalleerd hoeft te zijn. Ideaal toch?

Bug met kleine getallen

Recentelijk werd ik erop gewezen dat er een bug zit in de node om Excel-data te importeren. Bij kleine getallen onder de 0.1 worden ze soms uitgelezen als tekst (string) en niet als getal (double).

In dit voorbeeld wordt het getal 0.003 uitgelezen als een getal in Scientific Format en vanwege de ‘E’ beschouwd als een tekst. Het lastige is dat dit niet gebruikt kan worden in nodes die een getal verwachten, ze herkennen het niet als getal. De andere node die wel noodzakelijk Office nodig heeft, leest deze waarde wel keurig uit als 0.003 en als getal.

De bug is gemeld bij Autodesk en kudo’s voor de Autodesk medewerkers: ze pakken het altijd heel snel op! Niet dat het onmiddellijk opgelost is maar het wordt ook zeker niet genegeerd.

Zelf oplossen

Tot de nodes zijn verbeterd, als dat al lukt omdat men ook afhankelijk is van externe modules, kun je er zelf ook iets aan doen. Met een stukje Python code kun je teksten met een ‘E’ notatie omzetten naar getallen. Omdat je vaak gegevens verwerkt als lijsten binnen lijsten, is het handig om dit ook zo uit te voeren. De code ziet er wat complex uit vanwege de lambda toepassing maar het werkt prima.

 numbers = IN[0]
# Verwerken
ProcessLists = lambda function, lists: [ProcessLists(function, item)
    if isinstance(item, list)
    else function(item) for item in lists]

# Welke functie moet uitgevoerd worden?
convert = lambda x: float(x)

# Loop door de instances (item of list)
if isinstance(numbers, list):
    out = ProcessLists(convert, numbers)
else:
    out = convert(numbers)

# retourneren
OUT = out

De code zorgt ervoor dat als een enkele tekst wordt ingevoerd dat deze wordt geconverteerd, of als een lijst wordt ingevoerd dat deze lijst wordt doorlopen. En als die lijst is gevuld met lijsten dan worden die lijsten doorlopen. De feitelijke conversie van tekst naar getal is dit:

float(x)

Deze functie converteert een tekst naar een getal en accepteert ook Scientific Notations.

Fijn dat je het zo kunt oplossen maar nog fijner is het als de node is verbeterd.