From a29467d9b8e624f194f9763126c2229748c947e0 Mon Sep 17 00:00:00 2001 From: Benjamin Knebusch Date: Mon, 28 Feb 2022 11:30:37 +0100 Subject: [PATCH 1/5] The unit name has to be the whole string until the end of unit.name starting at len(prefix). The actual version only works for single character names like N or A. For longer names like Hertz the result would only be H which leads to an error in latex (and is also wrong...) --- pylatex/quantities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylatex/quantities.py b/pylatex/quantities.py index d6e60c8a..aaba2e74 100644 --- a/pylatex/quantities.py +++ b/pylatex/quantities.py @@ -46,7 +46,7 @@ def _dimensionality_to_siunitx(dim): # Split unitname into prefix and actual name if possible if unit.name.startswith(prefix): substring += '\\' + prefix - name = unit.name[len(prefix)] + name = unit.name[len(prefix):] break else: # Otherwise simply use the full name From b3aa2fcce10f18950d93cc6ff9567f7296201b04 Mon Sep 17 00:00:00 2001 From: Benjamin Knebusch Date: Mon, 21 Mar 2022 11:59:54 +0100 Subject: [PATCH 2/5] report --- pylatex/package.py | 1 + pylatex/quantities.py | 10 +++++++++ pylatex/tikz.py | 27 +++++++++++++++++------- pylatex/utils.py | 48 +++++++++++++++++++++---------------------- 4 files changed, 55 insertions(+), 31 deletions(-) diff --git a/pylatex/package.py b/pylatex/package.py index 040bed53..008f7e75 100644 --- a/pylatex/package.py +++ b/pylatex/package.py @@ -30,3 +30,4 @@ def __init__(self, name, options=None): """ super().__init__(arguments=name, options=options) + diff --git a/pylatex/quantities.py b/pylatex/quantities.py index aaba2e74..e15e3b13 100644 --- a/pylatex/quantities.py +++ b/pylatex/quantities.py @@ -24,6 +24,7 @@ 'Celsius': 'celsius', 'revolutions_per_minute': 'rpm', 'v': 'volt', + 'arcdegree': 'degree' } @@ -141,3 +142,12 @@ def _format(val): self.arguments._escape = False # dash in e.g. \num{3 +- 2} if self.options is not None: self.options._escape = False # siunitx uses dashes in kwargs + + def __str__(self): + return self.dumps() + + def __add__(self, other): + return str(self) + other + + def __radd__(self, other): + return other + str(self) diff --git a/pylatex/tikz.py b/pylatex/tikz.py index 98add4be..1fbe49e4 100644 --- a/pylatex/tikz.py +++ b/pylatex/tikz.py @@ -12,6 +12,10 @@ import math +class TikZLibrary(Package): + _latex_name = "usetikzlibrary" + + class TikZOptions(Options): """Options class, do not escape.""" @@ -27,13 +31,15 @@ class TikZ(Environment): """Basic TikZ container class.""" _latex_name = 'tikzpicture' - packages = [Package('tikz')] + packages = [Package('tikz'), TikZLibrary('positioning'),Package('pgfplots'), Command('pgfplotsset', 'compat=newest')] class Axis(Environment): """PGFPlots axis container class, this contains plots.""" - packages = [Package('pgfplots'), Command('pgfplotsset', 'compat=newest')] + packages = [Package('pgfplots'), + Command('pgfplotsset', 'compat=newest'), + Command('usepgfplotslibrary','groupplots')] def __init__(self, options=None, *, data=None): """ @@ -200,8 +206,9 @@ class TikZNode(TikZObject): """A class that represents a TiKZ node.""" _possible_anchors = ['north', 'south', 'east', 'west'] + _counter = 0 - def __init__(self, handle=None, options=None, at=None, text=None): + def __init__(self, handle=None, options=None, at=None, text=None, positioning=None): """ Args ---- @@ -215,9 +222,13 @@ def __init__(self, handle=None, options=None, at=None, text=None): Body text of the node """ super(TikZNode, self).__init__(options=options) - + if not handle: + handle = f'Node{TikZNode._counter}' + TikZNode._counter += 1 self.handle = handle + self._positioning = positioning + if isinstance(at, (TikZCoordinate, type(None))): self._node_position = at else: @@ -230,8 +241,7 @@ def __init__(self, handle=None, options=None, at=None, text=None): def dumps(self): """Return string representation of the node.""" - ret_str = [] - ret_str.append(Command('node', options=self.options).dumps()) + ret_str = [Command('node', options=self.options).dumps()] if self.handle is not None: ret_str.append('({})'.format(self.handle)) @@ -239,6 +249,9 @@ def dumps(self): if self._node_position is not None: ret_str.append('at {}'.format(str(self._node_position))) + if self._positioning is not None: + ret_str.append(f'[{self._positioning[1]} = of {self._positioning[0].handle}]') + if self._node_text is not None: ret_str.append('{{{text}}};'.format(text=self._node_text)) else: @@ -550,7 +563,7 @@ def dumps(self): self.error_bar): # ie: "(x,y) +- (e_x,e_y)" string += '(' + str(x) + ',' + str(y) + \ - ') +- (' + str(e_x) + ',' + str(e_y) + ')%\n' + ') +- (' + str(e_x) + ',' + str(e_y) + ')%\n' string += '};%\n%\n' diff --git a/pylatex/utils.py b/pylatex/utils.py index ed517b04..b2c3cc1e 100644 --- a/pylatex/utils.py +++ b/pylatex/utils.py @@ -36,30 +36,6 @@ def _is_iterable(element): return hasattr(element, '__iter__') and not isinstance(element, str) -class NoEscape(str): - """ - A simple string class that is not escaped. - - When a `.NoEscape` string is added to another `.NoEscape` string it will - produce a `.NoEscape` string. If it is added to normal string it will - produce a normal string. - - Args - ---- - string: str - The content of the `NoEscape` string. - """ - - def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, self) - - def __add__(self, right): - s = super().__add__(right) - if isinstance(right, NoEscape): - return NoEscape(s) - return s - - def escape_latex(s): r"""Escape characters that are special in latex. @@ -95,6 +71,30 @@ def escape_latex(s): return NoEscape(''.join(_latex_special_chars.get(c, c) for c in str(s))) +class NoEscape(str): + """ + A simple string class that is not escaped. + + When a `.NoEscape` string is added to another `.NoEscape` string it will + produce a `.NoEscape` string. If it is added to normal string it will + produce a normal string. + + Args + ---- + string: str + The content of the `NoEscape` string. + """ + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, self) + + def __add__(self, right): + s = super().__add__(right) + if isinstance(right, NoEscape): + return NoEscape(s) + return s + + def fix_filename(path): r"""Fix filenames for use in LaTeX. From db6daebd25f612eae6166e02fc1b3c6b503739c4 Mon Sep 17 00:00:00 2001 From: Benjamin Knebusch Date: Tue, 22 Mar 2022 17:32:33 +0100 Subject: [PATCH 3/5] report generation initial commit --- pylatex/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pylatex/document.py b/pylatex/document.py index 47d4c73f..85386e03 100644 --- a/pylatex/document.py +++ b/pylatex/document.py @@ -295,7 +295,7 @@ def generate_pdf(self, filepath=None, *, clean=True, clean_tex=True, else: # Notify user that none of the compilers worked. - raise(CompilerError( + raise (CompilerError( 'No LaTex compiler was found\n' 'Either specify a LaTex compiler ' 'or make sure you have latexmk or pdfLaTex installed.' From b924c6e18b7c2d563882cf8a9d2749418b80f747 Mon Sep 17 00:00:00 2001 From: Benjamin Knebusch Date: Sat, 21 May 2022 08:41:44 +0200 Subject: [PATCH 4/5] automated report generation for all reports added --- pylatex/figure.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pylatex/figure.py b/pylatex/figure.py index efbdd979..d2c1fd6c 100644 --- a/pylatex/figure.py +++ b/pylatex/figure.py @@ -41,6 +41,7 @@ def add_image(self, filename, *, width=NoEscape(r'0.8\textwidth'), if placement is not None: self.append(placement) + self.append(StandAloneGraphic(image_options=width, filename=fix_filename(filename))) From 004be6b048f2c9c5e4bf3698c864056b21496f13 Mon Sep 17 00:00:00 2001 From: Benjamin Knebusch Date: Tue, 5 Jul 2022 13:37:47 +0200 Subject: [PATCH 5/5] pep8 --- pylatex/figure.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pylatex/figure.py b/pylatex/figure.py index d2c1fd6c..efbdd979 100644 --- a/pylatex/figure.py +++ b/pylatex/figure.py @@ -41,7 +41,6 @@ def add_image(self, filename, *, width=NoEscape(r'0.8\textwidth'), if placement is not None: self.append(placement) - self.append(StandAloneGraphic(image_options=width, filename=fix_filename(filename)))