简体   繁体   English

在 PdfPages 页面 Python 内的 matplotlib 图中添加超链接

[英]Add a hyperlink in a matplotlib plot inside a PdfPages page Python

I am creating multiple multipage PDF reports using PdfPages by running a for loop through a dataframe.我通过在数据帧中运行 for 循环来使用 PdfPages 创建多个多页 PDF 报告。 I have everything ready, except I need to include some hyperlinks (between 0 and 3), preferably on msr_line4, but if they need to be on individual lines, I can make that work.我已经准备好了一切,除了我需要包含一些超链接(0 到 3 之间),最好在 msr_line4 上,但如果它们需要在单独的行上,我可以完成这项工作。

import pandas as pd
import numpy as np
import pickle
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.lines as mlines
from matplotlib.pyplot import figure
from matplotlib.backends.backend_pdf import PdfPages
import seaborn as sns
import matplotlib.image as mpimg
import mpl_toolkits.axisartist as axisartist

## Text

msr_line1 = r'$\bf{' + 'Name: ' + '}$' + 'Calls name from df'
msr_line2 = r'$\bf{' + 'Measure: ' + '}$' + 'Calls measure from df'
msr_line3 = r'$\bf{' + 'Direction: ' + '}$' + 'Calls direction from df'
msr_line4 = r'$\bf{' + 'Link\ to\ Resources: ' + '}$' + "NEED TO INSERT HYPERLINK HERE"

with PdfPages('msr.pdf') as pdf:
    plt.figure(figsize=(11, 8.5))

    ## Header text
    ax2 = plt.subplot2grid((9, 5), (1, 0), rowspan=1, colspan=2)
    ax2.text(0, .9, msr_line1, fontsize=9)
    ax2.text(0, 0.6, msr_line2, fontsize=9)
    ax2.text(0, 0.3, msr_line3, fontsize=9)
    ax2.text(0, 0, msr_line4, fontsize=9)
    plt.axis('off')
    pdf.savefig()
    plt.close

EDIT/UPDATE Libraries now being used:现在正在使用编辑/更新库:

import pandas as pd
import numpy as np
import pickle
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.lines as mlines
from matplotlib.pyplot import figure
import seaborn as sns
import matplotlib.image as mpimg
import mpl_toolkits.axisartist as axisartist
from matplotlib import rcParams

import matplotlib
matplotlib.use('pgf')
from PyPDF2 import PdfFileMerger
import os

Parameters:参数:

plt.rc('text', usetex=True)
rcParams['font.family'] = 'serif'
rcParams['font.serif'] = ['Georgia']
plt.rcParams['pgf.preamble'] = [r'\usepackage{hyperref} \hypersetup{hidelinks,' 
                                'colorlinks=true, urlcolor=cyan}', ]

ax2 = plt.subplot2grid((9, 5), (1, 0), rowspan=1, colspan=1)
plt.text(0, .9, msr_line1, fontsize=9)
plt.text(0, 0.6, msr_line2, fontsize=9)
plt.text(0, 0.3, msr_line3, fontsize=9)
plt.text(0, 0, r'\href{https://stackoverflow.com/questions/}{StackOverflow}', fontsize=9)
plt.axis('off')

The error that I am now getting is:我现在得到的错误是:

CalledProcessError                        Traceback (most recent call last)
~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\texmanager.py in _run_checked_subprocess(self, command, tex)
    303                                              cwd=self.texcache,
--> 304                                              stderr=subprocess.STDOUT)
    305         except FileNotFoundError as exc:

~\AppData\Local\Continuum\anaconda3\lib\subprocess.py in check_output(timeout, *popenargs, **kwargs)
    394     return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
--> 395                **kwargs).stdout
    396 

~\AppData\Local\Continuum\anaconda3\lib\subprocess.py in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    486             raise CalledProcessError(retcode, process.args,
--> 487                                      output=stdout, stderr=stderr)
    488     return CompletedProcess(process.args, retcode, stdout, stderr)

