1#!/usr/bin/env python3 2# encoding: utf-8 3# Copyright 2020 Huawei Technologies Co., Ltd 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# ============================================================================ 17import sys 18import math 19 20MIN_CHARS_PER_ROW = 20 # minimal number of chars on one line 21COLS_TO_ROWS_RATIO = 4 # ratio of # columns to # rows (unit is char) 22MAX_LABEL_LENGTH = 1000 # maximal number of chars of a label 23 24 25# for specified number of chars, calculate a suitable number for how many chars per row 26# Num Total Chars : n 27# Num Chars Per Row : m 28# Num Rows : k 29# (k - 1) * m < n <= k * m 30# suppose: m / k = u 31# ==> sqrt(u * n) <= m < u / 2 + sqrt(u * n + u * u / 4) 32# m = max(20, m) 33# parameters: 34# @total_chars number of total chars 35# @ratio ratio of # columns to # rows (unit is char) 36def calc_num_chars_per_row(total_chars, ratio): 37 chars_per_row = math.ceil(math.sqrt(total_chars * ratio)) 38 return max(MIN_CHARS_PER_ROW, chars_per_row) 39 40 41def process_label_text(text): 42 label_len = min(len(text), MAX_LABEL_LENGTH) 43 chars_per_row = calc_num_chars_per_row(label_len, COLS_TO_ROWS_RATIO) 44 if label_len <= MIN_CHARS_PER_ROW: 45 return text 46 beg_idx = 0 47 texts = [] 48 while beg_idx < label_len: 49 end_idx = beg_idx + chars_per_row 50 if end_idx >= label_len: 51 texts.append(text[beg_idx:label_len]) 52 else: 53 texts.append(text[beg_idx:end_idx]) 54 beg_idx = end_idx 55 return "\\n".join(texts) 56 57 58# insert '\n' to labels which are too long 59def process_file(f): 60 line_text = f.readline() 61 beg_idx = -1 # label begin index, index of 'label="' 62 end_idx = -1 # label end index, index of '"' 63 label_text = "" 64 label_prefix = "" 65 label_postfix = "" 66 while line_text: 67 line_text = line_text.rstrip() 68 69 if beg_idx < 0: 70 beg_idx = line_text.find('label="') 71 if beg_idx >= 0: 72 end_idx = line_text.find('"', beg_idx + len('label="')) 73 if end_idx >= 0: # the full label text is on one line 74 label = line_text[beg_idx + len('label="'):end_idx] 75 print('%slabel="%s"%s' % (line_text[0:beg_idx], process_label_text(label), line_text[end_idx + 1:])) 76 beg_idx = -1 # reset to initial conditions 77 else: # the label text is distributed on multiple lines 78 label_prefix = line_text[0:beg_idx] 79 label_text = line_text[beg_idx + len('label="'):] 80 else: 81 print(line_text) 82 else: 83 end_idx = line_text.find('"') 84 if end_idx >= 0: 85 label_text = label_text + line_text[0:end_idx] 86 label_postfix = line_text[end_idx + 1:] 87 print('%slabel="%s"%s' % (label_prefix, process_label_text(label_text), label_postfix)) 88 beg_idx = -1 # reset to initial conditions 89 else: 90 label_text += line_text 91 92 # print(f'{len(line_text)} - {line_text}') 93 line_text = f.readline() 94 95 96if __name__ == "__main__": 97 if len(sys.argv) > 1 and sys.argv[1] == "--help": 98 print("Usage: %s < dotfile | dot -Tpng -o filename.png" % sys.argv[0]) 99 sys.exit() 100 101 # read text from stdin 102 process_file(sys.stdin) 103