3
$\begingroup$

I would like to create a plot made of subplots containing ArrayPlots with colorbars.

Since Mathematica's native colorbars are still a pain to be placed correctly, I am using an adapted custom one from this question: Sizing cells in a GraphicsGrid/GraphicsRow:

colorbar[{min_, max_}, ticks_, fs_, is_, colorFunction_]:= 
DensityPlot[y, {x, 0, 0.1}, {y, min, max},
AspectRatio -> 30,
ColorFunction -> colorFunction,
Frame -> True, FrameLabel -> {{None, None}, {None, None}}, 
FrameStyle -> Directive[Black, AbsoluteThickness[2]],
FrameTicks -> {{None, {#[[1]], #[[2]], {0, 0.5}} & /@ ticks}, {None,
   None}}, 
FrameTicksStyle -> Directive[FontFamily -> "Helvetica", fs, Black],
ImageSize -> {Automatic, is}, MaxRecursion -> 0, PlotRangePadding -> 0, 
PlotPoints -> {2, 100}
]

A minimal example of the plot I am working on is:

{is, fs} = {400, 20};
fsColorbar = fs;
plotops2d = {
 FrameLabel -> {"y", "x"},
 FrameStyle -> Directive[AbsoluteThickness[2], Black, fs, FontFamily -> "Helvetica"],
 FrameTicks -> {All, All, None, None},
 ImagePadding -> {{60, 10}, {63, 10}},
 ImageSize -> {Automatic, is},
 PlotRangePadding -> None, PlotRange -> All,
 RotateLabel -> False
};

plot1 = Row[{
 ArrayPlot[RandomReal[{0, 1}, {30, 30}], ColorFunction -> "Rainbow", Evaluate[plotops2d]],
 Show[colorbar[{0, 1}, {{0, 0}, {1, 1}}, fsColorbar, is, "Rainbow"], ImageSize -> {Automatic, is}, ImagePadding -> {{1, 42}, {63, 10}}]
}];
plot2 = Row[{
 ArrayPlot[RandomReal[{0, 1}, {30, 30}], ColorFunction -> "SunsetColors", Evaluate[plotops2d]],
Show[colorbar[{0, 1}, {{0, 0}, {1, 1}}, fsColorbar, is, "SunsetColors"], ImageSize -> {Automatic, is}, ImagePadding -> {{1, 42}, {63, 10}}]
}];

pic = Grid[{{plot1}, {plot2}}]

This results in this nice plot:

still ok

However, if I would like to antialias the image with:

pic2 = Rasterize[pic, ImageResolution -> 300]

I get:

bad

I can get the correct alignment if I decrease the values for ImageResolution or ImageSize. However, this is not an option for me. Does anyone what the reason for that behavior is and how I can circumvent it?

$\endgroup$
  • $\begingroup$ Does it happen with GraphicsColumn[] too? $\endgroup$ – J. M. will be back soon Aug 13 '17 at 11:02
  • $\begingroup$ Did your fsColorbar mean to be fs (or vice versa)? $\endgroup$ – John Joseph M. Carrasco Aug 13 '17 at 11:45
  • $\begingroup$ yes fs = fsColorbar. $\endgroup$ – Oscillon Aug 13 '17 at 12:08
  • $\begingroup$ @J.M. GraphicsColumn looks even worse. It crops more than half of the image for some reason $\endgroup$ – Oscillon Aug 13 '17 at 12:23
3
$\begingroup$

Increasing Image Resolution on Graphical Elements

I suspect the glitch is applying Rasterize to the Grid[___], as opposed to the graphical elements. i.e.

newPic=pic /. Graphics[a___] :> Rasterize[Graphics[a], ImageResolution -> 300]

yields

rasterized picture

Let's first verify this does something. (Sure, by eye there's a change, but there should, e.g. be increased FileSize in an exported png, bigger ByteCount in newPic, etc.).

ByteCount/@{pic,newPic}

yields

{89448, 150445080}

and

Export["/tmp/orig.png",pic,"png"];
Export["/tmp/new.png",newPic,"png"];
FileSize/@{"/tmp/orig.png","/tmp/new.png"}

yields:

{23429, 95835}

So we see that our newPic has more data.

Breaking it down

We apply the delayed replace rule: Graphics[a___]:>Rasterize[Graphics[a], ImageResolution->300] instead of rasterizing everything.

Looking at the man page for Rasterize[] we see that it indeed need not act on Graphics[] objects it can act on cells as you originally applied it. Yet doing so goofed your formatting. Since Grid[_] and Row were evidently formatting things to your liking, let's not modify anything that they do, but just increase the resolution of the interesting elements, and in this case all you really care about are the graphical elements.

We apply a delayed rule :> ( documentation ) because we want to match to data, then rasterize on that matched data. We don't want to literally raster the element a or something.

Graphics[data_,options_] can have multiple arguments, so we want to make sure we collect all of them, some of whom could be optional. The three underscores, a___, is BlankNullSequence, which grabs 0 or more options as available and sticks them all in the Sequence: a. Documentation here.

Working around the Tick Glitch

Rasterize messing with Ticks is evidently a known problem, see here.

The easiest workaround as far as I can tell is at the level of the plot generation so as to not aggravate the PDF import with the colorbar.

fixRasterize[expr_, res_] := 
  expr // ExportString[#, "PDF"] & // ImportString // First // 
   Rasterize[#, ImageResolution -> res] &;
plot1HR = 
  Row[{ArrayPlot[RandomReal[{0, 1}, {30, 30}], 
      ColorFunction -> "Rainbow", Evaluate[plotops2d]] // 
     fixRasterize[#, 300] &, 
    Show[colorbar[{0, 1}, {{0, 0}, {1, 1}}, fs, is, "Rainbow"], 
     ImageSize -> {Automatic, is}, 
     ImagePadding -> {{1, 42}, {63, 10}}]}];
plot2HR = 
  Row[{ArrayPlot[RandomReal[{0, 1}, {30, 30}], 
      ColorFunction -> "SunsetColors", Evaluate[plotops2d]] // 
     fixRasterize[#, 300] &, 
    Show[colorbar[{0, 1}, {{0, 0}, {1, 1}}, fs, is, "SunsetColors"], 
     ImageSize -> {Automatic, is}, 
     ImagePadding -> {{1, 42}, {63, 10}}]}];
picHR = Grid[{{plot1HR}, {plot2HR}}];
$\endgroup$
  • $\begingroup$ Fascinating, that seems to do the trick! Could you explain why that works in more detail? I assume since pic is a Grid of Row's of Graphics, any Graphics object is first rasterized before plugged in? I am not sure about the use of ___ accompanying :>. Why can this get to any Graphics object no matter the hierarchical position? Why does -> not work? $\endgroup$ – Oscillon Aug 13 '17 at 12:21
  • $\begingroup$ I'll edit my answer to provide a little more detail. $\endgroup$ – John Joseph M. Carrasco Aug 13 '17 at 12:26
  • $\begingroup$ While trying it out, I noticed, that the size of frame ticks decrease to the point that they vanish (for ImageResolution->300 but not for ImageResolution->100). Is there a way around that, too? $\endgroup$ – Oscillon Aug 13 '17 at 13:01
  • $\begingroup$ Modified answer to incorporate known Tick workarounds from e.g. here. $\endgroup$ – John Joseph M. Carrasco Aug 13 '17 at 13:47
  • 1
    $\begingroup$ To make it even more convoluted, once could prefix colorbar with Rasterize[#,ImageResolution->300]&@ to get also an HR version of that part :) $\endgroup$ – Oscillon Aug 13 '17 at 16:31

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.