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 Parameters:
 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;


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

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

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

 50:   *axis = ad;
 51:   return 0;
 52: }

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

 57:     Collective

 59:     Input Parameters:
 60: .   axis - the axis context

 62:     Level: advanced

 64: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`
 65: @*/
 66: PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis)
 67: {
 68:   if (!*axis) return 0;
 70:   if (--((PetscObject)(*axis))->refct > 0) {
 71:     *axis = NULL;
 72:     return 0;
 73:   }

 75:   PetscFree((*axis)->toplabel);
 76:   PetscFree((*axis)->xlabel);
 77:   PetscFree((*axis)->ylabel);
 78:   PetscDrawDestroy(&(*axis)->win);
 79:   PetscHeaderDestroy(axis);
 80:   return 0;
 81: }

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

 87:     Logically Collective

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

 95:     Level: advanced

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

111: /*@C
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,ylabel - the labes for the x and y axis

121:     Notes:
122:     Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()`

124:     There should be no newlines in the arguments

126:     Level: advanced

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

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

145:     Logically Collective

147:     Input Parameters:
148: +   axis - the axis
149: .   xmin,xmax - limits in x
150: -   ymin,ymax - limits in y

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

155:     Level: advanced

157: .seealso: `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
158: @*/
159: PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis, PetscReal xmin, PetscReal xmax, PetscReal ymin, PetscReal ymax)
160: {
162:   if (axis->hold) return 0;
163:   axis->xlow  = xmin;
164:   axis->xhigh = xmax;
165:   axis->ylow  = ymin;
166:   axis->yhigh = ymax;
167:   PetscOptionsHasName(((PetscObject)axis)->options, ((PetscObject)axis)->prefix, "-drawaxis_hold", &axis->hold);
168:   return 0;
169: }

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

174:     Not Collective

176:     Input Parameters:
177: +   axis - the axis
178: .   xmin,xmax - limits in x
179: -   ymin,ymax - limits in y

181:     Level: advanced

183: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
184: @*/
185: PetscErrorCode PetscDrawAxisGetLimits(PetscDrawAxis axis, PetscReal *xmin, PetscReal *xmax, PetscReal *ymin, PetscReal *ymax)
186: {
188:   if (xmin) *xmin = axis->xlow;
189:   if (xmax) *xmax = axis->xhigh;
190:   if (ymin) *ymin = axis->ylow;
191:   if (ymax) *ymax = axis->yhigh;
192:   return 0;
193: }

195: /*@
196:     PetscDrawAxisSetHoldLimits -  Causes an axis to keep the same limits until this is called
197:         again

199:     Logically Collective

201:     Input Parameters:
202: +   axis - the axis
203: -   hold - `PETSC_TRUE` - hold current limits, `PETSC_FALSE` allow limits to be changed

205:     Level: advanced

207:     Note:
208:         Once this has been called with `PETSC_TRUE` the limits will not change if you call
209:      `PetscDrawAxisSetLimits()` until you call this with `PETSC_FALSE`

211: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
212: @*/
213: PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis, PetscBool hold)
214: {
217:   axis->hold = hold;
218:   return 0;
219: }

221: /*@
222:     PetscDrawAxisDraw - draws an axis.

224:     Collective

226:     Input Parameter:
227: .   axis - `PetscDrawAxis` structure

229:     Level: advanced

231:     Note:
232:     This draws the actual axis.  The limits etc have already been set.
233:     By picking special routines for the ticks and labels, special
234:     effects may be generated.  These routines are part of the Axis
235:     structure (axis).

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

251:   PetscDrawIsNull(axis->win, &isnull);
252:   if (isnull) return 0;
253:   MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank);

255:   draw = axis->win;

257:   ac = axis->ac;
258:   tc = axis->tc;
259:   cc = axis->cc;
260:   if (axis->xlow == axis->xhigh) {
261:     axis->xlow -= .5;
262:     axis->xhigh += .5;
263:   }
264:   if (axis->ylow == axis->yhigh) {
265:     axis->ylow -= .5;
266:     axis->yhigh += .5;
267:   }

269:   PetscDrawCollectiveBegin(draw);
270:   if (rank) goto finally;

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

298:   /* PetscDraw the axis lines */
299:   PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xhigh, axis->ylow, ac);
300:   PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xlow, axis->yhigh, ac);
301:   PetscDrawLine(draw, axis->xlow, axis->yhigh, axis->xhigh, axis->yhigh, ac);
302:   PetscDrawLine(draw, axis->xhigh, axis->ylow, axis->xhigh, axis->yhigh, ac);

304:   /* PetscDraw the top label */
305:   if (axis->toplabel) {
306:     PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->yhigh + 0.5 * th;
307:     PetscDrawStringCentered(draw, x, y, cc, axis->toplabel);
308:   }

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

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

367:   PetscDrawGetCoordinates(draw, &coors[0], &coors[1], &coors[2], &coors[3]);
368: finally:
369:   PetscDrawCollectiveEnd(draw);
370:   MPI_Bcast(coors, 4, MPIU_REAL, 0, PetscObjectComm((PetscObject)draw));
371:   PetscDrawSetCoordinates(draw, coors[0], coors[1], coors[2], coors[3]);
372:   return 0;
373: }

375: /*
376:     Removes all zeros but one from .0000
377: */
378: PetscErrorCode PetscStripe0(char *buf)
379: {
380:   size_t    n;
381:   PetscBool flg;
382:   char     *str;

384:   PetscStrlen(buf, &n);
385:   PetscStrendswith(buf, "e00", &flg);
386:   if (flg) buf[n - 3] = 0;
387:   PetscStrstr(buf, "e0", &str);
388:   if (str) {
389:     buf[n - 2] = buf[n - 1];
390:     buf[n - 1] = 0;
391:   }
392:   PetscStrstr(buf, "e-0", &str);
393:   if (str) {
394:     buf[n - 2] = buf[n - 1];
395:     buf[n - 1] = 0;
396:   }
397:   return 0;
398: }

400: /*
401:     Removes all zeros but one from .0000
402: */
403: PetscErrorCode PetscStripAllZeros(char *buf)
404: {
405:   size_t i, n;

407:   PetscStrlen(buf, &n);
408:   if (buf[0] != '.') return 0;
409:   for (i = 1; i < n; i++) {
410:     if (buf[i] != '0') return 0;
411:   }
412:   buf[0] = '0';
413:   buf[1] = 0;
414:   return 0;
415: }

417: /*
418:     Removes trailing zeros
419: */
420: PetscErrorCode PetscStripTrailingZeros(char *buf)
421: {
422:   char  *found;
423:   size_t i, n, m = PETSC_MAX_INT;

425:   /* if there is an e in string DO NOT strip trailing zeros */
426:   PetscStrchr(buf, 'e', &found);
427:   if (found) return 0;

429:   PetscStrlen(buf, &n);
430:   /* locate decimal point */
431:   for (i = 0; i < n; i++) {
432:     if (buf[i] == '.') {
433:       m = i;
434:       break;
435:     }
436:   }
437:   /* if not decimal point then no zeros to remove */
438:   if (m == PETSC_MAX_INT) return 0;
439:   /* start at right end of string removing 0s */
440:   for (i = n - 1; i > m; i++) {
441:     if (buf[i] != '0') return 0;
442:     buf[i] = 0;
443:   }
444:   return 0;
445: }

447: /*
448:     Removes leading 0 from 0.22 or -0.22
449: */
450: PetscErrorCode PetscStripInitialZero(char *buf)
451: {
452:   size_t i, n;

454:   PetscStrlen(buf, &n);
455:   if (buf[0] == '0') {
456:     for (i = 0; i < n; i++) buf[i] = buf[i + 1];
457:   } else if (buf[0] == '-' && buf[1] == '0') {
458:     for (i = 1; i < n; i++) buf[i] = buf[i + 1];
459:   }
460:   return 0;
461: }

463: /*
464:      Removes the extraneous zeros in numbers like 1.10000e6
465: */
466: PetscErrorCode PetscStripZeros(char *buf)
467: {
468:   size_t i, j, n;

470:   PetscStrlen(buf, &n);
471:   if (n < 5) return 0;
472:   for (i = 1; i < n - 1; i++) {
473:     if (buf[i] == 'e' && buf[i - 1] == '0') {
474:       for (j = i; j < n + 1; j++) buf[j - 1] = buf[j];
475:       PetscStripZeros(buf);
476:       return 0;
477:     }
478:   }
479:   return 0;
480: }

482: /*
483:       Removes the plus in something like 1.1e+2 or 1.1e+02
484: */
485: PetscErrorCode PetscStripZerosPlus(char *buf)
486: {
487:   size_t i, j, n;

489:   PetscStrlen(buf, &n);
490:   if (n < 5) return 0;
491:   for (i = 1; i < n - 2; i++) {
492:     if (buf[i] == '+') {
493:       if (buf[i + 1] == '0') {
494:         for (j = i + 1; j < n; j++) buf[j - 1] = buf[j + 1];
495:         return 0;
496:       } else {
497:         for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j];
498:         return 0;
499:       }
500:     } else if (buf[i] == '-') {
501:       if (buf[i + 1] == '0') {
502:         for (j = i + 1; j < n; j++) buf[j] = buf[j + 1];
503:         return 0;
504:       }
505:     }
506:   }
507:   return 0;
508: }