2 minute read

Files Too Big For Saxi

I have used Saxi for a long time to control my AxiDraw pen plotter. I’ve found Saxi’s user interface to be easy to use, its allowed me to stay away from Inkscape (yay!), and you can easily select layers or colors to plot individually. Additionally, I have it running on a Raspberry Pi, so it’s not tethered to my desktop computer!

The Problem

But, there are some files which are too large, and simply fail to start plotting. For me that seems to happen around plot times of 2 hours. Looking at the output from Saxi, I see:

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory Aborted

Likely this is a Raspberry Pi memory issue, and not a Saxi issue, as I haven’t heard anyone else complain that it fails on longer plots.

But I think we can develop a workaround! Using Vpype, I will split a single color file into equal n layers. This is an operation I could do in the design within p5.js if desired, but seems like a good general purpose solution when I run into this particular problem.

The Recipe

Let’s try and hard code a small and easy demo to use with Vpype.

vpype \
eval "%num_layers=int(input('Number of Layers: '))%" \
read -a d -a points --no-crop 'Demo.svg' \
forlayer \
lmove %_lid% "%_lid%%num_layers+1%" \
end \
linesort \
show

Let’s step thru this code and explain it piece by piece:

  1. eval…
    1. Using the python input function, we ask the user for the number of layers to split the design into, and store that variable for future use.
  2. read -a d…
    1. Here we are reading in our file and sorting into layers based on attribute “d” which is the SVG attribute for path information; and “points” which is the standard attribute generated by Vpype. I’m not sure these attributes are exhaustive, but it’s done a good job with the files I’ve tried so far. As long as we don’t have any duplicate paths, each path will get it’s own layer.
  3. forlayer
    1. A Block Processor command, this loops through every layer in the design we just read in. It needs an end command to mark the end of the for loop.
  4. lmove
    1. This command moves the current layer to a new layer.
    2. Normally, the percent sign is used in expression substitution in Vpype. But in addition to the outer %s for expression substitution, we are also using the percent sign as the modulo operator by using two percent signs in succession, one escaping the other. Lastly, we are adding one to the result of the modulo operation, as Vpype does not accept layer ids equal to zero.
    3. In this example, we expect to see _lid = 1,2,3,4,5,6… and the new layer id to be 2,3,4,1,2,3… in response. It only irks me slightly that we don’t start on layer 1, but it doesn’t really matter.
  5. linesort
    1. We’re sorting the lines here, as any previous optimization is likely no longer as effective.

Imperfections

The only real issue with this workaround is the need to manually start each new layer. Ideally one would be able to press play on a four hour plot, rather than need to press play on 4x one hour plots. Likely a more robust solution is needed, especially if I transition to a larger plotter. Another issue is that the plot time increases by a decent amount since I can’t optimize across the whole design.