0

Working with alot of business documents and would like to be able to build something like the below chart using post script code. I know something like this can be hardcoded as a plain text EPS file or even generated via JS scripting, have downloaded some documentation but find this a bit overwhelming and don't know where to start.

I'm sure the code for this would be built around an array, a for loop, and some variables like bar color, font size, etc.

Need to be able to set specific 'rules' as variables, like, bar thickness, vertical distance between each entry, width of text boxes. Things that normally need to be constructed and adjusted by hand in InDesign.

Would anybody have some sample code of a similar chart (could be very basic) or be able to help with a very basic setup?

I'm sure i could take over and do my own customizing if i got some basic building blocks to start from something. thanks!

enter image description here

  • 1
    This is surely possible. I've looked into hard coding .eps and .pdf files a while ago, but like you, found it too cumbersome. I simply didn't have the time and determination to learn the language and all it's quirks and pitfalls. I could code it in javascript/HTML/svg and with some difficulty probably also in Illustrator javascript. Would an Illustrator solution be out of the question for you? – Wolff May 16 at 22:27
  • I guess javascripting via AI could work aswell, i actually did some basic JS code for InDesign stuff. My concern is that many times i will need many charts, and some will be duplicated, so would imagine having separate EPS files as links would work better than editing the same JS file 30 times with different values. These charts are heavily modified by clients while reviewing work, so need separate access to every single one at any moment. – Lucian May 17 at 5:49
  • Ok, so even InDesign scripting could be a solution? You shouldn't need to change the script every time. The script should read the data from a separate file or simply from a text frame. The styling could maybe be automatized without scripting and then the script only updates the width of the bars. I would love to help, problem is that I'm drowning in work right now :-( – Wolff May 17 at 6:34
  • That's fine, you actually gave me some ideas to try out in INDD. Maybe some other member will have some ready made code and willing to share. thanks – Lucian May 17 at 6:37
  • 1
    äThis is actually not hard takes about 5 mins to do. I will template one for you as soon as i get to a computer. There is a huge benefit of it not being a script in adobe software. The eps file is a script, it links and updates in ai, indesign as if it were a complete document. If you were to write a script then you would need to have a 3rd component that is not aware of all other changes. – joojaa May 17 at 16:02
2

Don't try EPS, but use specialized software to do this. There are specialized programs such as GraphViz, but even Microsoft Excel should be able to draw such simple bar graphs.

You cannot use any and all fonts in an EPS – this one uses Calibri-Bold, which works dandy with Photoshop and Illustrator, but my InDesign fails to recognize it and only shows squares. (If you have a similar problem, try something like /Helvetica-Bold.)

All texts must be entered using the standard PostScript StandardEncoding; you cannot use UTF8 or any of your own system's encodings, and accented characters must be entered in escaped form. You cannot use kerning, or ligatures, or any other OpenType feature. You cannot enter text in Arabic, Hebrew, Chinese, Japanese, or Devanagari (added to prevent a few comments on regarding the same). While it's theoretically possible to devise a format to allow for basic text formatting (bold, italic, underline, super- and subscript), this is very hard to do, as it would require far more advanced string parsing.


Nevertheless ... it was a blast to go and try this in pure PostScript; always fun to exercise those brain muscles. I have added lots of comments throughout and tried to put all 'redefinable' stuff together. I suppose you would want the inserting and editing of the actual values to be as simple as possible, therefore I made it possible to insert them straight into the code, not as an array or with predefined delimiters. It's a simple format: each line holds a 'year' (it can actually be any label) and the value it should display. The bar values need to be integers only, and PostScript cannot handle very large integers, so keep an eye out for these.

You can change a lot of parameters; font, size, colors, bar width and max length, and a parameter biasWidth which, when set to something else than the default 0, gets subtracted from each value. Thus, you can display a range with, say, values such as 1200 and 1210 with a bias of 1190, so the two bars would be 10 and 20 units wide instead.

There is a problem with creating EPSes this way: there is no way to know in advance how large the graph is going to be, but the Bounding Box needs to be set in advance, at the top of the file, in a comment. Better make it large enough or your graphs will be clipped.

The code for this EPS comes pretty close to your original graph. You can immediately place it into InDesign (although it will be slow!), and import it in other software such as Photoshop and Illustrator if you want to manually add design.

Enjoy :)

%!PS-Adobe-2.0 EPSF-2.0
%%BoundingBox: 0 0 1018 966

% Note that 'officially' the BoundingBox cannot be set other than to a
% reasonable value -- we don't know at this point! And you cannot set it 'afterwards'

% first, a few convenience functions

% RGB values in PostScript are decimal fractions of 0..1
% so you might prefer 'whole' values in the range 0..255 instead.
% 0 0 255 setRGB -> dark blue
/setRGB {
   255 div 3 -1 roll 255 div 3 -1 roll 255 div 3 -1 roll setrgbcolor
} def

% this is the max width of your longest bar
/bar_scale 823 def

% value makebar -> create a path with the width set to value (biased and scaled)
% this uses fontSize to calculate the vertical offset to center the texts (more or less)
% -- the 0.7 is a reasonable assumption for the "cap height" of regular fonts
/makebar {
    biasWidth sub
    0 barThickness fontSize 0.7 mul add 2 div rmoveto
    0 barThickness neg rlineto 
    bar_scale mul 0 rlineto
    0 barThickness rlineto
    closepath
} def

