Interactive Data Table in Pluto.jl (via a silly hack)

@fonsp This is meant to be more fun than anything serious - I came up with a nice little hack for creating interactive data tables in my Pluto notebooks :slightly_smiling_face:

After wrangling a .csv file into a Dict with a very specific structure, I can convert it to JSON and pass it to a function that will return all of the HTML/JavaScript necessary to load the data table:

Convert to Dict:

states = readdlm(raw"C:\Users\mthel\Julia\src_data\states_abbrevs_fips.csv", ',', header=true)

states_dict = Dict(
    "headers" => [Dict("text" => "Name", "value" => "name"), Dict("text" => "Abbreviation", "value" => "abbrev"), Dict("text" => "FIPS", "value" => "fips")],
    "states" => [Dict("name" => states[1][i,1], "abbrev" => states[1][i,2], "fips" => states[1][i,3]) for i in 1:size(states[1],1)]
)

Function that takes JSON argument and returns data table:

function data_table(data)
	return HTML("""
		<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
		<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">

	  <div id="app">
		<v-app>
		  <v-data-table
		  :headers="headers"
		  :items="states"
		></v-data-table>
		</v-app>
	  </div>

	  <script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
	  <script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
	
	<script>
		new Vue({
		  el: '#app',
		  vuetify: new Vuetify(),
		  data () {
				return $data
			}
		})
	</script>
	<style>
		.v-application--wrap {
			min-height: 10vh;
		}
		.v-data-footer__select {
			display: none;
		}
	</style>
	""")
end

And the result:

13 Likes

Very cool! Happy to see that this is possible inside Pluto :slight_smile: Could you send the csv? I’d like to try it out!

This looks very useful already - maybe we can turn this into a feature/package/something one day!

4 Likes

Sure! The data is available here: https://gist.github.com/mthelm85/f3967387e13ff03f92f615f6423f0f45

The ability to render a Vue app inside of an output cell is pretty cool and opens the door to lots of interesting possibilities. In this case, I am leveraging the Vuetify plugin for the data table and Vuetify expects a JSON object of the following form:

{
headers: [
    { text: 'Column 1', value: 'col1' },
    { text: 'Column 2', value: 'col2' }
  ],
  data: [
    {
      col1: 'Item 1',
      col2: 500
    },
    {
      col1: 'Item 2',
      col2: 250
    }
  ]
}

I might write a simple function that can wrangle any .csv with a header row into this format so that I can use this in a more general way in my Pluto notebooks :grinning: I have a decent amount of experience with Vue (although I’m a bit rusty at the moment) so I can see myself leveraging it when I really want a wow factor in my Pluto notebooks.

4 Likes

Great idea!
It woud be good to support the Tables.jl interface for input. Then it would not only work for CSVs, but also for DataFrames, SQL Query results, etc.

4 Likes

I Absolutely love this hack.

I am recently thinking about wrapping Sigma.js library http://sigmajs.org/ and this might make it very easy to do (to some extent).

Any suggestions, how to include sigma.js script are welcomed, as I am a total newbie in this area, but I really want interactive tool to visualize graphs.

2 Likes

This hack isn’t silly, it’s very smart. :laughing:

I think you can drop this dependency:

<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">

since there are only two icons (< and >) and replace it with something minimal.

3 Likes

Does TableView not work out of the box with Pluto?

Does TableView not work out of the box with Pluto?

It didn’t work for me when I tried it…

Stipple (by @essenciary) uses also Vue

Maybe there are synergies between Stipple and PlutoUI?

1 Like

For sure! Planning to make Stipple run on Pluto soon (though probably not compatible with PlutoUI as they use different tech and do the same things).

5 Likes

For sure! Planning to make Stipple run on Pluto soon

Stipple + Pluto = one drool-worthy notebook…

1 Like

Changing the function in the OP to this should work with the Tables.jl interface (I just tested with CSV.File and with a DataFrame and it worked fine:

using JSON2
using Tables

function data_table(table)
	d = Dict(
        "headers" => [Dict("text" => string(name), "value" => string(name)) for name in Tables.columnnames(table)],
        "data" => [Dict(string(name) => row[name] for name in Tables.columnnames(table)) for row in Tables.rows(table)]
    )
	djson = JSON2.write(d)
	
	return HTML("""
		<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
		<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">

	  <div id="app">
		<v-app>
		  <v-data-table
		  :headers="headers"
		  :items="data"
		></v-data-table>
		</v-app>
	  </div>

	  <script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
	  <script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
	
	<script>
		new Vue({
		  el: '#app',
		  vuetify: new Vuetify(),
		  data () {
				return $djson
			}
		})
	</script>
	<style>
		.v-application--wrap {
			min-height: 10vh;
		}
		.v-data-footer__select {
			display: none;
		}
	</style>
	""")
end
2 Likes

You should try and get TableView to work. The lazy loading is essential for performance and non-trivial to implement. Without it things get very slow with many rows of data (10k+)

3 Likes

exciting! let me know if i can help - fonsvdplas@gmail.com

Fantastic @fonsp! I’ll follow up :star_struck:

Hi @mthelm85 I’m using your function, which is great btw, for composing a little report in Pluto where I need to print like 31 values, this kind of notebooks are really amazing when you export them as pdf, I would like to present the full table, 31 rows, to be able to export the notebook as pdf whit the full information, Do you think that you Table could present the 31 rows? Thanks btw.

@Peter24K2G, welcome to the Julia community!

Unfortunately, in order to display all 31 rows you would have to modify the Vuetify.js source code (I doubt it’s worth the effort). Instead, I think what I would do in your case is export your notebook as an .html file and then you should be able to just add to the HTML table that is generated. If you do a Google search for “html table generator” there are even sites that offer simple GUIs for creating your HTML table. You should then be able to plug this into the HTML document and then convert to a PDF, although I’ve never done such a thing myself.

1 Like

items-per-page looks like what you are looking for

1 Like

Oh! They do have a prop for that, nice! So, just do:

		  <v-data-table
		  :headers="headers"
		  :items="data"
          :items-per-page=31
		></v-data-table>
1 Like

This hack is genius and it gets me thinking – is there any way to build our own more complex javascript/Vue visualizations in a local file (say in the same repository as our notebook) and import them into pluto?