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: . draw - `PetscDraw` object where axis 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;
 33:   PetscAssertPointer(axis, 2);

 35:   PetscCall(PetscHeaderCreate(ad, PETSC_DRAWAXIS_CLASSID, "DrawAxis", "Draw Axis", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawAxisDestroy, NULL));
 36:   PetscCall(PetscObjectReference((PetscObject)draw));
 37:   ad->win       = draw;
 38:   ad->xticks    = PetscADefTicks;
 39:   ad->yticks    = PetscADefTicks;
 40:   ad->xlabelstr = PetscADefLabel;
 41:   ad->ylabelstr = PetscADefLabel;
 42:   ad->ac        = PETSC_DRAW_BLACK;
 43:   ad->tc        = PETSC_DRAW_BLACK;
 44:   ad->cc        = PETSC_DRAW_BLACK;
 45:   ad->xlabel    = NULL;
 46:   ad->ylabel    = NULL;
 47:   ad->toplabel  = NULL;
 48:   *axis         = ad;
 49:   PetscFunctionReturn(PETSC_SUCCESS);
 50: }

 52: /*@
 53:   PetscDrawAxisDestroy - Frees the space used by an axis structure.

 55:   Collective

 57:   Input Parameter:
 58: . axis - the axis context

 60:   Level: advanced

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

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

 82: /*@
 83:   PetscDrawAxisSetColors -  Sets the colors to be used for the axis,
 84:   tickmarks, and text.

 86:   Logically Collective

 88:   Input Parameters:
 89: + axis - the axis
 90: . ac   - the color of the axis lines
 91: . tc   - the color of the tick marks
 92: - cc   - the color of the text strings

 94:   Level: advanced

 96: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
 97: @*/
 98: PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis, int ac, int tc, int cc)
 99: {
100:   PetscFunctionBegin;
105:   axis->ac = ac;
106:   axis->tc = tc;
107:   axis->cc = cc;
108:   PetscFunctionReturn(PETSC_SUCCESS);
109: }

111: /*@
112:   PetscDrawAxisSetLabels -  Sets the x and y axis labels.

114:   Logically Collective

116:   Input Parameters:
117: + axis   - the axis
118: . top    - the label at the top of the image
119: . xlabel - the x axis label
120: - ylabel - the y axis label

122:   Level: advanced

124:   Notes:
125:   Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()`

127:   There should be no newlines in the arguments

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

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

147:   Logically Collective

149:   Input Parameters:
150: + axis - the axis
151: . xmin - the lower x limit
152: . xmax - the upper x limit
153: . ymin - the lower y limit
154: - ymax - the upper y limit

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 - the lower x limit
184: . xmax - the upper x limit
185: . ymin - the lower y limit
186: - ymax - the upper y limit

188:   Level: advanced

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

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

207:   Logically Collective

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

213:   Level: advanced

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

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

230: #if defined(__GNUC__) && !defined(__clang__)
231:   #pragma GCC diagnostic push
232:   #pragma GCC diagnostic ignored "-Wclobbered"
233: #endif
234: /*@
235:   PetscDrawAxisDraw - draws an axis.

237:   Collective

239:   Input Parameter:
240: . axis - `PetscDrawAxis` structure

242:   Level: advanced

244:   Note:
245:   This draws the actual axis.  The limits etc have already been set.
246:   By picking special routines for the ticks and labels, special
247:   effects may be generated.  These routines are part of the Axis
248:   structure (axis).

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

263:   PetscFunctionBegin;
265:   PetscCall(PetscDrawIsNull(axis->win, &isnull));
266:   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
267:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank));

269:   draw = axis->win;

271:   ac = axis->ac;
272:   tc = axis->tc;
273:   cc = axis->cc;
274:   if (axis->xlow == axis->xhigh) {
275:     axis->xlow -= .5;
276:     axis->xhigh += .5;
277:   }
278:   if (axis->ylow == axis->yhigh) {
279:     axis->ylow -= .5;
280:     axis->yhigh += .5;
281:   }

283:   PetscDrawCollectiveBegin(draw);
284:   if (rank) goto finally;

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

312:   /* PetscDraw the axis lines */
313:   PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xhigh, axis->ylow, ac));
314:   PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xlow, axis->yhigh, ac));
315:   PetscCall(PetscDrawLine(draw, axis->xlow, axis->yhigh, axis->xhigh, axis->yhigh, ac));
316:   PetscCall(PetscDrawLine(draw, axis->xhigh, axis->ylow, axis->xhigh, axis->yhigh, ac));

318:   /* PetscDraw the top label */
319:   if (axis->toplabel) {
320:     PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->yhigh + 0.5 * th;

322:     PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->toplabel));
323:   }

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

349:     if (axis->xlabelstr) y -= 1.5 * th;
350:     PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->xlabel));
351:   }

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

379:     if (axis->ylabelstr) x -= ((PetscReal)ytlen + .5) * tw;
380:     PetscCall(PetscStrlen(axis->ylabel, &len));
381:     PetscCall(PetscDrawStringVertical(draw, x, y + ((PetscReal)len) * th / 2, cc, axis->ylabel));
382:   }

384:   PetscCall(PetscDrawGetCoordinates(draw, &coors[0], &coors[1], &coors[2], &coors[3]));
385: finally:
386:   PetscDrawCollectiveEnd(draw);
387:   PetscCallMPI(MPI_Bcast(coors, 4, MPIU_REAL, 0, PetscObjectComm((PetscObject)draw)));
388:   PetscCall(PetscDrawSetCoordinates(draw, coors[0], coors[1], coors[2], coors[3]));
389:   PetscFunctionReturn(PETSC_SUCCESS);
390: }
391: #if defined(__GNUC__) && !defined(__clang__)
392:   #pragma GCC diagnostic pop
393: #endif

