Repository: josdejong/mathjs
Pull request #531 (2016-01-04 18:31:26)

ObjectNode: prettier LaTeX output
This is my current approach, tell me if I should change something.

Example:
![latex](https://cloud.githubusercontent.com/assets/4294942/12096902/e0c49652-b318-11e5-9f65-5190986b63d0.png)

josdejong: Cool, smart idea to use a matrix for this. 

I experimented a bit further with your idea. I think it looks nicer when the key and value are on the same row:

![image](https://cloud.githubusercontent.com/assets/568626/12100801/80dfd210-b331-11e5-9016-65ffdb2cd22c.png)

or maybe without closing bracket, and with keys/values in a single cell:

![image](https://cloud.githubusercontent.com/assets/568626/12100882/0a813752-b332-11e5-9e77-7b1b38db468a.png)

Still, I think it becomes messy when you have larger objects with deep nesting, but that may not be a big problem in practice.
josdejong: I also tried a more "traditional" solution, see this fiddle: http://jsfiddle.net/emqchL0a/3/, but I didn't yet manage to position the matrix cells top left.
josdejong: Hey, we could also use `\begin{cases} ... \end{cases}` ([see example](http://timmurphy.org/2011/12/12/math-case-definitions-in-latex/)) instead of matrix, that way we can left align the keys and values:

![image](https://cloud.githubusercontent.com/assets/568626/12101342/6ef2f91c-b334-11e5-94b0-3228cc1b4a11.png)
 
This will make the LaTeX much better readable in case of deep nesting.
FSMaxB: The `cases` environment doesn't work for empty objects, because it will just be an opening curly brace. This could be handled by an extra check for empty objects, but it would make everything inconsistent.

I couldn't find a way to do alignment with matrices, but the `array` environment seems to work just fine.

I'll update the code with everything being on the same row and using left aligned arrays, but including a closing curly brace for now.

Patch:
diff --git a/lib/expression/node/ObjectNode.js b/lib/expression/node/ObjectNode.js
index 27cd7c3a9..84c3b9319 100644
--- a/lib/expression/node/ObjectNode.js
+++ b/lib/expression/node/ObjectNode.js
@@ -120,14 +120,13 @@ function factory (type, config, load, typed) {
    * @return {string} str
    */
   ObjectNode.prototype._toTex = function(options) {
-    // TODO: improve LaTeX formatting of JSON objects
     var entries = [];
     for (var key in this.properties) {
       if (this.properties.hasOwnProperty(key)) {
-        entries.push('"' + key + '": ' + this.properties[key].toTex(options));
+        entries.push("\\mathbf{" + key + ':} & ' + this.properties[key].toTex(options) + "\\\\");
       }
     }
-    return '\\{' + entries.join(', ') + '\\}';
+    return '\\left\\{\\begin{array}{ll}' + entries.join('\n') + '\\end{array}\\right\\}';
   };
 
   return ObjectNode;


Test patch:
diff --git a/test/expression/node/ObjectNode.test.js b/test/expression/node/ObjectNode.test.js
index 87e40f6ec..c0099a399 100644
--- a/test/expression/node/ObjectNode.test.js
+++ b/test/expression/node/ObjectNode.test.js
@@ -248,7 +248,7 @@ describe('ObjectNode', function() {
     var n1 = new ObjectNode({a: a, b: b});
     var n2 = new ObjectNode({c: c, n1: n1});
 
-    assert.equal(n2.toTex(), '\\{"c": 3, "n1": \\{"a": 1, "b": 2\\}\\}');
+    assert.equal(n2.toTex(), '\\left\\{\\begin{array}{ll}\\mathbf{c:} & 3\\\\\n\\mathbf{n1:} & \\left\\{\\begin{array}{ll}\\mathbf{a:} & 1\\\\\n\\mathbf{b:} & 2\\\\\\end{array}\\right\\}\\\\\\end{array}\\right\\}')
   });
 
   it ('should LaTeX an ObjectNode with custom toTex', function () {
@@ -262,7 +262,7 @@ describe('ObjectNode', function() {
     var b = new ConstantNode(2);
     var n = new ObjectNode({a: a, b: b});
 
-    assert.equal(n.toTex({handler: customFunction}), '\\{"a": const\\left(1, number\\right), "b": const\\left(2, number\\right)\\}');
+    assert.equal(n.toTex({handler: customFunction}), '\\left\\{\\begin{array}{ll}\\mathbf{a:} & const\\left(1, number\\right)\\\\\n\\mathbf{b:} & const\\left(2, number\\right)\\\\\\end{array}\\right\\}');
   });
 
 });