Exporting multi page Dash app to pdf with entire layout

Yes! You will need an additional package on top of PDFkit and Blob-stream called HTML2Canvas (https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js) in the assets folder. You can convert any DIV and anything inside it to an image then use PDFKit to put the image in a pdf. However it is not as reliable as the first method since it takes a screenshot of a div.

import dash_table
import pandas as pd
import dash
import dash_html_components as html
from dash.dependencies import Input, Output

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Button(id='button', children='Print Dash DataTable'),
    html.Div([
        dash_table.DataTable(
            id='table',
            columns=[{"name": i, "id": i} for i in df.columns],
            data=df.to_dict('records'),
        ),
    ], id='table_div'),
    html.Div(id='img_div')
    ])


app.clientside_callback(
    '''
    function (n_clicks) {
        if (n_clicks > 0) {
            html2canvas(document.getElementById('table_div')).then(function(canvas) {
                var img = new Image();
                var height = canvas.height;
                img.src = canvas.toDataURL("image/png");
                document.getElementById('img_div').appendChild(img);

                var doc = new PDFDocument({layout:'portrait', margin: 25});
                var stream = doc.pipe(blobStream());

                var img_container = document.getElementById('img_div');
                var imgElement = img_container.getElementsByTagName('img');
                var imgSrc = imgElement[imgElement.length - 1].src;
                doc.image(imgSrc, {width: 600});

                doc.end();

                var saveData = (function () {
                    var a = document.createElement("a");
                    document.body.appendChild(a);
                    a.style = "display: none";
                    return function (blob, fileName) {
                        var url = window.URL.createObjectURL(blob);
                        a.href = url;
                        a.download = fileName;
                        a.click();
                        window.URL.revokeObjectURL(url);
                    };
                }());

                stream.on('finish', function() {
                  var blob = stream.toBlob('application/pdf');
                  saveData(blob, 'Dash_DataTable.pdf');
                });
            });


        }
        return false;
    }
    ''',
    Output('button', 'disabled'),
    [
        Input('button', 'n_clicks'),
    ]
)


if __name__ == '__main__':
    app.run_server(debug=True)

A downside of this method is I haven’t been able to add more than one screenshot of a div to the pdf, so if you have multiple charts/tables you need to wrap everything to a div and screenshot that div to the pdf. If the div goes beyond A4 size then you need to make the pdf longer.

2 Likes