Mixing iTorch and gfx server for plotting with Torch
While working with torch, I often has issues to get interactive plots. I found torch Gnuplot`s wrappers a bit restrictive. Thus, I looked for other frameworks
On the one hand, iTorch provides user-friendly and nice plotting abilities. It is based on the bokeh library. One may draw a nice plot in a single line:
1 |
local plot = Plot():histogram(torch.randn(10000):draw()) |
Yet, you need to use iTorch ebook to interactively plot your figures. Otherwise, you need to save the plot into a html file and refresh your browser. That is quite a pain.
On the other hand, there is the gfx project made by Clement Faraber. One may run a server that is going to display figures on a browser. Plots are stored in a repository and the server update a webpage upon creation/modification of files in this repository. That works pretty well! The API wraps some figures from nvd3 library. Yet , I thought that bokeh libraries were a bit better and easier to use.
So, should I use iTorch or gfx? Well, let take the best of the two worlds.
Ou goal is to get something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
gfx = require 'gfx.js' Plot = require 'itorch.Plot' -- use iTorch features x1=torch.randn(10) y1=torch.randn(10) plot = Plot() plot:quad(x1,y1,x1+1,y1+1,'red','') plot:gfx() -- use gfx features gfx.image(image.lena()) gfx.chart(torch.randn(100), {chart='line'}) |
That will render something like that
First of all, you need to modify the following file: ~/.gfx.js/static
Add the following line
1 2 |
<script type="text/javascript" src="http://cdn.pydata.org/bokeh-0.7.0.js"></script> <link rel="stylesheet" href="http://cdn.pydata.org/bokeh-0.7.0.min.css" type="text/css" /> |
The goal is to load the bokeh javascript/css in your HTML page.
I am not a big fan of forking projects, therefore, I neither modify the iTorch code nor gfx code. In addition, I avoid copy/past as much as possible. Therefore I ended with a working but a bit crappy solution. That modify the settalble of Plot. It also parsed the xml twice, but it does the job.
One may choose to modify the iTorch html template (That is a far cleaner solution), but again, I dislike forking projects…
The code can be downloaded there:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
function appendGfxToPlot(gfx, Plot) -- Load the xml parser to modify the xml require("LuaXML") if xml == nil then xml = require("LuaXML") end -- Append Non-ASCII-127 char decoding/encoding xml.registerCode('&quot;', '"') xml.registerCode('&apos;', "'") xml.registerCode('&amp;' , "&") xml.registerCode('&lt;' , "<") xml.registerCode('&gt;' , ">") -- Simulate the uid method from gfx to fit the gfx format local function uid() return 'dom_' .. (os.time() .. math.random()):gsub('%.','') end -- append a new method gfx to the Plot metatable Plot["gfx"] = function(self) -- compute the gtx id of the plot local idGfx = uid() local gfxFile = gfx.static .. idGfx .. ".html" -- compute the iTorch HTML local html = self:toHTML() local txml = xml.eval(html) --Copy the script node into a new object that has the core functions local script = xml.new("script") script["type"] = "text/javascript" -- This is crapy --> look for something better but xmllua sucks for _, node in pairs(txml:find("meta")) do if node.TAG ~= nil then -- the script node is the core function is the only node that is not empty if node[node.TAG] == "script" and node[1] ~= nil then -- copy the script data script[1] = node[1] break end end end --Look for the single div of the file that contains the plot features local iTorchDiv = txml:find("div") iTorchDiv["style"] = "background:#fff" -- fit gtx colours --Create a new div to fit Gfx requirement local divGfx = xml.new("div") divGfx["id"] = idGfx divGfx:append(iTorchDiv) -- Append the script and the div to a new file -- NB : gtx requires no encapsulating tag local f = io.open(gfxFile, "w") f:write(divGfx:str()) f:write(script:str()) f:close() print("[gfx.js] rendering cell <" .. idGfx .. ">") end end |
Thanks for the hack. Question. You mention to add two lines in ~/gfx.js/static. But it is a directory and there are multiple files and folders in there. Could you please let me know in which file I need to add these two lines..
Sorry for the earlier comment, just was that you mention HTML page..