Hello,
AFAIK, current backends (I only tested agg, pdf, and ps) do not
properly respect the text baseline when text is rendered using TeX.
The get_text_width_height_descent() method in Agg and PS backends
simply return 0 for the descent value. While PDF backend uses the
dviread module to figure out correct descent values, there are cases
this does not work well (e.g. $\frac{1}{2}\pi$).
As an example, the attached figure shows the result for the Agg
backend. In all cases, the texts are placed at (0,0) with
baseline-alignment. Leftmost one is when usetex=False, which has a
correct baseline. The middle one is when usetex=True. It is bottom
aligned, which is not intended. The rightmost one is also when
usetex=True but after the patch I describe below.
First of all, I borrowed this idea from the PyX which is in GPL.
Although there is little of copying, other than the basic idea, I'm
not 100% sure if this could be BSD-compatible.
Anyhow, the idea is that you can have LateX to print out the width,
height, and descent (=depth) of a given text by enclosing the text in
a box. For example,
\newbox\MatplotlibBox%
\setbox\MatplotlibBox=\hbox{$\frac{1}{2}\pi$}%
\copy\MatplotlibBox
\immediate\write16{MatplotlibBox:\the\wd\MatplotlibBox,\the\ht\MatplotlibBox,\the\dp\MatplotlibBox}%
I define a newbox (called MatplotlibBox) which encloses
$\frac{1}{2}\pi$. And then print out the width, height and depth of
the box.
Attached is a patch of a texmanager.py which utilize above method to
figure out the dimension of the text. The template string to generate
a ".tex" file is slightly modified. After latex is run, the
dimensional information of the text is extracted and saved in
".baseline" file and get_text_width_height_descent() method is added
under the TexManager class, which reads in the ".baseline" file and
return its content. (you need to empty out the tex.cache directory for
this work correctly).
A backend can simply call the get_text_width_height_descent() of
texmanager (a simple patch for the Agg backend is attached). I also
tested this with PS and PDF backends and they worked out fine.
So if the license issue is okay, I wonder if this patch can be
reviewed and applied (after any necessary modifications) to improve
the baseline handling in matploltib.
Regards,
-JJ
<<attachment: test_baseline_comparison.png>>
Index: lib/matplotlib/texmanager.py
===================================================================
--- lib/matplotlib/texmanager.py (revision 6055)
+++ lib/matplotlib/texmanager.py (working copy)
@@ -236,6 +236,12 @@
else:
unicode_preamble = ''
+
+
+ # newbox, setbox, immediate, etc. are used to find the box
+ # extent of the rendered text.
+
+
s = r"""\documentclass{article}
%s
%s
@@ -243,7 +249,10 @@
\usepackage[papersize={72in,72in}, body={70in,70in}, margin={1in,1in}]{geometry}
\pagestyle{empty}
\begin{document}
-\fontsize{%f}{%f}%s
+\newbox\MatplotlibBox%%
+\setbox\MatplotlibBox=\hbox{{\fontsize{%f}{%f}%s}}%%
+\copy\MatplotlibBox
+\immediate\write16{MatplotlibBox:\the\wd\MatplotlibBox,\the\ht\MatplotlibBox,\the\dp\MatplotlibBox}%%
\end{document}
""" % (self._font_preamble, unicode_preamble, custom_preamble,
fontsize, fontsize*1.25, tex)
@@ -283,6 +292,14 @@
fh = file(outfile)
report = fh.read()
fh.close()
+
+ # find the box extent information in the latex output
+ # file and save them in basefile+".baseline" file
+ si = report.find("MatplotlibBox:")
+ ssi = si + len("MatplotlibBox:")
+ ei = report.find("\n", ssi)
+ open(basefile+'.baseline',"w").write(report[ssi:ei])
+
except IOError:
report = 'No latex error report available.'
if exit_status:
@@ -292,6 +309,7 @@
for fname in glob.glob(basefile+'*'):
if fname.endswith('dvi'): pass
elif fname.endswith('tex'): pass
+ elif fname.endswith('baseline'): pass
else:
try: os.remove(fname)
except OSError: pass
@@ -441,3 +459,22 @@
self.rgba_arrayd[key] = Z
return Z
+
+
+ def get_text_width_height_descent(self, tex, fontsize):
+ """
+ return text size in point
+ """
+ basefile = self.get_basefile(tex, fontsize)
+ baselinefile = '%s.baseline'% basefile
+
+
+ if DEBUG or not os.path.exists(baselinefile):
+ dvifile = self.make_dvi(tex, fontsize)
+
+ # width, height, depth of the bpx
+ # depth = descent, and height does not include depth
+ l = open(baselinefile).read().split(",")
+ width, height, depth = [float(l1[:-2]) for l1 in l] # get rid of "pt"
+
+ return width, height+depth, depth
Index: lib/matplotlib/backends/backend_agg.py
===================================================================
--- lib/matplotlib/backends/backend_agg.py (revision 6055)
+++ lib/matplotlib/backends/backend_agg.py (working copy)
@@ -121,15 +121,16 @@
# texmanager more efficient. It is not meant to be used
# outside the backend
"""
+
+
if ismath=='TeX':
- # todo: handle props
- size = prop.get_size_in_points()
texmanager = self.get_texmanager()
- Z = texmanager.get_grey(s, size, self.dpi)
- m,n = Z.shape
- # TODO: descent of TeX text (I am imitating backend_ps here -JKS)
- return n, m, 0
+ fontsize = prop.get_size_in_points() /72.*self.dpi
+ w, h, d = texmanager.get_text_width_height_descent(s, fontsize)
+ return w, h, d
+
+
if ismath:
ox, oy, width, height, descent, fonts, used_characters = \
self.mathtext_parser.parse(s, self.dpi, prop)
------------------------------------------------------------------------- This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________ Matplotlib-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
