exporting protovis to PDF in one line: mostly working

146 views
Skip to first unread message

Brandon Heller

unread,
Feb 7, 2011, 4:00:44 PM2/7/11
to protovis
I recently used Protovis to generate some matrix diagrams for use in a
research paper. The vector output looked great, but saving as a PDF
through the browser became an annoying manual process.

On the the mailing list, there are plenty of hits for similar
requests:

* Issue 41: Allow one to save the generated image
http://code.google.com/p/protovis-js/issues/detail?id=41
Method there uses {jquery, rsvg, php}
* server side engine - Options? [Feb 15, 2010, Pedro Alves]
http://groups.google.com/group/protovis/browse_thread/thread/ee5737796b4235eb
Nice discussion of various options and tradeoffs, with Jamie Love's
demo "rhinotest.zip" at the bottom.
* Vector Export [Aug 17, 2009, toomim]:
http://groups.google.com/group/protovis/browse_thread/thread/3169031c3b2aae52/eb1c5d6c4747f0aa
* Export protovis SVG to image in python/django [Nov 5 2010, Jan van
Gemert]
http://groups.google.com/group/protovis/browse_thread/thread/529e2cb095e3ef75?pli=1

I had trouble getting the rsvg approach to work on a Mac via MacPorts,
which wouldn't compile, though it was easier on Ubuntu. Ideally, you
wouldn't need to build anything.

The approach of using the Rhino Java-based JavaScript engine along w/
envJS to get a headless browser, then extracting the protovis-
generated SVG via innerHTML, seemed to work fine. Once you have SVG
you can use Batik to turn it into a PDF. This uses a pre-built
Java .jar so there's nothing to install.

I put together a Python script to generate PDF output in one line,
based on Jamie Love's code post. It's usable, though there's a bug
with text elements that appears to be issue with the envjs CSS
implementation as well as more complicated stuff (like the Matrix
example) running out of memory. I've put up the work-in-progress
here:

https://github.com/brandonheller/pv_export

It would be great if a CSS/SVG expert could take a quick look and see
if there's a workaround to get text style changes working, or if this
requires more envjs implementation; if we could get past that bug, it
should be much easier to generate Protovis PDFs offline.

Thanks,
Brandon Heller


Issues:

(1) Running the Area Chart example w/protovis-d3.2:
http://vis.stanford.edu/protovis/ex/area.html

...yields this error:

js: "protovis-d3.2.js", line 5057: uncaught JavaScript runtime
exception: TypeError: Cannot call method "removeProperty" of undefined

I can effectively comment out the error to get past it, and the output
loooks OK.

diff --git a/protovis-d3.2.js b/protovis-d3.2.js
index bfe5a02..63f4996 100644
--- a/protovis-d3.2.js
+++ b/protovis-d3.2.js
@@ -5054,7 +5054,7 @@ pv.SvgScene.expect = function(e, type,
attributes, style)
for (var name in style) {
var value = style[name];
if (value == this.implicit.css[name]) value = null;
- if (value == null) e.style.removeProperty(name);
+ if (value == null) 1; //e.style.removeProperty(name);
else e.style[name] = value;
}
return e;

The same error happens when using the PV master branch.

Adding some prints, I get this:

