Skip to content
Snippets Groups Projects
Commit 8d4ab7c9 authored by tuhe's avatar tuhe
Browse files

Updates/removal of thtools

parent 59d7d1a4
Branches
No related tags found
No related merge requests found
# slider # Slider
Slide overlay software based on beamer and inkscape Slide overlay software based on beamer and inkscape. This project is currently used in coursebox.
\ No newline at end of file The software also offers a package for jinja2 (jinjafy) which offers a handful of convenient extensions.
\ No newline at end of file
# #!/usr/bin/env python
# """Convert inkscape SVG files to TeX input.
#
# - SVG to PDF or EPS with inkscape, optionally with LaTeX output.
# - DOT to SVG
#
# Skips conversion if PDF file found newer than SVG source.
# Requires `inkscape` in path.
# """
# # Copyright 2010-2017 by Ioannis Filippidis
# # All rights reserved. Licensed under BSD-2.
# #
# import argparse
# import datetime
# import fnmatch
# import logging
# import os
# import shlex
# import subprocess
# import time
#
# import humanize
#
# import svg2latex as convert
# # from svglatex import convert
#
#
# log = logging.getLogger(__name__)
#
#
# def main():
# """Start from here."""
# args = parse_args()
# f = '{name}.svg'.format(name=args.input_file)
# out_type = args.method
# if './img/' in f:
# files = [f]
# else:
# files = locate(f, './img')
# svg = None
# for svg in files:
# log.info('Will convert SVG file "{f}" to {t}'.format(
# f=svg, t=out_type))
# convert_if_svg_newer(svg, out_type)
# if svg is None:
# raise Exception(
# 'SVG file "{f}" not found! '
# 'Cannot export to PDF.'.format(f=f))
#
#
# def parse_args():
# """Parse command-line arguments using."""
# parser = argparse.ArgumentParser()
# parser.add_argument(
# '-i', '--input-file', type=str,
# help=(
# 'Name (w/o extension) of SVG file. '
# 'Either file name to search for under `./img`, '
# 'or path that starts with `./img`.'))
# choices = [
# 'latex-pdf', 'pdf',
# 'latex-eps', 'eps']
# parser.add_argument(
# '-m', '--method', type=str, choices=choices,
# help=(
# 'Export to this file type. '
# 'The prefix "latex" produces also a file `*.pdf_tex` '
# 'that contains the text from the SVG. '
# 'The command `\includesvgpdf` passes `pdf`, '
# 'and `\includesvg` passes `latex-pdf`.'))
# args = parser.parse_args()
# return args
#
#
# def convert_if_svg_newer(svg, out_type):
# """Convert SVG file to PDF or EPS."""
# base, ext = os.path.splitext(svg)
# assert ext == '.svg', ext
# if 'pdf' in out_type:
# out = base + '.pdf'
# elif 'eps' in out_type:
# out = base + '.eps'
# else:
# raise ValueError(out_type)
# if not os.access(svg, os.F_OK):
# raise FileNotFoundError(
# 'No SVG file "{f}"'.format(f=svg))
# fresh = is_newer(out, svg)
# if out_type == 'latex-pdf':
# pdf_tex = base + '.pdf_tex'
# fresh &= is_newer(pdf_tex, svg)
# if fresh:
# log.info('No update needed, target newer than SVG.')
# return
# log.info('File not found or old. Converting from SVG...')
# convert_svg(svg, out, out_type)
#
#
# def is_newer(target, source):
# """Return `True` if `target` newer than `source` file."""
# assert os.path.isfile(source), source
# if not os.path.isfile(target):
# return False
# t_src = os.stat(source)[8]
# t_tgt = os.stat(target)[8]
# _print_dates(source, target, t_src, t_tgt)
# return t_src < t_tgt
#
#
# def _print_dates(source, target, t_src, t_tgt):
# s = _format_time(t_src)
# t = _format_time(t_tgt)
# log.info((
# 'last modification dates:\n'
# ' Source ({source}): {s}\n'
# ' Target ({target}): {t}').format(
# source=source, target=target,
# s=s, t=t))
#
#
# def _format_time(t):
# """Return time readable by humans."""
# return humanize.naturaltime(
# datetime.datetime.fromtimestamp(t))
#
#
# def convert_svg(svg, out, out_type):
# """Convert from SVG to output format."""
# # TODO: implement options `latex-eps`, `eps`
# assert out_type in ('latex-pdf', 'pdf'), out_type
# if out_type == 'latex-pdf':
# convert.main(svg)
# elif out_type == 'pdf':
# inkscape = convert.which_inkscape()
# svg_path = os.path.realpath(svg)
# out_path = os.path.realpath(out)
# args = [
# inkscape,
# '--without-gui',
# '--export-area-drawing',
# '--export-ignore-filters',
# '--export-dpi={dpi}'.format(dpi=96),
# '--export-pdf={out}'.format(out=out_path),
# svg_path]
# r = subprocess.call(args)
# if r != 0:
# raise Exception('Conversion error')
#
#
# def convert_svg_using_inkscape(svg, out, out_type):
# """Convert from SVG to output format."""
# # inkscape need be called with an absolute path on OS X
# # http://wiki.inkscape.org/wiki/index.php/MacOS_X
# symlink_relpath = 'bin/inkscape'
# home = os.path.expanduser('~')
# symlink_abspath = os.path.join(home, symlink_relpath)
# inkscape_abspath = os.path.realpath(symlink_abspath)
# svg_abspath = os.path.realpath(svg)
# args = ['{inkscape_abspath} -z -D --file={svg}'.format(
# inkscape_abspath=inkscape_abspath, svg=svg_abspath)]
# if 'pdf' in out_type:
# args.append('--export-pdf={pdf}'.format(pdf=out))
# if 'eps' in out_type:
# args.append('--export-eps={eps}'.format(eps=out))
# if 'latex' in out_type:
# args.append('--export-latex')
# args = shlex.split(' '.join(args))
# r = subprocess.call(args)
# if r != 0:
# raise Exception(
# 'conversion from "{svg}" to "{out}" failed'.format(
# svg=svg, out=out))
#
#
# def locate(pattern, root=os.curdir):
# """Locate all files matching supplied filename pattern under `root`."""
# for path, dirs, files in os.walk(os.path.abspath(root)):
# for filename in fnmatch.filter(files, pattern):
# yield os.path.join(path, filename)
#
#
# if __name__ == '__main__':
# main()
...@@ -27,5 +27,5 @@ setuptools.setup( ...@@ -27,5 +27,5 @@ setuptools.setup(
package_dir={"": "src"}, package_dir={"": "src"},
packages=setuptools.find_packages(where="src"), packages=setuptools.find_packages(where="src"),
python_requires=">=3.8", python_requires=">=3.8",
install_requires=['jinja2',], install_requires=['jinja2', 'numpy', 'scipy', 'bs4', 'lxml', 'codecs', 'optparse', 'PyPDF2', 'pickle'],
) )
from jinjafy.jinjafy import jinjafy_comment
from jinjafy.jinjafy import jinjafy_template
from jinjafy.jinja_matlab_load import matlab_load
from jinjafy.textools import mat2table
import subprocess
# from subprocess import subprocess
# def get_system_name():
# if is_win():
# return "Win"
# if is_compute():
# return "thinlinc.compute.dtu.dk"
# if is_cogsys_cluster():
# return "cogys cluster"
def execute_command(command, shell=True):
if not isinstance(command, list):
command = [command]
# if not is_compute():
# result = subprocess.run(command, stdout=subprocess.PIPE, shell=shell)
# out = result.stdout
# else:
out = subprocess.check_output(command, shell=shell)
s = out.decode("utf-8")
OK = True
return s, OK
\ No newline at end of file
from thtools.cache.simplecache import cache_update_str as cache_update_str
from thtools.cache.simplecache import cache_contains_str as cache_contains_str
from thtools.cache.simplecache import cache_update_file as cache_update_file
from thtools.cache.simplecache import cache_contains_file as cache_contains_file
from thtools.cache.simplecache import cache_update_dir as cache_update_dir
from thtools.cache.simplecache import cache_contains_dir as cache_contains_dir
\ No newline at end of file
from hashlib import md5
import os
import pickle
import glob
def dir_content_cache_(dir, pattern="*"):
fl = glob.glob(dir + "/" + pattern)
s = ''.join(fl)
key = "key_"+dir
return fl, s,key
def cache_contains_dir(cache_base, dir, pattern="*"):
# fl = glob.glob(dir)
fl,s,key = dir_content_cache_(dir, pattern=pattern)
v = [cache_contains_file(cache_base, f) for f in fl]
if all(v) and cache_contains_str(cache_base, key, s):
return True
return False
def cache_update_dir(cache_base, dir, pattern="*"):
fl, s, key = dir_content_cache_(dir, pattern=pattern)
cache_update_str(cache_base, key, s)
for f in fl:
cache_update_file(cache_base, f)
def cache_contains_str(cache_base,key=None,value=None):
assert(key or value)
value = hash_binary_(value.encode())
if not key: key = value
return cache_contains_hash(cache_base, key, value)
def cache_update_str(cache_base,key,value):
assert(key or value)
value = hash_binary_(value.encode())
if not key: key = value
return cache_update_hash(cache_base, key, value)
def cache_contains_file(cache_base,file):
key = os.path.abspath(file)
if not os.path.exists(file):
return False
value = hash_file_(file)
return cache_contains_hash(cache_base, key, value)
def hash_file_(file):
import hashlib
hasher = hashlib.md5()
with open(file, 'rb') as afile:
buf = afile.read()
hasher.update(buf)
return hasher.hexdigest()
def cache_update_file(cache_base, file):
key = os.path.abspath(file)
value = hash_file_(file)
return cache_update_hash(cache_base, key, value)
def cache_contains_hash(cache_base,key,hash_val):
cc = load_cache(cache_base)
return cc.get(key,"Not found") == hash_val
def cache_update_hash(cache_base,key,hash_val):
cc = load_cache(cache_base)
cc[key] = hash_val
save_cache(cache_base, cc)
def hash_binary_(str_bin):
return md5(str_bin).hexdigest()
def cache_file(cache_base):
return os.path.join(cache_base, "cache.pkl")
def save_cache(cache_base, cache):
with open(cache_file(cache_base), 'wb') as f:
pickle.dump(cache,f)
def load_cache(cache_base):
if not os.path.exists(cache_file(cache_base)):
save_cache(cache_base, {'default' : 42})
return load_cache(cache_base)
with open(cache_file(cache_base), 'rb') as f:
return pickle.load(f)
if __name__ == "__main__":
cache_base = "./"
print("Hello World")
import numpy as np
from fractions import Fraction
import jinja2
def format_list_symbols(list, pattern, symbol="x", seperator=",\ "):
return format_join(list, pattern=symbol+"_{%i}", seperator=seperator)
def n2w(i):
w = {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7: 'seven', 8: 'eight',
9: 'nine', 10: 'ten'}
return i if i < 0 or i > 10 else w[i]
def format_list(list_, pattern):
list_ = tolist(list_)
return [pattern % s for s in list_]
def format_join(list, pattern, seperator=",\ ",withand=False,withor=False,lastsep=None):
ls = format_list(list, pattern)
if withand:
return seperator.join(ls[:-1]) + "$, and $" + ls[-1]
if withor:
return seperator.join(ls[:-1]) + "$, or $" + ls[-1]
return seperator.join(ls)
def format_join_enum(list, pattern="x_{%i}=%g", seperator=",\ "):
list = tolist(list)
return seperator.join(format_list( zip( range(1,len(list)+1 ), list), pattern))
def as_set(l, symbol='f_{%i}'):
if type(l) != list and type(l) != np.ndarray:
l = [l]
l = tolist(l)
s = [symbol%(i,) for i in l]
s = '\{' + ", ".join(s) + "\}"
return s
def as_set_list(ll, symbol='%g'):
s = []
for l in ll.flat:
l = tolist(l)
s.append(as_set(l, symbol))
s = ["$"+ds+"$" for ds in s]
s = ", ".join(s)
return s
def infty(n,tol=10^8):
if n > tol:
s = '\infty'
else:
s = str(n)
return s
def flatten(ar):
v = []
if type(ar) is np.ndarray or type(ar) is np.array:
for x in ar.flat:
m = flatten(x)
if type(m) == list:
v = v + m
else:
v.append(m)
else:
v = ar
return v
def tolist(l):
if type(l) == np.ndarray:
l2 = []
for x in l.flat:
l2.append( x.tolist() if isinstance(x,np.ndarray) else x )
l = l2
elif type(l) == list or hasattr(l, '__iter__'):
pass
else:
l = [l]
return l
def jget(A,n=0):
A = flatten(A)
return A[n]
def as_rational(x, output='tex', always_frac=False):
if type(x) == jinja2.runtime.Undefined:
return "UNDEFINED(jinja2)"
b = Fraction.from_float(x).limit_denominator(10000)
s = "output_error_in_as_rational_filter"
if output == 'tex':
if (b.denominator == 1 or b.numerator == 0) and not always_frac:
s = '%i'%b.numerator
else:
s = "\\frac{%i}{%i}"%(b.numerator, b.denominator)
return s
def mylen(l):
if isinstance(l, np.ndarray):
sz = l.size
else:
sz = len(l)
return sz
def permute_exam_answers(section,permutation):
v = section.split("\\item")
v = v[:5] + v[-1:]
assert(len(v) == 6)
permutation = [0] + permutation + [5]
v[0] = "\\begin{answer}[%i]\n"%permutation.index(1)
v2 = "\\item".join( [v[i] for i in permutation] )
return v2
def startswithvowel(value):
if value.lower().startswith(("a", "e", "i", "o","u")):
return True
else:
return False
def aan(s):
if s.startswith("no "):
return ""
return "an" if startswithvowel(s) else "a"
import numpy as np
import scipy.io as spio
def matlab_load(mfile):
j = mfile.rfind('.')
if j > -1:
ex = mfile[j + 1:]
base = mfile[:j]
else:
ex = ''
base = mfile
mat = loadmat(base + '.mat')
mat = uuroll(mat)
mat = fix_1_arrays(mat)
mat = fix_strings(mat)
mat = fix_simple_lists(mat)
return mat
def loadmat(filename):
'''
this function should be called instead of direct spio.loadmat
as it cures the problem of not properly recovering python dictionaries
from mat files. It calls the function check keys to cure all entries
which are still mat-objects
'''
data = spio.loadmat(filename,struct_as_record=False)
data2 = _check_keys(data)
return data2
def _check_keys(dd):
'''
checks if entries in dictionary are mat-objects. If yes
todict is called to change them to nested dictionaries
'''
if isinstance(dd, spio.matlab.mio5_params.mat_struct):
dd = _check_keys(_todict(dd))
elif type(dd) == dict:
for key in dd:
kv = flist(dd[key])
if type( kv ) == spio.matlab.mio5_params.mat_struct:
dd[key] = _check_keys(kv)
else:
dd[key] = _check_keys(dd[key])
elif type(dd) == list:
dd = [_check_keys(l) for l in dd]
elif type(dd) == np.ndarray:
if dd.dtype.str == '|O' and dd.size > 0:
if type( flist(dd.flat[0]) ) == spio.matlab.mio5_params.mat_struct:
for i in range( dd.size ):
dd.flat[i] = _check_keys( flist( dd.flat[i]) )
else:
for i in range(dd.size):
dd.flat[i] = _check_keys(dd.flat[i])
return dd
def fix_simple_lists(l):
if type(l) == dict:
for k,v in l.items():
l[k] = fix_simple_lists(v)
elif type(l) == np.ndarray and l.dtype.name == "uint8" and l.shape[0] == 1 and l.ndim == 2:
# l = l.tolist()
l = l.tolist()[0]
return l
def apply_recursively(l, myfun):
if type(l) == dict:
for k,v in l.items():
l[k] = apply_recursively(v, myfun)
elif type(l) == np.ndarray and l.dtype.str == '|O' and l.size > 0:
for i in range( l.size ):
l.flat[i] = apply_recursively( l.flat[i], myfun)
else:
l = myfun(l)
return l
def fix_1_arrays(l):
def _fix_1_arrays(l):
if type(l) == np.ndarray and l.size == 1 and np.issubdtype(l.dtype, np.number):
l = l.flat[0]
return l
l = apply_recursively(l, _fix_1_arrays)
return l
def fix_strings(l):
if type(l) == dict:
for k,v in l.items():
l[k] = fix_strings(v)
elif type(l) == np.ndarray and l.size > 0:
tp = type(superpop(l.flat[0]))
if tp == str or tp == np.str_:
l = [superpop(x) for x in l.flat ]
if len(l) == 1:
l = l.pop()
return l
def superpop(l):
if type(l) == list and len(l) == 1:
return superpop(l[0])
if type(l) == np.ndarray and l.size == 1:
return superpop(l.tolist())
return l
def flist(l):
if type(l) == list and len(l) == 1:
l = flist( l.pop() )
if type(l) == np.ndarray and l.dtype.name == "object":
l3 = [flist(v) for v in l.flat]
l = flist( l3 )
return l
def _todict(matobj):
'''
A recursive function which constructs from matobjects nested dictionaries
'''
dict = {}
for strg in matobj._fieldnames:
elem = matobj.__dict__[strg]
if isinstance(elem, spio.matlab.mio5_params.mat_struct):
dict[strg] = _todict(elem)
else:
dict[strg] = elem
return dict
def uuroll(v):
if type(v) is dict:
for key,val in v.items():
v[key] = uuroll(val)
if type(v) is np.ndarray or type(v) is np.array:
for j in range(v.size):
v.flat[j] = uuroll(v.flat[j])
return v
def uroll(mat):
for k in mat.keys():
v = mat[k]
v = uuroll(v)
mat[k] = v
return mat
\ No newline at end of file
import inspect
import jinja2
from math import floor, log10
import os
import numpy as np
from jinjafy import jinja_env
def jinjafy_template(data,file_in,file_out=None, filters={},template_searchpath=None):
if template_searchpath:
file_in = os.path.relpath(file_in, template_searchpath)
return jinjafy_comment(data, file_in=file_in, file_out=file_out,jinja_tag=None, filters=filters,template_searchpath=template_searchpath)
def jinjafy_comment(data,file_in=None,file_out=None,jinja_tag="jinja",jinja_code=None,trim_whitespace=True,trim_comments=True,comment_char="#",
filters={},template_searchpath=None):
# Extract all comments from the given file and jinjafy them.
if file_in is None:
frame = inspect.stack()[1]
module = inspect.getmodule(frame[0])
file_in = module.__file__
elif not jinja_tag:
trim_comments=False
trim_whitespace=False
if not template_searchpath:
with open(file_in,'r') as f:
s = f.read()
if jinja_tag:
stag = "<" + jinja_tag + ">"
etag = "</" + jinja_tag + ">"
i_start = s.find(stag)
i_end = s.find(etag)
s = s[i_start+len(stag):i_end]
ss = [s]
if trim_comments:
ss = [ds.strip()[1:] for ds in s.splitlines() if len(ds.strip()) > 0 and ds.strip()[0] in ["#", "%"] ]
if trim_whitespace:
ss = [ds.strip() for ds in ss]
jinja_code = '\n'.join(ss)
from thtools.jinjafy.snipper import SnipperExtension
extensions = [SnipperExtension]
if template_searchpath:
if not isinstance(template_searchpath, list):
template_searchpath = [template_searchpath]
template_searchpath = [ts.replace("\\", "/") for ts in template_searchpath]
templateLoader = jinja2.FileSystemLoader(searchpath=template_searchpath)
env = jinja2.Environment(lstrip_blocks=True, trim_blocks=True,loader=templateLoader, extensions=extensions)
else:
env = jinja2.Environment(lstrip_blocks=True, trim_blocks=True, extensions=extensions)
import math
env.globals['exp'] = math.exp
env.globals['sqrt'] = math.sqrt
env.globals['cos'] = math.cos
env.globals['sin'] = math.sin
env.globals['mround'] = mround
env.globals['bold'] = bold
env.globals['fmat'] = fmat
env.globals['enumerate'] = enumerate
env.globals['zip'] = zip
env.globals['ensure_numpy'] = ensure_numpy
env.globals['transpose'] = transpose
import math
env.globals['ceil'] = math.ceil
env.globals['floor'] = math.floor
import thtools
if not thtools.is_cluster():
from pylatexenc import latexencode
env.globals['utf8tolatex'] = latexencode.utf8tolatex
env.globals['as_set'] = jinja_env.as_set
env.globals['as_set_list'] = jinja_env.as_set_list
env.globals['len'] = jinja_env.mylen
env.globals['get'] = jinja_env.jget
env.globals['tolist'] = jinja_env.tolist
filters['as_set'] = jinja_env.as_set
filters['format_list'] =jinja_env.format_list
filters['format_join'] = jinja_env.format_join
filters['format_join_enum'] = jinja_env.format_join_enum
filters['pm'] = lambda x: f" {x}" if x < 0 else f"+{x}"
filters['bold'] = bold
filters['capfirst'] = lambda x: (x[0].upper() + x[1:] if len(x) > 1 else x.upper()) if x != None and isinstance(x, str) else x
filters['lowerfirst'] = lambda x: (x[0].lower() + x[1:] if len(x) > 1 else x.lower()) if x != None and isinstance(x, str) else x
filters['infty'] = jinja_env.infty
filters['n2w'] = jinja_env.n2w
def latex_url(url):
if not isinstance(url, str):
return url
url = url.replace("%", r"\%")
return url
filters['latex_url'] = latex_url
filters['format_list_symbols'] = jinja_env.format_list_symbols
filters['mround'] = mround
def eround(val,l):
x = str(mround(val, l))
if l == 0:
return x
if '.' not in x:
x = x + "."
n = l - (len(x) - x.find(".") - 1)
if n > 0:
x = x + "0"*n
return x
filters['eround'] = eround
filters['get'] = jinja_env.jget
filters['flatten'] = jinja_env.flatten
filters['aan'] = jinja_env.aan
filters['bracket'] = bracket
filters['tolist'] = jinja_env.tolist
filters['rational'] = jinja_env.as_rational
filters['permute_exam_answers'] = jinja_env.permute_exam_answers
env.filters.update(filters)
data['block_start_string'] = '{%'
if not template_searchpath:
jinja_out = env.from_string(jinja_code).render(data)
else:
file_in = file_in.replace("\\", "/")
template = env.get_template(file_in)
jinja_out = template.render(data)
if file_out is not None:
with open(file_out,'w',encoding='utf-8') as f:
# jinja_out = jinja_out.encode('utf-8')
f.write(jinja_out)
print("Writing to: " + file_out)
return jinja_out
def bold(bob,d=True) :
if not isinstance(bob, str) :
bob = str(bob)
if d :
bob = '\\textbf{' + bob +"}"
return bob
def fmat(bob,l=2,dobold=False) :
bob = mround(bob,l)
bob = bold(bob, dobold)
return bob
def bracket(s):
return "{"+str(s)+"}"
def un2str(x, xe, precision=2):
"""pretty print nominal value and uncertainty
x - nominal value
xe - uncertainty
precision - number of significant digits in uncertainty
returns shortest string representation of `x +- xe` either as
x.xx(ee)e+xx
or as
xxx.xx(ee)"""
# base 10 exponents
x_exp = int(floor(log10(x)))
xe_exp = int(floor(log10(xe)))
# uncertainty
un_exp = xe_exp - precision + 1
un_int = round(xe * 10 ** (-un_exp))
# nominal value
no_exp = un_exp
no_int = round(x * 10 ** (-no_exp))
# format - nom(unc)exp
fieldw = x_exp - no_exp
fmt = '%%.%df' % fieldw
result1 = (fmt + '(%.0f)e%d') % (no_int * 10 ** (-fieldw), un_int, x_exp)
# format - nom(unc)
fieldw = max(0, -no_exp)
fmt = '%%.%df' % fieldw
result2 = (fmt + '(%.0f)') % (no_int * 10 ** no_exp, un_int * 10 ** max(0, un_exp))
# return shortest representation
if len(result2) <= len(result1):
return result2
else:
return result1
def mround(val, l=2):
if not isinstance(l, int):
return un2str(val, l, 1)
else:
if isinstance(val, np.ndarray):
return np.round(val * 10 ** l) / (10 ** l)
else:
return round(val * 10 ** l) / (10 ** l)
def transpose(X):
return np.transpose( ensure_numpy( X) )
def ensure_numpy(X):
if type(X) != np.ndarray:
X = np.asarray(X)
if X.ndim == 1:
X = np.transpose( np.expand_dims(X,1) )
return X
\ No newline at end of file
from jinja2 import nodes
from jinja2.ext import Extension
import os
import thtools
class SnipperExtension(Extension):
# a set of names that trigger the extension.
tags = set(['snipper'])
def __init__(self, environment):
super(SnipperExtension, self).__init__(environment)
# add the defaults to the environment
environment.extend(
fragment_cache_prefix='',
fragment_cache=None
)
self.ofile = ""
def parse(self, parser):
# the first token is the token that started the tag. In our case
# we only listen to ``'cache'`` so this will be a name token with
# `cache` as value. We get the line number so that we can give
# that line number to the nodes we create by hand.
lineno = next(parser.stream).lineno
# now we parse a single expression that is used as cache key.
args = [parser.parse_expression()]
ofile = os.path.join(os.path.dirname(parser.filename), args[0].value)
args[0].value = ofile
thtools.ensure_dir_exists(os.path.dirname(ofile))
self.ofile = ofile
print("Snipper args", args, "ofile", ofile)
# if there is a comma, the user provided a timeout. If not use
# None as second parameter.
if parser.stream.skip_if('comma'):
args.append(parser.parse_expression())
else:
args.append(nodes.Const(None))
# now we parse the body of the cache block up to `endcache` and
# drop the needle (which would always be `endcache` in that case)
body = parser.parse_statements(['name:endsnipper'], drop_needle=True)
# now return a `CallBlock` node that calls our _cache_support
# helper method on this extension.
return nodes.CallBlock(self.call_method('_snip_method', args),
[], [], body).set_lineno(lineno)
# parser.environment.loader.searchpath
# parser.parse_statements(body)
return body
def _snip_method(self, name, timeout, caller):
# rv = 0
# key = self.environment.fragment_cache_prefix + name
# try to load the block from the cache
# if there is no fragment in the cache, render it and store
# it in the cache.
# rv = self.environment.fragment_cache.get(key)
# if rv is not None:
# return rv
rv = caller()
outfile = name
print("Actually snipping to ", self.ofile, "name", name, "timeout", timeout)
with open(name, 'w') as f:
f.write(rv)
# print("Actually snipping to ", self.ofile, 'writing', rv)
# self.environment.fragment_cache.add(key, rv, timeout)
return rv
def _cache_support(self, name, timeout, caller):
"""Helper callback."""
key = self.environment.fragment_cache_prefix + name
# try to load the block from the cache
# if there is no fragment in the cache, render it and store
# it in the cache.
rv = self.environment.fragment_cache.get(key)
if rv is not None:
return rv
rv = caller()
self.environment.fragment_cache.add(key, rv, timeout)
return rv
\ No newline at end of file
from jinjafy import jinjafy_comment
import numpy as np
#"<jinja1>"
#\begin{tabular}{ {{cc}} }
# {% if bookstabs %}\toprule{% endif %}
# {% if vvlabels %}
# {% for vl in vvlabels %}
# {% if loop.index > 1 %} & {% endif %} \multicolumn{ {{vl[0]}} }{ {{vl[2]}} }{ {{vl[1]}} }
# {% endfor %} \\
# {% for vl in vvlabels %}
# {% if vl[3] %}
# \cmidrule(r){ {{vl[3]}} }
# {% endif %}
# {% endfor %}
# {% endif %}
# {% for row in X %}
# {% if bookstabs and loop.index == 2%}\midrule{% endif %}
# {% for c in row %}
# {% if loop.index > 1 %} & {% endif %} {{ c['tex'] }} {% if loop.index == W %} \\ {% endif %}
# {% endfor %}
# {% endfor %}
# {% if bookstabs %}\bottomrule{% endif %}
#\end{tabular}
#</jinja1>
# Convert a matrix to a table super quickly
def mat2table(X,vlabels=None,hlabels=None,file_out = None, bookstabs=True, vvlabels=None,plot=False,pdf_out=None, standalone=False):
X, Xx, Xerr,Xdl = fmat_X2dict(X)
if pdf_out: plot = True
#%%
if plot:
import matplotlib.pyplot as plt
#plt.style.use('ggplot')
plt.style.use('seaborn')
fig = plt.figure()
ax = fig.gca()
#ax = plt.gca()
ls = []
for j in range(X.shape[0]):
ls.append(ax.plot(Xx[j, :]).pop() )
if Xerr[j]:
plt.errorbar(range(X.shape[1]), Xx[j,:], yerr=Xerr[j], color=ls[j].get_color())
for i in range( X.shape[1] ):
if 'xs' in X[j,i]:
plt.plot([i]*len(X[j,i]['xs']), X[j,i]['xs'], '.', color=ls[j].get_color())
if vlabels:
plt.legend(ls, vlabels, bbox_to_anchor=(1.04, 1), loc="upper left")
if hlabels:
plt.xticks(range(X.shape[1]), hlabels[1:])
#plt.subplots_adjust(right=0.5)
plt.tight_layout(rect=[0, 0, 1, 1])
plt.show()
#if pdf_out:
# fig.savefig(pdf_out, bbox_inches='tight')
if vlabels:
vltex = [{'tex': v} for v in vlabels]
for i in range(len(Xdl)):
Xdl[i] = [vltex[i]] + Xdl[i]
if hlabels:
Xdl = [ [{'tex': h} for h in hlabels] ] + Xdl
if vvlabels:
cc = 1
for i in range(len(vvlabels)):
if len(vvlabels[i]) < 3:
vvlabels[i].append("c")
dl = vvlabels[i][0]
if dl == 1:
a = None
else:
a = "%i-%i"%(cc, cc+dl-1)
cc = cc + dl
vvlabels[i] = vvlabels[i] + [a]
H = len(Xdl)
W = len(Xdl[0])
cc = ["c" for i in range(W)]
if vlabels:
cc[0] = "l"
cc = "".join(cc)
def fmat(x):
if isinstance(x, int):
x = str(x)
if isinstance(x, float):
x = "%2.3f"%x
return x
#X = [ [fmat(x) for x in row] for row in X]
data = {'X' : Xdl, 'hlabels': hlabels, 'vlabels': vlabels, 'cc': cc, 'H':H, 'W': W, 'bookstabs': bookstabs,
'vvlabels': vvlabels}
from thtools.jinjafy.jinjafy import jinjafy_comment
s = jinjafy_comment(data,jinja_tag="jinja1")
if file_out:
print("Writing to: " + file_out)
if standalone:
s = jinjafy_comment({"s": s}, jinja_tag="jinja3")
with open(file_out, 'w') as f:
f.write(s)
if standalone:
from thtools import latexmk
latexmk(file_out)
return s
# "<jinja3>"
# \documentclass[crop]{standalone}
# \usepackage{booktabs}
# \usepackage{siunitx}
# \begin{document}
# {{s}}
# \end{document}
# </jinja3>
def fmat_X2dict(X):
X = np.asarray(X, dtype=np.object)
if len(X.shape) > 2:
X2 = np.ndarray(X.shape[:2], dtype=np.object)
for i in range(X.shape[0]):
for j in range(X.shape[1]):
X2[i, j] = X[i, j, :].squeeze()
X = X2
X = np.reshape(X, X.shape[:2])
for i in range(X.shape[0]):
for j in range(X.shape[1]):
dx = X[i,j]
if isinstance(dx, (list, np.ndarray)):
dx = [x for x in np.ravel(dx)]
if not isinstance(dx, dict):
dx = {'x': dx}
elif not isinstance(dx['x'], str):
x = dx['x']
# if isinstance(x, np.ndarray):
if 'tex' not in dx:
dx['std'] = np.std(x)
dx['std_mean'] = np.std(x) / np.sqrt( len(x))
dx['xs'] = x
dx['x'] = np.mean(x)
x2, u2 = mround( dx['x'], dx['std_mean'] )
dx['tex'] = '\\SI{%g\\pm %.2f}{}'%(x2, u2)
if 'tex' not in dx:
dx['tex'] = dx['x']
X[i,j] = dx
Xerr = [None] * X.shape[0]
Xx = np.zeros(X.shape)
for i in range(X.shape[0]):
if "std" in X[0,0]:
Xerr[i] = [dx['std_mean'] for dx in X[i]]
for j in range(X.shape[1]):
Xx[i,j] = X[i,j]['x']
Xdl = []
for i in range(X.shape[0]):
dx = []
for j in range(X.shape[1]):
dx.append(X[i,j])
Xdl.append(dx)
return X,Xx,Xerr,Xdl
import math
def mround(x,u):
n = np.floor(np.log10(x)+1)
dx = np.round(x / np.power(10.0, n), 2)
du = np.round(u / np.power(10.0, n), 2)
return dx * np.power(10, n), du * np.power(10.0,n)
from thtools import execute_command from jinjafy import execute_command
import os
from bs4 import BeautifulSoup
# import thtools
def svg2pdf(fin, fout=None, crop=True, text_to_path=False, export_area_page=True): def svg2pdf(fin, fout=None, crop=True, text_to_path=False, export_area_page=True):
""" """
...@@ -65,9 +68,6 @@ def pdfcrop(fin, fout=None): ...@@ -65,9 +68,6 @@ def pdfcrop(fin, fout=None):
execute_command(cmd.split()) execute_command(cmd.split())
import os
from bs4 import BeautifulSoup
import thtools
def svg_edit_to_importable(svg_edit_file,verbose=False, keep_background_layer=True): def svg_edit_to_importable(svg_edit_file,verbose=False, keep_background_layer=True):
""" """
...@@ -114,7 +114,7 @@ def svg_edit_to_importable(svg_edit_file,verbose=False, keep_background_layer=Tr ...@@ -114,7 +114,7 @@ def svg_edit_to_importable(svg_edit_file,verbose=False, keep_background_layer=Tr
f2.write(s2.encode("UTF-8")) f2.write(s2.encode("UTF-8"))
cmd = ['inkscape', '-C', '-T', '--without-gui', '--file=%s'%svg_fonts_layers[-1], '--export-pdf=%s' % pdf_nofonts_layers[-1]] cmd = ['inkscape', '-C', '-T', '--without-gui', '--file=%s'%svg_fonts_layers[-1], '--export-pdf=%s' % pdf_nofonts_layers[-1]]
thtools.execute_command(cmd) execute_command(cmd)
if verbose: if verbose:
print("svg_edit_to_importable called. Converting svg file\n > %s\nto files:"%svg_edit_file) print("svg_edit_to_importable called. Converting svg file\n > %s\nto files:"%svg_edit_file)
......
#!/usr/bin/env python
"""Convert inkscape SVG files to TeX input.
- SVG to PDF or EPS with inkscape, optionally with LaTeX output.
- DOT to SVG
Skips conversion if PDF file found newer than SVG source.
Requires `inkscape` in path.
"""
# Copyright 2010-2017 by Ioannis Filippidis
# All rights reserved. Licensed under BSD-2.
#
import argparse
import datetime
import fnmatch
import logging
import os
import shlex
import subprocess
import time
import humanize
import svg2latex as convert
# from svglatex import convert
log = logging.getLogger(__name__)
def main():
"""Start from here."""
args = parse_args()
f = '{name}.svg'.format(name=args.input_file)
out_type = args.method
if './img/' in f:
files = [f]
else:
files = locate(f, './img')
svg = None
for svg in files:
log.info('Will convert SVG file "{f}" to {t}'.format(
f=svg, t=out_type))
convert_if_svg_newer(svg, out_type)
if svg is None:
raise Exception(
'SVG file "{f}" not found! '
'Cannot export to PDF.'.format(f=f))
def parse_args():
"""Parse command-line arguments using."""
parser = argparse.ArgumentParser()
parser.add_argument(
'-i', '--input-file', type=str,
help=(
'Name (w/o extension) of SVG file. '
'Either file name to search for under `./img`, '
'or path that starts with `./img`.'))
choices = [
'latex-pdf', 'pdf',
'latex-eps', 'eps']
parser.add_argument(
'-m', '--method', type=str, choices=choices,
help=(
'Export to this file type. '
'The prefix "latex" produces also a file `*.pdf_tex` '
'that contains the text from the SVG. '
'The command `\includesvgpdf` passes `pdf`, '
'and `\includesvg` passes `latex-pdf`.'))
args = parser.parse_args()
return args
def convert_if_svg_newer(svg, out_type):
"""Convert SVG file to PDF or EPS."""
base, ext = os.path.splitext(svg)
assert ext == '.svg', ext
if 'pdf' in out_type:
out = base + '.pdf'
elif 'eps' in out_type:
out = base + '.eps'
else:
raise ValueError(out_type)
if not os.access(svg, os.F_OK):
raise FileNotFoundError(
'No SVG file "{f}"'.format(f=svg))
fresh = is_newer(out, svg)
if out_type == 'latex-pdf':
pdf_tex = base + '.pdf_tex'
fresh &= is_newer(pdf_tex, svg)
if fresh:
log.info('No update needed, target newer than SVG.')
return
log.info('File not found or old. Converting from SVG...')
convert_svg(svg, out, out_type)
def is_newer(target, source):
"""Return `True` if `target` newer than `source` file."""
assert os.path.isfile(source), source
if not os.path.isfile(target):
return False
t_src = os.stat(source)[8]
t_tgt = os.stat(target)[8]
_print_dates(source, target, t_src, t_tgt)
return t_src < t_tgt
def _print_dates(source, target, t_src, t_tgt):
s = _format_time(t_src)
t = _format_time(t_tgt)
log.info((
'last modification dates:\n'
' Source ({source}): {s}\n'
' Target ({target}): {t}').format(
source=source, target=target,
s=s, t=t))
def _format_time(t):
"""Return time readable by humans."""
return humanize.naturaltime(
datetime.datetime.fromtimestamp(t))
def convert_svg(svg, out, out_type):
"""Convert from SVG to output format."""
# TODO: implement options `latex-eps`, `eps`
assert out_type in ('latex-pdf', 'pdf'), out_type
if out_type == 'latex-pdf':
convert.main(svg)
elif out_type == 'pdf':
inkscape = convert.which_inkscape()
svg_path = os.path.realpath(svg)
out_path = os.path.realpath(out)
args = [
inkscape,
'--without-gui',
'--export-area-drawing',
'--export-ignore-filters',
'--export-dpi={dpi}'.format(dpi=96),
'--export-pdf={out}'.format(out=out_path),
svg_path]
r = subprocess.call(args)
if r != 0:
raise Exception('Conversion error')
def convert_svg_using_inkscape(svg, out, out_type):
"""Convert from SVG to output format."""
# inkscape need be called with an absolute path on OS X
# http://wiki.inkscape.org/wiki/index.php/MacOS_X
symlink_relpath = 'bin/inkscape'
home = os.path.expanduser('~')
symlink_abspath = os.path.join(home, symlink_relpath)
inkscape_abspath = os.path.realpath(symlink_abspath)
svg_abspath = os.path.realpath(svg)
args = ['{inkscape_abspath} -z -D --file={svg}'.format(
inkscape_abspath=inkscape_abspath, svg=svg_abspath)]
if 'pdf' in out_type:
args.append('--export-pdf={pdf}'.format(pdf=out))
if 'eps' in out_type:
args.append('--export-eps={eps}'.format(eps=out))
if 'latex' in out_type:
args.append('--export-latex')
args = shlex.split(' '.join(args))
r = subprocess.call(args)
if r != 0:
raise Exception(
'conversion from "{svg}" to "{out}" failed'.format(
svg=svg, out=out))
def locate(pattern, root=os.curdir):
"""Locate all files matching supplied filename pattern under `root`."""
for path, dirs, files in os.walk(os.path.abspath(root)):
for filename in fnmatch.filter(files, pattern):
yield os.path.join(path, filename)
if __name__ == '__main__':
main()
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
# https://github.com/eea/odfpy # https://github.com/eea/odfpy
import os import os
import shutil import shutil
import thtools # import thtools
from thtools.jinjafy import jinjafy_comment from jinjafy import jinjafy_comment
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import glob import glob
from jinjafy import execute_command
CDIR = os.path.dirname(os.path.realpath(__file__)) CDIR = os.path.dirname(os.path.realpath(__file__))
CDIR = CDIR.replace('\\','/') CDIR = CDIR.replace('\\','/')
...@@ -26,7 +27,7 @@ def join_pdfs(slide_deck_pdf, outfile): ...@@ -26,7 +27,7 @@ def join_pdfs(slide_deck_pdf, outfile):
files = [os.path.relpath(os.path.dirname(pdf), start=dn) + "/" + os.path.basename(pdf) for pdf in slide_deck_pdf] files = [os.path.relpath(os.path.dirname(pdf), start=dn) + "/" + os.path.basename(pdf) for pdf in slide_deck_pdf]
outf = os.path.relpath(os.path.dirname(outfile), start=dn) + "/" + os.path.basename(outfile) outf = os.path.relpath(os.path.dirname(outfile), start=dn) + "/" + os.path.basename(outfile)
cmd = "cd " + dn + " && pdftk " + " ".join(files) + " cat output " + outf cmd = "cd " + dn + " && pdftk " + " ".join(files) + " cat output " + outf
thtools.execute_command(cmd.split()) execute_command(cmd.split())
def li_import(slide_deck_pdf, tex_output_path=None, num_to_take=None, force=False, svg_pfix="osvg", svg_height=743.75, svg_width=992.5, def li_import(slide_deck_pdf, tex_output_path=None, num_to_take=None, force=False, svg_pfix="osvg", svg_height=743.75, svg_width=992.5,
......
from thtools.slider import legacy_importer from slider import legacy_importer
import PyPDF2 import PyPDF2
import os import os
import thtools # import thtools
from thtools.slider.legacy_importer import SVG_EDIT_RELPATH, SVG_TMP_RELPATH, move_template_files, DTU_beamer_base from slider.legacy_importer import SVG_EDIT_RELPATH, SVG_TMP_RELPATH, move_template_files, DTU_beamer_base
from thtools.cache import cache_update_str, cache_contains_str, cache_contains_file, cache_update_file from jinjafy.cache import cache_update_str, cache_contains_str, cache_contains_file, cache_update_file
import shutil import shutil
from thtools.slider.slide_fixer import check_svg_file_and_fix_if_broken from slider.slide_fixer import check_svg_file_and_fix_if_broken
dc = "\\documentclass" dc = "\\documentclass"
def fix_handout(s): def fix_handout(s):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment