12
$\begingroup$

Is there a way to construct an interface so that the Code and the Graphics remain in sync? For example I would like to be able to drag/drop and move around different shapes in Graphic while seeing the code change. Then I would like to edit the code so the graphic changes.

Updated image to clarify interface

enter image description here

I'm aware that you can see the graphics source by hitting Ctrl+Shift+E, but this isn't ideal because the graphics source code is often in the displayform and much more verbose. Additionally it doesn't allow me to see how the code changes while I am editing the code. I'm working on some code that uses dynamic currently, but I'm not sure of the right technique just yet.

EDIT: Both the InputField and the Graphics should be live and editable. The problem currently is that the the Graphics elements can't seem to be Dynamic. If you set it as Dynamic it is impossible to re size and move the elements around.

$\endgroup$
3
  • $\begingroup$ Have you tried to use Manipulate[]? $\endgroup$
    – Rod
    Commented Jul 4, 2013 at 12:06
  • $\begingroup$ @RodLm Yes I have tried using Manipulate. I have updated the question to try and make it more clear. Thanks $\endgroup$
    – William
    Commented Jul 4, 2013 at 14:55
  • $\begingroup$ Just as a comment, pt={0,0};Graphics@Circle@Dynamic@pt will update pt as you move the circle. If all you want are edits, it could be handled this way. But it won't work if you plan to add new shapes with the drawing tools. It would require more work $\endgroup$
    – Rojo
    Commented Jul 4, 2013 at 22:26

4 Answers 4

15
$\begingroup$

Here's a V9 solution (CellObject is new in V9). The output is two cells, one with graphics to be edited and another that contains an InputField. The connection between them is maintained by identifying the graphics cell by the tag CellTags -> "DrawOnMe", which needs to be unique, and by the V9 feature CurrentValue[cellobj, CellChangeTimes]. By putting this inside the Dynamic passed to InputField, variable gr is updated whenever the CellChangeTimes changes in the graphics cell. Reciprocally, whenever the InputField is edited, the graphics cell is regenerated with the new input.

