Exporting networkD3 graphs as vector graphics - r

Assume a network graph generated via the R library networkD3. Assume further that you can save that network graph as an external stand alone HTML file (see section Output) or, alternatively, render it via the R library htmlwidgets.
Do you see any way to export a network so generated as a vector graphic (pdf or svg), irrespective of whether inside or outside of R?
Note: I understand that the primary purpose of the D3.js library is not to generate static data visualizations, but surely there is a way to use/convert D3 network graphs for print publication.
Edit 1:
Following the suggestion by CJ Yetman, I inspected the DOM properties of the HTML file via Firefox Developer Edition. Using this method, it is possible to specifically see SVG properties (see this example), but they are mostly empty. However, how do I 'extract the SVG from the DOM', as CJ Yetman indicated?

Since you do mention htmlwidgets, I can share how I managed..
I have my NetworkD3 app as a webpage (easiest you can just create an account with shinyapps.io and plug your code into their server for free through RStudio using a NetworkD3 shiny app template)
And then open your plot using Opera browser (did not work with Chrome) and right click on your plot and Save as PDF... this will give you vectorized figures that you can zoom in endlessly without losing resolution.

Here is a bit of code... Let's assume that you have a chart rendered into a div with id="watcher".
<button onClick={() => alert(document.getElementById('watcher').innerHTML)} style={{ padding: '10px' }}>
Show generated html/svg
</button>
The above is code for React, but can be adapted for any environment.
You can therefore grab the rendered HTML into a variable with a line like this:
svgMarkup = document.getElementById('watcher').innerHTML
Basically it's a string, which you can then send to a backend for saving, or to file.
Another approach is to server side render the SVG and save it directly to the file without the need to display it. D3 should be able to handle that.

View it in a browser and then use the browser’s developer tools to extract the SVG from the DOM... some browsers (I think Chrome) will even let you right click on an SVG to save it to your local drive. It has to be rendered in a browser first though, because the underlying JavaScript is what ultimately generates the SVG.
Using something like SVG Crowbar might make it even easier to save the SVG from a webpage.

Related

Confluence: Is there a way to use space variables in Global PDF Stylesheet? Or somehow include it on PDF Exports

For PDF exports, I'm trying to export the space name to the bottom center of the export.
I tried the following but no luck so far:
#bottom-center
{
content: $space.getName();
}
I think the space variables do not work within the PDF CSS Stylesheet.
Is there another way of possibly achieving this?
I look forward to your ideas.
You might want to have a look at our Scroll PDF Exporter for Confluence.
Scroll PDF Exporter is an app for Confluence Server and Cloud that allows you to further customize your exports using a graphical template designer.
One key feature of the app is the possibility to use placeholders for specific metadata (e.g. the space name). Those placeholders can be used in the header or footer of your exported file and will be replaced during export with the wanted information.
You can find further information about all available placeholders in our Scroll PDF Exporter documentation.
For your specific use case the placeholder "Space Name" should work.
You can try out Scroll PDF Exporter using a 30 day trial license via the Atlassian Marketplace.
In case you have any further questions regarding the app, please get in touch with us via support[at]k15t.com.
We'll be happy to help.
Best,
Nils

Is there a way to style Google Chrome default PDF viewer

