Mathematica: Changing the options of a Graphics object - wolfram-mathematica

Is it possible to change the options of a Graphics object? Say you are working with a graphics object G2D as in the following picture
You can see from the InputForm of G2D that the PlotRange option is set to {{-0.025,1.025},{0,1.05}}. But later on on the code I decided to change the PlotRange option to a different one. What happens with the InputForm? The new option simply gets appended.
You can obtain the options set by a graphics object by using Options and AbsoluteOptions but I haven't found a way to change those options. The function SetOptions seemed like a likely candidate but it turns out that
this function only works with streams and functions. That is, it only allows to set the default behavior as they show in the examples.

If you want to clean up the set of options in the graphic, it's probably easiest to just construct the graphic anew. You can extract the main body of the graphic with First, and use DeleteDuplicates and Options to get the simplified list of options:
old = Graphics[{Blue, Disk[]}];
old = Show[old, ImageSize -> 1000];
old = Show[old, ImageSize -> 500];
old = Show[old, ImageSize -> 250];
old = Show[old, ImageSize -> 100]
InputForm[old]
new = Graphics[First[old],
DeleteDuplicates[Options[old], First[#] === First[#2] &]]
InputForm[new]
I've used Options because the options to Graphics can be, but aren't always, enclosed in a list, and Options will standardize the form.
I'd also like to point out that technically Show is prepending the option values, so the duplicated options aren't really harming anything, although they can make it harder to debug graphics output and slightly increase the size of the file.
You can also use SetOptions to change the default value for all graphics:
SetOptions[Graphics, Background -> Gray];
Graphics[Disk[]]

Related

Controlling the Rasterize[] width for notebook-related expressions

Update Mr Wizard's answer gives pixel-perfect results, but it is Windows-only and destroys the clipboard contents. My answer should work on any platform, but it's less precise: e.g. it omits In/Out labels. It does allow setting the rasterization width though.
This problem came up when I was trying to make a preview window for an image uploader (see the end of that answer).
I would like to create a palette button that will upload the current notebook selection as an image. Before uploading, I would like to show a preview of the image, to reduce the chance of something going awry before contacting the server.
This is what I have so far (includes only the preview code, not the uploader):
button = Button[
"Preview",
Module[
{expr = NotebookRead#InputNotebook[]},
If[expr =!= {},
With[{img = Rasterize[expr]},
MessageDialog[
Column[{"Would you like to perform the action?", img}],
{"Do it!" :> doIt[img], "Cancel" :> Null}
]
]
]
]
]
In case you are wondering why I used a nested With inside the Module instead of making img a module-variable too: it's because by the time doIt[img] is evaluated, the local module variables will have been cleared, so I need to substitute the rasterized expression directly into the doIt function,
This button works (more or less). You can try it by creating a graphic in the same notebook (e.g. Graphics[Circle[]]), selecting it using a single click, then clicking the Preview button.
However, if I put it in a palette using CreatePalette[button], then the rasterization will happen for the window-width of the palette, and I get something like this:
How can I control the width of rasterization, or more generally, how can I create a preview dialog for the uploader that avoids this issue?
For an additional improvement, it would be nice to be able to size the message window so it fits the preview image (and still shows the button: the button disappears with WindowSize -> All).
Answers
Mr. Wizard's suggestion:
button = Button[
"Preview", (FrontEndExecute[
FrontEndToken[FrontEnd`SelectedNotebook[], "CopySpecial", "MGF"]];
MessageDialog[
First#Cases[NotebookGet#ClipboardNotebook[],
RasterBox[data_, ___] :>
Image[data, "Byte", ColorSpace -> "RGB", Magnification -> 1],
Infinity]])]
CreatePalette[button]
Problems: It (probably) only works on Windows, and it destroys the clipboard contents.
If it is practical to use the clipboard in this operation you might use: FrontEnd`CopySpecial["MGF"] (copy as bitmap).
I managed to do this by copying the selection to a new notebook, rasterizing the full notebook, then closing it.
CreatePalette#Button["Preview",
Module[{target},
target =
CreateDocument[{}, WindowSelected -> False, Visible -> False];
NotebookWrite[target, NotebookRead[SelectedNotebook[]]];
CreateDialog[{Rasterize[target], DefaultButton[]}];
NotebookClose[target]
]
]
The WindowSize -> 500 option can be added to CreateDocument to set the rasterization width to 500 pixels.
Note some disadvantages (advantages in some cases) of this method compared to copying as bitmap:
Custom styles are lost
In/Out labels are lost
Notebook magnification value is lost
If there's a need, some of these can be remedied by explicitly transferring some notebook options from the SelectedNotebook to the newly created one.
I think this should work without you needing to make a new notebook:
button = Button["Preview",
Module[{expr = NotebookRead#InputNotebook[]},
If[expr =!= {},
With[{img =
Rasterize[expr,
ImageFormattingWidth ->
First#(WindowSize /.
AbsoluteOptions[InputNotebook[], WindowSize])]},
MessageDialog[
Column[{"Would you like to perform the action?",
img}], {"Do it!" :> doIt[img], "Cancel" :> Null},
WindowSize -> {First#ImageDimensions#img, All}]]]]];
CreateDialog[button,
WindowFloating -> True,
WindowClickSelect -> False,
Selectable -> False
]
I used a little option searcher to find ImageFormattingWidth and by passing the image width as the window width you can make the dialog fit the picture nicely and still display the button.
Here's a demo of its results:
Rasterizing a cell from a pallete
Have you tried using ExportString[] to create the graphic into memory? (technically into a temp file, but what do you care:] )
ExportString[your_mathematica_stuff_here,"PNG",Background->None]
See the output on a colored background to verify transparent BG:
Framed[ImportString[ExportString[x^2,"PNG",Background->None]
,"PNG"]
,Background->Yellow]
For images with many color variations (like 3D plots), I recommend JPEG2000 format, and for solid-colored images where transparency is not necessary, use GIF to preserve color detail.
Yes, you can control ImageSize when you export string of the image.

Separate "hand-drawn" objects in Mathematica

What is the simplest / most convenient way to separate hand-drawn objects in Mathematica from programmatically generated ones?
The interactive drawing tools are convenient and useful. But if I draw something on top of the plot, it will get lost as soon as the plot is re-generated. Is there a convenient solution for this?
I could make the drawing on top of an empty plot, them combine them with the actual plot. But this is again inconvenient as I need to manually set the plot range of the empty plot and I don't see the background on top of which I'm adding the annotations.
One approach, using an annotation to flag the generated content:
Plot[Annotation[Sin[x], "GeneratedPrimitives"], {x, 0, 10}]
RecoverDrawing[g_Graphics] := g /. Annotation[_, "GeneratedPrimitives"] :> {}
RecoverDrawing[<modified graphic>]
Unfortunately, the best thing I can think of is writing a program using ClickPane or EventHandler which not only draws bu records the points being added to the image. A modification of code like:
DynamicModule[{pts = {}},
ClickPane[Dynamic[Framed#Graphics[Line[pts], PlotRange -> 1]],
AppendTo[pts, #] &]]

Programmatically radius image

Currently our website department have a process where they manually radius the corners of each images to +4% to create "nicer" looking images for the web.
They currently do this using the radius function of Serif Photoplus, I was hoping people could think of a way to do this programmatically to a whole folder of images ideally using open source or free tools.
I'm aware we could do the radiusing with CSS, but I have yet to be convinced that there is an easy way to do this that is effective across all browsers and legacy browsers although I'm open to options in regard to this.
I think ImageMagick would be the right tool for the job.
This thread explains how to make rounded corners on images. It seems there are many ways to do this, this is why I listed no particular solution here. ImageMagick also has a batch function, with that you can apply the corner rounding to all the images in a directory.
ImageMagick is distributed under the Apache 2.0 license, so you can use it freely for commercial purposes.
You could do it by hand, creating a mask and then adding the images.
Example in Mathematica:
id = ImageDimensions;
ImageAdd[#,
Rasterize[
Graphics[Rectangle[{0, 0}, id##, RoundingRadius -> Max#id##/25],
PlotRange -> Transpose#{{0, 0}, id##}],
ImageSize -> id##]] &#
Import#"http://tutor-atlanta.com/wp-content/uploads/2010/11/test2.jpg"

Exporting a row of graphics objects broken in MMA8

How do you make Mathematica export a Row of graphics. I do not like how GraphicsRow handles the graphics, all the aspect ratios and paddings in the figures get messed up. What I like to do is work with each individual figure and then use a simple Row,Column or Grid to combine my figures. Take the following for instance:
g1 = Plot[Sin[x], {x, -Pi, Pi},
Frame -> True, FrameLabel -> {"x", "y"}, ImageSize -> 2.6*72
]
This creates the Sin plot. What I want to do now is create the following Figure:
Fig = Row[{g1, g1, g1}]
Then you can use Export
Export["TestFig.pdf", Fig]
This is the pdf I obtain in MMA8:
I just tried this code in MMA7 and it works fine. It had been a while since I wanted to create this type of figures and I never bothered to check if it worked in MMA8. Does any one have a fix for this in MMA8?
The desired output is the one I obtained in MMA7:
It is worth bearing in mind that GraphicsGrid assumes equal-width columns so using Grid is sometimes more useful. The same syntax as in belisarius' answer applies. It might be worth exploring the ImageSize option to Export (see documentation and tutorial).
Also, note the exporting in PDF format uses the PrintingStyleEnvironment, which is not how things look on screen. You might get better results if you change your page setup in Printing Settings.
Export["c:\\TestFig.pdf", GraphicsGrid[{{g1, g1, g1}}]]

Tweaking style/attributes of existing Graphics objects in Mathematica

One of Mathematica's strengths is its consistent underlying representation of objects. Thus, to change attributes of a plot without redoing the computation used to generate it, I could do something like
Replace[myplot, {Graphics[x_List, y_List] :>
Graphics[x,Flatten[{y,
BaseStyle -> {FontFamily -> Helvetica, FontSize -> 20}}]]}]
Unfortunately, every time I want to use this approach to modify a plot in order to change the style/color of lines, points, fonts, etc. I have to figure out what the appropriate replacement rule is by trial and error, which negates any efficiency gained by not having to recompute the plotted data. Here's another example:
myplot = Plot[{Cos[x], Sin[x]}, {x, 0, 2 Pi},
PlotStyle -> {{Red, Dashing[None]}, {Green, Dashing[None]}}]
myplot /. { {x___, PatternSequence[Red, Dashing[_]], y___}
-> {x, Green, Thickness[.02], Dashing[Tiny], y},
{x___, Green, y___}
-> {x, Thickness[Large], Red, y} }
This gets the job done (changes line color/dashing/thickness), but seems voodoo-ish.
Is there any documentation (guides or tutorials) -- short of poring over the exact specifications for Graphics objects and primitives -- that could guide me in constructing the appropriate replacements?.. If not, are there better ways of tweaking the appearance of plots without recomputing (other than saving data in a variable and using ListPlot)?
I await more examples of your desired manipulations, but for now I'll point out that it may be possible to do a class of them without replacements at all. Forced to merely guess at what you want, one interpretation follows.
myplot = Plot[{Sin[x], Csc[x]}, {x, 1, 10}];
Replace[myplot, {Graphics[x_List, y_List] :>
Graphics[x,
Flatten[{y,
BaseStyle -> {FontFamily -> "Helvetica", FontSize -> 20}}]]}]
Show[myplot, BaseStyle -> {FontFamily -> "Helvetica", FontSize -> 20}]
As you can see, in this case Replace is not needed.
Addressing your updated question, there are two different categories of graphical objects in a Plot output.
The plotted lines of the functions (Sin[x], Cos[x]) and their styles are "hard coded" into Line objects, which Graphics can understand.
Auxiliary settings such as Axes -> True, PlotLabel -> "Sine Cosecant Plot" and AxesStyle -> Orange are understood by Graphics directly, without conversion, and therefore remain within the myplot object.
The second kind of settings can be easily changed after the fact because they are soft settings.
The first kind much be processed in some way. This is complicated by the fact that different *Plot functions output different patterns of Graphics and Plot itself may give different patterns of output depending on the input it is given.
I am not aware of any global way to restyle all plot types, and if you do such restyling often, it probably makes more sense to retain the data that is required and simply regenerate the graphic with Plot. Nevertheless, for basic uses, your method can be improved. Each function plotted creates a Line object, in the given order. Therefore, you can use something like this to completely restyle a plot:
myplot = Plot[{Cos[x], Sin[x]}, {x, 0, 2 Pi},
PlotStyle -> {{Red, Dashing[None]}, {Green, Dashing[None]}}]
newstyles = Directive ###
{{Green, Thickness[.02], Dashing[Tiny]},
{Thickness[Large], Red}};
i = 1;
MapAt[# /. {__, l : Line[__]} :> {newstyles[[i++]], l} &, myplot, {1, 1}]
Please note the part in bold-italic in the last line of code above. This is the part specification for the location of the Line objects within myplot, and it may change. Usually this will work as is, but if you find that you must change this often, a function to detect its position should be possible (ask if needed).
Graphics Inspector
telefunkenvf14's comment reminded me that I was negligent to not mention the Graphics Inspector.
While I personally tend to avoid extensive after-Plot restyling, because I like to keep everything on one place (the Plot command), and I prefer to make what changes I do with code, so that there is a record of my settings without having to dig into the Graphics object, the Graphics Inspector is directly applicable.
Double click the plot. The border should change from orange to thick gray.
Single click one of the plot lines. (the pointed should change when you hover over an element)
Press Ctrl+g to open the Graphics Inspector.
Make the changes you desire, and close the Graphics Inspector.
You can now copy and paste the entire graphic, or directly assign it to a symbol: p = <graphic>
Also, see: http://www.wolfram.com/broadcast/screencasts/howtoeditmathematicagraphics/
I sometimes find it useful to replace the entire rule/option, rather than just the RHS of the rule. For instance, something like this, based on your example:
myplot /. (PlotStyle -> x__) -> (PlotStyle -> myRestyle[x]);
I also like that this avoids the problem of appending duplicates of the option.
This is handy for restyling other objects, such as:
styledText /. (FontSize->x_) -> (FontSize->2x)

Resources