Ilya Zakharevich on Fri, 18 Oct 2019 12:11:50 +0200 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
Resend: [PATCH v2.11.1] High-resolution PS plotting |
As Bill says, the original message was too long for the list. I’m resending without one of the attachments, available at http://ilyaz.org/software/tmp/tst-plot-new.pdf ==================== Date: Wed, 16 Oct 2019 20:09:36 -0700 After the high-quality plotting was removed from gp/PARI (around v2.0.22, IIRC), only very rough hardcopy plots are available.¹⁾ ¹⁾ Math::Pari comes with patches which restore this functionality, up to v2.3.* of GP/PARI. The main problems are: • Very low resolution (worse than VGA; causes “staircases” everywhere); • Spurious spikes (due to very high default value of the miter-limit in Postscript); • The conflict between the visibility requiring thick lines, and detalization requiring very thin lines (especially visible for fractal-like graphs — such as the graphs of modular symbols). The first attached graph demonstrates these defects. It is made with \\ 9 is eblue, 10-16... are R,G,B,Orange,Purple,Brown,Violet; \\ 17-22 are parula: B/orange/yellow/purple/G/light-blue/R default(graphcolormap,["white", "black", "gray", "violetred", "red", "green", "blue", "gainsboro", "purple", "#0080ff", "#ed2d2e", "#008c47", "#1859a9", "#f37d22", "#662c91", "#a11d20", "#b33893", "#0072bd", "#d95319", "#edb120", "#7e2f8e", "#77ac30", "#4dbeee", "#a2142f"]) default(graphcolors,[16,11,12,10,14]) write("tst-plot.ps",s=plothexport("ps",X=-0.001,0.01, \ X*[1,-1,if(X,sin(1/X),0),if(X,cos(1.1/X),0)],,5000)); The second attached graph shows how these problems are fixed by the patch below: • It increases PS resolution 1000 times. This leads to longer numbers written to the PS file (the size of PS file grows less than 2x). This also causes a comparable increase in the size of generated PDF files. (I think that one could live with 200–300 taken instead of 1000 — but I wanted some margin to be future-proof. The overhead in size of files is minuscule.) • It switches to round linejoins (restoring the default when drawing rectangles). • The PostScript driver causes every line in the graph to be drawn several times with different thicknesses. Without zooming in, only the thickiest lines are visibible (so there is no visible change w.r.t. the old way). However, after zooming in the hairlines become visible, allowing visualization of finer behavior of the plots. (The thickness of the extra lines and their number is controlled by an array in the generated PS file. Making this array empty restores the old behaviour.) Unfortunately, this PS code is unwound in the generated PDF files, so by default, their size grows EXTRA 3 times. Still, I think this is negligible by today’s standards — comparing to the benefits. Enjoy, Ilya --- pari-2.11.1-build32/src/graph/plotport.c-pre 2018-10-31 15:38:08.000000000 -0700 +++ pari-2.11.1-build32/src/graph/plotport.c 2019-10-16 18:10:24.369566200 -0700 @@ -81,6 +81,8 @@ DTOL(double t) { return (long)(t + 0.5); static const long PS_WIDTH = 1120 - 60; /* 1400 - 60 for hi-res */ static const long PS_HEIGH = 800 - 40; /* 1120 - 60 for hi-res */ +static const long PS_SCALE = 1000; /* Allowing 64x zoom (max on many viewers) on 500ppi display requires about 450 */ +static const char* const PS_EXTRASTROKES = "65 25"; /* Tuned to be very visible on 100ppi displays with 64x zoom */ static void _psdraw_scale(PARI_plot *T, GEN w, GEN x, GEN y) @@ -97,12 +99,12 @@ _psdraw(PARI_plot *T, GEN w, GEN x, GEN static void pari_get_psplot(PARI_plot *T) { - T->width = PS_WIDTH; - T->height = PS_HEIGH; - T->fheight= 15; - T->fwidth = 6; - T->hunit = 5; - T->vunit = 5; + T->width = PS_WIDTH*PS_SCALE; + T->height = PS_HEIGH*PS_SCALE; + T->fheight= 15*PS_SCALE; + T->fwidth = 6*PS_SCALE; + T->hunit = 5*PS_SCALE; + T->vunit = 5*PS_SCALE; T->dwidth = 0; T->dheight= 0; T->draw = NULL; @@ -2121,7 +2123,7 @@ static void ps_rect(void *data, long x, long y, long w, long h) { pari_str *S = (pari_str*)data; - str_printf(S,"%ld %ld m %ld %ld l %ld %ld l %ld %ld l closepath stroke\n", + str_printf(S,"%ld %ld m %ld %ld l %ld %ld l %ld %ld l closepath currentlinejoin 0 setlinejoin stroke setlinejoin\n", y,x, y,x+w, y+h,x+w, y+h,x); } @@ -2129,7 +2131,7 @@ static void ps_fillrect(void *data, long x, long y, long w, long h) { pari_str *S = (pari_str*)data; - str_printf(S,"%ld %ld m %ld %ld l %ld %ld l %ld %ld l closepath fill\n", + str_printf(S,"%ld %ld m %ld %ld l %ld %ld l %ld %ld l closepath currentlinejoin 0 setlinejoin fill setlinejoin\n", y,x, y,x+w, y+h,x+w, y+h,x); } @@ -2145,9 +2147,9 @@ ps_lines(void *data, long nb, struct plo { pari_str *S = (pari_str*)data; long i; - str_printf(S,"%ld %ld m\n",p[0].y,p[0].x); - for (i=1; i<nb; i++) str_printf(S, "%ld %ld l\n", p[i].y, p[i].x); - str_printf(S,"stroke\n"); + str_printf(S,"%ld %ld mm\n",p[0].y,p[0].x); + for (i=1; i<nb; i++) str_printf(S, "%ld %ld ll\n", p[i].y, p[i].x); + str_printf(S,"mlstroke\n"); } static void @@ -2174,30 +2176,69 @@ rect2ps_i(GEN w, GEN x, GEN y, PARI_plot PARI_plot U; pari_str S; double xs = 0.65, ys = 0.65; + int rescale = 1; + const char *extra = ""; if (T) /* res wrt T dimens */ { if (plotps) xs = ys = 1; else { - xs *= ((double)PS_WIDTH) / T->width; - ys *= ((double)PS_HEIGH) / T->height; + xs *= ((double)PS_WIDTH*PS_SCALE) / T->width; + ys *= ((double)PS_HEIGH*PS_SCALE) / T->height; + rescale = PS_SCALE; + extra = PS_EXTRASTROKES; } } else { T = &U; pari_get_psplot(T); + rescale = PS_SCALE; + extra = PS_EXTRASTROKES; } str_init(&S, 1); /* Definitions taken from post terminal of Gnuplot. */ str_printf(&S, "%%!\n\ 50 50 translate\n\ -/p {moveto 0 2 rlineto 2 0 rlineto 0 -2 rlineto closepath fill} def\n\ +1 %d div 1 %d div scale\n\ +%d setlinewidth\n\ +1 setlinejoin\n\ +/p {moveto 0 2 rlineto 2 0 rlineto 0 -2 rlineto closepath currentlinejoin 0 setlinejoin fill setlinejoin} def\n\ /c0 {0 0 0 setrgbcolor} def\n\ -/c {setrgbcolor} def\n\ /l {lineto} def\n\ -/m {moveto} def\n" -"/Times-Roman findfont %ld scalefont setfont\n", DTOL(T->fheight * xs)); +/m {moveto} def\n\ +/postLW %% linewidths of extra passes (colors alternate: white and orig)\n\ + [ %s ] def %% empty is OK; second width down to 15 is still comfortable\n\ +postLW length 0 gt {\n\ + /mlN 0 def\n\ + /mlD 20 dict def\n\ + /lMulti {%% [coords] --> -\n\ + dup length 2 sub 0 2 3 2 roll {%% [coords] idxCoord --> [coords]\n\ + 2 copy 2 copy get 3 1 roll 1 add get l pop } for pop} def\n\ + %% curveArray=[[start] [[coords] [coords] ...] [color]] --> curveArray\n\ + /replot { dup 0 get aload pop m dup 1 get { lMulti } forall } def\n\ + /postmlCurve {%% needColor idxCurve --> needColor\n\ + mlD exch string get 1 index {dup 2 get aload pop setrgbcolor} if\n\ + replot pop stroke } def\n\ + /postmlPass {%% idxPass --> -\n\ + dup postLW exch get setlinewidth 2 mod 0 eq dup { 1 1 1 setrgbcolor} if\n\ + not 1 1 mlN { postmlCurve } for pop } def\n\ + /postml { 0 1 postLW length 1 sub { postmlPass } for } def\n\ + /C 3 array def\n\ + /c {C astore aload pop setrgbcolor} def\n\ + /mlstroke { ] ] [ C aload pop ] 3 array astore /mlN mlN 1 add def\n\ + mlN string exch mlD begin store end stroke} def\n\ + /ll {2 copy lineto /ptN ptN 1 add def ptN 5 ge { /ptN 0 def ] [ } if} def\n\ + /mm {2 copy 2 array astore 3 1 roll moveto /ptN 0 def [ [ } def\n\ +} {\n\ + /c {setrgbcolor} def\n\ + /ll {lineto} def\n\ + /mm {moveto} def\n\ + /mlstroke {stroke} def\n\ + /postml {} def\n\ +} ifelse\n" +"/Times-Roman findfont %ld scalefont setfont\n", + rescale, rescale, rescale, extra, DTOL(T->fheight * xs)); pl.sc = &ps_sc; pl.pt = &ps_point; @@ -2212,7 +2253,7 @@ rect2ps_i(GEN w, GEN x, GEN y, PARI_plot if (plotps) str_printf(&S,"0 %ld translate -90 rotate\n", T->height - 50); gen_draw(&pl, w, x, y, xs, ys); - str_puts(&S,"stroke showpage\n"); + str_puts(&S,"stroke postml showpage\n"); *S.cur = 0; return S.string; } char * ----- End forwarded message ----- ----- End forwarded message -----
Attachment:
tst-plot.pdf
Description: Adobe PDF document