Is there a way to style google chrome default pdf view? I'm trying to change the gray background color to white also make the scroller little bigger for mobile devices if possible.
I tried to target it on css with no luck
// pdf viewer custom style
iframe {
html {
body {
background-color: #ffffff !important;
}
#zoom-toolbar {
display: none !important;
}
#zoom-buttons {
display: none !important;
}
}
}
It looks like it's creating shadow document on the html but I couldn't find any way to target it
There is no way to directly style the Chrome default PDF viewer (PDFium). Because the plugin displays and controls content outside the scope of the current page's DOM, it can only be modified by the plugin. As indicated here it is impossible to make modifications to this sort of plugin controlled content unless the plugin also adds a content script that allows the page to pass messages to the plugin; the plugin must additionally be programmed to respond to messages and appropriately update the content. In other words the PDF viewer uses a separate DOM to the page which is not directly accessible. Instead you need to access an implemented API.
In this discussion Mike West (Google/Chromium dev) states, in answer to a question on DOM accessibility in Chrome's PDF viewer:
The functionality available in the PDF viewer is (intentionally) fairly limited ... The APIs you're having trouble finding simply don't exist.
Basic API functions are some of those specified by Adobe in their Parameters for Opening PDF Files and are accessed through the URL (eg http://example.org/doc.pdf#page=3&pagemode=thumbs. They are, as indicated above, quite limited, allowing the user to go directly to a page, set zoom factor, show thumbnails etc. Accessing an expanded API through content script messages can potentially be done if you know the available JavaScript messages. A complete list of available JS message names can be determined from the relevant PDFium source here from which it can be seen that advanced styling of the viewer, such as changing colours, isn't possible. (This question gives an example of how to implement the API). Certainly there is no access to PDFium's DOM.
This API is deliberately left undocumented; it may change with additions or removals at any time. Thus, while it's possible that in the future there will be an API to let you style some aspects of the viewer, it's very unlikely that any would go so far as to change the background colour or modify a CSS shadow. And, as stated above, without an API you can't modify content controlled by a plugin when you don't have access to its DOM.
You may, instead, wish to try PDF.js. It is an open source JavaScript library that renders PDF files using HTML5 Canvas. It is also Firefox's default PDF viewer and is quite capable.
Implementing it as a web app is beyond the scope of this question, but there are many helpful tutorials available. And as you, the developer, will have access to all constituent files, you will certainly be able to style the PDF.js viewer as much as you wish.
Just paste this into your browser console.
var cover = document.createElement("div");
let css = `
position: fixed;
pointer-events: none;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: #3aa757;
mix-blend-mode: multiply;
z-index: 1;
`
cover.setAttribute("style", css);
document.body.appendChild(cover);
Update: Recent versions of Chrome seem to have moved the PDF viewer resources out of resources.pak and into the browser binary itself. It should still be possible to download the Chromium source, edit the files described below, and then recompile, but that's much more painful than simply hacking resources.pak. Thanks, Google.
As a matter of fact, there is a way, but we've got to get our hands dirty, and the process must be repeated every time we update Chrome. Still, to me, the effort is well worth it. I like to change the PDF viewer's background to white, so that when I activate the color-inverting Deluminate extension at night, I get a nice solid black background. It's so much easier on my eyes compared to the default background, which, when inverted, is blindingly bright.
The Chrome source tree contains thousands of HTML, JS, and CSS files that control the behavior and appearance of many parts of the browser, including the PDF viewer. When Chrome is built, these "resources" are bundled together into a single file, resources.pak, which the browser unpacks into memory during startup. What we need to do is unpack resources.pak on disk, edit the files that style the PDF viewer, and then repack the bundle.
The first thing we need is a tool that can unpack resources.pak. The only one that I know of is ChromePAK-V5. It's written in Go, so we need that to build it. We also need to install a build-time dependency called go-bindata. Here's how I went about it:
cd ~/code/chrome
go get -u github.com/jteeuwen/go-bindata/...
git clone https://github.com/shuax/ChromePAK-V5.git
cd ChromePAK-V5
~/go/bin/go-bindata -nomemcopy -o assets.go assets
go build
cd ..
Now that we've got the binary ChromePAK-V5/ChromePAK-V5, we can use it to unpack resources.pak. In my case, running Chromium on Linux, the file is located at /usr/lib/chromium/resources.pak, but it might be somewhere else for you. Once you've found it, copy it, make a backup, and unpack it:
cd ~/code/chrome
cp /usr/lib/chromium/resources.pak .
cp resources.pak resources.pak.bak
ChromePAK-V5/ChromePAK-V5 -c=unpack -f=resources.pak
At this point, the files we need will be located somewhere in the resources directory. Now, in the original Chrome source tree, these files all had sensible paths, such as chrome/browser/resources/pdf/pdf_viewer.js. Unfortunately, these original paths are not recorded in the resources.pak file. ChromePAK-V5 tries to be clever by using a table that maps the SHA1 hashes of resources files to their original paths, but over time, files change, along with their hashes, and ChromePAK-V5 can no longer recognize them. If a file is unrecognized, ChromePAK-V5 will unpack it to, e.g., resources/unknown/12345. And, in general, these numbers change from one Chrome release to the next. So, to find the files that we need to edit, we basically need to grep for "fingerprints" that identify them. Let's get started.
The background color of the PDF viewer is controlled by the file which, in the Chrome source tree, is named chrome/browser/resources/pdf/pdf_viewer.js. To find the file, grep inside resources/unknown for the string PDFViewer.BACKGROUND_COLOR. In my case, the file was unpacked at unknown/10282. Open this file, and change the line (at/near the end of the file) that sets PDFViewer.BACKGROUND_COLOR. I changed it to 0xFFFFFFFF, i.e., white (which becomes black under Deluminate).
Going further, we can also restyle the PDF viewer's toolbar. By default, the toolbar is dark, so it becomes obnoxiously bright under Deluminate. To fix that, we need to find chrome/browser/resources/pdf/elements/viewer-pdf-toolbar.html. I found it at unknown/10307 by grepping for shadow-elevation-2dp. What I did was to go to the #toolbar block and add filter: invert(100%);. Voila, no more blinding toolbar at night.
Finally, if we really want to go all the way, we can get rid of the brief "flash" of the original background color that occurs when loading a PDF. This color is controlled by chrome/browser/resources/pdf/index.css, which I found at unknown/10304 by grepping for viewer-page-indicator {. I changed the background-color property of body to white (i.e. black under Deluminate).
The hard part is now over. The final step is to repack the resources and overwrite the system resources.pak:
ChromePAK-V5/ChromePAK-V5 -c=repack -f=resources.json
sudo cp resources.pak /usr/lib/chromium # or wherever yours should go
Now restart the browser and enjoy!
A codeless approach is to install a tampermonkey plugin.
https://greasyfork.org/en/scripts/437073-pdf-background-color-controller
This is very useful if you are reading a pdf via a browser and just want to change the background color.

Embedding image in ipython notebook for distribution

I have an ipython notebook with an embedded image from my local drive. I was expecting it to be embedded in the JSON along with the output of code cells, but when I distributed the notebook, the image did not appear to users. What is the recommended way (or ways) to embed an image in a Notebook, so that it doesn't disappear if users rerun code cells, clear cell output, etc.?
The notebook system caches images included with ![label](image.png), but they last only until the python "kernel" serving the notebook is restarted. If I rename the image file on disk, I can close and reopen the notebook and it still shows the image; but it disappears when I restart the kernel.
Edit: If I generate an image as code cell output and then export the notebook to html, the image is embedded in the html as encoded data. Surely there must be a way to hook into this functionality and load the output into a markdown (or better yet "raw nbconvert") cell?
from IPython.display import Image
Image(filename='imagename.png')
will be exported (with ipython nbconvert) to html that contains the following:
<div class="output_png output_subarea output_execute_result">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAnAAAAFgCAYAAAA...
</div>
However, even when I manually embedded this snippet into a markdown cell, I couldn't get the image to display. What am I doing wrong?
Update (2020)
Apparently, the problem has (finally!) been addressed in the newer notebook / Jupyter versions: as of 2018 (thanks for the link #Wayne), the html sanitizer will accept an embedded html image, as in <img src="data:image/png;base64,iV...> . Markdown image syntax also accepts images as embedded data, so there are two ways to do this. Details in these helpful answers:
markdown image syntax (answer by #id01)
html element syntax (in answer by #tel -- note that it works now!)
Are you happy to use an extra code cell to display the image? If so, use this:
from IPython.display import Image
Image(filename="example.png")
The output cell will have the raw image data embedded in the .ipynb file so you can share it and the image will be retained.
Note that the Image class also has a url keyword, but this will only link to the image unless you also specify embed=True (see the documentation for details). So it's safer to use the filename keyword unless you are referring to an image on a remote server.
I'm not sure if there is an easy solution if you require the image to be included in a Markdown cell, i.e. without a separate code cell to generate the embedded image data. You may be able to use the python markdown extension which allows dynamically displaying the contents of Python variables in markdown cells. However, the extension generates the markdown cells dynamically, so in order to retain the output when sharing the notebook you will need to run ipython nbconvert --to notebook original_notebook.ipynb --output preprocessed_notebook using the preprocessor pymdpreprocessor.py as mentioned in the section "Installation". The generated notebook then has the data embedded in the markdown cell as an HTML tag of the form <img src="data:image/png;base64,..."> so you can delete the corresponding code cell from preprocessed_notebook.ipynb. Unfortunately, when I tried this the contents of the <img> tag weren't actually displayed in the browser, so not sure if this is a viable solution. :-/
A different option would be to use the Image class in a code cell to generate the image as above, and then use nbconvert with a custom template to remove code input cells from the notebook. See this thread for details. However, this will strip all code cells from the converted notebook, so it may not be what you want.
The reason why the
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAnAAAAFgCAYAAAA...
tag doesn't do anything when you put it in a markdown cell is because IPython uses an HTML sanitizer (something called Google Caja) that screens out this type of tag (and many others) before it can be rendered.
The HTML sanitizer in IPython can be completely disabled by adding the following line to your custom.js file (usually located at ~/.ipython/profile_default/static/custom/custom.js):
iPython.security.sanitize_html = function (html) { return html; };
It's not a great solution though, as it does create a security risk, and it doesn't really help that much with distribution.
Postscript:
The ability to render base64 encoded strings as images != obvious security concern, so there should be a way for the Caja people to eventually allow this sort of thing through (although the related feature request ticket was first opened back in 2012, so don't hold your breath).
I figured out that replacing the image URL in the ![name](image) with a base64 URL, similar to the ones found above, can embed an image in a markdown container.
Example markdown:
![smile](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAD9JREFUGJW1jzEOADAIAqHx/1+mE4ltNXEpI3eJQknCIGsiHSLJB+aO/06PxOo/x2wBgKR2jCeEy0rOO6MDdzYQJRcVkl1NggAAAABJRU5ErkJggg==)
If using the IPython HTML() function to output raw HTML, you can embed a linked image in base64 inside an <img> tag using the following method:
import base64
import requests
from IPython.core.display import HTML
def embedded_image(url):
response = requests.get(url)
uri = ("data:" +
response.headers['Content-Type'] + ";" +
"base64," + str(base64.b64encode(response.content).decode('utf-8')))
return uri
# Here is a small example. When you export the notebook as HTML,
# the image will be embedded in the HTML file
html = f'<img src="{embedded_image("https://upload.wikimedia.org/wikipedia/commons/5/56/Kosaciec_szczecinkowaty_Iris_setosa.jpg")}" />'
HTML(html)
UPDATE: As pointed out by #alexis, this doesn't actually answer the question correctly, this will not allow users to re-run cells and have images persist (this solution only allows one to embed the images into exports).
As of Jupyter Notebook 5, you can attach image data to cells, and refer to them from the cell via attachment:<image-file-name>. See the menu Edit > Insert Image, or use drag and drop.
Unfortunately, when converting notebooks with attached (embedded) images to HTML, those images will not show up.
To get them into the HTML code, you can use (for instance) nbtoolbelt.
It will replace those attachment: references by data: with the image data embedded in the img tag.

Is there a way to remove the Adobe border from an embedded PDF object?

I'm trying to remove the standard PDF frame from an embedded PDF on my page. I'd like just the PDF to show up without the toolbar on top and thick black frame from the page. I don't want the print, save, or anything to effect the look of the page. Below is the code I am using:
<object data="update404.pdf" type="application/pdf" width="693" height="1130">
</object>
Thank you in advance for your help!
Using object to embed PDF documents is not recommend - it will render different results in different devices and browsers and there is no way to make sure that it will look like you intend to. Have a look at the following projects for a better way to embed your project
PDF.JS
https://github.com/mozilla/pdf.js
FlexPaper
http://flexpaper.devaldi.com
Check out PDF Object:
http://pdfobject.com/examples/simplest.html
http://pdfobject.com/
This should let you accomplish what you wanted across all browsers.

A "shortcut" method for exporting an ASP.Net Page to pdf/xls

I want to export a few Pages to pdf/xls. By Pages I mean as the eye sees it - a screenshot of the Page's contents. I know how to build pdf/xls documents using 3rd party tools but is there any way to quickly export the rendered contents of say a Panel?
edit: maybe a tool that can render the page's output as a browser would, and save it as an image file?
There is an open source console program named wkhtmltopdf which you could call from asp.net to convert the page. It can convert to PDF or an image with wkhtmltoimage (JPG, PNG, etc.) using the webkit rendering engine.
Check my answer to this question to see an example of how to convert from a html to a pdf using C#:
Easiest way of porting html table data to readable document
I can recommend http://www.screengrab.org/ for firefox.

Resources