# Prevent graphics render inside held expression

Assuming each odd line is input I would like the even lines to be the output of the following lines.

In the above the Graphics are inside Hold/HoldForm therefore IMO it doesn't make sense to have Mathematica try and render such expressions. For example Hold[Graphics[{Red, Circle[]}]] throws an error because built in colors don't get replaced.

How might I prevent Graphics from being rendered and instead print the Graphics code?

The following code works at reassigning Graphics inside Hold/HoldForm, but it prints something like Graphics[{Circle[{0, 0}]}] without the HoldForm/Hold.

Unprotect[Graphics]
Graphics /: HoldForm[Graphics[x___]] := (
InputForm[Graphics[x]]
);
Graphics /: Hold[Graphics[x___]] := (
InputForm[Graphics[x]]
);

Ideally the code should be generalize to work with irregular constructs like HoldForm["a",Graphics[{Circle[{0, 0}]}]]. More importantly how might insure HoldComplete doesn't render Graphics either. As rm-rf pointed out the Villegas–Gayley trick will likely be needed.

EDIT: Generalizing to HoldComplete and simplifying John Fultz answer slightly, you get the following. I am in the process of trying to figure out how to generalize it to multiple variable HoldForm[a,Graphics..].

-
This is not exactly what you want but: ToString[#, InputForm] &@Graphics[{Red, Circle[]}] –  Kuba Sep 14 at 0:32
Also not exactly what you want, use graphics instead of Graphics and replace when it's time to render. –  ssch Sep 14 at 0:39
I don't think you're going to get anywhere by monkeying with Graphics. As I see it, solving your problem requires changing the way the fonte end's output printer works. I don't have a clue on to do that. –  m_goldberg Sep 14 at 1:50
@m_goldberg you are right. At this point I am just trying to prevent the rendering of Graphics, which I have already partly done with MakeBoxes. Other ideas are certainly welcome. –  Liam William Sep 14 at 1:57
Possibly related: Making customized InputForm and ShortInputForm. –  Alexey Popkov Sep 15 at 1:36

Recall that the rendering of Graphics has nothing to do with evaluation. It is done entirely in typesetting. And therefore, a robust solution will treat this as a problem of typesetting, and not as a problem of evaluation.

Once you frame the problem properly, the solution is fairly straightforward. What you want to do is to change the typesetting of Hold (and friends). Take a look at this:

Unprotect[Hold];
Hold /: MakeBoxes[Hold[expr_], fmt : StandardForm | TraditionalForm] :=
Block[{Graphics, Graphics3D}, Unprotect[Graphics, Graphics3D];
Clear[Graphics, Graphics3D];
RowBox[{"Hold", "[", MakeBoxes[expr, fmt], "]"}]]
Protect[Hold]

Fortunately, Hold (and HoldForm and HoldComplete) has no typesetting rules directly attached to it that you're fighting, which you can determine using FormatValues[Hold]. But Graphics and Graphics3D do; it's how typesetting of graphics works at all. We want to suppress those rules, but only within the typesetting of Hold. So we use Block to contain the damage we're about to do to the Graphics and Graphics3D symbols, and then use Clear to clear them. From there on out, we let MakeBoxes do what it would normally do.

Note that this example cheats a bit; it only works if you pass one argument to Hold. I did that for purpose of code simplicity and illustration. To make the formatting rules work properly for Hold[expr___], I would have to write multiple and more sophisticated rules, or I would have to use the Villegas-Gayley trick.

Edit: As came up in the comment discussion, it really isn't necessary to Unprotect and Clear the symbols Graphics and Graphics3D, as Block is effectively doing that already. I've considered editing the code to make it shorter/simpler, but perhaps the existing code is clearer for people who don't fully understand how Block works (and, public confession here, while I understand Block scoping, I had just plumb forgotten how Block initializes variables, so this more an oversight on my part than a planned teaching moment).

-
Nice explanation and solution,+1. It is not clear to me however, why Unprotect and Clear are needed, since Block automatically clears all symbol's definitions and attributes (in contrast to InternalInheritedBlock). –  Leonid Shifrin Sep 14 at 13:34
@LeonidShifrin I think it was simply John Fultz kind attempt to make it clearer to what is exactly going on. They way it is currently written makes perfect sense(at least to me). Additionally if I don't understand the differences between With,Module, and Block/InternalInheritedBlock. How do you prevent evaluation of a function? Well by Removing and Clearing it of course. –  Liam William Sep 14 at 14:55
Actually, believe it or not, there are limits to my knowledge of Mathematica, and for some reason, it didn't occur to me to see if Block would automatically clear a Protected System symbol. I appreciate @Liam reading the benefit of hidden wisdom into my answer, though! :) And, in fact, that response gives me pause about editing the answer to shorten the code. –  John Fultz Sep 14 at 16:36

This is not an answer but an extended comment.

This occurs because although the front end attempts to render the Graphics element the internal code won't replace Directives inside of a Held expression.

This is not the case. Consider

Hold[Graphics[{RGBColor[1, 0, 0], Thick, Circle[]}]]

and

With[{red = Red}, Hold[Graphics[{red, Circle[]}]]]

So the error message comes from using the built-in symbol Red and not from the front end doing anything funny with directives.

-
Is Color Directives more appropriate then? Seems to be an issue for all colors. –  Liam William Sep 14 at 1:59
@Liam. RGBColor[1, 0, 0] is a color directive; Red,Green, Blue, etc. are not. –  m_goldberg Sep 14 at 2:02
That's fair although I find it odd that the colors are listed under guide/GraphicsDirectives Graphics Directives in the docs. Would simply colors be an appropriate name? –  Liam William Sep 14 at 2:04
@Liam. I regard that to be an error in the docs. They are symbols that evaluate to graphic directives, but of course not inside Hold. –  m_goldberg Sep 14 at 2:08
@Liam. You might well ask "Why then does Thick work?" I wonder about that myself. –  m_goldberg Sep 14 at 2:12
show 1 more comment