Actual source code: axisc.c

  1: #include <petsc/private/drawimpl.h>

  3: #define PETSC_DRAW_AXIS_MAX_SEGMENTS 20
  4: PetscClassId PETSC_DRAWAXIS_CLASSID = 0;

  6: /*@
  7:    PetscDrawAxisCreate - Generate the axis data structure.

  9:    Collective

 11:    Input Parameter:
 12: .  win - `PetscDraw` object where axis to to be made

 14:    Output Parameter:
 15: .  axis - the axis datastructure

 17:    Note:
 18:    The MPI communicator that owns the underlying draw object owns the `PetscDrawAxis` object, but calls to set `PetscDrawAxis` options are
 19:    ignored by all processes except the first MPI rank in the communicator

 21:    Level: advanced

 23: .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawLGGetAxis()`, `PetscDrawSPGetAxis()`,
 24:           `PetscDrawHGGetAxis()`, `PetscDrawBarGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisDestroy()`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetHoldLimits()`,
 25:           `PetscDrawAxisDraw()`
 26: @*/
 27: PetscErrorCode PetscDrawAxisCreate(PetscDraw draw, PetscDrawAxis *axis)
 28: {
 29:   PetscDrawAxis ad;

 31:   PetscFunctionBegin;

 35:   PetscCall(PetscHeaderCreate(ad, PETSC_DRAWAXIS_CLASSID, "DrawAxis", "Draw Axis", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawAxisDestroy, NULL));

 37:   PetscCall(PetscObjectReference((PetscObject)draw));
 38:   ad->win = draw;

 40:   ad->xticks    = PetscADefTicks;
 41:   ad->yticks    = PetscADefTicks;
 42:   ad->xlabelstr = PetscADefLabel;
 43:   ad->ylabelstr = PetscADefLabel;
 44:   ad->ac        = PETSC_DRAW_BLACK;
 45:   ad->tc        = PETSC_DRAW_BLACK;
 46:   ad->cc        = PETSC_DRAW_BLACK;
 47:   ad->xlabel    = NULL;
 48:   ad->ylabel    = NULL;
 49:   ad->toplabel  = NULL;

 51:   *axis = ad;
 52:   PetscFunctionReturn(PETSC_SUCCESS);
 53: }

 55: /*@
 56:     PetscDrawAxisDestroy - Frees the space used by an axis structure.

 58:     Collective

 60:     Input Parameter:
 61: .   axis - the axis context

 63:     Level: advanced

 65: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`
 66: @*/
 67: PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis)
 68: {
 69:   PetscFunctionBegin;
 70:   if (!*axis) PetscFunctionReturn(PETSC_SUCCESS);
 72:   if (--((PetscObject)(*axis))->refct > 0) {
 73:     *axis = NULL;
 74:     PetscFunctionReturn(PETSC_SUCCESS);
 75:   }

 77:   PetscCall(PetscFree((*axis)->toplabel));
 78:   PetscCall(PetscFree((*axis)->xlabel));
 79:   PetscCall(PetscFree((*axis)->ylabel));
 80:   PetscCall(PetscDrawDestroy(&(*axis)->win));
 81:   PetscCall(PetscHeaderDestroy(axis));
 82:   PetscFunctionReturn(PETSC_SUCCESS);
 83: }

 85: /*@
 86:     PetscDrawAxisSetColors -  Sets the colors to be used for the axis,
 87:                          tickmarks, and text.

 89:     Logically Collective

 91:     Input Parameters:
 92: +   axis - the axis
 93: .   ac - the color of the axis lines
 94: .   tc - the color of the tick marks
 95: -   cc - the color of the text strings

 97:     Level: advanced

 99: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
100: @*/
101: PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis, int ac, int tc, int cc)
102: {
103:   PetscFunctionBegin;
108:   axis->ac = ac;
109:   axis->tc = tc;
110:   axis->cc = cc;
111:   PetscFunctionReturn(PETSC_SUCCESS);
112: }

