【问题标题】:Overlaying matplotlib commands on existing Cairo image surface/context在现有 Cairo 图像表面/上下文上覆盖 matplotlib 命令
【发布时间】:2012-06-05 18:31:53
【问题描述】:

我有一个从 SVG 文件创建并使用 cairosvg 库加载的图表。

我想通过直接 matplotlib 命令以编程方式定义的附加叠加图进一步增强此图。

我正在尝试在内存中执行此操作,写入文件并重新加载。仅保存最终文件。

然而,事实证明很难将现有的 cairo 与 matplotlib 呈现的 结合。我以为this was a potential solution,但不确定。

简化示例:

import matplotlib
matplotlib.use('Cairo') # Make sure here that our figures will use Cairo!
from cairosvg import surface
from cairosvg import parser
import matplotlib.pyplot as plt
import matplotlib.image as img 
import numpy as np

SVG='\
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="500" height="500">\
<rect id="arena" x="10" y="10" width="480" height="480" fill="#ff5555" fill-opacity="0.5"/>\
</svg>\
'

svg = parser.Tree(bytestring=SVG)

surf = surface.PNGSurface(svg,None,1)
#surf.cairo.write_to_png("test-svg.png") # Can do this to see svg render to file
surf.finish() # Required?
ctx = surf.context # Can get the context here fine..

fig = plt.imshow(ctx) # <----- MAGIC REQUIRED HERE ABOUTS
#fig = plt.figure() # This works like a normal plot - but no svg

ax = fig.gca() # Create some overlay data
x = np.array(np.random.randn(100))
y = np.array(np.random.randn(100))
ax.plot(x,y)

plt.savefig("test-final.png") # Save svg & overlay plot

编辑:也一直在尝试以下,基于之前的上述链接。不过还是不开心。

from matplotlib.artist import Artist

class SurfArtist(Artist):
  def __init__(self,surf):
    Artist.__init__(self)
    self._surf = surf

  def draw(self,renderer):
    from matplotlib.backends.backend_cairo import RendererCairo
    if not isinstance(renderer, RendererCairo):
      raise TypeError("backend not supported")
    ctx = renderer.gc.ctx if hasattr(renderer, "gc") else renderer.ctx
    self._surf.context = ctx
    self._surf.cairo.show_page()

...

fig = plt.figure()
ax = fig.gca()
surf_artist = SurfArtist(surf)
surf_artist.set_zorder(float('inf'))
ax.artists.append(surf_artist)

【问题讨论】:

  • 对“surf.finish()”的调用看起来很可疑。这意味着您已经完成了表面,它可以丢弃所有数据。我想下一次调用“surf.context”已经失败了。你能检查一下上下文的状态吗?我猜是通过打印'ctx.status'。如果你不调用 'surf.finish()' 会发生什么?
  • @UliSchlachter - 关于finish() 的要点。查看 cairosvg src 它似乎确实输出了所有数据。但是,删除它仍然会导致相同的错误:TypeError: Image data can not convert to float。可悲的是,我也找不到任何来自 cairo.Context 的状态方法 (cairographics.org/documentation/pycairo/2/reference/…)

标签: python matplotlib overlay diagram cairo


【解决方案1】:

下面的代码应该可以工作,首先将表面转换为numpy数组,如https://github.com/Kozea/CairoSVG/issues/57


matplotlib.use('Cairo') # Make sure here that our figures will use Cairo!
from cairosvg import surface
from cairosvg import parser
import matplotlib.pyplot as plt
import matplotlib.image as img 
import numpy as np

# function to convert to array
def surface_to_npim(surface):
    """ Transforms a Cairo surface into a numpy array. """
    im = +np.frombuffer(surface.get_data(), np.uint8)
    H,W = surface.get_height(), surface.get_width()
    im.shape = (H,W, 4) # for RGBA
    return im[:,:,:3]


SVG='\
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="500" height="500">\
<rect id="arena" x="10" y="10" width="480" height="480" fill="#ff5555" fill-opacity="0.5"/>\
</svg>\
'

svg = parser.Tree(bytestring=SVG)

surf = surface.PNGSurface(svg,None,1)
#surf.cairo.write_to_png("test-svg.png") # Can do this to see svg render to file
surf.finish() # Required?


# convert svg and plot
img = surface_to_npim(surf.cairo)
plt.imshow(img)

# Create some overlay data
x = np.array(np.random.randn(100))
y = np.array(np.random.randn(100))
plt.plot(x,y)

plt.savefig("test-final.png") # Save svg & overlay plot





【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多