-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Declarative Graphing + JSON/DataFrames #482
Conversation
Not at the moment (see #258) but this is on the roadmap! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wohooo, this is amazing! This mostly looks good, but can you please add some more docs? It's a bit difficult to review as it is
examples/json.dx
Outdated
|
||
|
||
data DataFrame key n value = | ||
AsDataFrame (n => key => value) (key => String) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since value
doesn't depend on key
this is really a homogeneous data frame instead, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point... it's heterogeneous because of the variant type for value. I guess ideally this would be a table where columns are of different types? I will have to think more if that is possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohhh it's heterogeneous because you store all values as JSON! When we initially thought of data frames, we usually considered them as tables-of-records (n=>{field1: Float & field2 : Int}
). A nice benefit of that is that those do have an efficient lowering, unlike this huge variant. But it would make it much harder to store the column=>meta
association, because the column
index set really indexes the fields of the record 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah records are definitely the right solution to this. But I couldn't really figure out how to cleanly enumerate over fields.
Although maybe I just need like a variant over Iso's instead of values. I guess the Meta could could do that work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh actually @danieldjohnson , maybe the cute solution is to have col metadata Iso Variant indexed and the columns in a Iso record. The metadata needs to provide a function to extract it's column (say into json)
Downside: The user would have to manually link them. Same names?
Upside: homogenous data columns, variant named columns (not ordering based), column enumeration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried a slightly different strategy. I think maybe flat dataframes are a hack and kind of unneeded in dex. To make graphing work, you can just construct the flat data representation along with the graph description. This can come from a record or from any other source.
n = Fin 100
df2 : {x1: n => Float &
x2: n => Float &
weight: n => Float &
label : n => Class}
...
chart2 = (AsVLDescriptor (pure Point) [("title", "Scatter")]
[{title="X1", encodings=pureLs X, encType=Quantitative, rows=wrapCol #x1 df2},
{title="X2", encodings=pureLs Y, encType=Quantitative, rows=wrapCol #x2 df2},
{title="Weight", encodings=pureLs Size, encType=Quantitative, rows=wrapCol #weight df2},
{title="Label", encodings=toList [pure Color, pure Tooltip], encType=Nominal, rows=wrapCol #label df2}])
:html showVega $ toJSON chart2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh, I like the most recent version!
I think that manipulating records will be much, much easier once we can enumerate over fields in userspace. So hopefully the "manually linking" downsides will no longer be a problem at that point.
static/index.html
Outdated
@@ -10,6 +10,12 @@ | |||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-AfEj0r4/OFrOo5t7NnNe46zW/tFgW6x/bCJG8FqQCEo3+Aro6EYUG4+cU+KJWu/X" crossorigin="anonymous"> | |||
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-g7c+Jr9ZivxKLnZTDUhnkOnsh30B4H0rpLUpJ4jAIKs4fnJI+sEnkvrMWph2EDg4" crossorigin="anonymous"></script> | |||
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-mll67QQFJfxn0IYznZYonOWZ644AWYC+Pt2cHqMaRhXVrursRwvLnLaebdGIlYNa" crossorigin="anonymous"></script> | |||
|
|||
<script> | |||
function resizeIframe(obj) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is maybe lame, I need to look more into how to sandbox javascript per cell.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to dynamic.js
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding the docs, this is super helpful. I would only like to sort out the resizeIframe
situation and I think it might be good to merge. Also, how about we rename the example to vega-plotting.dx
or something like that? That part is even cooler than JSON for me 😛
examples/json.dx
Outdated
def pureLs (x:a) : List (Opts a) = | ||
AsList 1 [WithOpts x AsNone] | ||
|
||
def mergeOpts [ToJSON a, ToJSON b] (x : a) (y : b) : Value = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess one caveat here is that you probably shouldn't be merging too many overlapping options 😃 But this is fine for now!
examples/json.dx
Outdated
|
||
|
||
def showVega (x: Value) : String = | ||
"<iframe width=\"100%\" frameborder=\"0\" scrolling=\"no\" onload=\"resizeIframe(this)\" srcdoc='<html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this resizeIframe
business be done with something like style="height:100%"
on a bunch of the tags below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently you can't do this :( Need to resize with js as far as I can tell. But the JS seems to work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM. I'm particularly happy that the data frames themselves don't hold any JSON, because that would make it very hard to transform them from inside Dex.
examples/vega-plotting.dx
Outdated
' Start with a well type and useful Dex record | ||
|
||
df1 = {a = ["A", "B", "C", "D", "E", "F", "G", "H", "I"], | ||
b = [28, 55, 43, 91, 81, 53, 19, 87, 52]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to make data frames records-of-tables? I thought that table-of-records is a bit more intuitive, because that's closer to relational algebra
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. Switched to rows.
I've pushed a small update that avoids modifying our builtin JS sources just for this example. Will merge once the CI confirms that it's all good! |
This example code implements:
(This is not meant to overlap / intersect with the Dex plotting. I just got interested in how clean this Vega-Lite Library was compared to Plotly and wanted to try it out. )
Here's what the rendered output looks like https://srush.github.io/dex-lang/examples/json.html
Neat parts:
Questionable Parts:
Nasty parts (most of this I knew already):