e: text
e.style: undefined
type: text
attributes: ({'pointer-events':"none", cursor:null, x:"-3", y:0,
dy:".35em", transform:"translate(0,200)", fill:"rgb(0,0,0)", 'fill-
opacity':1, 'text-anchor':"end"})
style: ({font:"10px sans-serif", 'text-shadow':null, 'text-
decoration':null})
name: font

Here's the function getting called, with the error marked:

/**
* Expects the element <i>e</i> to be the specified type. If the
element does
* not exist, a new one is created. If the element does exist but is
the wrong
* type, it is replaced with the specified element.
*
* @param e the current SVG element.
* @param type {string} an SVG element type, such as "rect".
* @param attributes an optional attribute map.
* @param style an optional style map.
* @returns a new SVG element.
*/
pv.SvgScene.expect = function(e, type, attributes, style) {
if (e) {
if (e.tagName == "a") e = e.firstChild;
if (e.tagName != type) {
var n = this.create(type);
e.parentNode.replaceChild(n, e);
e = n;
}
} else {
e = this.create(type);
}
for (var name in attributes) {
var value = attributes[name];
if (value == this.implicit.svg[name]) value = null;
if (value == null) e.removeAttribute(name);
else e.setAttribute(name, value);
}
for (var name in style) {
var value = style[name];
if (value == this.implicit.css[name]) value = null;
if (value == null) e.style.removeProperty(name) // ERROR
else {e.style[name] = value};
}
return e;
};

I'm trying to trace the bug here, and the first confusion is what
this.implicit.css is. 'implicit' doesn't turn up outside of this
function. It's evaluating to the same thing as value - "10px sans-
serif" - which for some reason sets value to null. Then on the next
line the code tries to remove a property from a newly created element
that has no properties! This seems to be a difference in behavior w/
envJS: when I run in Firefox, and print the created e w/Firebug, it's
been initialized:

e: <text pointer-events="none" x="-3" dy="0.35em"
transform="translate(0, 200)" fill="rgb(0,0,0)" text-anchor="end">

... and e.style is:
CSSStyleDeclaration { length=0 }


(2) (probably due to the hack for #1, or same root cause):
I can't change text properties, and get an error when trying to do
something like this to on a label:
.font("12px sans-serif")

(3) Rhino can't handle the full matrix example - causes heap space
errors. Tried adjusting this by starting the JVM with -Xss,
increasing to 128m, but always seemed to crash after a minute or so.

rioderaca

unread,
Feb 8, 2011, 6:13:59 AM2/8/11
to protovis
Just a side comment to this topic: it seams that many people are
interested in using protovis as a research tool. I stumbled upon
protovis while looking for a gnuplot alternate. So, as a conclusion...
maybe would be nice for protovis to address directly this issue of
exporting ready to use charts (pdf, png, etc) avoiding browser export.
I'm definitely not an expert to realize what effort is needed to make
that happen but as an end-user this facility would be great to have.

thanks,
Cristian

On Feb 7, 9:00 pm, Brandon Heller <brandon.hel...@gmail.com> wrote:
> I recently used Protovis to generate some matrix diagrams for use in a
> research paper.  The vector output looked great, but saving as a PDF
> through the browser became an annoying manual process.
>
> On the the mailing list, there are plenty of hits for similar
> requests:
>
> * Issue 41: Allow one to save the generated imagehttp://code.google.com/p/protovis-js/issues/detail?id=41
> Method there uses {jquery, rsvg, php}
> * server side engine - Options? [Feb 15, 2010, Pedro Alves]http://groups.google.com/group/protovis/browse_thread/thread/ee573779...
> Nice discussion of various options and tradeoffs, with Jamie Love's
> demo "rhinotest.zip" at the bottom.
> * Vector Export [Aug 17, 2009, toomim]:http://groups.google.com/group/protovis/browse_thread/thread/3169031c...
> * Export protovis SVG to image in python/django [Nov 5 2010, Jan van
> Gemert]http://groups.google.com/group/protovis/browse_thread/thread/529e2cb0...

Brandon Heller

unread,
Feb 8, 2011, 2:55:53 PM2/8/11
to protovis
On Feb 8, 3:13 am, rioderaca <rioder...@gmail.com> wrote:
> Just a side comment to this topic: it seams that many people are
> interested in using protovis as a research tool. I stumbled upon
> protovis while looking for a gnuplot alternate. So, as a conclusion...
> maybe would be nice for protovis to address directly this issue of
> exporting ready to use charts (pdf, png, etc) avoiding browser export.
> I'm definitely not an expert to realize what effort is needed to make
> that happen but as an end-user this facility would be great to have.

Perhaps the last email wasn't clear, but we're in the same boat. I
use matplotlib (a Python replacement for gnuplot) but I really like
the control protovis provides for more custom stuff.

pv_export does _not_ use a browser. It uses a JavaScript interpreter
(Rhino) which hosts a bare HTML DOM implementation (envJS) and then
uses the Protovis library code w/a vis to extract SVG. Batik-
rasterizer supports turning the SVG into PDF, PNG, and other outputs,
despite the name.

Give it a try... I made some major changes yesterday to pv_export, so
now with one modified line you can generate PDFs of the online
examples.

-b
Reply all
Reply to author
Forward
0 new messages