diff --git a/README.md b/README.md
index ac1044421de..749cf3a64d9 100644
--- a/README.md
+++ b/README.md
@@ -91,9 +91,9 @@ In the Study config file, we define the feasible space of parameters and configu
## Web UI
-Katib provides a Web UI based on ModelDB(https://github.com/mitdbg/modeldb). The ingress setting is defined in [`manifests/modeldb/frontend/ingress.yaml`](manifests/modeldb/frontend/ingress.yaml).
-
-![katib-demo](https://user-images.githubusercontent.com/10014831/38241910-64fb0646-376e-11e8-8b98-c26e577f3935.gif)
+Katib provides a Web UI.
+You can visualize general trend of Hyper parameter space and each training history.
+![katibui](https://user-images.githubusercontent.com/10014831/48778081-a4388b80-ed17-11e8-938b-fc59a5d2e574.gif)
## CLI Documentation
diff --git a/cmd/ui/template/index.html b/cmd/ui/template/index.html
index 5e2dda27e0a..4d454fe4336 100644
--- a/cmd/ui/template/index.html
+++ b/cmd/ui/template/index.html
@@ -2,17 +2,30 @@
diff --git a/cmd/ui/template/parallelcood.js b/cmd/ui/template/parallelcood.js
index 42381c05e88..134353db38b 100644
--- a/cmd/ui/template/parallelcood.js
+++ b/cmd/ui/template/parallelcood.js
@@ -92,10 +92,7 @@ ctx.globalAlpha = 0.15;
ctx.lineWidth = 1.5;
ctx.scale(devicePixelRatio, devicePixelRatio);
-var output = d3.select("#paracood")
- .append("table")
- .attr("class", "table table-hover")
- .attr("id", "study-result")
+var output = d3.select("#result-table")
var axes = svg.selectAll(".axis")
.data(dimensions)
@@ -196,6 +193,9 @@ d3.csv("./{{.IDList.StudyId}}/csv", function(error, data) {
.append("a")
.attr("href", function(d) { return "/katib/{{.IDList.StudyId}}/"+d.key+"/"+d.value;})
.text(function(d) { return d.value;});
+ jQuery(function($){
+ $("#result-table").DataTable();
+ });
function project(d) {
return dimensions.map(function(p,i) {
// check if data element has property and contains a value
@@ -303,28 +303,24 @@ d3.csv("./{{.IDList.StudyId}}/csv", function(error, data) {
ctx.clearRect(0,0,width,height);
ctx.globalAlpha = d3.min([0.85/Math.pow(selected.length,0.3),1]);
render(selected);
-
- output.select("tbody").remove()
- output.append("tbody")
- .selectAll("tr")
- .data(selected)
- .enter()
- .append("tr")
- .selectAll("td")
- .data(function(row) { return d3.entries(row); })
- .enter()
- .append("td")
- .text(function(d) {
- if (d.key == "WorkerID" || d.key == "TrialID"){
- return "";
- } else {
- return d.value;
- }
- })
- .filter(function(d){ return d.key == "WorkerID" || d.key == "TrialID"})
- .append("a")
- .attr("href", function(d) { return "/katib/{{.IDList.StudyId}}/"+d.key+"/"+d.value;})
- .text(function(d) { return d.value;});
+ var resultTable = $("#result-table").DataTable();
+ resultTable.rows().every( function () {
+ this.remove().draw();
+ });
+ var labels = d3.keys(data[0]);
+ var newtable = [];
+ for (var s in selected){
+ var l = [];
+ for (i in labels){
+ if (labels[i] == "WorkerID" || labels[i] == "TrialID"){
+ l.push(""+selected[s][labels[i]]+" ");
+ } else {
+ l.push(selected[s][labels[i]]);
+ }
+ }
+ newtable.push(l);
+ }
+ resultTable.rows.add(newtable).draw();
}
});
diff --git a/cmd/ui/template/study.html b/cmd/ui/template/study.html
index 3355d560273..9b07e474dc7 100644
--- a/cmd/ui/template/study.html
+++ b/cmd/ui/template/study.html
@@ -2,6 +2,8 @@
+
+
diff --git a/cmd/ui/template/trial.html b/cmd/ui/template/trial.html
index 5c5bfe18b38..04335013735 100644
--- a/cmd/ui/template/trial.html
+++ b/cmd/ui/template/trial.html
@@ -6,10 +6,10 @@ Trial ID: {{.IDList.TrialId}}
Parameter Set
-
- Name
- Value
-
+
+ Name
+ Value
+
{{- range .Trial.ParameterSet}}
diff --git a/cmd/ui/template/worker.html b/cmd/ui/template/worker.html
index 9edc0bc030c..14a10e0be47 100644
--- a/cmd/ui/template/worker.html
+++ b/cmd/ui/template/worker.html
@@ -6,7 +6,7 @@
Worker ID: {{.IDList.WorkerId}}
TrialID {{.IDList.TrialId}}
diff --git a/pkg/ui/ui.go b/pkg/ui/ui.go
index 7920c8af8f7..0e12152b52e 100644
--- a/pkg/ui/ui.go
+++ b/pkg/ui/ui.go
@@ -67,13 +67,26 @@ func (k *KatibUIHandler) Index(w http.ResponseWriter, r *http.Request) {
log.Printf("Get Study list failed %v", err)
return
}
+ type StudyNameStack struct {
+ StudyId string
+ Owner string
+ }
type StudyListView struct {
- IDList *IDList
- StudyOverviews []*api.StudyOverview
+ IDList *IDList
+ StudySummarys map[string][]*StudyNameStack
+ }
+ slv := &StudyListView{
+ IDList: &IDList{},
+ StudySummarys: make(map[string][]*StudyNameStack),
}
- slv := StudyListView{
- IDList: &IDList{},
- StudyOverviews: gslrep.StudyOverviews,
+ for _, so := range gslrep.StudyOverviews {
+ if _, ok := slv.StudySummarys[so.Name]; !ok {
+ slv.StudySummarys[so.Name] = []*StudyNameStack{}
+ }
+ slv.StudySummarys[so.Name] = append(slv.StudySummarys[so.Name], &StudyNameStack{
+ StudyId: so.Id,
+ Owner: so.Owner,
+ })
}
t, err := template.ParseFiles("/template/layout.html", "/template/index.html", "/template/breadcrumb.html")
if err != nil {