Note: Editors may update language strings and add additional languages, but please keep English as the leftmost language and do not change the ID column or the formatting of the cells.
#!/usr/bin/env python
import re, math, urllib2, numbers, xml.etree.ElementTree
## http://stackoverflow.com/a/7088472
try: from html import escape ## Python 3.x
except ImportError: from cgi import escape ## Python 2.x
def extract_text(html, tag): ## http://stackoverflow.com/a/7315891
return [escape(element.text.strip()).encode('ascii', 'xmlcharrefreplace')
if element.text is not None else None
for element in xml.etree.ElementTree.XML(html).findall('.//' + tag)]
def tabbify(cellss, delimiter='|'):
cellpadss = [list(rows) + [''] * (len(max(cellss, key=len)) - len(rows)) for rows in cellss]
fmts = ['%%%ds' % (max([len(str(cell)) for cell in cols])) for cols in zip(*cellpadss)]
return '\n'.join([delimiter.join([('%' if isinstance(rows[i], numbers.Number) else
'%-') + fmt[1:] for (i,fmt) in enumerate(fmts)]) % tuple(rows) for rows in cellpadss])
def roundm(x, multiple=1):
if (isinstance(x, tuple)): return tuple(roundm(list(x), multiple))
elif (isinstance(x, list )): return [roundm(x_i, multiple) for x_i in x]
else: return int(math.floor(float(x) / multiple + 0.5)) * multiple
def swap_braces(text):
return (text.replace('{{','\b').replace('{','{{').replace('\b','{')
.replace('}}','\b').replace('}','}}').replace('\b','}'))
diagramss = [
{'name':'sfftp','se':1,'fe':1,'fi':1},
{'name':'sfutp','se':1,'fe':1,'fi':0},
{'name': 'sutp','se':1,'fe':0,'fi':0},
{'name': 'sftp','se':1,'fe':0,'fi':1},
{'name': 'uftp','se':0,'fe':0,'fi':1},
{'name': 'uutp','se':0,'fe':0,'fi':0},
{'name': 'fftp','se':0,'fe':1,'fi':1},
{'name': 'futp','se':0,'fe':1,'fi':0},
]
## Read translations
# """ ## read live page using code from http://stackoverflow.com/a/3336735
url = 'http://commons.wikimedia.org/wiki/template:i18n_twisted_pair'
html = urllib2.urlopen(urllib2.Request(url, headers={'User-Agent':'Magic Browser'})).read()
""" ## read from cache to not bombard Commons during development
with open('twisted_pair_diagram.htm') as f: html = f.read();
# """
table = re.search(r'<table.*?/table>', html, flags=re.DOTALL|re.IGNORECASE).group(0)
print(table)
ths = extract_text(table, 'th')
i_scale = [i for (i, th) in enumerate(ths) if th and '%' in th][0] ## find %
scales = ths[i_scale + 1:]
langs = ths[1:i_scale]
## http://stackoverflow.com/a/10124783
stringss = [['ID\\lang'] + langs] + zip(*[iter(extract_text(table, 'td'))] *
(len(langs) + 1))
print(tabbify(stringss))
## Create font scale per language
out_scales = []
for (lang, scale) in zip(langs, scales):
if (scale != '100'): out_scales.append('''
text[systemLanguage="%s" i] { font-size:%s%%; }''' % (lang, scale))
## Create switch tags
out_switchs = {}
for strings in stringss[1:]:
id = strings[0]
out_langs = []
for (i_lang, lang) in enumerate(langs + [None]):
out_langs.append('''<text y="0.6ex"%s>%s</text>''' %
('' if lang is None else ' systemLanguage="%s"' % (lang),
strings[1 if lang is None else i_lang + 1]))
out_switchs[id] = '''<switch>%s</switch>''' % (''.join(out_langs))
print(tabbify(out_switchs.items()))
## Output SVG files
for diagrams in diagramss:
n_text = 3
ys = {}
if diagrams['fi']: ys['fi'] = n_text; n_text += 1
if diagrams['fe']: ys['fe'] = n_text; n_text += 1
if diagrams['se']: ys['se'] = n_text; n_text += 1
n_text += 1
out_ys = [roundm(21 * (i * 2.0 / (n_text - 1) - 1)) for i in range(n_text)]
basename = 'twisted_pair_%s' % (diagrams['name'])
filename = '%s.svg' % (basename)
print('%s\t%d\t%s' % (filename, n_text, out_ys))
with open(filename, 'w') as f:
f.write(swap_braces('''\
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="-5 -27 162 54">
<title>{{basename}}</title>
<desc>Twisted pair cable diagram by CMG Lee.</desc>
<style type="text/css">
svg { font-family:'Liberation Sans',Helvetica,Arial,sans-serif; font-size:6px; text-anchor:middle; stroke:none; stroke-width:0.2; }
text { fill-opacity:1; stroke:none; filter:url(#filter_stroke); }
.lead { fill:none; stroke:#666; marker-start:url(#marker_leader); marker-end:url(#marker_leader); }
<!-- Resize text for individual languages as per
http://commons.wikimedia.org/w/index.php?title=Commons:Graphic_Lab/Illustration_workshop&diff=prev&oldid=1077344410
-->{{out_scale}}
</style>
<defs>
<filter id="filter_stroke">
<feMorphology operator="dilate" radius="1"/>
<feColorMatrix type="matrix" values="0,0,0,0,1 0,0,0,0,1 0,0,0,0,1 0,0,0,1,0"/>
<feBlend in="SourceGraphic"/>
<feBlend in="SourceGraphic"/>
</filter>
<filter id="filter_shade" y="-50%" height="200%">
<feGaussianBlur stdDeviation="1"/>
<feOffset dx="0" dy="2"/>
<feColorMatrix type="matrix" values="1,0,0,0,0 0,1,0,0,0 0,0,1,0,0 0,0,0,0.3,0"/>
<feComposite operator="in" in="SourceAlpha"/>
<feBlend in2="SourceGraphic" mode="multiply"/>
</filter>
<marker id="marker_leader" refX="1.5" refY="1.5">
<circle r="1.8" cx="1.5" cy="1.5" fill="#333"/>
</marker>
<marker id="marker_tip" refY="1.5">
<path d="M 0.5,0.75 a 0.3,0.75 0 1 0 0.01,0" fill="#666"/>
<path d="M 2.5,1 h -2 a 0.2,0.5 0 0 0 0,1 h 2" fill="url(#grad_tip)"/>
<path d="M 2.5,1 a 0.2,0.5 0 1 0 0.01,0" fill="#f90"/>
</marker>
<linearGradient id="grad_tip" x1="0" y1="0" x2="0" y2="1">
<stop offset="0.0" stop-color="#c60"/>
<stop offset="0.3" stop-color="#f90"/>
<stop offset="1.0" stop-color="#c60"/>
</linearGradient>
<linearGradient id="grad_s" x1="0" y1="0" x2="0" y2="1">
<stop offset="0.0" stop-color="#c93"/>
<stop offset="0.3" stop-color="#fd9"/>
<stop offset="1.0" stop-color="#c93"/>
</linearGradient>
<linearGradient id="grad_fe" x1="0" y1="0" x2="0" y2="1">
<stop offset="0.0" stop-color="#9cf"/>
<stop offset="0.1" stop-color="#cef"/>
<stop offset="0.5" stop-color="#9cf"/>
<stop offset="0.6" stop-color="#cef"/>
<stop offset="1.0" stop-color="#9cf"/>
</linearGradient>
<linearGradient id="grad_fi" x1="0" y1="0" x2="0" y2="1">
<stop offset="0.0" stop-color="#9ef"/>
<stop offset="0.1" stop-color="#cff"/>
<stop offset="0.5" stop-color="#9ef"/>
<stop offset="0.6" stop-color="#cff"/>
<stop offset="1.0" stop-color="#9de"/>
</linearGradient>
<pattern id="pattern_se" patternUnits="userSpaceOnUse" width="2" height="4">
<path d="M 1,0 L 2,2 L 1,4 L 0,2 Z" fill="none" stroke="#bbb" stroke-width="0.5"/>
</pattern>
<pattern id="pattern_pair" patternUnits="userSpaceOnUse" width="20" height="40">
<g stroke="#09f">
<g id="pair" fill="none" stroke-width="3" transform="translate(0,5)" filter="url(#filter_shade)">
<use xlink:href="#color" transform="scale(1,-1)"/>
<g id="white">
<path id="color" d="M 0,2 c 4,0 6,-4 10,-4"/>
<use xlink:href="#color" stroke="#fff" stroke-width="2"/>
</g>
<use xlink:href="#white" transform="translate(10,0) scale(1,-1)"/>
<use xlink:href="#color" transform="translate(10,0)"/>
</g>
</g>
<use xlink:href="#pair" stroke="#930" transform="translate(0,10)"/>
<use xlink:href="#pair" stroke="#f60" transform="translate(0,20)"/>
<use xlink:href="#pair" stroke="#090" transform="translate(0,30)"/>
</pattern>
<g id="underlay">
<path d="M 20,-25 a 4,25 0 1 0 0.01,0 M 105,0 a 25,25 0 1 1 0,0.01 h 2 a 23,23 0 1 0 0,-0.01" fill="#fc0"/>
<path d="M 20,-22 a 3,22 0 1 0 0.01,0" fill="#c90"/>
<path d="M 0,-20 H 60 V 20 H 0" fill="url(#pattern_pair)"/>
<path d="M 59,-17 Z v 4 v 6 v 4 v 6 v 4 v 6 v 4 Z" stroke-width="2" marker-mid="url(#marker_tip)"/>
<g transform="translate(130,0)" fill="#09f">
<g id="pair_section">
<g id="wire_section">
<circle cx="3" cy="10" r="3" stroke="none"/>
<path d="M 3,8 a 2,2 0 0 0 0,4" fill="none" stroke-width="1.3"/>
<circle cx="3" cy="10" r="1.5" fill="#f90" stroke="#000"/>
</g>
<use xlink:href="#wire_section" stroke="#fff" transform="scale(-1,1)"/>
</g>
<use xlink:href="#pair_section" fill="#930" transform="rotate(270)"/>
<use xlink:href="#pair_section" fill="#f60" transform="rotate(180)"/>
<use xlink:href="#pair_section" fill="#090" transform="rotate(90)"/>
</g>
</g>
<g id="overlay">
<path d="M 20,-25 H 0 a 4,25 0 0 0 0,50 H 20 a 4,25 0 0 1 0,-50" fill="url(#grad_s)"/>
<path d="M 20,-25 a 4,25 0 0 0 0,50 V 22 a 3,22 0 0 1 0,-44" fill="#fc0"/>
<path class="lead" d="M 62,-17 L 80,{{y_c}} m 10,0 L 127,-10"/>
<path class="lead" d="M 56,-15 L 80,{{y_i}} m 10,0 L 126, -8"/>
<path class="lead" d="M 59, -7 L 80,{{y_p}} m 10,0 L 117, -3"/>
<path class="lead" d="M 59, -3 L 80,{{y_p}} m 10,0 L 117, 3"/>
<path class="lead" d="M 15, 24 L 80,{{y_s}} m 10,0 L 130, 24"/>
<g transform="translate(85,{{y_c}})">{{text_c}}</g>
<g transform="translate(85,{{y_i}})">{{text_i}}</g>
<g transform="translate(85,{{y_p}})">{{text_p}}</g>
<g transform="translate(85,{{y_s}})">{{text_s}}</g>
</g>
<g id="fi">
<path id="fi_side" d="M 0,-19 H 50 a 0.5,4 0 0 0 0,8 H 0" fill="url(#grad_fi)"/>
<use xlink:href="#fi_side" transform="translate(0,10)"/>
<use xlink:href="#fi_side" transform="translate(0,20)"/>
<use xlink:href="#fi_side" transform="translate(0,30)"/>
<g transform="translate(130,0)">
<path id="fi_section" d="M 0,4 a 8,6 0 1 0 0.01,0 v 2 a 6,4 0 1 1 -0.01,0" fill="#6ef"/>
<use xlink:href="#fi_section" transform="rotate(90)"/>
<use xlink:href="#fi_section" transform="rotate(180)"/>
<use xlink:href="#fi_section" transform="rotate(270)"/>
</g>
<path class="lead" d="M 45, 5 L 80,{{y_fi}} m 10,0 L 117, 6"/>
<g transform="translate(85,{{y_fi}})">{{text_fi}}</g>
</g>
<g id="fe">
<path d="M 0,-20 H 41 a 1,20 0 0 0 0,40 H 0" fill="url(#grad_fe)"/>
<path d="M 111,0 a 19,19 0 1 1 0,0.01 h 2 a 17,17 0 1 0 0,-0.01" fill="#69f" fill-opacity="0.5"/>
<path class="lead" d="M 35, 11 L 80,{{y_fe}} m 10,0 L 115, 10"/>
<g transform="translate(85,{{y_fe}})">{{text_fe}}</g>
</g>
<g id="se">
<path d="M 0,-22 H 31.7 a 2,22 0 0 0 0,44 H 0 M 108,0 a 22,22 0 1 1 0,0.01 h 2 a 20,20 0 1 0 0,-0.01" fill="url(#pattern_se)"/>
<path class="lead" d="M 25, 16 L 80,{{y_se}} m 10,0 L 117, 16"/>
<g transform="translate(85,{{y_se}})">{{text_se}}</g>
</g>
</defs>
<circle cx="0" cy="0" r="99999" fill="#fff"/>
<use xlink:href="#underlay"/>
{{flag_fi}}{{flag_fe}}{{flag_se}}
<use xlink:href="#overlay"/>
</svg>''').format(
flag_fi ='<use xlink:href="#fi"/>' if diagrams['fi'] else '',
flag_fe ='<use xlink:href="#fe"/>' if diagrams['fe'] else '',
flag_se ='<use xlink:href="#se"/>' if diagrams['se'] else '',
text_s =out_switchs['s' ], y_s =out_ys[ n_text - 1 ],
text_c =out_switchs['c' ], y_c =out_ys[ 0 ],
text_i =out_switchs['i' ], y_i =out_ys[ 1 ],
text_p =out_switchs['p' ], y_p =out_ys[ 2 ],
text_fi =out_switchs['fi'], y_fi=out_ys[ys.get('fi',0)],
text_fe =out_switchs['fe'], y_fe=out_ys[ys.get('fe',0)],
text_se =out_switchs['se'], y_se=out_ys[ys.get('se',0)],
basename=basename , out_scale=''.join(out_scales)))