114: /*@C
115:     PetscDrawAxisSetLabels -  Sets the x and y axis labels.

117:     Logically Collective

119:     Input Parameters:
120: +   axis - the axis
121: .   top - the label at the top of the image
122: -   xlabel,ylabel - the labes for the x and y axis

124:     Level: advanced

126:     Notes:
127:     Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()`

129:     There should be no newlines in the arguments

131: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
132: @*/
133: PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis, const char top[], const char xlabel[], const char ylabel[])
134: {
135:   PetscFunctionBegin;
137:   PetscCall(PetscFree(axis->xlabel));
138:   PetscCall(PetscFree(axis->ylabel));
139:   PetscCall(PetscFree(axis->toplabel));
140:   PetscCall(PetscStrallocpy(xlabel, &axis->xlabel));
141:   PetscCall(PetscStrallocpy(ylabel, &axis->ylabel));
142:   PetscCall(PetscStrallocpy(top, &axis->toplabel));
143:   PetscFunctionReturn(PETSC_SUCCESS);
144: }

146: /*@
147:     PetscDrawAxisSetLimits -  Sets the limits (in user coords) of the axis

149:     Logically Collective

151:     Input Parameters:
152: +   axis - the axis
153: .   xmin,xmax - limits in x
154: -   ymin,ymax - limits in y

156:     Options Database Key:
157: .   -drawaxis_hold - hold the initial set of axis limits for future plotting

159:     Level: advanced

161: .seealso: `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
162: @*/
163: PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis, PetscReal xmin, PetscReal xmax, PetscReal ymin, PetscReal ymax)
164: {
165:   PetscFunctionBegin;
167:   if (axis->hold) PetscFunctionReturn(PETSC_SUCCESS);
168:   axis->xlow  = xmin;
169:   axis->xhigh = xmax;
170:   axis->ylow  = ymin;
171:   axis->yhigh = ymax;
172:   PetscCall(PetscOptionsHasName(((PetscObject)axis)->options, ((PetscObject)axis)->prefix, "-drawaxis_hold", &axis->hold));
173:   PetscFunctionReturn(PETSC_SUCCESS);
174: }

176: /*@
177:     PetscDrawAxisGetLimits -  Gets the limits (in user coords) of the axis

179:     Not Collective

181:     Input Parameters:
182: +   axis - the axis
183: .   xmin,xmax - limits in x
184: -   ymin,ymax - limits in y

186:     Level: advanced

188: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
189: @*/
190: PetscErrorCode PetscDrawAxisGetLimits(PetscDrawAxis axis, PetscReal *xmin, PetscReal *xmax, PetscReal *ymin, PetscReal *ymax)
191: {
192:   PetscFunctionBegin;
194:   if (xmin) *xmin = axis->xlow;
195:   if (xmax) *xmax = axis->xhigh;
196:   if (ymin) *ymin = axis->ylow;
197:   if (ymax) *ymax = axis->yhigh;
198:   PetscFunctionReturn(PETSC_SUCCESS);
199: }

201: /*@
202:     PetscDrawAxisSetHoldLimits -  Causes an axis to keep the same limits until this is called
203:         again

205:     Logically Collective

207:     Input Parameters:
208: +   axis - the axis
209: -   hold - `PETSC_TRUE` - hold current limits, `PETSC_FALSE` allow limits to be changed

211:     Level: advanced

213:     Note:
214:         Once this has been called with `PETSC_TRUE` the limits will not change if you call
215:      `PetscDrawAxisSetLimits()` until you call this with `PETSC_FALSE`

217: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
218: @*/
219: PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis, PetscBool hold)
220: {
221:   PetscFunctionBegin;
224:   axis->hold = hold;
225:   PetscFunctionReturn(PETSC_SUCCESS);
226: }

