Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)?

like image 544
Leo Alekseyev Avatar asked Apr 13 '11 05:04

Leo Alekseyev


1 Answers

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.

  1. The plotted lines of the functions (Sin[x], Cos[x]) and their styles are "hard coded" into Line objects, which Graphics can understand.

  2. 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}]

enter image description here

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/

like image 66
Mr.Wizard Avatar answered Sep 20 '22 01:09

Mr.Wizard