Output panel

Batch Plot

Plots the layouts you pick to PDF, one file per layout, in a folder you choose, and remembers the folder, the naming and the page setup for next time.

On the ribbonButton, Output panel
NeedsAn open drawing with at least one layout (the button is greyed without a drawing)
CommandPYBATCHPLOT
AliasBP

What it does#

Plots each ticked paper space layout to its own PDF with AutoCAD's DWG To PDF.pc3, in the foreground, one after another. A layout that fails does not stop the rest; the failures are listed at the end. The folder, the naming pattern and the page setup you used are remembered and offered first next time.

How to use it#

  1. Click Batch Plot, or type PYBATCHPLOT. A drawing with only the model tab gets a toast instead.
  2. Untick the layouts you do not want. They are listed in tab order and all start ticked.
  3. Pick the folder for the PDFs. The picker starts in the folder you used last time, else the drawing's own folder.
  4. Pick the naming. The three choices are shown as real file names for the first layout you ticked, the one you used last time first:
    PatternExample for Level 2.dwg, layout A-201
    {drawing} - {layout}.pdfLevel 2 - A-201.pdf
    {layout}.pdfA-201.pdf
    {drawing}_{layout}.pdfLevel 2_A-201.pdf
  5. If the drawing has named page setups for paper space, pick one, or Each layout's own settings. A drawing without any skips this question.
  6. If any of the PDFs already exist in the folder, confirm that they may be replaced.
  7. A progress window shows "Plotting A-201 (2 of 6)". Cancel stops after the layout being plotted.
  8. A toast reports "Plotted 6 layouts to PDF" with the folder. If some failed, a window lists each layout with the reason, and Copy puts the list on the clipboard.

What goes into each PDF#

Each plot starts from the layout's own plot settings, or from the page setup you picked (the layouts themselves are not changed). Then a few settings are always overridden:

  • The device is always DWG To PDF.pc3, whatever the layout or page setup names.
  • The paper size is kept when DWG To PDF.pc3 offers the same paper; when it does not, the device's default paper is used, without a warning.
  • The plot area is the layout, scaled to fit, centred, with no rotation. A layout set up at 1:1 therefore plots fitted to the printable area, not at an exact 1:1.

The plot style table, lineweights and the other settings come from the layout or page setup unchanged.

Limitations#

  • PDF only, through DWG To PDF.pc3. To plot to a printer or another PC3, use PUBLISH.
  • One PDF per layout. There is no option to combine them into one multi-sheet PDF.
  • The model tab is not offered. Only paper space layouts plot.
  • Only the open drawing. To plot many drawings, run the tool in each.
  • Scale, rotation and centring are fixed, as described above. A page setup that relies on a set scale or a 90 degree rotation will not plot the way it does from PLOT.
  • A PDF that is open in a viewer cannot be replaced; that layout is listed as failed.

Good to know#