CalledProcessError: Command '['latex', '-interaction=nonstopmode', '--halt-on-error', 
'C:\\Users\\KrumlinZ\\.matplotlib\\tex.cache\\2d92c6482fbb9d5f9ece1213452d403d.tex']' returned non-zero exit status 1.

The above exception was the direct cause of the following exception:

RuntimeError                              Traceback (most recent call last)
<ipython-input-13-c8cf5db9d20c> in <module>
    226 
    227     measure_page = str(ProviderNumber) + str(msr) + '_msr.pdf'
--> 228     plt.savefig(measure_page)
    229     merger.append(measure_page)
    230     #os.remove(measure_page)

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\pyplot.py in savefig(*args, **kwargs)
    720 def savefig(*args, **kwargs):
    721     fig = gcf()
--> 722     res = fig.savefig(*args, **kwargs)
    723     fig.canvas.draw_idle()   # need this if 'transparent=True' to reset colors
    724     return res

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\figure.py in savefig(self, fname, transparent, **kwargs)
   2178             self.patch.set_visible(frameon)
   2179 
-> 2180         self.canvas.print_figure(fname, **kwargs)
   2181 
   2182         if frameon:

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, **kwargs)
   2080                     orientation=orientation,
   2081                     bbox_inches_restore=_bbox_inches_restore,
-> 2082                     **kwargs)
   2083             finally:
   2084                 if bbox_inches and restore_bbox:

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\backends\backend_pdf.py in print_pdf(self, filename, dpi, bbox_inches_restore, metadata, **kwargs)
   2501                 RendererPdf(file, dpi, height, width),
   2502                 bbox_inches_restore=bbox_inches_restore)
-> 2503             self.figure.draw(renderer)
   2504             renderer.finalize()
   2505             if not isinstance(filename, PdfPages):

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     36                 renderer.start_filter()
     37 
---> 38             return draw(artist, renderer, *args, **kwargs)
     39         finally:
     40             if artist.get_agg_filter() is not None:

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\figure.py in draw(self, renderer)
   1707             self.patch.draw(renderer)
   1708             mimage._draw_list_compositing_images(
-> 1709                 renderer, self, artists, self.suppressComposite)
   1710 
   1711             renderer.close_group('figure')

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    133     if not_composite or not has_images:
    134         for a in artists:
--> 135             a.draw(renderer)
    136     else:
    137         # Composite any adjacent images together

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     36                 renderer.start_filter()
     37 
---> 38             return draw(artist, renderer, *args, **kwargs)
     39         finally:
     40             if artist.get_agg_filter() is not None:

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\axes\_base.py in draw(self, renderer, inframe)
   2645             renderer.stop_rasterizing()
   2646 
-> 2647         mimage._draw_list_compositing_images(renderer, self, artists)
   2648 
   2649         renderer.close_group('axes')

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    133     if not_composite or not has_images:
    134         for a in artists:
--> 135             a.draw(renderer)
    136     else:
    137         # Composite any adjacent images together

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     36                 renderer.start_filter()
     37 
---> 38             return draw(artist, renderer, *args, **kwargs)
     39         finally:
     40             if artist.get_agg_filter() is not None:

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\text.py in draw(self, renderer)
    668 
    669         with _wrap_text(self) as textobj:
--> 670             bbox, info, descent = textobj._get_layout(renderer)
    671             trans = textobj.get_transform()
    672 

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\text.py in _get_layout(self, renderer)
    296             if clean_line:
    297                 w, h, d = renderer.get_text_width_height_descent(
--> 298                     clean_line, self._fontproperties, ismath=ismath)
    299             else:
    300                 w = h = d = 0

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\backends\_backend_pdf_ps.py in get_text_width_height_descent(self, s, prop, ismath)
     45             fontsize = prop.get_size_in_points()
     46             w, h, d = texmanager.get_text_width_height_descent(
---> 47                 s, fontsize, renderer=self)
     48             return w, h, d
     49         elif ismath:

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\texmanager.py in get_text_width_height_descent(self, tex, fontsize, renderer)
    446         else:
    447             # use dviread. It sometimes returns a wrong descent.