395: /*
396:     Removes all zeros but one from .0000
397: */
398: PetscErrorCode PetscStripe0(char *buf)
399: {
400:   size_t    n;
401:   PetscBool flg;
402:   char     *str = NULL;

404:   PetscFunctionBegin;
405:   PetscCall(PetscStrlen(buf, &n));
406:   PetscCall(PetscStrendswith(buf, "e00", &flg));
407:   if (flg) buf[n - 3] = 0;
408:   PetscCall(PetscStrstr(buf, "e0", &str));
409:   if (str) {
410:     buf[n - 2] = buf[n - 1];
411:     buf[n - 1] = 0;
412:   }
413:   PetscCall(PetscStrstr(buf, "e-0", &str));
414:   if (str) {
415:     buf[n - 2] = buf[n - 1];
416:     buf[n - 1] = 0;
417:   }
418:   PetscFunctionReturn(PETSC_SUCCESS);
419: }

421: /*
422:     Removes all zeros but one from .0000
423: */
424: PetscErrorCode PetscStripAllZeros(char *buf)
425: {
426:   size_t i, n;

428:   PetscFunctionBegin;
429:   PetscCall(PetscStrlen(buf, &n));
430:   if (buf[0] != '.') PetscFunctionReturn(PETSC_SUCCESS);
431:   for (i = 1; i < n; i++) {
432:     if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
433:   }
434:   buf[0] = '0';
435:   buf[1] = 0;
436:   PetscFunctionReturn(PETSC_SUCCESS);
437: }

439: /*
440:     Removes trailing zeros
441: */
442: #if (PETSC_SIZEOF_SIZE_T == 8)
443:   #define MAX_SIZE_T PETSC_INT64_MAX
444: #else
445:   #define MAX_SIZE_T INT_MAX
446: #endif
447: PetscErrorCode PetscStripTrailingZeros(char *buf)
448: {
449:   char  *found = NULL;
450:   size_t i, n, m = MAX_SIZE_T;

452:   PetscFunctionBegin;
453:   /* if there is an e in string DO NOT strip trailing zeros */
454:   PetscCall(PetscStrchr(buf, 'e', &found));
455:   if (found) PetscFunctionReturn(PETSC_SUCCESS);

457:   PetscCall(PetscStrlen(buf, &n));
458:   /* locate decimal point */
459:   for (i = 0; i < n; i++) {
460:     if (buf[i] == '.') {
461:       m = i;
462:       break;
463:     }
464:   }
465:   /* if not decimal point then no zeros to remove */
466:   if (m == MAX_SIZE_T) PetscFunctionReturn(PETSC_SUCCESS);
467:   /* start at right end of string removing 0s */
468:   for (i = n - 1; i > m; i++) {
469:     if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
470:     buf[i] = 0;
471:   }
472:   PetscFunctionReturn(PETSC_SUCCESS);
473: }

475: /*
476:     Removes leading 0 from 0.22 or -0.22
477: */
478: PetscErrorCode PetscStripInitialZero(char *buf)
479: {
480:   size_t i, n;

482:   PetscFunctionBegin;
483:   PetscCall(PetscStrlen(buf, &n));
484:   if (buf[0] == '0') {
485:     for (i = 0; i < n; i++) buf[i] = buf[i + 1];
486:   } else if (buf[0] == '-' && buf[1] == '0') {
487:     for (i = 1; i < n; i++) buf[i] = buf[i + 1];
488:   }
489:   PetscFunctionReturn(PETSC_SUCCESS);
490: }

492: /*
493:      Removes the extraneous zeros in numbers like 1.10000e6
494: */
495: PetscErrorCode PetscStripZeros(char *buf)
496: {
497:   size_t i, j, n;

499:   PetscFunctionBegin;
500:   PetscCall(PetscStrlen(buf, &n));
501:   if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
502:   for (i = 1; i < n - 1; i++) {
503:     if (buf[i] == 'e' && buf[i - 1] == '0') {
504:       for (j = i; j < n + 1; j++) buf[j - 1] = buf[j];
505:       PetscCall(PetscStripZeros(buf));
506:       PetscFunctionReturn(PETSC_SUCCESS);
507:     }
508:   }
509:   PetscFunctionReturn(PETSC_SUCCESS);
510: }

512: /*
513:       Removes the plus in something like 1.1e+2 or 1.1e+02
514: */
515: PetscErrorCode PetscStripZerosPlus(char *buf)
516: {
517:   size_t i, j, n;

519:   PetscFunctionBegin;
520:   PetscCall(PetscStrlen(buf, &n));
521:   if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
522:   for (i = 1; i < n - 2; i++) {
523:     if (buf[i] == '+') {
524:       if (buf[i + 1] == '0') {
525:         for (j = i + 1; j < n; j++) buf[j - 1] = buf[j + 1];
526:         PetscFunctionReturn(PETSC_SUCCESS);
527:       } else {
528:         for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j];
529:         PetscFunctionReturn(PETSC_SUCCESS);
530:       }
531:     } else if (buf[i] == '-') {
532:       if (buf[i + 1] == '0') {
533:         for (j = i + 1; j < n; j++) buf[j] = buf[j + 1];
534:         PetscFunctionReturn(PETSC_SUCCESS);
535:       }
536:     }
537:   }
538:   PetscFunctionReturn(PETSC_SUCCESS);
539: }