Characters Windows does not allow in a file name (< > : " / \ | ? *) become _. Two layouts never write the same file: if their names collide, the second gets (2) before .pdf. An unsaved drawing is called untitled in the name.

Background plotting is switched off for the run (BACKGROUNDPLOT is set to 0) and put back afterwards, so each PDF is finished before the next starts.

The remembered choices are stored in %APPDATA%\pyACAD\settings\cfg_pyacad_tab_output_panel_batch_plot_pushbutton.json. There is no Shift+Click action; delete that file to forget them.

Other uses#

  • Name layouts by sheet number and use {layout}.pdf: the PDFs come out named exactly like the sheets.
  • Keep a "Check print" page setup and pick it for quick review sets, without touching the layouts' own settings.

Source#

The tool's own files, word for word as shipped in Output.panel/Batch_Plot.pushbutton. Every pyACAD tool is an ordinary bundle: copy these into your own extension and change what you like.

script.py Runs on a click. View on GitHub
# -*- coding: utf-8 -*-
"""Plots the layouts you pick to PDF, one file per layout, in a folder you choose.

File names come from plot.batch_names, so two layouts never write the same
file. The folder, the naming and the page setup are remembered for next time.
A layout that fails to plot does not stop the rest: the failures are listed
at the end.
"""

import os

from pyacad import doc, forms, layouts, plot, script, toast

__title__ = 'Batch Plot'

_TITLE = 'Batch plot'
_PATTERNS = ['{drawing} - {layout}.pdf', '{layout}.pdf', '{drawing}_{layout}.pdf']
_OWN_SETTINGS = "Each layout's own settings"
_DEFAULTS = {'folder': '', 'pattern': _PATTERNS[0], 'page_setup': ''}


def run():
    if not _has_drawing():
        toast.warning('No drawing is open', 'Open a drawing and run Batch Plot again.')
        return
    names = layouts.names()
    if not names:
        toast.info('No layouts to plot', 'This drawing has only the model tab.')
        return
    config = script.get_config(_DEFAULTS)
    drawing = doc.path()

    picked = forms.select_from_list(names, _TITLE, multiselect=True,
                                    prompt='Layouts to plot', checked=names)
    if picked is None:
        return
    if not picked:
        toast.info('Nothing plotted', 'No layout was ticked.')
        return

    folder = forms.pick_folder('Folder for the PDFs', _start_folder(config['folder'], drawing))
    if not folder:
        return

    pattern = _ask_pattern(drawing, picked[0], config['pattern'])
    if pattern is None:
        return

    setup = _ask_page_setup(config['page_setup'])
    if setup is False:
        return

    targets = plot.batch_names(drawing, picked, folder, pattern)
    existing = [path for _, path in targets if os.path.exists(path)]
    if existing and not forms.confirm(
            '%s already in %s. Replace %s?'
            % (_count(len(existing), 'of these PDFs is', 'of these PDFs are'), folder,
               'it' if len(existing) == 1 else 'them'), _TITLE):
        return

    script.save_config({'folder': folder, 'pattern': pattern, 'page_setup': setup or ''})

    done, failures, stopped = _plot_all(targets, setup)
    _report(done, failures, stopped, len(targets), folder)


def _has_drawing():
    try:
        doc.active()
    except RuntimeError:
        return False
    return True


def _start_folder(saved, drawing):
    """The folder last plotted to, else the drawing's own folder, else none."""
    if saved and os.path.isdir(saved):
        return saved
    folder = os.path.dirname(drawing)
    return folder if folder and os.path.isdir(folder) else None


def _ask_pattern(drawing, layout, saved):
    """The naming pattern, offered as example file names for the first picked
    layout; the one used last time comes first."""
    order = sorted(_PATTERNS, key=lambda p: p != saved)
    examples = [plot.output_name(p, drawing, layout) for p in order]
    choice = forms.ask_options('Each layout plots to its own PDF. Name them like:',
                               examples, _TITLE)
    return None if choice is None else order[examples.index(choice)]


def _ask_page_setup(saved):
    """A paper space page setup name, None for each layout's own settings, or
    False on cancel. No question when the drawing has no page setups."""
    setups = layouts.page_setups(paper_only=True)
    if not setups:
        return None
    options = [_OWN_SETTINGS] + setups
    choice = forms.select_from_list(options, _TITLE, prompt='Plot with which page setup?',
                                    checked=[saved if saved in setups else _OWN_SETTINGS])
    if choice is None:
        return False
    return None if choice == _OWN_SETTINGS else choice


def _plot_all(targets, setup):
    """Plots each (layout, path); returns (plotted count, [(layout, reason)],
    True when the person cancelled part way)."""
    done = 0
    failures = []
    total = len(targets)
    try:
        with forms.progress(_TITLE, 'Starting') as bar:
            for index, (layout, path) in enumerate(targets):
                bar.check()
                bar.update(float(index) / total,
                           'Plotting %s (%d of %d)' % (layout, index + 1, total))
                try:
                    plot.to_pdf(layout, path, page_setup=setup)
                    done += 1
                except Exception as error:
                    script.get_logger().error('batch plot: %s failed: %s' % (layout, error))
                    failures.append((layout, str(error) or type(error).__name__))
            bar.update(1.0, 'Done')
    except forms.Cancelled:
        return done, failures, True
    return done, failures, False


def _report(done, failures, stopped, total, folder):
    if stopped:
        toast.info('Batch plot stopped', 'Plotted %d of %s before you cancelled'
                   % (done, _count(total, 'layout', 'layouts')))
    elif not failures:
        toast.success('Plotted %s to PDF' % _count(done, 'layout', 'layouts'), folder)
    if failures:
        if not stopped:
            toast.warning('Plotted %d of %s' % (done, _count(total, 'layout', 'layouts')),
                          '%d failed' % len(failures))
        text = '\n'.join('%s: %s' % (layout, reason) for layout, reason in failures)
        forms.alert('%s did not plot:\n\n%s'
                    % (_count(len(failures), 'layout', 'layouts'), text), _TITLE, copy=text)


def _count(n, one, many):
    return '%d %s' % (n, one if n == 1 else many)


run()
bundle.yaml The bundle contract: the keys pyACAD reads for this tool. View on GitHub
title: Batch Plot
tooltip: Plots the layouts you pick to PDF, one file per layout, in a folder you choose. Remembers the folder, the file naming and the page setup for next time.
context: doc
keytip: OP
alias: BP