vegas-viz / Vegas

The missing MatPlotLib for Scala + Spark
MIT License
730 stars 98 forks source link

how to use vega with IScala jupyter kernel? #91

Closed lJoublanc closed 6 years ago

lJoublanc commented 7 years ago

Trying to use vega 0.3.6 to render some plots with the IScala kernel (not the jupyter-scala kernel).

I use the following for a display function:

implicit val displayer = display.HTMLDisplay( (plot : vegas.DSL.ExtendedUnitSpecBuilder) => plot.pageHTML())

But, using the example plot from your README.md, I get the following:

Javascript error adding output!
ReferenceError: vg is not defined
See your browser Javascript console for more details.

The output of plot.pageHTML() is as follows, and the culprit appears to be the call to vg.embed. Is this normal?

<html>
  <head>
    <script src="http://cdn.jsdelivr.net/webjars/org.webjars.bower/d3/3.5.17/d3.min.js" charset="utf-8"></script>
<script src="http://cdn.jsdelivr.net/webjars/org.webjars.bower/vega/2.6.3/vega.min.js" charset="utf-8"></script>
<script src="http://cdn.jsdelivr.net/webjars/org.webjars.bower/vega-lite/1.2.0/vega-lite.min.js" charset="utf-8"></script>
<script src="https://vega.github.io/vega-editor/vendor/vega-embed.js" charset="utf-8"></script>
  </head>
  <body>
 <script>
   var embedSpec = {
     mode: "vega-lite",
     spec: {
  "mark" : "bar",
  "encoding" : {
    "x" : {
      "field" : "country",
      "type" : "nominal"
    },
    "y" : {
      "field" : "population",
      "type" : "quantitative"
    }
  },
  "description" : "Country Pop",
  "data" : {
    "values" : [
      {
        "country" : "USA",
        "population" : 314
      },
      {
        "country" : "UK",
        "population" : 64
      },
      {
        "country" : "DK",
        "population" : 80
      }
    ]
  }
}
   }
   vg.embed("#vegas-d9265233-b327-4519-bf09-0581277786bc", embedSpec, function(error, result) {});
 </script>
 <div id='vegas-d9265233-b327-4519-bf09-0581277786bc'></div>
    </body>
</html>

It would also be nice if somebody could add these instructions to the readme.

Thanks!

EDIT:

And here's the javascript console:

ReferenceError: vg is not defined
    at eval (eval at globalEval (jquery.min.js:4), <anonymous>:34:4)
    at eval (<anonymous>)
    at Function.globalEval (jquery.min.js:4)
    at init.domManip (jquery.min.js:5)
    at init.append (jquery.min.js:5)
    at OutputArea._safe_append (outputarea.js:413)
    at OutputArea.append_execute_result (outputarea.js:440)
    at OutputArea.append_output (outputarea.js:286)
    at OutputArea.handle_output (outputarea.js:233)
    at output (codecell.js:359)
lJoublanc commented 7 years ago

Ok I've found that this will make plot.show() work:

implicit val displayer : String => Unit = { s =>
  import org.refptr.iscala.display._
  implicit val rawHtml : HTMLDisplay[String] = HTMLDisplay( (t : String) => t)
  display_html(s)
}

I was somewhat confused by the fact that there are two ways of triggering the html display:

  1. matlab style, using plot,.show(), a side-effecting function call of type String => Unit, which as seen above, calls display_html.
  2. functionally, as the return value of the cell. For example if you create a cell
    plot

    the return value is of type vegas.DSL.ExtendedUnitSpecBuilder. In this case IScala looks for an implicit HTMLDisplay[ExtendedUnitSpecBuilder], which is used to display the plot. Without this implicit conversion, a default is used, and you get back the same as what the REPL would print. e.g.:

ExtendedUnitSpecBuilder(ExtendedUnitSpec(None,None,Bar,Some(Encoding(None,None,Some(PositionChannelDef(None,None,None,Some(country),Some(Nominal),None,None,None,None,None)),Some(PositionChannelDef(None,None,None,Some(population),Some(Quantitative),None,None,None,None,None)),None,None,None,None,None,None,None,None,None,None,None)),None,Some(Country Pop),Some(Data(None,None,Some(List(Values(Map(country -> USA, population -> 314)), Values(Map(country -> UK, population -> 64)), Values(Map(country -> DK, population -> 80)))))),None,None))

This is what I was doing in the OP. By adding a second implicit, IScala will display the graph instead:

implicit val displayer2 : HTMLDisplay[vegas.DSL.ExtendedUnitSpecBuilder] = 
  HTMLDisplay { plot : vegas.DSL.ExtendedUnitSpecBuilder => plot.show.toString }