228: /*@
229:     PetscDrawAxisDraw - draws an axis.

231:     Collective

233:     Input Parameter:
234: .   axis - `PetscDrawAxis` structure

236:     Level: advanced

238:     Note:
239:     This draws the actual axis.  The limits etc have already been set.
240:     By picking special routines for the ticks and labels, special
241:     effects may be generated.  These routines are part of the Axis
242:     structure (axis).

244: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
245: @*/
246: PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis)
247: {
248:   int         i, ntick, numx, numy, ac, tc, cc;
249:   PetscMPIInt rank;
250:   size_t      len, ytlen = 0;
251:   PetscReal   coors[4], tickloc[PETSC_DRAW_AXIS_MAX_SEGMENTS], sep, tw, th;
252:   PetscReal   xl, xr, yl, yr, dxl = 0, dyl = 0, dxr = 0, dyr = 0;
253:   char       *p;
254:   PetscDraw   draw;
255:   PetscBool   isnull;

257:   PetscFunctionBegin;
259:   PetscCall(PetscDrawIsNull(axis->win, &isnull));
260:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
261:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank));

263:   draw = axis->win;

265:   ac = axis->ac;
266:   tc = axis->tc;
267:   cc = axis->cc;
268:   if (axis->xlow == axis->xhigh) {
269:     axis->xlow -= .5;
270:     axis->xhigh += .5;
271:   }
272:   if (axis->ylow == axis->yhigh) {
273:     axis->ylow -= .5;
274:     axis->yhigh += .5;
275:   }

277:   PetscDrawCollectiveBegin(draw);
278:   if (rank) goto finally;

280:   /* get canonical string size */
281:   PetscCall(PetscDrawSetCoordinates(draw, 0, 0, 1, 1));
282:   PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
283:   /* lower spacing */
284:   if (axis->xlabelstr) dyl += 1.5 * th;
285:   if (axis->xlabel) dyl += 1.5 * th;
286:   /* left spacing */
287:   if (axis->ylabelstr) dxl += 7.5 * tw;
288:   if (axis->ylabel) dxl += 2.0 * tw;
289:   /* right and top spacing */
290:   if (axis->xlabelstr) dxr = 2.5 * tw;
291:   if (axis->ylabelstr) dyr = 0.5 * th;
292:   if (axis->toplabel) dyr = 1.5 * th;
293:   /* extra spacing */
294:   dxl += 0.7 * tw;
295:   dxr += 0.5 * tw;
296:   dyl += 0.2 * th;
297:   dyr += 0.2 * th;
298:   /* determine coordinates */
299:   xl = (dxl * axis->xhigh + dxr * axis->xlow - axis->xlow) / (dxl + dxr - 1);
300:   xr = (dxl * axis->xhigh + dxr * axis->xlow - axis->xhigh) / (dxl + dxr - 1);
301:   yl = (dyl * axis->yhigh + dyr * axis->ylow - axis->ylow) / (dyl + dyr - 1);
302:   yr = (dyl * axis->yhigh + dyr * axis->ylow - axis->yhigh) / (dyl + dyr - 1);
303:   PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr));
304:   PetscCall(PetscDrawStringGetSize(draw, &tw, &th));

306:   /* PetscDraw the axis lines */
307:   PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xhigh, axis->ylow, ac));
308:   PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xlow, axis->yhigh, ac));
309:   PetscCall(PetscDrawLine(draw, axis->xlow, axis->yhigh, axis->xhigh, axis->yhigh, ac));
310:   PetscCall(PetscDrawLine(draw, axis->xhigh, axis->ylow, axis->xhigh, axis->yhigh, ac));

312:   /* PetscDraw the top label */
313:   if (axis->toplabel) {
314:     PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->yhigh + 0.5 * th;
315:     PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->toplabel));
316:   }

318:   /* PetscDraw the X ticks and labels */
319:   if (axis->xticks) {
320:     numx = (int)(.15 * (axis->xhigh - axis->xlow) / tw);
321:     numx = PetscClipInterval(numx, 2, 6);
322:     PetscCall((*axis->xticks)(axis->xlow, axis->xhigh, numx, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS));
323:     /* PetscDraw in tick marks */
324:     for (i = 0; i < ntick; i++) {
325:       PetscCall(PetscDrawLine(draw, tickloc[i], axis->ylow, tickloc[i], axis->ylow + .5 * th, tc));
326:       PetscCall(PetscDrawLine(draw, tickloc[i], axis->yhigh, tickloc[i], axis->yhigh - .5 * th, tc));
327:     }
328:     /* label ticks */
329:     if (axis->xlabelstr) {
330:       for (i = 0; i < ntick; i++) {
331:         if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
332:         else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
333:         else sep = 0.0;
334:         PetscCall((*axis->xlabelstr)(tickloc[i], sep, &p));
335:         PetscCall(PetscDrawStringCentered(draw, tickloc[i], axis->ylow - 1.5 * th, cc, p));
336:       }
337:     }
338:   }
339:   if (axis->xlabel) {
340:     PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->ylow - 1.5 * th;
341:     if (axis->xlabelstr) y -= 1.5 * th;
342:     PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->xlabel));
343:   }