gr = Graphics[{}];
CellPrint@ExpressionCell[gr, CellTags -> "DrawOnMe"];
cellobj = First@Cells[EvaluationNotebook[], CellTags -> "DrawOnMe"];
InputField[
 Dynamic[CurrentValue[cellobj, CellChangeTimes]; 
  InputForm@(gr = ToExpression[First@NotebookRead[cellobj], StandardForm]),
  (gr = #;
   NotebookWrite[cellobj, Cell[BoxData@MakeBoxes[#, StandardForm], CellTags -> "DrawOnMe"]];
   cellobj = First@Cells[EvaluationNotebook[], CellTags -> "DrawOnMe"]) &]
 ]

Note that the front end seems to do some optimizing or processing of graphics code, so that the input form of gr won't necessarily be the same as what you type in.

The only pre V9 solution I can come up with is halirutan's.

$\endgroup$
2
  • $\begingroup$ This is a nice one. I assume you fiddled around for some time. A big +1 $\endgroup$
    – halirutan
    Commented Jul 4, 2013 at 22:55
  • $\begingroup$ This is really cool - and educational too, for learning about the structure of graphics. $\endgroup$
    – cormullion
    Commented Jul 5, 2013 at 6:43
7
$\begingroup$

The hard part is the

drag/drop and move around different shapes in Graphic

Let's assume you want to drag a circle, then I would use a Locator with Appearance->None as center of the circle so that when you click and drag near the center you can move the circle around.

Another example would be a triangle where you can drag the corners. In this example I used 3 locators and drew a gray Polygon. To display the code is pretty straight forward: Just use InputForm and what you will see is not the graphic but the code. Don't forget Dynamic on things that change and you are done.

Mathematica graphics

And the code for this is

DynamicModule[{pt = {{1, 1}/2, {-1, 1}/2, {1, -1}/2}, gr},
 gr[pts_] := 
  Graphics[{Gray, Polygon[pts]}, PlotRange -> {{-2, 2}, {-2, 2}}];
 Column[
  {LocatorPane[Dynamic[pt], Dynamic@gr[pt], Appearance -> None],
   Dynamic[InputForm[gr[pt]]]}]
]

Update

Not quite what you ask for since it is not fully dynamic, but a start. Open a notebook and evaluate the following:

nb = SelectedNotebook[];
Graphics[{Rectangle[]}, PlotRange -> {{-5, 5}, {-5, 5}}, 
 Frame -> True, FrameTicks -> False]

This stores the current notebook in nb and gives you a graphics to draw in. In a second notebook you execute

Button["Gime da codes",
 SelectionMove[nb, All, Cell];
 grCode = NotebookRead[nb];
 ]
Dynamic[InputForm @@ MakeExpression[First[grCode]]]

Now use the Drawing Tools and change whatever you like in the graphics and as when you press the button you get the updated graphics code. This only works, when you have selected the graphics (which you usually have, when you draw in it).

$\endgroup$
6
  • $\begingroup$ @hailrutan I was looking to have both the text and the graphics editable and updatable live. I don't see how this is is different then just outputting a Graphics object and edit the shapes using that interface, while outputting the text is some way. $\endgroup$
    – William
    Commented Jul 4, 2013 at 14:04
  • $\begingroup$ @hailrutan I have updated question with a newer picture and longer explanation to try and make the question more clear. $\endgroup$
    – William
    Commented Jul 4, 2013 at 14:56
  • $\begingroup$ @Liam What was missing in your question is that you want to edit the graphics using the Drawing Tools. Unfortunately, the most direct way, which is to wrap Dynamic around a graphics makes, that the drawing tools are not working anymore. $\endgroup$
    – halirutan
    Commented Jul 4, 2013 at 14:56
  • $\begingroup$ is there some way to latch onto an onchange event or something? $\endgroup$
    – William
    Commented Jul 4, 2013 at 15:00
  • $\begingroup$ @Liam I updated the post, to give you a start. $\endgroup$
    – halirutan
    Commented Jul 4, 2013 at 18:04
0
$\begingroup$

I am still working on the code, but I have found the following solution to work the best in M8 because M8 doesn't have the Cells function. I had to use Quiet in several places to do bugs in Mathematica's internal code.

enter image description here

GetCode[] := 
  Cell[BoxData[
    StyleBox[
     DynamicBox[
      ToBoxes[Refresh[
        InputForm @@ 
         MakeExpression@
          First@First@
            Quiet[Cases[NotebookGet[EvaluationNotebook[]][[1]], 
              Cell[___, CellTags -> "MyGraphic", ___], Infinity]], 
        UpdateInterval -> 1], StandardForm]], StripOnInput -> False, 
     LineColor -> GrayLevel[0.5], FrontFaceColor -> GrayLevel[0.5], 
     BackFaceColor -> GrayLevel[0.5], GraphicsColor -> GrayLevel[0.5],
      FontColor -> GrayLevel[0.5]]], "Output", CellTags -> "MyCode"];

DynamicQ[] :=
  (Length@
     Cases[Quiet[
       Cases[NotebookGet[EvaluationNotebook[]][[1]], 
        Cell[___, CellTags -> "MyCode", ___], Infinity], 
       First::first], DynamicBox[___], Infinity] == 1);

CellPrint@
  Cell[BoxData[
    ToBoxes[Graphics[{Circle[]}, ImageSize -> {100, Automatic}]]], 
   "Output", CellTags -> "MyGraphic"];

Print[Button["Diable/Enable Dynamic", If[DynamicQ[],
      NotebookLocate["MyGraphic"];
      code = 
       InputForm @@ 
        MakeExpression@NotebookRead[EvaluationNotebook[]][[1, 1]];
      NotebookLocate["MyCode"];
      NotebookWrite[EvaluationNotebook[], 
       Cell[BoxData[ToBoxes[code]], "Input", CellTags -> "MyCode"]];
      , NotebookLocate["MyCode"];
      Quiet[NotebookWrite[EvaluationNotebook[], GetCode[]]];];

    ] Button["Update Graphics",
    NotebookLocate["MyCode"];
    code = NotebookRead[EvaluationNotebook[]][[1, 1]];
    NotebookLocate["MyGraphic"];
    NotebookWrite[EvaluationNotebook[], Cell[BoxData[ToBoxes@
        ToExpression[code]
       ], "Input", CellTags -> "MyGraphic"]
     ];]];

CellPrint@GetCode[];

Older Revisions:1st 2nd 3rd 3.1

$\endgroup$
0
$\begingroup$

I don't know if this qualifies as an answer, but I think that trying to keep code and graphics in sync is a poor objective. The routine written by Michael E2 is pretty fantastic. But suppose you want to include generated curves? I was able to use the Presentations Draw statement and that worked, but the problem is that the items in the "code" InputField get evaluated so one ends up with long lists of points. This is not convenient code to work with.

Almost every graphic or presentation project is unique. It depends crucially on the content of the data or the concept that one is trying to illustrate. The important questions are scientific or technical - one or a number of graphics? how to meld graphics with textual discussion? graph or table? serial presentation or complicated dynamic? Each graphic or dynamic should have a written specification in clear form so it could be modified by editing in the future. It's really a work of art and there are not a lot of shortcuts. (That's why Drawing Tools is not too great for finished work; it's more for temporary sketches.)

But, since most of us have programming backgrounds, such projects often slither over into computer science programming projects, trying to find a new generalized interface for all graphics. I've stumbled into this myself - to my regret. I was once contacted by someone who was producing a calculus text for a university and he wanted a single graphical statement, with 40 or 50 arguments, that could be used to produce EACH of the graphics that would be in the book. Couldn't convince him otherwise and don't know how it worked out.

My advice is that only if you have made a fair number of graphics or dynamics using detailed specification and they have a limited domain and range, which you have become quite familiar with, and you're going to make many more in the future, then consider programming specialized input forms for it.

The advantage of a dynamic display of code (especially not very readable code!) and graphics over simply editing and reevaluating a specification is not very great.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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