diff --git a/examples/demo02.yml b/examples/demo02.yml index f03e7a2b..00ee5546 100644 --- a/examples/demo02.yml +++ b/examples/demo02.yml @@ -13,7 +13,6 @@ ferrules: ferrule_crimp: type: Crimp ferrule subtype: 0.25 mm² - color: YE connectors: X1: diff --git a/src/wireviz/Harness.py b/src/wireviz/Harness.py index d47aa048..394640ac 100644 --- a/src/wireviz/Harness.py +++ b/src/wireviz/Harness.py @@ -4,7 +4,7 @@ from wireviz.DataClasses import Connector, Cable from graphviz import Graph from wireviz import wv_colors -from wireviz.wv_helper import awg_equiv, mm2_equiv, tuplelist2tsv, nested, flatten2d, index_if_list +from wireviz.wv_helper import awg_equiv, mm2_equiv, tuplelist2tsv, nested, nested_html_table, flatten2d, index_if_list, html_line_breaks, graphviz_line_breaks, remove_line_breaks from collections import Counter from typing import List @@ -60,24 +60,18 @@ def create_graph(self): for key, connector in self.connectors.items(): if connector.category == 'ferrule': - rows = [[connector.type, connector.subtype, connector.color, '' if connector.color else None], + rows = [[html_line_breaks(connector.type), html_line_breaks(connector.subtype), connector.color, '' if connector.color else None], [connector.manufacturer, f'MPN: {connector.manufacturer_part_number}' if connector.manufacturer_part_number else None, - f'IPN: {connector.internal_part_number}' if connector.internal_part_number else None]] + f'IPN: {connector.internal_part_number}' if connector.internal_part_number else None], + [html_line_breaks(connector.notes)]] rows = [list(filter(None, row)) for row in rows] # remove missing attributes - html = '' - for row in rows: - if len(row) > 0: - html = f'{html}' - html = f'{html}
' - for cell in row: - html = f'{html}' - html = f'{html}
{cell}
' + html = nested_html_table(rows) if connector.color: # add color bar next to color info, if present - colorbar = f'' - html = html.replace('', colorbar) + colorbar = f' bgcolor="{wv_colors.translate_color(connector.color, "HEX")}" width="4">' # leave out ' tag + html = html.replace('>', colorbar) dot.node(key, label=f'<{html}>', shape='none', margin='0', style='filled', fillcolor='white') @@ -86,8 +80,8 @@ def create_graph(self): f'MPN: {connector.manufacturer_part_number}' if connector.manufacturer_part_number else '', f'IPN: {connector.internal_part_number}' if connector.internal_part_number else ''] - attributes = [connector.type, - connector.subtype, + attributes = [graphviz_line_breaks(connector.type), + graphviz_line_breaks(connector.subtype), f'{connector.pincount}-pin' if connector.show_pincount else''] pinouts = [[], [], []] for pinnumber, pinname in zip(connector.pinnumbers, connector.pinout): @@ -98,7 +92,7 @@ def create_graph(self): pinouts[0].append(f'{pinnumber}') if connector.ports_right: pinouts[2].append(f'{pinnumber}') - label = [connector.name if connector.show_name else '', identification, attributes, pinouts, connector.notes] + label = [connector.name if connector.show_name else '', identification, attributes, pinouts, graphviz_line_breaks(connector.notes)] dot.node(key, label=nested(label)) if len(connector.loops) > 0: @@ -132,7 +126,7 @@ def create_graph(self): f'IPN: {cable.internal_part_number}' if (cable.internal_part_number and not isinstance(cable.internal_part_number, list)) else ''] identification = list(filter(None, identification)) - attributes = [f'{cable.type}' if cable.type else '', + attributes = [html_line_breaks(cable.type) if cable.type else '', f'{len(cable.colors)}x' if cable.show_wirecount else '', f'{cable.gauge} {cable.gauge_unit}{awg_fmt}' if cable.gauge else '', '+ S' if cable.shield else '', @@ -153,7 +147,7 @@ def create_graph(self): html = f'{html}' # end identification row html = f'{html}' # attribute row for attrib in attributes: - html = f'{html}{attrib}' + html = f'{html}{attrib}' html = f'{html}' # attribute row html = f'{html}' # name+attributes table @@ -204,7 +198,7 @@ def create_graph(self): html = f'{html}' # main table if cable.notes: - html = f'{html}{cable.notes}' # notes table + html = f'{html}{html_line_breaks(cable.notes)}' # notes table html = f'{html} ' # spacer at the end html = f'{html}' # main table @@ -308,8 +302,8 @@ def bom(self): shared = next(iter(items.values())) designators = list(items.keys()) designators.sort() - conn_type = f', {shared.type}' if shared.type else '' - conn_subtype = f', {shared.subtype}' if shared.subtype else '' + conn_type = f', {remove_line_breaks(shared.type)}' if shared.type else '' + conn_subtype = f', {remove_line_breaks(shared.subtype)}' if shared.subtype else '' conn_pincount = f', {shared.pincount} pins' if shared.category != 'ferrule' else '' conn_color = f', {shared.color}' if shared.color else '' name = f'Connector{conn_type}{conn_subtype}{conn_pincount}{conn_color}' @@ -328,7 +322,7 @@ def bom(self): designators = list(items.keys()) designators.sort() total_length = sum(i.length for i in items.values()) - cable_type = f', {shared.type}' if shared.type else '' + cable_type = f', {remove_line_breaks(shared.type)}' if shared.type else '' gauge_name = f' x {shared.gauge} {shared.gauge_unit}' if shared.gauge else ' wires' shield_name = ' shielded' if shared.shield else '' name = f'Cable{cable_type}, {shared.wirecount}{gauge_name}{shield_name}' @@ -342,7 +336,7 @@ def bom(self): if bundle.category == 'bundle': # add each wire from each bundle to the wirelist for index, color in enumerate(bundle.colors, 0): - wirelist.append({'gauge': bundle.gauge, 'gauge_unit': bundle.gauge_unit, 'length': bundle.length, 'color': color, 'designator': bundle.name, + wirelist.append({'type': bundle.type, 'gauge': bundle.gauge, 'gauge_unit': bundle.gauge_unit, 'length': bundle.length, 'color': color, 'designator': bundle.name, 'manufacturer': index_if_list(bundle.manufacturer, index), 'manufacturer part number': index_if_list(bundle.manufacturer_part_number, index), 'internal part number': index_if_list(bundle.internal_part_number, index)}) @@ -355,8 +349,8 @@ def bom(self): designators = list(dict.fromkeys(designators)) # remove duplicates designators.sort() total_length = sum(i['length'] for i in items) - wire_type = f', {shared["type"]}' if 'type' in shared else '' - gauge_name = f', {shared["gauge"]} {shared["gauge_unit"]}' if 'gauge' in shared else '' + wire_type = f', {remove_line_breaks(shared["type"])}' if shared.get('type', None) else '' + gauge_name = f', {shared["gauge"]} {shared["gauge_unit"]}' if shared.get('gauge', None) else '' gauge_color = f', {shared["color"]}' if 'color' in shared != '' else '' name = f'Wire{wire_type}{gauge_name}{gauge_color}' item = {'item': name, 'qty': round(total_length, 3), 'unit': 'm', 'designators': designators, diff --git a/src/wireviz/wv_helper.py b/src/wireviz/wv_helper.py index 69d65507..83ee46ee 100644 --- a/src/wireviz/wv_helper.py +++ b/src/wireviz/wv_helper.py @@ -44,6 +44,20 @@ def nested(inp): l.append(str(x)) return '|'.join(l) +def nested_html_table(rows): + # input: list of lists + # output: a parent table with one child table per parent list item + # purpose: create the appearance of one table, where cell widths are independent between rows + html = '' + for row in rows: + if len(row) > 0: + html = f'{html}' + html = f'{html}
' + for cell in row: + html = f'{html}' + html = f'{html}
{cell}
' + return html + def int2tuple(inp): if isinstance(inp, tuple): @@ -69,3 +83,12 @@ def tuplelist2tsv(inp, header=None): # Return the value indexed if it is a list, or simply the value otherwise. def index_if_list(value, index): return value[index] if isinstance(value, list) else value + +def html_line_breaks(inp): + return inp.replace('\n', '
') if isinstance(inp, str) else inp + +def graphviz_line_breaks(inp): + return inp.replace('\n', '\\l') if isinstance(inp, str) else inp # \l generates left-aligned new lines. http://www.graphviz.org/doc/info/attrs.html#k:escString + +def remove_line_breaks(inp): + return inp.replace('\n', ' ').rstrip() if isinstance(inp, str) else inp diff --git a/tutorial/tutorial06.yml b/tutorial/tutorial06.yml index 7ff042f8..f69499c3 100644 --- a/tutorial/tutorial06.yml +++ b/tutorial/tutorial06.yml @@ -5,7 +5,7 @@ connectors: subtype: female F_10_1: # manually define a ferrule (with unique designator) category: ferrule - type: Crimp ferrule + type: Ferrule, crimp subtype: 1.0 mm² color: YE