--> 448             dvifile = self.make_dvi(tex, fontsize)
    449             with dviread.Dvi(dvifile, 72 * dpi_fraction) as dvi:
    450                 page, = dvi

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\texmanager.py in make_dvi(self, tex, fontsize)
    336                 self._run_checked_subprocess(
    337                     ["latex", "-interaction=nonstopmode", "--halt-on-error",
--> 338                      texfile], tex)
    339             for fname in glob.glob(basefile + '*'):
    340                 if not fname.endswith(('dvi', 'tex')):

~\AppData\Local\Continuum\anaconda3\lib\site-packages\matplotlib\texmanager.py in _run_checked_subprocess(self, command, tex)
    315                     prog=command[0],
    316                     tex=tex.encode('unicode_escape'),
--> 317                     exc=exc.output.decode('utf-8'))) from exc
    318         _log.debug(report)
    319         return report

RuntimeError: latex was not able to process the following string:
b'\\\\href{https://stackoverflow.com/questions/}{StackOverflow}'

Here is the full report generated by latex:
This is pdfTeX, Version 3.14159265-2.6-1.40.20 (MiKTeX 2.9.7250 64-bit)
entering extended mode
(C:/Users/KrumlinZ/.matplotlib/tex.cache/2d92c6482fbb9d5f9ece1213452d403d.tex
LaTeX2e <2019-10-01> patch level 3

("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/base\article.cl
s"
Document Class: article 2019/10/25 v1.4k Standard LaTeX document class
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/base\size10.clo
"))
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/type1cm\type1cm
.sty")
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/base\textcomp.s
ty"
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/base\ts1enc.def
"
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/base\ts1enc.dfu
")))
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/base\inputenc.s
ty")
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/geometry\geomet
ry.sty"
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/graphics\keyval
.sty")
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/generic/iftex\ifvtex.
sty"
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/generic/iftex\iftex.s
ty"))
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/geometry\geomet
ry.cfg")

Package geometry Warning: Over-specification in `h'-direction.
    `width' (5058.9pt) is ignored.


Package geometry Warning: Over-specification in `v'-direction.
    `height' (5058.9pt) is ignored.

) (2d92c6482fbb9d5f9ece1213452d403d.aux)
("C:\Users\KrumlinZ\AppData\Local\Programs\MiKTeX 2.9\tex/latex/base\ts1cmr.fd"
)
*geometry* driver: auto-detecting
*geometry* detected driver: dvips
! Undefined control sequence.
l.14 ...tsize{9.000000}{11.250000}{\rmfamily \href
                                                  {https://stackoverflow.com...
No pages of output.
Transcript written on 2d92c6482fbb9d5f9ece1213452d403d.log.


Error in callback <function install_repl_displayhook.<locals>.post_execute at 0x000001EAC6E4CA68> (for post_execute):

You will need to use LaTex and PGF to accomplish this (unless outputting SVG is an option).您将需要使用 LaTex 和 PGF 来完成此操作(除非可以选择输出 SVG)。 This will require a LaTex installation (TexLive, MikTex, etc).这将需要安装 LaTex(TexLive、MikTex 等)。 Unfortunately this is incompatible with the PdfPages backend.不幸的是,这与PdfPages后端不兼容。 However, you can concatenate the output PDFs on the fly fairly easily.但是,您可以相当轻松地即时连接输出 PDF。

Here is an working example:这是一个工作示例:

import matplotlib
matplotlib.use('pgf')
import matplotlib.pyplot as plt
from PyPDF2 import PdfFileMerger
import os

plt.rc('text', usetex=True)
plt.rc('font', family='serif')
plt.rcParams['pgf.preamble'] = [r'\usepackage{hyperref} \hypersetup{hidelinks,' 
                                'colorlinks=true, urlcolor=cyan}', ]

merger = PdfFileMerger()
for i in range(5):
    plt.figure()
    plt.text(0.5, 0.5, 
             r'\href{https://stackoverflow.com/questions/}{StackOverflow '+str(i)+'}')

    out = './out.'+str(i)+'.pdf'
    plt.savefig(out)
    merger.append(out)
    os.remove(out)

merger.write('./out.pdf')
merger.close()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM