%% $Id: pst-bar.tex 603 2022-09-10 07:53:35Z herbert $ %% %% %% This is file `pst-bar.tex', %% %% IMPORTANT NOTICE: %% %% Package `pst-bar.tex' %% %% Alan Ristow %% Herbert Voss %% %% This program can be redistributed and/or modified under the terms %% of the LaTeX Project Public License Distributed from CTAN archives %% in directory macros/latex/base/lppl.txt. %% %% DESCRIPTION: %% `pst-bar' is a PSTricks package for additionals to the standard %% pstricks package %% \csname PSTBarLoaded\endcsname% \let\PSTBarLoaded\endinput% \ifx\PSTricksLoaded\endinput\else\input pstricks \fi \ifx\PSTplotLoaded\endinput\else\input pst-plot \fi \ifx\PSTXKeyLoaded\endinput\else\input pst-xkey \fi \def\fileversion{0.93} \def\filedate{2022/09/10} \message{`pst-bar' v\fileversion, \filedate\space (Alan Ristow, hv)}% \edef\PstAtCode{\the\catcode`\@} \catcode`\@=11\relax \pstheader{pst-bar.pro}% \pst@addfams{pst-bar} \newlength\psk@labelwidth% \define@key[psset]{pst-bar}{barsep}{\edef\psk@barsep{#1}}% \define@key[psset]{pst-bar}{barcolsep}{\edef\psk@barcolsep{#1}}% \define@key[psset]{pst-bar}{barstyle}{\def\@barstylelist{#1}}% \define@key[psset]{pst-bar}{barlabelrot}{\edef\psk@barlabelrot{#1}}% \define@key[psset]{pst-bar}{labelalign}{\def\psk@labelalign{#1}}% \define@key[psset]{pst-bar}{labelwidth}{\setlength\psk@labelwidth{#1}}% \def\psk@labelalign{\centering}% \setlength\psk@labelwidth{0.5in}% % % chartstyle=cluster|stack|block (0,1,2) \define@key[psset]{pst-bar}{chartstyle}{\pst@expandafter\psset@@chartstyle{#1}\@nil\psk@chartstyle}% \def\psset@@chartstyle#1#2\@nil#3{% \ifx#1c\let#3\z@\else \ifx#1s\let#3\@ne\else \ifx#1b\let#3\tw@\else \@pstrickserr{Bad argument: `#1#2'}\@ehpa \fi \fi \fi }% % orientation=vertical|horizontal (0,1) \define@key[psset]{pst-bar}{orientation}{\pst@expandafter\psset@@orientation{#1}\@nil\psk@orientation}% \def\psset@@orientation#1#2\@nil#3{% \ifx#1h\let#3\p@\else \ifx#1v\let#3\z@\else \@pstrickserr{Bad argument: `#1#2'}\@ehpa \fi \fi }% \define@key[psset]{pst-bar}{header}{\pst@expandafter\psset@@header{#1}\@nil\psk@header}% \def\psset@@header#1#2\@nil#3{% \ifx#1t\let#3\z@\else \ifx#1f\let#3\@ne\else \@pstrickserr{Bad argument: `#1#2'}\@ehpa \fi \fi }% \psset[pst-bar]{barsep=0.0,barcolsep=0.4,barstyle=\@empty,barlabelrot=0,% chartstyle=cluster,orientation=vertical,header=true}% \def\psbarchart{\def\pst@par{}\pst@object{psbarchart}}% \def\pstbar@header{\@empty}% \def\psbarlabel#1{#1}% \def\psbarlabelsep{0pt}% \def\psbarscale(#1)#2{% \def\psbar@mul{#1\space}% \def\psbar@psop{#2\space}% } \def\psbar@mul{1\space}% \def\psbar@psop{\@empty}% \newread\pstbar@file% % Define bar chart styles \def\newpsbarstyle#1#2{\@namedef{psbarcs@#1}{\psset{#2}}}% \def\begin@barstyle{\def\pst@tempd{/barstyles [ }}% \def\add@barstyle{% \def\pst@code{}% \ifpsshadow% \pst@closedshadow% \fi% \ifdim\psk@border\p@>\z@% \pst@addborder% \fi% \psk@fillstyle% \pst@stroke% \ifpsdoubleline% \pst@doublestroke% \fi% \def\pst@tempa{\strip@pt\psk@orientation}% \edef\pst@tempd{ \pst@tempd (% \pst@tempc \psk@cornersize% xbar1 ybar1 xbar2 ybar2 4 -\pst@tempa\space roll \psk@dimen% \tx@Frame% \pst@code )% }% } \def\end@barstyle{\edef\pst@tempd{ \pst@tempd ] def }}% \def\setbarstyle{% \begin@barstyle% \expandafter\@setbarstyle\@barstylelist,\@nil\ignorespaces% \end@barstyle% }% \def\@setbarstyle#1,{% \@@setbarstyle{#1}% \@ifnextchar\@nil{\@gobble}{\@setbarstyle}% }% \def\@@setbarstyle#1{% \@ifundefined{psbarcs@#1}% {\@pstrickserr{Custom bar chart style `#1' undefined}\@ehpa}% {\@nameuse{psbarcs@#1}\add@barstyle}% }% % Default bar chart styles \newpsbarstyle{red}{fillcolor=red,fillstyle=solid,framearc=0}% \newpsbarstyle{green}{fillcolor=green,fillstyle=solid,framearc=0}% \newpsbarstyle{blue}{fillcolor=blue,fillstyle=solid,framearc=0}% \newpsbarstyle{black}{fillcolor=black,fillstyle=solid,framearc=0}% \newpsbarstyle{white}{fillcolor=white,fillstyle=solid,framearc=0}% \newpsbarstyle{gray}{fillcolor=gray,fillstyle=solid,framearc=0}% \newpsbarstyle{lightgray}{fillcolor=lightgray,fillstyle=solid,framearc=0}% \newpsbarstyle{darkgray}{fillcolor=darkgray,fillstyle=solid,framearc=0}% %\psset@barstyle{black,darkgray,gray,lightgray,white,red,green,blue}% \psset[pst-bar]{barstyle={black,darkgray,gray,lightgray,white,red,green,blue}}% \def\readpsbardata{\@ifnextchar[{\readpsbardata@i}{\readpsbardata@i[]}} \def\readpsbardata@i[#1]#2#3{% \def\pst@tempa{#1}% \ifx\pst@tempa\@empty\else\psset{#1}\fi \openin\pstbar@file=#3\relax% \ifeof\pstbar@file% \@pstrickserr{Data file `#3' not found.}\@ehpa \else \def\pst@tempb{\@empty}% \ifx\psk@header\z@% \@readpsbarheader% \fi \readpsbardata@ii% \edef\pst@tempb{[\pst@tempb]}% \let#2\pst@tempb% \fi \closein\pstbar@file% }% \def\readpsbardata@ii{% \read\pstbar@file to \pst@tempa \ifeof\pstbar@file \relax \else \edef\pst@tempb{\pst@tempb [}% \expandafter\readpsbardata@iii\pst@tempa,\@nil\ignorespaces% \edef\pst@tempb{\pst@tempb ]}% \readpsbardata@ii% \fi }% \def\readpsbardata@iii#1,{% \edef\pst@tempb{\pst@tempb #1\space}% \@ifnextchar\@nil{\@gobble}{\readpsbardata@iii}% }% \def\@readpsbarheader{% \read\pstbar@file to \pst@tempa \ifeof\pstbar@file \relax \else \let\pstbar@header\pst@tempa \fi }% % Apply labels from file header to bar chart columns. % TODO: Deal with column headings that contain commas. % The trimspaces command is (c) Michael Downes 1994 % (http://www.tug.org/tex-archive/info/aro-bend/answer.015). \catcode`\Q=3 \def\psbar@trimspaces#1{% \begingroup \aftergroup\toks\aftergroup0\aftergroup{% \expandafter\trimb\expandafter\noexpand#1Q Q}% \edef#1{\the\toks0}% } \def\trimb#1 Q{\trimc#1Q} \def\trimc#1Q#2{\afterassignment\endgroup \vfuzz\the\vfuzz#1} \catcode`\Q=11 \def\pstbar@xlabels{% \pst@dima=-0.5pt\relax% \expandafter\pstbar@xlabels@i\pstbar@header,\@nil\ignorespaces% }% \def\pstbar@xlabels@i#1,{% \def\pst@tempa{#1}% \psbar@trimspaces\pst@tempa% \advance\pst@dima by 1pt% \def\pst@tempb{\strip@pt\pst@dima}% \uput[-90]{\psk@barlabelrot}(\pst@tempb,-\psbarlabelsep){\psbarlabel{\parbox{\psk@labelwidth}{\psk@labelalign\pst@tempa}}}% \@ifnextchar\@nil{\@gobble}{\pstbar@xlabels@i}% }% \def\pstbar@labelcount#1{% \pst@dima=0pt\relax% \expandafter\pstbar@labelcount@i\pstbar@header,\@nil\ignorespaces% \let#1\pst@dima% }% \def\pstbar@labelcount@i#1,{% \advance\pst@dima by 1pt% \@ifnextchar\@nil{\@gobble}{\pstbar@labelcount@i}% }% \def\pstbar@ylabels{% \pstbar@labelcount{\pst@dima}% \advance\pst@dima by 0.5pt% \expandafter\pstbar@ylabels@i\pstbar@header,\@nil\ignorespaces% }% \def\pstbar@ylabels@i#1,{% \def\pst@tempa{#1}% \psbar@trimspaces\pst@tempa% \advance\pst@dima by -1pt% \def\pst@tempb{\strip@pt\pst@dima}% \uput[180]{\psk@barlabelrot}(-\psbarlabelsep,\pst@tempb){\psbarlabel{\parbox{\psk@labelwidth}{\psk@labelalign\pst@tempa}}}% \@ifnextchar\@nil{\@gobble}{\pstbar@ylabels@i}% }% \def\psbarchart@i#1{% \pst@killglue% \begingroup% \use@par% \psbarchart@ii{#1}% \endgroup% \ignorespaces% }% \def\psbarchart@ii#1{% \begin@SpecialObj% % Save contents of \pst@code and load start-of-path code % into \pst@tempc \let\pst@tempb\pst@code% \def\pst@code{}% \solid@star% \let\pst@tempc\pst@code% % Load end-of-path code into \pst@tempd and restore original % contents of \pst@code \begin@barstyle% \expandafter\@setbarstyle\@barstylelist,\@nil\ignorespaces% \end@barstyle% \let\pst@code\pst@tempb% % Draw bar chart \pst@checknum\psk@barcolsep\pst@tempa% \pst@checknum\psk@barsep\pst@tempb% \ifx\psk@orientation\z@ % vertical \pst@dima=\psxunit% \pst@dimb=\psyunit% \def\pst@tempc{true}% \else\ifx\psk@orientation\p@ % horizontal \pst@dima=\psyunit% \pst@dimb=\psxunit% \def\pst@tempc{false}% \else \@pstrickserr{Bad orientation specification}\@ehpa \fi\fi \ifcase\psk@chartstyle% chartstyle=cluster \addto@pscode{% /scx { \pst@number\psxunit mul } def /scy { \pst@number\psyunit mul } def \pst@tempd% /BARDATA #1 def /nbars BARDATA length def /ncols BARDATA 0 get length def /colwidth \pst@number\pst@dima def /barcolsep \pst@tempa \pst@number\pst@dima mul def /barsep \pst@tempb \pst@number\pst@dima mul def /barwidth colwidth barcolsep sub nbars 1 sub barsep mul sub nbars div def /bXoffset 0.5 barcolsep mul def /colcount \pst@tempc\space {0}{ncols 1 sub} ifelse def /barcount 0 def /ybar1 0 def BARDATA { /DATAVECTOR exch def DATAVECTOR { /ybar2 exch \psbar@psop \psbar@mul mul \pst@number\pst@dimb mul def /xoffset barwidth barsep add barcount mul bXoffset add def /xbar1 colcount colwidth mul xoffset add def /xbar2 xbar1 barwidth add def ybar1 ybar2 ne { % if ybar1 == ybar2, don't stroke a path newpath barstyles barcount get cvx exec } if /colcount \pst@tempc\space {colcount 1 add}{colcount 1 sub} ifelse def } forall /colcount \pst@tempc\space {0}{ncols 1 sub} ifelse def /barcount barcount 1 add def } forall }% \or% chartstyle=stack \addto@pscode{% \pst@tempd% tx@BarDict begin /BARDATA #1 transpose def /ncols BARDATA length def /colwidth \pst@number\pst@dima def /barcolsep \pst@tempa \pst@number\pst@dima mul def /barwidth colwidth barcolsep sub def /bXoffset 0.5 barcolsep mul def /colcount \pst@tempc\space {0}{ncols 1 sub} ifelse def /barcount 0 def /ybar1 0 def BARDATA { /DATAVECTOR exch def /xbar1 colcount colwidth mul bXoffset add def /xbar2 xbar1 barwidth add def /count 0 def DATAVECTOR { count 0 eq { /ybar2 exch \psbar@psop \psbar@mul mul \pst@number\pst@dimb mul ybar1 add def }{ /ybar2 exch \psbar@mul mul \pst@number\pst@dimb mul ybar1 add def } ifelse ybar1 ybar2 ne { % if ybar1 == ybar2, don't stroke a path newpath barstyles barcount get cvx exec closepath } if /ybar1 ybar2 def /barcount barcount 1 add def /count count 1 add def } forall /barcount 0 def /ybar1 0 def /colcount \pst@tempc\space {colcount 1 add}{colcount 1 sub} ifelse def } forall end }% \or% chartstyle=block \addto@pscode{% \pst@tempd% tx@BarDict begin /BARDATA #1 transpose def /ncols BARDATA length def /nbars BARDATA 0 get length 2 idiv def /colwidth \pst@number\pst@dima def /barcolsep \pst@tempa \pst@number\pst@dima mul def /barsep \pst@tempb \pst@number\pst@dima mul def /barwidth colwidth barcolsep sub nbars 1 sub barsep mul sub nbars div def /bXoffset 0.5 barcolsep mul def /colcount \pst@tempc\space {0}{ncols 1 sub} ifelse def /barcount 0 def /ybar1 0 def BARDATA { /DATAVECTOR exch def 0 1 nbars 1 sub { dup /ybar1 exch 2 mul DATAVECTOR exch get \psbar@psop \psbar@mul mul \pst@number\pst@dimb mul def /ybar2 exch 2 mul 1 add DATAVECTOR exch get \psbar@psop \psbar@mul mul \pst@number\pst@dimb mul def /xoffset barwidth barsep add barcount mul bXoffset add def /xbar1 colcount colwidth mul xoffset add def /xbar2 xbar1 barwidth add def ybar1 ybar2 ne { % if ybar1 == ybar2, don't stroke a path newpath barstyles barcount get cvx exec } if /barcount barcount 1 add def } for /barcount 0 def /colcount \pst@tempc\space {colcount 1 add}{colcount 1 sub} ifelse def } forall end }% \else% \@pstrickserr{Unknown chart style.}\@ehpa% \fi% \ifx\psk@orientation\z@% \pstbar@xlabels% \else \pstbar@ylabels% \fi \end@SpecialObj% }% \catcode`\@=\PstAtCode\relax \endinput