Understanding CDF
Actually this is just meant as a side note to your own answer, but it became too long for a comment. As you can guess I'm interested in this myself and have done some testing, most of what I mentioned is from that experience. It has been reported that there would be differences in what the player would allow depending on whether Mathematica is installed or not. I don't believe that this is true, at least not by design, but as of now this is one of the things I have not explicitly checked..
I think some of the confusion about what can be done in a CDF format comes from the fact that one has to make a distinction between:
- CDF as a format
- restrictions of the Wolfram Player Pro (called Mathematica Player Pro for vs. 6 and 7)
- restrictions of the free CDF-Player
- restrictions of the browser plugin (full window mode)
- restrictions of the browser plugin (embedded cdf in html)
- restrictions of the pre version 8 Mathematica Reader
- restrictions of the demonstration site
and of course it doesn't help that some of the WRI documentation seems to not be very precise concerning these distinctions. The most relevant statement on restrictions seems to be this, from here
Can I use any Mathematica functionality that I want?
Yes. Almost all of Mathematica's computational functions can be incorporated into CDFs. However, in files saved straight out of Mathematica 8 for the free CDF Player, some functionality is not available: non-numeric input fields, dialog windows, and data import and export (except from Wolfram-curated data sources, e.g. ChemicalData, CountryData, and WordData). Please contact us about activating higher-level application content in CDFs.
To me it looks like the CDF format itself does not imply any restrictions, meaning that when you open a CDF document with a full version of Mathematica, it just behaves like a normal notebook (NB) file. The main difference seems to be a signature that is added to the CDF but not the NB files. I guess it is this signature that will be checked by the various players to see which restrictions are to be used when e.g. showing the dynamic content. While saving with Mathematica will create a signature that will only let the free CDF player use some functionality, it seems possible (but only by WRI) to create signatures that will allow the free CDF-Player to allow more or all (?) functionality. It is most probably this possibility that they are calling "activate higher-level application content in CDFs" or "CDFs with enhanced functionality". You would need to contact WRI to make use of that possibility, of course. This is a very different approach from using the Wolfram Player Pro, which already could show and play dynamic content within normal notebook files in earlier versions and of course can do so with CDF files as well. Unlike the CDF-Player, the Wolfram Player Pro will even allow shift-return-evaluations and import and export external files, including loading packages, which must be Encode
d, though.
I think you got the restrictions mostly sorted right by now in your own answer, except for some details:
Complex Functions
I think the restriction that only a very limited set of functions is allowed in dynamic content of a CDF document is only enforced for the CDF browser plugin, but the standalone free CDF Player will run dynamic content that makes use of almost every function. The CDF will then be shown with a warning header about potentially dangerous content but after explicitly enabling dynamics there the dynamic content will work alright. Unlike mentioned elsewhere I also don't think that the way how you create the CDF document will make a difference concerning these restrictions. It is the use of the CDF browser plugin for showing that document that makes a difference. If you deploy to be embedded in html the formatting of the CDF document will be slightly changed to something more condensed. But when opening the CDF document created that way with the standalone CDF Player, it behaves mostly like one that is deployed as "Standalone" or saved directly as CDF (except for the mentioned formatting).
Edit: I just learned that there is another distinction, since the browser plugin will behave differently when it is embedded in html or running in a "full screen" mode which will fill the full browser window. The difference is that in the latter it can show the docked cell to let the user allow "dynamic content for potential dangerous code" while it can't do so in the embedded mode. If the user allows dynamic content then some of the restrictions of the browser-plugin are released, but I think there will still be some more than with the standalone player. There is a workaround which allows for that docked cell to appear even in when the cdf is embedded in html, which was obviously uncovered here, but that might have problems with resizing (and probably other) and is not officially supported, so could even go away with future versions. In any case, the difference seems again not be within the CDF document but in by which program and how it is shown.
Manipulate
From all test I have done there seems to be no need to use a Manipulate
, despite the fact that this is mentioned in the WRI docs. It is just the most comfortable way to get the initialization of your dynamic content right, especially if the dynamic content depends on nontrivial functionality (that is many functions/symbols). Using the SaveDefinitions
option is much more convenient than putting all the function definitions in the Initialization
option of a DynamicModule
or Dynamic
by hand, and it is only available for Manipulate
, not e.g. DynamicModule
. Nevertheless, the following will make your first example work well in the (standalone) free CDF-Player, with no Manipulate
involved at all:
DynamicModule[{x = 0},
Panel[Column@{InputField[Dynamic@x, Number], Dynamic@func@x}],
Initialization :> (func[x_] := 100*x)
]
For most practical considerations I think you can think of SaveDefinitions
as an option that will create a correct Initialization
option for you by inspecting the code, trying to determine dependencies and save all definitions that the code depends to that Initialization
option. This can go wrong, and whether it works or not most probably doesn't have anything to do with what the CDF document or any of the ways to show such a document would allow to be run.
Needs
For the Needs
restriction I think the point is that it's not possible to read external files in the free CDF-Player from CDF-documents created from a normal Mathematica, and thus it's not possible to load an external package file in the free CDF-Player from such a CDF-document. I don't have seen any restrictions concerning anything related to the name spaces (Contexts
) so I think as long as you manage to get the initialization right (so that all dynamic content will work correctly) the symbols used can live in any namespace you want. It's just not that easy to achieve this, as has been discussed in e.g. this post (which I think you know about), and in some cases the SaveDefinition
option probably isn't getting things right, too.
I think it's worth repeating here that you will need to enclose all code ("function definitions") and all data that is used by the dynamic content in the CDF document for it to work in the free CDF Player or the browser plugin. Only when shown in Wolfram Player Pro or Mathematica, code and data could come in separate files as well.
Edit: I just learned that Import
will actually work for nonlocal url's, so it should be possible to load data from a public webserver with the CDF-Player and even the browser plugin, but probably not for every format that Mathematica supports. But it's definitely not supposed to be possible to load data from a local filesystem, neither in the standalone version nor the browser plugin.
Nontrivial Example
During my tests I was trying to get as far as I could in deploying an application in the free CDF player. The following is what I managed to do, some of it is still worth improving and the whole example is just a proof of concept, but I think it shows that one can do a lot more in the free CDF player than is obvious at first sight.
CurrentValue[EvaluationNotebook[], TaggingRules] = {
"Context" -> "cdfapp`",
"Code" -> Compress["
BeginPackage[\"cdfapp`\"];
run::usage=\"run[]\";
clear::usage=\"clear[]\";
Begin[\"`Private`\"];
run[]:=With[{cntxt=CurrentValue[ButtonNotebook[],{TaggingRules,\"Context\"}]},
Set@@Join[
ToExpression[cntxt<>\"content\",InputForm,Hold],
Hold[Manipulate[Plot[x^n,{x,0,1},PlotRange->{0,1}],
{n,1,100},AppearanceElements->None]]
]
];
clear[]:=With[{cntxt=CurrentValue[ButtonNotebook[],{TaggingRules,\"Context\"}]},
Unset@@ToExpression[cntxt<>\"content\",InputForm,Hold]
];
End[];
EndPackage[];
"
]
};
SetOptions[EvaluationNotebook[], DockedCells -> {
Cell[BoxData[ToBoxes[
Row[{
Button["Run",
ToExpression[
Uncompress[
CurrentValue[ButtonNotebook[], {TaggingRules, "Code"}]]];
Symbol["run"][], Method -> "Queued"
],
Button["Clear",
ToExpression[
Uncompress[
CurrentValue[ButtonNotebook[], {TaggingRules, "Code"}]]];
Symbol["clear"][], Method -> "Queued"
],
Spacer[30],
Button["Quit", FrontEnd`FrontEndToken["EvaluatorQuit"],
Evaluator -> None],
Spacer[30],
Button["Show Packed Code",
CreateDialog[
CurrentValue[ButtonNotebook[], {TaggingRules, "Code"}],
WindowSize -> {500, 500}], Method -> "Queued"],
Button["Show Clear Code",
CreateDialog[
Uncompress@
CurrentValue[ButtonNotebook[], {TaggingRules, "Code"}],
WindowSize -> {500, 500}], Method -> "Queued"]
}]
]], "DockedCell"]
}];
Dynamic[Replace[cdfapp`content, s_Symbol :> ""],
TrackedSymbols :> {cdfapp`content}]
To run this do the following: create a new CDF document in Mathematica, copy the above code to it and evaluate. It should add a docked cell to the document and an empty output cell. Delete everything except for the empty output cell and save it. Then open it with the free CDF player and try the buttons in the docked cells.
Disclaimer
As I said, much is just deduced from my experiments, some I learned from the CDF-Workshop and the documentation. Anyway I'm glad to hear about any corrections or improvements to these statements.
Updated: presentations are now available from the Wolfram CDF Virtual Workshop.
General info on the CDF format/creation/deployment:
- presentations of the CDF Virtual Workshop (4.24.2012)
- CDF FAQ
- download the CDF InfoKit
- Create a CDF File (Documentation Center)
1. Manipulate or DynamicModule?
Though it is often stated that the interactive content in a CDF must be Manipulate
-based, or must be generated with the Manipulate
command, this is not necessarily true. Thus one can create a DynamicModule
object:
In[1] := func[x_] := 123;
In[2] := DynamicModule[{x = 0}, Panel[Column@{InputField[Dynamic@x, Number], Dynamic@func@x}]]
but when the output cell is deployed, and the created CDF file is opened (in Mathematica or with the plugin in the browser), the result is this:
Apparently, the DynamicModule
is accepted by the CDF-deployer, but the external function is not recognized. This, according to Sjoerd's answer, can be solved by wrapping the internals (or the whole) of DynamicModule
in Manipulate
. Manipulate
, however, does not solve everything, see next section.
To conclude, it is definitely not true that only Manipulate
objects can be used in a deployed cdf. Looking at the source code of the examples of the CDF Info Kit, one can realize that rather complex dynamic interfeces can be constructed within the boundaries of the cdf-restrictions, that can be opened as fully functional documents with the Player.
It was explicitly stated by Yu-Sung Chang (CDF Workshop 2012) that Manipulate
, Dynamic
and DynamicModule
are allowed to be the backbone of a CDF. The major benefit of using Manipulate instead of DynamicModule is described next, and in Albert's answer.
2. Save definitions
First, there is no need to put every function that is external to the Manipulate
/DynamicModule
/Dynamic
output into the Manipulate
/... body. If they are in the same notebook when the output panel is deployed, and SaveDefinitions->True
is used, they are saved with the output correctly.
This works for even packaged function, while we are using full CDFs (i.e. non-free CDFs, to open with Mathematica or Player Pro), as this video demonstrates it.
The problem happens when one wants to deploy for the web or for the CDF Player. The following example demonstrates, that SaveDefinitions
does not grab all the definitions from the packages:
func[x_] := 123;
DynamicModule[{x = 0},
Manipulate[
Column@{Dynamic@func@x, myPackage`myFunc@"test"},
{dummy, None},
Initialization :> (Needs@"myPackage`"),
SaveDefinitions -> True]
]
where myPackage`
is a custom package. When the above code is deployed for the browser plugin, the result is this:
Thus func
is saved but not the packaged function myFunc
. The same thing happens if I remove the DynamicModule
wrapper, or move the Manipulate
to be the outer wrapper. It very much seems so that the free CDF version, deployed for the browser plugin or CDF Player, is not able to handle packaged functions, only the full CDF version, intended to open with Mathematica or with Player Pro.
One important point to mention here is the difference of the evaluation sequence of CDFs. While a normal notebook's evaluation sequence follows cell order, loading initialization cells before anything else, this is not the case for CDFs! Dynamic CDF content is evaluated when it is first displayed on screen (i.e. in order of display), in a preemptive method. Input cells, including initialization cells, will not be evaluated! "There is no guarantee that cells will be evaluated in order." (Yu-Sung Chang). It is wrong to assume that a following cell relying on the evaluation of a previous cell will be evaluated correctly, as their order of evaluation is not determined by cell order.
This prompts that all content for a CDF (if it is outside of the Manipulate
/DynamicModule
) should be in the same dynamic cell, where the actual dynamic content resides, to make sure they got evaluated together. Since no order of evaluation can be guaranteed, a Dynamic cell should not depend on any other cell! So instead of deploying
p = 10;
Dynamic[p]
where p = 10
won't be saved with the deployed dynamic output cell, use instead:
Dynamic[p, Initialization :> (p = 10)]
which explicitly saves the value of p
with the dynamic cell. Another way to ensure evaluation is to use SaveDefinitions -> True
, if one uses Manipulate
.
Also, it is stated here by the User Interface Group at WRI:
"
SaveDefinitions
can also be used for function definitions, although it doesn't always reach into packages correctly. Nonetheless, it often works well, and is used in Demonstrations by default."
meaning that it works well with standard packages, but not with user packages.
So SaveDefinitions
does not grab the packaged function for the free player, it only gets definitions correctly with Player Pro (or Mathematica). One solution is to use DynamicModule[{(* local variables *)}, (* dynamic content *), Initialization :> (* my code *)]
putting everyting under Initialization
, and live with the fact that a security warning will appear when deployed. An other hacky method exists though (Yu-Sung's trick), that can be used to load user packages in CDFs, during runtime, via ImportString
:
data = ImportString["myPackage.m", "Text"];
Manipulate[
(* dynamic content *),
{a, None},
Initialization :> (ImportString[a, "NB"])
]
3. Deploying the output only vs. the whole document
...
4. Differences between Mathematica Player, the browser plugin, and Mathematica Player Pro
Basically, there are two Players and two types of CDF files (as Albert has pointed out as well). The players are: the free CDF Player and the non-free Player Pro. The formats are: free CDF and licenced CDF. Any of Mathematica, CDF Player or Player Pro installs the web plugin as well:
"The free player installs the browser plug-in, as do all Mathematica-based products. The plug-in tends to be the lowest common denominator wrt to feature support."
(by André Kuzniarek, CDF Workshop 2012). These plugins can also be installed from the Mathematica preferences page or during installation. Also, the plugin is different from all other applications (CDF Player, Player Pro, Mathematica), as for it the strictest security concerns apply, and therefore it is sandboxed. It provides the most restricted (though most secure) environment. The browser plugin (at the moment) is not available under Linux.
Following detailes gathered mostly from here:
Mathematica Player (or CDF Player)
- Released just after V6 (pre V6 there was MathReader, a free static notebook viewer with no interactive elements and no evaluation capability)
- Static notebook viewer
- Free desktop runtime for viewing
Manipulate
-based interactive content (and supported the launch of the Demonstrations site) (note that it is not necessary to useManipulate
as the base, see above sections) - Required uploading of notebooks to Demonstrations site to be "playable"
- The CDF Player also installs a web plug-in:
- Full-screen mode
- Embeddable objects (as seen on the Demonstrations site)
- concerning licensing:
- Terms spelled out on website
- CDF usage is tied to Player licensing
- Free when content is free, licensing required when content is licensed
- Player displays logo in corner of embedded content, and terms language on toolbar for full page and desktop content
- Publisher level signing of CDF docs removes these "watermarks" for commercial content
Mathematica Player Pro (to open commercial/full CDFs)
- Same features as Player but allowing evaluation of inputs and higher level Mathematica functionality (data loading etc.)
- $200 app
- No need to upload notebooks, works with any notebook
- Commercial app deployment channel
5. Differences between free CDF and full CDF
I borrowed the terminology from Jens' post. Some differences are listed in the official guidelines here, indicating what you can not do in a free CDF:
- All interactive content must be generated with the
Manipulate
command and may only use mouse-driven elements, such asSlider
,Locator
,Checkbox
,PopupMenu
, etc.- Dialog windows are not supported.
- MathLink operations, including J/Link and .NET/Link, are not supported.
- Data import and export are not supported from within CDF Player with the exception of Wolfram-curated data sources (
ChemicalData
,CountryData
,WordData
, etc.).
More from the CDF Workshop:
Import
from public web sources is allowed- online Wolfram curated data is available
- local file operations are prohibited
- any *Link technology is disabled
- string
InputField
is not allowed - notebook related operations are not allowed
- no webcam (though there is a debate ATM, so it could change in the future)
- no parallel computation
- no GPU access
- no 3D hardware antialiasing
Though there are methods to partially overcome some of these. Some other restrictions I figured out:
- Free CDF does not work with
Initialization :> Needs["MyPackage`"]
calls. - Mostly all complex functions (more complex than
f[x_] := x + 2
) cause some kind of security issues causing the disabling of dynamic updating, see next section.
6. Security issues
The followings are small detailes gathered from the CDF Workshop. The security issue rises when a function is involved in the dynamic output:
- with definitions
- that changes attributes
- with options
- package related functions
ToExpression
/MakeExpression
Compress
/Uncompress
These are only issues in the CDF Player or in the browser plugin, as they have more strict restrictions on security. This kind of security issue is due to the fact that the location where the CDF lives, is not part of a default trusted path. John McLoone stated in the CDF Workshop that this issue wouldn't be an issue at all on a server, where the CDF would be opened from a safe location on the server, under the browser. He also stated that it is in development (or planned) to set up a trusting mechanism, where the user can set trusted paths and authors.
You can use SaveDefinitions->True
to do this. If you copy a Manipulate
box created with this option set to an empty notebook and save this as CDF, it will contain all necessary definitions to let it stand alone. The use of Manipulate
is a prerequisite for CDF deployments. More information here:
All interactive content must be generated with the Manipulate command and may only use mouse-driven elements, such as Slider, Locator, Checkbox, PopupMenu, etc.
However, Mike and you are right that the CDF plug-in seems to allow DynamicModule
contrary to claims in the documentation. Anyway, if you add a Manipulate
you will be able to use SaveDefinitions
and your code works in my browser.
DynamicModule[{x = 0},
Manipulate[
Panel[Column@{InputField[Dynamic@x, Number], Dynamic@func@x}],
SaveDefinitions -> True]]
I don't think a CDF doc used in a browser plug-in can read external packages. So, any definitions you rely on have to be in place before deployment. You therefore need to evaluate the code and deploy the resulting panel, not the code itself.