% value prettyNumber -> show value as thousands separated string
% note that this routine *cannot* handle floating point numbers
% nor negative value, nor too large values
/prettyNumber {
    /val exch cvi def
    % show each next thousands separated part

    /padZeros false def
    val 1000000 ge {
        /padZeros true def
        val 1000000 idiv =string cvs show
        (,) show
        /val val 1000000 mod def
    } if

    padZeros {
        val 100000 lt {
            (0) show
        } if
        val 10000 lt {
            (0) show
        } if
        val 1000 idiv =string cvs show
        (,) show
        /val val 1000 mod def
    } {
        val 1000 ge {
            /padZeros true def
            val 1000 idiv =string cvs show
            (,) show
            /val val 1000 mod def
        } if
    } ifelse

    padZeros {
        val 100 lt {
            (0) show
        } if
        val 10 lt {
            (0) show
        } if
    } if

    val =string cvs show
} def

% [year value] -> display complete bar, 'year' then bar with number
/bar {
    dup 0 get /year exch def
    1 get /value exch def

    % show the 'year' string in its own color
    yearColor setRGB
    year =string cvs show

    currentpoint /y exch def /x exch 23 add def

    % this is to make a number 'peek out' in black if the bar is shorter than its value
    x 21 add y moveto
    0 0 0 setRGB
    value prettyNumber

    % set color for the bar
    value max eq {
        maxColor setRGB
    } {
        barColor setRGB
    } ifelse

    newpath
    x y moveto
    value makebar
    fill

    x y moveto
    value makebar
    gsave
        clip
        inBarColor setRGB
        x 21 add y moveto
        value prettyNumber
    grestore
} def

% end of the convenience functions

% per-graph values come below

% this is the size of all texts
/fontSize 35 def

% this is your font definition
/Calibri-Bold findfont fontSize scalefont setfont

% title at the top
/title (GROWTH IN PRICE PER SQM BETWEEN 2008 AND 2018) def

% color of the title; all colors are in RGB
/titleColor { 33 51 101 } def

% the color of the year at the left
/yearColor { 33 51 101 } def

% the color of the number inside the bars
/inBarColor { 192 255 255 } def

% the color of regular bars
/barColor { 52 98 175 } def

% the color of the Maximum bar
/maxColor { 61 188 161 } def

% the value to bias the bar widths with --
% this gets subtracted from the value before calculating the bar width
% Do NOT make it larger than the smallest bar! This code will *possibly* handle negative numbers ... weirdly
% in case of doubt, set it to 0 (this will accurately scale all bars)
/biasWidth 0 def

% bar thickness -- best set to a value larger than your font size
/barThickness 59 def

% inter-bar spacing
/barSpacing 12 def

% let's define your values inline
% first put everything into an array until END is encountered
% you can add blank lines -- but don't accidentally insert spaces on these!
[
{
    { currentfile 100 string readline
        { dup () eq
            { pop }
            {dup (END) eq
                { pop exit } if
            } ifelse
        } { exit } ifelse
    } loop
} exec

2018 48799
2017 41335
2016 41401
2015 36001
2014 37179
2013 31750
2012 29791
2011 31260
2010 28173
2009 24538
2008 28342
END
] /values exch def

% convert to a double array for easier access
[
    values {
        [ exch
        token {
            exch token pop exch pop
        } if
        ]
    } forall
] /values exch def

% then show it!

/max values 0 get 1 get def
values {
    1 get
    dup max
    gt {
        /max exch def
    } {
        pop
    } ifelse
} forall

% we re-define bar_scale here to a fraction
/bar_scale bar_scale max biasWidth sub div def

% get the top position for the title, and top-down display
% the bars
/ypos  values length barSpacing barThickness add mul 10 add def

% fetch a 'year' string to get its height and width
% so the title can be placed at the bar start position
values 0 get 0 get
=string cvs stringwidth pop
47 add 23 add ypos 92 add moveto

titleColor setRGB
title show

% and all that's left is to show all of the values!
values {
    47 ypos moveto
    bar
    /ypos ypos barSpacing sub barThickness sub def
} forall

%%EOF

The result, as rasterized by Photoshop:

bar graph with fictional values


I should add that my PostScript was rusty enough to need the help of the PostScript Reference Manual by Paul Bourke, lots of Googling for code samples, but especially the excellent xpost PostScript interpreter on https://tio.run/#postscript-xpost, written by Stack Overflow member luser droog.

  • Nice, a bit verbose but still (you might want to parse a list instead of doing exec then a csv is easy to insert into the stream with less code). GraphViz does not draw things like this. The problem with specialized software is that there is very very rare to find software that actually does cmyk color. Therefore the user end up doing cmyk conversion all day long. The benefit of EPS is that if you link this to a adobe software you can update the table at a later date, even after you destroyed the original excel file meaning your job has less dependencies. – joojaa May 18 at 7:07
  • Its not really true that you can not know in advance how large the data is going to be though. Just like in excel or any other graphing program you can always scale your data to fit the size you have. Also make the color cmyk which is really the only reason to use eps. – joojaa May 18 at 7:12
  • CMYK would have to be a must and also need the ability to set the 'artboard' size of this, because many times i'm working with grids and this needs to be exactly 87mm wide for example (longest bar + year tag). But i do get the point now better, i guess i can customize and build my own. THanks for commenting the code! – Lucian May 18 at 9:56
  • @Lucian: if you had mentioned CMYK in your initial question, I'd have used setcmykcolor instead. It's still a small change – although I hope you can work out the necessary rolls by yourself. Sometimes I wished for an interactive PS renderer. (I actually learned to write PS interactively, using an ancient DOS based modem program to talk to an Apple LaserWriter. Ye gods, the excitement of seeing that first prompt PS>!) – Anonymous Jun 5 at 21:49
  • @Anonymous there is one. Its called illustrator and indesign..If you just edit the eps file the result will update every time you save and alt tab into the preview software – joojaa Jul 23 at 12:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.