345:   /* PetscDraw the Y ticks and labels */
346:   if (axis->yticks) {
347:     numy = (int)(.50 * (axis->yhigh - axis->ylow) / th);
348:     numy = PetscClipInterval(numy, 2, 6);
349:     PetscCall((*axis->yticks)(axis->ylow, axis->yhigh, numy, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS));
350:     /* PetscDraw in tick marks */
351:     for (i = 0; i < ntick; i++) {
352:       PetscCall(PetscDrawLine(draw, axis->xlow, tickloc[i], axis->xlow + .5 * tw, tickloc[i], tc));
353:       PetscCall(PetscDrawLine(draw, axis->xhigh, tickloc[i], axis->xhigh - .5 * tw, tickloc[i], tc));
354:     }
355:     /* label ticks */
356:     if (axis->ylabelstr) {
357:       for (i = 0; i < ntick; i++) {
358:         if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
359:         else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
360:         else sep = 0.0;
361:         PetscCall((*axis->ylabelstr)(tickloc[i], sep, &p));
362:         PetscCall(PetscStrlen(p, &len));
363:         ytlen = PetscMax(ytlen, len);
364:         PetscCall(PetscDrawString(draw, axis->xlow - (len + .5) * tw, tickloc[i] - .5 * th, cc, p));
365:       }
366:     }
367:   }
368:   if (axis->ylabel) {
369:     PetscReal x = axis->xlow - 2.0 * tw, y = (axis->ylow + axis->yhigh) / 2;
370:     if (axis->ylabelstr) x -= (ytlen + .5) * tw;
371:     PetscCall(PetscStrlen(axis->ylabel, &len));
372:     PetscCall(PetscDrawStringVertical(draw, x, y + len * th / 2, cc, axis->ylabel));
373:   }

375:   PetscCall(PetscDrawGetCoordinates(draw, &coors[0], &coors[1], &coors[2], &coors[3]));
376: finally:
377:   PetscDrawCollectiveEnd(draw);
378:   PetscCallMPI(MPI_Bcast(coors, 4, MPIU_REAL, 0, PetscObjectComm((PetscObject)draw)));
379:   PetscCall(PetscDrawSetCoordinates(draw, coors[0], coors[1], coors[2], coors[3]));
380:   PetscFunctionReturn(PETSC_SUCCESS);
381: }

383: /*
384:     Removes all zeros but one from .0000
385: */
386: PetscErrorCode PetscStripe0(char *buf)
387: {
388:   size_t    n;
389:   PetscBool flg;
390:   char     *str = NULL;

392:   PetscFunctionBegin;
393:   PetscCall(PetscStrlen(buf, &n));
394:   PetscCall(PetscStrendswith(buf, "e00", &flg));
395:   if (flg) buf[n - 3] = 0;
396:   PetscCall(PetscStrstr(buf, "e0", &str));
397:   if (str) {
398:     buf[n - 2] = buf[n - 1];
399:     buf[n - 1] = 0;
400:   }
401:   PetscCall(PetscStrstr(buf, "e-0", &str));
402:   if (str) {
403:     buf[n - 2] = buf[n - 1];
404:     buf[n - 1] = 0;
405:   }
406:   PetscFunctionReturn(PETSC_SUCCESS);
407: }

409: /*
410:     Removes all zeros but one from .0000
411: */
412: PetscErrorCode PetscStripAllZeros(char *buf)
413: {
414:   size_t i, n;

416:   PetscFunctionBegin;
417:   PetscCall(PetscStrlen(buf, &n));
418:   if (buf[0] != '.') PetscFunctionReturn(PETSC_SUCCESS);
419:   for (i = 1; i < n; i++) {
420:     if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
421:   }
422:   buf[0] = '0';
423:   buf[1] = 0;
424:   PetscFunctionReturn(PETSC_SUCCESS);
425: }

