4
$\begingroup$

The Problem

I need to put together different graphics objects in a precise way inside a Graphics. Some objects are drawn directly by graphics primitives, some others are the result of calls to built-in and custom functions.

I've use Inset to place these objects, but the result is unsatisfactory, as the objects appears in wrong sizes.

For analizing better the problem, I've wrote a simple general example, where there are five objects that are placed in the Graphics sharing the very same shape, size and parameters. They differ only by the way how they are generated (please see the full code below).

There are five bars: redBar, greenBar, blueBar, yellowBar, orangeBar, they should be draw as the following picture (manually adjusted):

enter image description here

but instead, putting the elements together with this code (fragment):

 Graphics[{
   redBar[barW, barH]
   , Inset[greenBar[barW, barH, options], {0, yPos}, {0, 0}] /. {yPos -> 100}
   , Inset[blueBar[barW, barH, options], {0, yPos}, {Left, Bottom}] /. {yPos -> 200}
   , Inset[yellowBar[barW, barH, options], {0, yPos}, {Left, Bottom}] /. {yPos -> 300}
   , Inset[orangeBar[barW, barH, options], {0, yPos}, {Left, Bottom}] /. {yPos -> 400}
   }
  , Axes -> True
  , PlotRange -> {{0, slideW}, {0, slideH}}
  , ImageSize -> {slideW, slideH}
  , AspectRatio -> Automatic
  ]

will give this kind of output:

enter image description here

Sample Code

Here it is the full code for this example:

(* --- Functions definitions --- *)

(* a simple bar as a base for the red, green and blue bars*)
bar[w_, h_] := {Opacity[0.6], Rectangle[{0, 0}, {w, h}]};

(* Red Bar: this return a simple graphics Primitive *)
redBar[w_, h_] := {Red, bar[w, h]};

(* Green Bar: this returns a Graphics object, based on the shared bar primitive *)   
greenBar[w_, h_, options_] := Graphics[{Green, bar[w, h]}, Sequence@options];

(* Blue Bar: this returns a composed Graphics object *)
blueBarToInset[w_, h_, options_] := Graphics[{Blue, bar[w, h]}, Sequence@options];
blueBar[w_, h_, options_] := Graphics[Inset[blueBarToInset[w, h, options], {0, 0}, {Left, Bottom}], Sequence@options];

(* Yellow Bar, this is just the usual Plot function output *)
yellowBar[w_, h_, options_] := Plot[Sin[x], {x, 0, 4 Pi}, Axes -> True, Background -> Directive[Opacity[0.6], Yellow], Evaluate@Sequence@options];

(* Orange Bar, this is just the same as above, but without Axes  *)
orangeBar[w_, h_, options_] := Plot[Sin[x], {x, 0, 4 Pi}, Axes -> False,  Background -> Directive[Opacity[0.6], Orange], Evaluate@Sequence@options];

(* --- Main code --- *)
slideW = 500;
slideH = 500;

barW = 300;
barH = 100;

Manipulate[

 (*shared Graphics options*)
 options = {ImageSize -> {barW, barH}, AspectRatio -> aspectRatio, PlotRangePadding -> plotRangePadding};

 (*put elements together*)
 Graphics[{
   redBar[barW, barH]
   , Inset[greenBar[barW, barH, options], {0, yPos}, {0, 0}] /. {yPos -> 100}
   , Inset[blueBar[barW, barH, options], {0, yPos}, {Left, Bottom}] /. {yPos -> 200}
   , Inset[yellowBar[barW, barH, options], {0, yPos}, {Left, Bottom}] /. {yPos -> 300}
   , Inset[orangeBar[barW, barH, options], {0, yPos}, {Left, Bottom}] /. {yPos -> 400}
   }
  , Axes -> True
  , PlotRange -> {{0, slideW}, {0, slideH}}
  , ImageSize -> {slideW, slideH}
  , AspectRatio -> Automatic
  ]

 , {plotRangePadding, {Automatic, None}}
 , {aspectRatio, {Automatic, Full, (barH/barW) -> "barH/barW"}}
 ]

Another Test

To be sure that the graphics elements are actually similar in size, I've put them in a Column, obtaining almost the proper size, so this may prove than the problem is within Inset, not with the graphics elements themselfs:

Framed@Column[{
orangeBar[barW, barH, options],
yellowBar[barW, barH, options],
blueBar[barW, barH, options],
greenBar[barW, barH, options],
Graphics[redBar[barW, barH], options]
}
, Alignment -> Left
, Spacings -> 0]

enter image description here

IMHO

Maybe is my fault in understanding which option is to be given, but I think that this kind of (apparently simple) operations hasn't to be so difficult and frustrating..

$\endgroup$
  • 1
    $\begingroup$ I agree that it's frustrating. Inset is a little mysterious, and it took me a little while to figure out how it works. In addition, GraphicsColumn is non-ideal for various reasons. In any case, see these posts: (1), (2), (3) for some ideas. I recommend using GraphicsColumn (which uses Inset internally) with equal padding, and scaling all the figures to be the same size. $\endgroup$ – march Oct 30 '15 at 17:47
  • 1
    $\begingroup$ Also related: (16475), (73522), (83636) $\endgroup$ – Mr.Wizard Oct 30 '15 at 17:52
  • $\begingroup$ Thank you for the links, I've already read some of them before posting, but I've post this question hoping to find a general explanation of why these things happen rather than find a specific solution. As you point out Inset is a little bit obscure, it is really difficult to understand when the problem is coming from a hypothetical bug or from the user's incompetence $\endgroup$ – Guido Oct 30 '15 at 18:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.