427: /*
428:     Removes trailing zeros
429: */
430: #if (PETSC_SIZEOF_SIZE_T == 8)
431:   #define MAX_SIZE_T PETSC_INT64_MAX
432: #else
433:   #define MAX_SIZE_T INT_MAX
434: #endif
435: PetscErrorCode PetscStripTrailingZeros(char *buf)
436: {
437:   char  *found = NULL;
438:   size_t i, n, m = MAX_SIZE_T;

440:   PetscFunctionBegin;
441:   /* if there is an e in string DO NOT strip trailing zeros */
442:   PetscCall(PetscStrchr(buf, 'e', &found));
443:   if (found) PetscFunctionReturn(PETSC_SUCCESS);

445:   PetscCall(PetscStrlen(buf, &n));
446:   /* locate decimal point */
447:   for (i = 0; i < n; i++) {
448:     if (buf[i] == '.') {
449:       m = i;
450:       break;
451:     }
452:   }
453:   /* if not decimal point then no zeros to remove */
454:   if (m == MAX_SIZE_T) PetscFunctionReturn(PETSC_SUCCESS);
455:   /* start at right end of string removing 0s */
456:   for (i = n - 1; i > m; i++) {
457:     if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
458:     buf[i] = 0;
459:   }
460:   PetscFunctionReturn(PETSC_SUCCESS);
461: }

463: /*
464:     Removes leading 0 from 0.22 or -0.22
465: */
466: PetscErrorCode PetscStripInitialZero(char *buf)
467: {
468:   size_t i, n;

470:   PetscFunctionBegin;
471:   PetscCall(PetscStrlen(buf, &n));
472:   if (buf[0] == '0') {
473:     for (i = 0; i < n; i++) buf[i] = buf[i + 1];
474:   } else if (buf[0] == '-' && buf[1] == '0') {
475:     for (i = 1; i < n; i++) buf[i] = buf[i + 1];
476:   }
477:   PetscFunctionReturn(PETSC_SUCCESS);
478: }

480: /*
481:      Removes the extraneous zeros in numbers like 1.10000e6
482: */
483: PetscErrorCode PetscStripZeros(char *buf)
484: {
485:   size_t i, j, n;

487:   PetscFunctionBegin;
488:   PetscCall(PetscStrlen(buf, &n));
489:   if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
490:   for (i = 1; i < n - 1; i++) {
491:     if (buf[i] == 'e' && buf[i - 1] == '0') {
492:       for (j = i; j < n + 1; j++) buf[j - 1] = buf[j];
493:       PetscCall(PetscStripZeros(buf));
494:       PetscFunctionReturn(PETSC_SUCCESS);
495:     }
496:   }
497:   PetscFunctionReturn(PETSC_SUCCESS);
498: }

500: /*
501:       Removes the plus in something like 1.1e+2 or 1.1e+02
502: */
503: PetscErrorCode PetscStripZerosPlus(char *buf)
504: {
505:   size_t i, j, n;

507:   PetscFunctionBegin;
508:   PetscCall(PetscStrlen(buf, &n));
509:   if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
510:   for (i = 1; i < n - 2; i++) {
511:     if (buf[i] == '+') {
512:       if (buf[i + 1] == '0') {
513:         for (j = i + 1; j < n; j++) buf[j - 1] = buf[j + 1];
514:         PetscFunctionReturn(PETSC_SUCCESS);
515:       } else {
516:         for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j];
517:         PetscFunctionReturn(PETSC_SUCCESS);
518:       }
519:     } else if (buf[i] == '-') {
520:       if (buf[i + 1] == '0') {
521:         for (j = i + 1; j < n; j++) buf[j] = buf[j + 1];
522:         PetscFunctionReturn(PETSC_SUCCESS);
523:       }
524:     }
525:   }
526:   PetscFunctionReturn(PETSC_SUCCESS);
527: }