diff --git a/CHANGELOG.md b/CHANGELOG.md
index 39f5170396..0e6d85f264 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,13 @@
 ## v1.2.0 [unreleased]
 
 ### Upcoming Bug Fixes
+  1. [#865](https://github.com/influxdata/chronograf/issues/865): Support for String fields compare kapacitor rules in Chronograf UI
 
 ### Upcoming Features
   1. [#838](https://github.com/influxdata/chronograf/issues/838): Add detail node to kapacitor alerts
   2. [#853](https://github.com/influxdata/chronograf/issues/853): Updated builds to use yarn over npm install
-  3. [#864](https://github.com/influxdata/chronograf/issues/864): Add support to kapacitor rule alert config for:
+  3. [#860](https://github.com/influxdata/chronograf/issues/860): Add gzip encoding and caching of static assets to server
+  4. [#864](https://github.com/influxdata/chronograf/issues/864): Add support to kapacitor rule alert config for:
     - HTTP
     - TCP
     - Exec
@@ -13,6 +15,11 @@
     - Alerta
 
 ### Upcoming UI Improvements
+  1. [#822](https://github.com/influxdata/chronograf/issues/822): Simplify and improve layout of the Data Explorer
+    - The Data Explorer's intention and purpose has always been the ad hoc and ephemeral   exploration of your schema and data.
+      The concept of `Exploration` sessions and `Panels` betrayed this initial intention. The DE turned into a "poor man's"
+      dashboarding tool. In turn, this introduced complexity in the code and the UI.  In the future if I want to save, manipulate,
+      and view multiple visualizations this will be done more efficiently and effectively in our dashboarding solution.
 
 ## v1.2.0-beta1 [2017-01-27]
 
diff --git a/Godeps b/Godeps
index f2c6cb8bad..a81e679b1e 100644
--- a/Godeps
+++ b/Godeps
@@ -1,3 +1,4 @@
+github.com/NYTimes/gziphandler 6710af535839f57c687b62c4c23d649f9545d885
 github.com/Sirupsen/logrus 3ec0642a7fb6488f65b06f9040adc67e3990296a
 github.com/boltdb/bolt 5cc10bbbc5c141029940133bb33c9e969512a698
 github.com/bouk/httprouter ee8b3818a7f51fbc94cc709b5744b52c2c725e91
diff --git a/LICENSE_OF_DEPENDENCIES.md b/LICENSE_OF_DEPENDENCIES.md
index 5efd655a68..0f96a24c34 100644
--- a/LICENSE_OF_DEPENDENCIES.md
+++ b/LICENSE_OF_DEPENDENCIES.md
@@ -1,4 +1,5 @@
 ### Go
+* github.com/NYTimes/gziphandler [APACHE-2.0](https://github.com/NYTimes/gziphandler/blob/master/LICENSE.md)
 * github.com/Sirupsen/logrus [MIT](https://github.com/Sirupsen/logrus/blob/master/LICENSE)
 * github.com/boltdb/bolt [MIT](https://github.com/boltdb/bolt/blob/master/LICENSE)
 * github.com/bouk/httprouter [BSD](https://github.com/bouk/httprouter/blob/master/LICENSE)
diff --git a/dist/dist.go b/dist/dist.go
index 07b9d0ab41..ba3d3c938f 100644
--- a/dist/dist.go
+++ b/dist/dist.go
@@ -3,6 +3,7 @@ package dist
 //go:generate go-bindata -o dist_gen.go -ignore 'map|go' -pkg dist ../ui/build/...
 
 import (
+	"fmt"
 	"net/http"
 
 	"github.com/elazarl/go-bindata-assetfs"
@@ -32,6 +33,21 @@ func (b *BindataAssets) Handler() http.Handler {
 	return b
 }
 
+// addCacheHeaders requests an hour of Cache-Control and sets an ETag based on file size and modtime
+func (b *BindataAssets) addCacheHeaders(filename string, w http.ResponseWriter) error {
+	w.Header().Add("Cache-Control", "public, max-age=3600")
+	fi, err := AssetInfo(filename)
+	if err != nil {
+		return err
+	}
+
+	hour, minute, second := fi.ModTime().Clock()
+	etag := fmt.Sprintf(`"%d%d%d%d%d"`, fi.Size(), fi.ModTime().Day(), hour, minute, second)
+
+	w.Header().Set("ETag", etag)
+	return nil
+}
+
 // ServeHTTP wraps http.FileServer by returning a default asset if the asset
 // doesn't exist.  This supports single-page react-apps with its own
 // built-in router.  Additionally, we override the content-type if the
@@ -52,8 +68,14 @@ func (b *BindataAssets) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 			// Additionally, because we know we are returning the default asset,
 			// we need to set the default asset's content-type.
 			w.Header().Set("Content-Type", b.DefaultContentType)
+			if err := b.addCacheHeaders(b.Default, w); err != nil {
+				return nil, err
+			}
 			return Asset(b.Default)
 		}
+		if err := b.addCacheHeaders(name, w); err != nil {
+			return nil, err
+		}
 		return octets, nil
 	}
 	var dir http.FileSystem = &assetfs.AssetFS{
diff --git a/kapacitor/tickscripts_test.go b/kapacitor/tickscripts_test.go
index c00e043782..d201d44b89 100644
--- a/kapacitor/tickscripts_test.go
+++ b/kapacitor/tickscripts_test.go
@@ -199,6 +199,280 @@ trigger
 	}
 }
 
+func TestThresholdStringCrit(t *testing.T) {
+	alert := chronograf.AlertRule{
+		Name:    "haproxy",
+		Trigger: "threshold",
+		Alerts:  []string{"email"},
+		TriggerValues: chronograf.TriggerValues{
+			Operator: "equal to",
+			Value:    "DOWN",
+		},
+		Every:   "10s",
+		Message: `Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} `,
+		Details: "Email template",
+		Query: chronograf.QueryConfig{
+			Database:        "influxdb",
+			RetentionPolicy: "autogen",
+			Measurement:     "haproxy",
+			Fields: []chronograf.Field{
+				{
+					Field: "status",
+					Funcs: []string{"last"},
+				},
+			},
+			GroupBy: chronograf.GroupBy{
+				Time: "10s",
+				Tags: []string{"pxname"},
+			},
+			AreTagsAccepted: true,
+		},
+	}
+
+	tests := []struct {
+		name    string
+		alert   chronograf.AlertRule
+		want    chronograf.TICKScript
+		wantErr bool
+	}{
+		{
+			name:  "Test valid template alert",
+			alert: alert,
+			want: `var db = 'influxdb'
+
+var rp = 'autogen'
+
+var measurement = 'haproxy'
+
+var groupBy = ['pxname']
+
+var whereFilter = lambda: TRUE
+
+var period = 10s
+
+var every = 10s
+
+var name = 'haproxy'
+
+var idVar = name + ':{{.Group}}'
+
+var message = 'Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} '
+
+var idTag = 'alertID'
+
+var levelTag = 'level'
+
+var messageField = 'message'
+
+var durationField = 'duration'
+
+var outputDB = 'chronograf'
+
+var outputRP = 'autogen'
+
+var outputMeasurement = 'alerts'
+
+var triggerType = 'threshold'
+
+var details = 'Email template'
+
+var crit = 'DOWN'
+
+var data = stream
+    |from()
+        .database(db)
+        .retentionPolicy(rp)
+        .measurement(measurement)
+        .groupBy(groupBy)
+        .where(whereFilter)
+    |window()
+        .period(period)
+        .every(every)
+        .align()
+    |last('status')
+        .as('value')
+
+var trigger = data
+    |alert()
+        .crit(lambda: "value" == crit)
+        .stateChangesOnly()
+        .message(message)
+        .id(idVar)
+        .idTag(idTag)
+        .levelTag(levelTag)
+        .messageField(messageField)
+        .durationField(durationField)
+        .details(details)
+        .email()
+
+trigger
+    |influxDBOut()
+        .create()
+        .database(outputDB)
+        .retentionPolicy(outputRP)
+        .measurement(outputMeasurement)
+        .tag('alertName', name)
+        .tag('triggerType', triggerType)
+
+trigger
+    |httpOut('output')
+`,
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		gen := Alert{}
+		got, err := gen.Generate(tt.alert)
+		if (err != nil) != tt.wantErr {
+			t.Errorf("%q. Threshold() error = %v, wantErr %v", tt.name, err, tt.wantErr)
+			continue
+		}
+		if got != tt.want {
+			diff := diffmatchpatch.New()
+			delta := diff.DiffMain(string(tt.want), string(got), true)
+			t.Errorf("%q\n%s", tt.name, diff.DiffPrettyText(delta))
+		}
+	}
+}
+
+// TODO: Check with Nathaniel if kapacitor can do inequalities on strings
+// If it cannot, I think we should add operator checks.
+func TestThresholdStringCritGreater(t *testing.T) {
+	alert := chronograf.AlertRule{
+		Name:    "haproxy",
+		Trigger: "threshold",
+		Alerts:  []string{"email"},
+		TriggerValues: chronograf.TriggerValues{
+			Operator: "greater than",
+			Value:    "DOWN",
+		},
+		Every:   "10s",
+		Message: `Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} `,
+		Details: "Email template",
+		Query: chronograf.QueryConfig{
+			Database:        "influxdb",
+			RetentionPolicy: "autogen",
+			Measurement:     "haproxy",
+			Fields: []chronograf.Field{
+				{
+					Field: "status",
+					Funcs: []string{"last"},
+				},
+			},
+			GroupBy: chronograf.GroupBy{
+				Time: "10s",
+				Tags: []string{"pxname"},
+			},
+			AreTagsAccepted: true,
+		},
+	}
+
+	tests := []struct {
+		name    string
+		alert   chronograf.AlertRule
+		want    chronograf.TICKScript
+		wantErr bool
+	}{
+		{
+			name:  "Test valid template alert",
+			alert: alert,
+			want: `var db = 'influxdb'
+
+var rp = 'autogen'
+
+var measurement = 'haproxy'
+
+var groupBy = ['pxname']
+
+var whereFilter = lambda: TRUE
+
+var period = 10s
+
+var every = 10s
+
+var name = 'haproxy'
+
+var idVar = name + ':{{.Group}}'
+
+var message = 'Haproxy monitor : {{.ID}} : {{ index .Tags "server" }} : {{ index .Tags "pxname" }} is {{ .Level }} '
+
+var idTag = 'alertID'
+
+var levelTag = 'level'
+
+var messageField = 'message'
+
+var durationField = 'duration'
+
+var outputDB = 'chronograf'
+
+var outputRP = 'autogen'
+
+var outputMeasurement = 'alerts'
+
+var triggerType = 'threshold'
+
+var details = 'Email template'
+
+var crit = 'DOWN'
+
+var data = stream
+    |from()
+        .database(db)
+        .retentionPolicy(rp)
+        .measurement(measurement)
+        .groupBy(groupBy)
+        .where(whereFilter)
+    |window()
+        .period(period)
+        .every(every)
+        .align()
+    |last('status')
+        .as('value')
+
+var trigger = data
+    |alert()
+        .crit(lambda: "value" > crit)
+        .stateChangesOnly()
+        .message(message)
+        .id(idVar)
+        .idTag(idTag)
+        .levelTag(levelTag)
+        .messageField(messageField)
+        .durationField(durationField)
+        .details(details)
+        .email()
+
+trigger
+    |influxDBOut()
+        .create()
+        .database(outputDB)
+        .retentionPolicy(outputRP)
+        .measurement(outputMeasurement)
+        .tag('alertName', name)
+        .tag('triggerType', triggerType)
+
+trigger
+    |httpOut('output')
+`,
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		gen := Alert{}
+		got, err := gen.Generate(tt.alert)
+		if (err != nil) != tt.wantErr {
+			t.Errorf("%q. Threshold() error = %v, wantErr %v", tt.name, err, tt.wantErr)
+			continue
+		}
+		if got != tt.want {
+			diff := diffmatchpatch.New()
+			delta := diff.DiffMain(string(tt.want), string(got), true)
+			t.Errorf("%q\n%s", tt.name, diff.DiffPrettyText(delta))
+		}
+	}
+}
+
 func TestThresholdDetail(t *testing.T) {
 	alert := chronograf.AlertRule{
 		Name:    "name",
diff --git a/kapacitor/vars.go b/kapacitor/vars.go
index f9239e6bfd..081f349fb7 100644
--- a/kapacitor/vars.go
+++ b/kapacitor/vars.go
@@ -3,6 +3,7 @@ package kapacitor
 import (
 	"fmt"
 	"sort"
+	"strconv"
 	"strings"
 
 	"github.com/influxdata/chronograf"
@@ -39,15 +40,13 @@ func Vars(rule chronograf.AlertRule) (string, error) {
 		%s
         var crit = %s
  `
-			return fmt.Sprintf(vars,
-				common,
-				rule.TriggerValues.Value), nil
+			return fmt.Sprintf(vars, common, formatValue(rule.TriggerValues.Value)), nil
 		} else {
 			vars := `
 			%s
 					var lower = %s
 					var upper = %s
-	 `
+`
 			return fmt.Sprintf(vars,
 				common,
 				rule.TriggerValues.Value,
@@ -178,3 +177,13 @@ func whereFilter(q chronograf.QueryConfig) string {
 
 	return "lambda: TRUE"
 }
+
+// formatValue return the same string if a numeric type or if it is a string
+// will return it as a kapacitor formatted single-quoted string
+func formatValue(value string) string {
+	// Test if numeric if it can be converted to a float
+	if _, err := strconv.ParseFloat(value, 64); err == nil {
+		return value
+	}
+	return "'" + value + "'"
+}
diff --git a/kapacitor/vars_test.go b/kapacitor/vars_test.go
new file mode 100644
index 0000000000..e19104aeff
--- /dev/null
+++ b/kapacitor/vars_test.go
@@ -0,0 +1,50 @@
+package kapacitor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/influxdata/chronograf"
+)
+
+func TestVarsCritStringEqual(t *testing.T) {
+	alert := chronograf.AlertRule{
+		Name:    "name",
+		Trigger: "threshold",
+		TriggerValues: chronograf.TriggerValues{
+			Operator: "equal to",
+			Value:    "DOWN",
+		},
+		Every: "30s",
+		Query: chronograf.QueryConfig{
+			Database:        "telegraf",
+			Measurement:     "haproxy",
+			RetentionPolicy: "autogen",
+			Fields: []chronograf.Field{
+				{
+					Field: "status",
+				},
+			},
+			GroupBy: chronograf.GroupBy{
+				Time: "10m",
+				Tags: []string{"pxname"},
+			},
+			AreTagsAccepted: true,
+		},
+	}
+
+	raw, err := Vars(alert)
+	if err != nil {
+		fmt.Printf("%s", raw)
+		t.Fatalf("Error generating alert: %v %s", err, raw)
+	}
+
+	tick, err := formatTick(raw)
+	if err != nil {
+		t.Errorf("Error formatting alert: %v %s", err, raw)
+	}
+
+	if err := validateTick(tick); err != nil {
+		t.Errorf("Error validating alert: %v %s", err, tick)
+	}
+}
diff --git a/server/mux.go b/server/mux.go
index 927f935798..0c28a53027 100644
--- a/server/mux.go
+++ b/server/mux.go
@@ -7,6 +7,7 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/NYTimes/gziphandler"
 	"github.com/bouk/httprouter"
 	"github.com/influxdata/chronograf" // When julienschmidt/httprouter v2 w/ context is out, switch
 	"github.com/influxdata/chronograf/jwt"
@@ -119,7 +120,10 @@ func NewMux(opts MuxOpts, service Service) http.Handler {
 		auth := AuthAPI(opts, router)
 		return Logger(opts.Logger, auth)
 	}
-	return Logger(opts.Logger, router)
+
+	compressed := gziphandler.GzipHandler(router)
+	logged := Logger(opts.Logger, compressed)
+	return logged
 }
 
 // AuthAPI adds the OAuth routes if auth is enabled.
diff --git a/server/url_prefixer.go b/server/url_prefixer.go
index 54e2a35f8e..d20563fc15 100644
--- a/server/url_prefixer.go
+++ b/server/url_prefixer.go
@@ -22,16 +22,27 @@ type wrapResponseWriter struct {
 	Substitute *io.PipeWriter
 
 	headerWritten bool
-	dupHeader     http.Header
+	dupHeader     *http.Header
 }
 
-func (wrw wrapResponseWriter) Write(p []byte) (int, error) {
+func (wrw *wrapResponseWriter) Write(p []byte) (int, error) {
 	return wrw.Substitute.Write(p)
 }
 
-func (wrw wrapResponseWriter) WriteHeader(code int) {
+func (wrw *wrapResponseWriter) WriteHeader(code int) {
 	if !wrw.headerWritten {
-		wrw.ResponseWriter.Header().Set("Content-Type", wrw.Header().Get("Content-Type"))
+		wrw.ResponseWriter.Header().Set("Content-Type", wrw.dupHeader.Get("Content-Type"))
+		header := wrw.ResponseWriter.Header()
+		// Filter out content length header to prevent stopping writing
+		if wrw.dupHeader != nil {
+			for k, v := range *wrw.dupHeader {
+				if k == "Content-Length" {
+					continue
+				}
+				header[k] = v
+			}
+		}
+
 		wrw.headerWritten = true
 	}
 	wrw.ResponseWriter.WriteHeader(code)
@@ -39,13 +50,16 @@ func (wrw wrapResponseWriter) WriteHeader(code int) {
 
 // Header() copies the Header map from the underlying ResponseWriter to prevent
 // modifications to it by callers
-func (wrw wrapResponseWriter) Header() http.Header {
-	wrw.dupHeader = http.Header{}
-	origHeader := wrw.ResponseWriter.Header()
-	for k, v := range origHeader {
-		wrw.dupHeader[k] = v
+func (wrw *wrapResponseWriter) Header() http.Header {
+	if wrw.dupHeader == nil {
+		h := http.Header{}
+		origHeader := wrw.ResponseWriter.Header()
+		for k, v := range origHeader {
+			h[k] = v
+		}
+		wrw.dupHeader = &h
 	}
-	return wrw.dupHeader
+	return *wrw.dupHeader
 }
 
 const CHUNK_SIZE int = 512
@@ -73,7 +87,7 @@ func (up *URLPrefixer) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
 	nextRead, nextWrite := io.Pipe()
 	go func() {
 		defer nextWrite.Close()
-		up.Next.ServeHTTP(wrapResponseWriter{ResponseWriter: rw, Substitute: nextWrite}, r)
+		up.Next.ServeHTTP(&wrapResponseWriter{ResponseWriter: rw, Substitute: nextWrite}, r)
 	}()
 
 	// setup a buffer which is the max length of our target attrs
diff --git a/ui/spec/data_explorer/reducers/dataExplorerUISpec.js b/ui/spec/data_explorer/reducers/dataExplorerUISpec.js
deleted file mode 100644
index b0f4404676..0000000000
--- a/ui/spec/data_explorer/reducers/dataExplorerUISpec.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import reducer from 'src/data_explorer/reducers/dataExplorerUI';
-import {activatePanel} from 'src/data_explorer/actions/view';
-
-describe('DataExplorer.Reducers.UI', () => {
-  it('can set the active panel', () => {
-    const activePanel = 123;
-    const actual = reducer({}, activatePanel(activePanel));
-
-    expect(actual).to.deep.equal({activePanel});
-  });
-});
diff --git a/ui/spec/data_explorer/reducers/panelSpec.js b/ui/spec/data_explorer/reducers/panelSpec.js
deleted file mode 100644
index 8182edd052..0000000000
--- a/ui/spec/data_explorer/reducers/panelSpec.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import reducer from 'src/data_explorer/reducers/panels';
-import {deletePanel} from 'src/data_explorer/actions/view';
-
-const fakeAddPanelAction = (panelID, queryID) => {
-  return {
-    type: 'CREATE_PANEL',
-    payload: {panelID, queryID},
-  };
-};
-
-describe('Chronograf.Reducers.Panel', () => {
-  let state;
-  const panelID = 123;
-  const queryID = 456;
-
-  beforeEach(() => {
-    state = reducer({}, fakeAddPanelAction(panelID, queryID));
-  });
-
-  it('can add a panel', () => {
-    const actual = state[panelID];
-    expect(actual).to.deep.equal({
-      id: panelID,
-      queryIds: [queryID],
-    });
-  });
-
-  it('can delete a panel', () => {
-    const nextState = reducer(state, deletePanel(panelID));
-
-    const actual = nextState[panelID];
-    expect(actual).to.equal(undefined);
-  });
-});
diff --git a/ui/src/data_explorer/actions/view/index.js b/ui/src/data_explorer/actions/view/index.js
index f79fc537ad..8e5f36b224 100644
--- a/ui/src/data_explorer/actions/view/index.js
+++ b/ui/src/data_explorer/actions/view/index.js
@@ -1,51 +1,20 @@
 import uuid from 'node-uuid';
 
-export function createPanel() {
-  return {
-    type: 'CREATE_PANEL',
-    payload: {
-      panelID: uuid.v4(), // for the default Panel
-      queryID: uuid.v4(), // for the default Query
-    },
-  };
-}
-
-export function renamePanel(panelId, name) {
-  return {
-    type: 'RENAME_PANEL',
-    payload: {
-      panelId,
-      name,
-    },
-  };
-}
-
-export function deletePanel(panelId) {
-  return {
-    type: 'DELETE_PANEL',
-    payload: {
-      panelId,
-    },
-  };
-}
-
-export function addQuery(panelId, options) {
+export function addQuery(options = {}) {
   return {
     type: 'ADD_QUERY',
     payload: {
-      panelId,
-      queryId: uuid.v4(),
+      queryID: uuid.v4(),
       options,
     },
   };
 }
 
-export function deleteQuery(panelId, queryId) {
+export function deleteQuery(queryID) {
   return {
     type: 'DELETE_QUERY',
     payload: {
-      queryId,
-      panelId,
+      queryID,
     },
   };
 }
@@ -159,12 +128,3 @@ export function updateRawQuery(queryID, text) {
     },
   };
 }
-
-export function activatePanel(panelID) {
-  return {
-    type: 'ACTIVATE_PANEL',
-    payload: {
-      panelID,
-    },
-  };
-}
diff --git a/ui/src/data_explorer/components/DatabaseList.js b/ui/src/data_explorer/components/DatabaseList.js
index c903290ea0..ca08c79c19 100644
--- a/ui/src/data_explorer/components/DatabaseList.js
+++ b/ui/src/data_explorer/components/DatabaseList.js
@@ -60,18 +60,21 @@ const DatabaseList = React.createClass({
     const {onChooseNamespace, query} = this.props;
 
     return (
-      <ul className="qeditor--list">
-        {this.state.namespaces.map((namespace) => {
-          const {database, retentionPolicy} = namespace;
-          const isActive = database === query.database && retentionPolicy === query.retentionPolicy;
+      <div className="query-builder--column">
+        <div className="query-builder--column-heading">Databases</div>
+        <ul className="qeditor--list">
+          {this.state.namespaces.map((namespace) => {
+            const {database, retentionPolicy} = namespace;
+            const isActive = database === query.database && retentionPolicy === query.retentionPolicy;
 
-          return (
-            <li className={classNames('qeditor--list-item qeditor--list-radio', {active: isActive})} key={`${database}..${retentionPolicy}`} onClick={_.wrap(namespace, onChooseNamespace)}>
-              {database}.{retentionPolicy}
-            </li>
-          );
-        })}
-      </ul>
+            return (
+              <li className={classNames('qeditor--list-item qeditor--list-radio', {active: isActive})} key={`${database}..${retentionPolicy}`} onClick={_.wrap(namespace, onChooseNamespace)}>
+                {database}.{retentionPolicy}
+              </li>
+            );
+          })}
+        </ul>
+      </div>
     );
   },
 });
diff --git a/ui/src/data_explorer/components/FieldList.js b/ui/src/data_explorer/components/FieldList.js
index ee700c638d..8253d0bf6a 100644
--- a/ui/src/data_explorer/components/FieldList.js
+++ b/ui/src/data_explorer/components/FieldList.js
@@ -41,25 +41,26 @@ const FieldList = React.createClass({
   },
 
   componentDidMount() {
-    const {database, measurement, retentionPolicy} = this.props.query;
+    const {database, measurement} = this.props.query;
     if (!database || !measurement) {
       return;
     }
 
-    const {source} = this.context;
-    const proxySource = source.links.proxy;
-    showFieldKeys(proxySource, database, measurement, retentionPolicy).then((resp) => {
-      const {errors, fieldSets} = showFieldKeysParser(resp.data);
-      if (errors.length) {
-        // TODO: do something
-      }
+    this._getFields();
+  },
 
-      this.setState({
-        fields: fieldSets[measurement].map((f) => {
-          return {field: f, funcs: []};
-        }),
-      });
-    });
+  componentDidUpdate(prevProps) {
+    const {database, measurement, retentionPolicy} = this.props.query;
+    const {database: prevDB, measurement: prevMeas, retentionPolicy: prevRP} = prevProps.query;
+    if (!database || !measurement) {
+      return;
+    }
+
+    if (database === prevDB && measurement === prevMeas && retentionPolicy === prevRP) {
+      return;
+    }
+
+    this._getFields();
   },
 
   handleGroupByTime(groupBy) {
@@ -72,7 +73,8 @@ const FieldList = React.createClass({
     const hasGroupByTime = query.groupBy.time;
 
     return (
-      <div>
+      <div className="query-builder--column">
+        <div className="query-builder--column-heading">Fields</div>
         {
           hasAggregates ?
             <div className="qeditor--list-header">
@@ -94,23 +96,43 @@ const FieldList = React.createClass({
       return <div className="qeditor--empty">No <strong>Measurement</strong> selected</div>;
     }
 
-    return (<ul className="qeditor--list">
-      {this.state.fields.map((fieldFunc) => {
-        const selectedField = this.props.query.fields.find((f) => f.field === fieldFunc.field);
-        return (
-          <FieldListItem
-            key={fieldFunc.field}
-            onToggleField={this.props.onToggleField}
-            onApplyFuncsToField={this.props.applyFuncsToField}
-            isSelected={!!selectedField}
-            fieldFunc={selectedField || fieldFunc}
-            isKapacitorRule={this.props.isKapacitorRule}
-          />
-        );
-      })}
-    </ul>
+    return (
+      <ul className="qeditor--list">
+        {this.state.fields.map((fieldFunc) => {
+          const selectedField = this.props.query.fields.find((f) => f.field === fieldFunc.field);
+          return (
+            <FieldListItem
+              key={fieldFunc.field}
+              onToggleField={this.props.onToggleField}
+              onApplyFuncsToField={this.props.applyFuncsToField}
+              isSelected={!!selectedField}
+              fieldFunc={selectedField || fieldFunc}
+              isKapacitorRule={this.props.isKapacitorRule}
+            />
+          );
+        })}
+      </ul>
     );
   },
+
+  _getFields() {
+    const {database, measurement, retentionPolicy} = this.props.query;
+    const {source} = this.context;
+    const proxySource = source.links.proxy;
+
+    showFieldKeys(proxySource, database, measurement, retentionPolicy).then((resp) => {
+      const {errors, fieldSets} = showFieldKeysParser(resp.data);
+      if (errors.length) {
+        // TODO: do something
+      }
+
+      this.setState({
+        fields: fieldSets[measurement].map((f) => {
+          return {field: f, funcs: []};
+        }),
+      });
+    });
+  },
 });
 
 export default FieldList;
diff --git a/ui/src/data_explorer/components/MeasurementList.js b/ui/src/data_explorer/components/MeasurementList.js
index 58e7857214..91521eeacc 100644
--- a/ui/src/data_explorer/components/MeasurementList.js
+++ b/ui/src/data_explorer/components/MeasurementList.js
@@ -34,19 +34,21 @@ const MeasurementList = React.createClass({
       return;
     }
 
-    const {source} = this.context;
-    const proxy = source.links.proxy;
-    showMeasurements(proxy, this.props.query.database).then((resp) => {
-      const {errors, measurementSets} = showMeasurementsParser(resp.data);
-      if (errors.length) {
-        // TODO: display errors in the UI.
-        return console.error('InfluxDB returned error(s): ', errors); // eslint-disable-line no-console
-      }
+    this._getMeasurements();
+  },
 
-      this.setState({
-        measurements: measurementSets[0].measurements,
-      });
-    });
+  componentDidUpdate(prevProps) {
+    const {query} = this.props;
+
+    if (!query.database) {
+      return;
+    }
+
+    if (prevProps.query.database === query.database) {
+      return;
+    }
+
+    this._getMeasurements();
   },
 
   handleFilterText(e) {
@@ -69,9 +71,10 @@ const MeasurementList = React.createClass({
 
   render() {
     return (
-      <div>
+      <div className="query-builder--column">
+        <div className="query-builder--column-heading">Measurements</div>
         {this.props.query.database ? <div className="qeditor--list-header">
-          <input className="qeditor--filter" ref="filterText" placeholder="Filter Measurements..." type="text" value={this.state.filterText} onChange={this.handleFilterText} onKeyUp={this.handleEscape} />
+          <input className="qeditor--filter" ref="filterText" placeholder="Filter" type="text" value={this.state.filterText} onChange={this.handleFilterText} onKeyUp={this.handleEscape} />
           <span className="icon search"></span>
         </div> : null }
         {this.renderList()}
@@ -97,6 +100,23 @@ const MeasurementList = React.createClass({
       </ul>
     );
   },
+
+  _getMeasurements() {
+    const {source} = this.context;
+    const proxy = source.links.proxy;
+    showMeasurements(proxy, this.props.query.database).then((resp) => {
+      const {errors, measurementSets} = showMeasurementsParser(resp.data);
+      if (errors.length) {
+        // TODO: display errors in the UI.
+        return console.error('InfluxDB returned error(s): ', errors); // eslint-disable-line no-console
+      }
+
+      this.setState({
+        measurements: measurementSets[0].measurements,
+      });
+    });
+  },
+
 });
 
 export default MeasurementList;
diff --git a/ui/src/data_explorer/components/MultiTable.js b/ui/src/data_explorer/components/MultiTable.js
index aa12fb7fb5..3fe57d310b 100644
--- a/ui/src/data_explorer/components/MultiTable.js
+++ b/ui/src/data_explorer/components/MultiTable.js
@@ -2,7 +2,14 @@ import React, {PropTypes} from 'react';
 import Table from './Table';
 import classNames from 'classnames';
 
-const {bool, string, shape, arrayOf, func} = PropTypes;
+const {
+  arrayOf,
+  bool,
+  func,
+  number,
+  shape,
+  string,
+} = PropTypes;
 
 const MultiTable = React.createClass({
   propTypes: {
@@ -10,6 +17,7 @@ const MultiTable = React.createClass({
       host: arrayOf(string.isRequired).isRequired,
       text: string.isRequired,
     })),
+    height: number,
   },
 
   getInitialState() {
@@ -40,13 +48,14 @@ const MultiTable = React.createClass({
   },
 
   renderTable() {
+    const {height} = this.props;
     const query = this.getActiveQuery();
     const noQuery = !query || !query.text;
     if (noQuery) {
       return null;
     }
 
-    return <Table key={query.text} query={query} />;
+    return <Table key={query.text} query={query} height={height} />;
   },
 
   renderTabs() {
diff --git a/ui/src/data_explorer/components/Panel.js b/ui/src/data_explorer/components/Panel.js
deleted file mode 100644
index 50ddf8621f..0000000000
--- a/ui/src/data_explorer/components/Panel.js
+++ /dev/null
@@ -1,183 +0,0 @@
-import React, {PropTypes} from 'react';
-import classNames from 'classnames';
-import QueryEditor from './QueryEditor';
-import QueryTabItem from './QueryTabItem';
-import RenamePanelModal from './RenamePanelModal';
-import SimpleDropdown from 'src/shared/components/SimpleDropdown';
-
-const Panel = React.createClass({
-  propTypes: {
-    panel: PropTypes.shape({
-      id: PropTypes.string.isRequired,
-    }).isRequired,
-    queries: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
-    timeRange: PropTypes.shape({
-      upper: PropTypes.string,
-      lower: PropTypes.string,
-    }).isRequired,
-    isExpanded: PropTypes.bool.isRequired,
-    onTogglePanel: PropTypes.func.isRequired,
-    actions: PropTypes.shape({
-      chooseNamespace: PropTypes.func.isRequired,
-      chooseMeasurement: PropTypes.func.isRequired,
-      chooseTag: PropTypes.func.isRequired,
-      groupByTag: PropTypes.func.isRequired,
-      addQuery: PropTypes.func.isRequired,
-      deleteQuery: PropTypes.func.isRequired,
-      toggleField: PropTypes.func.isRequired,
-      groupByTime: PropTypes.func.isRequired,
-      toggleTagAcceptance: PropTypes.func.isRequired,
-      applyFuncsToField: PropTypes.func.isRequired,
-      deletePanel: PropTypes.func.isRequired,
-      renamePanel: PropTypes.func.isRequired,
-    }).isRequired,
-    setActiveQuery: PropTypes.func.isRequired,
-    activeQueryID: PropTypes.string,
-  },
-
-  handleSetActiveQuery(query) {
-    this.props.setActiveQuery(query.id);
-  },
-
-  handleAddQuery() {
-    this.props.actions.addQuery();
-  },
-
-  handleAddRawQuery() {
-    this.props.actions.addQuery({rawText: `SELECT "fields" from "db"."rp"."measurement"`});
-  },
-
-  handleDeleteQuery(query) {
-    this.props.actions.deleteQuery(query.id);
-  },
-
-  handleSelectPanel() {
-    this.props.onTogglePanel(this.props.panel);
-  },
-
-  handleDeletePanel(e) {
-    e.stopPropagation();
-    this.props.actions.deletePanel(this.props.panel.id);
-  },
-
-  getActiveQuery() {
-    const {queries, activeQueryID} = this.props;
-    const activeQuery = queries.find((query) => query.id === activeQueryID);
-    const defaultQuery = queries[0];
-
-    return activeQuery || defaultQuery;
-  },
-
-  openRenamePanelModal(e) {
-    e.stopPropagation();
-    $(`#renamePanelModal-${this.props.panel.id}`).modal('show'); // eslint-disable-line no-undef
-  },
-
-  handleRename(newName) {
-    this.props.actions.renamePanel(this.props.panel.id, newName);
-  },
-
-
-  render() {
-    const {panel, isExpanded} = this.props;
-
-    return (
-      <div className={classNames('panel', {active: isExpanded})}>
-        <div className="panel--header" onClick={this.handleSelectPanel}>
-          <div className="panel--name">
-            <span className="icon caret-right"></span>
-            {panel.name || "Graph"}
-          </div>
-          <div className="panel--actions">
-            {/* <div title="Export Queries to Dashboard" className="panel--action"><span className="icon export"></span></div> */}
-            <div title="Rename Graph" className="panel--action" onClick={this.openRenamePanelModal}><span className="icon pencil"></span></div>
-            <div title="Delete Graph" className="panel--action" onClick={this.handleDeletePanel}><span className="icon trash"></span></div>
-          </div>
-        </div>
-        {this.renderQueryTabList()}
-        {this.renderQueryEditor()}
-        <RenamePanelModal panel={panel} onConfirm={this.handleRename} />
-      </div>
-    );
-  },
-
-  renderQueryEditor() {
-    if (!this.props.isExpanded) {
-      return null;
-    }
-
-    const {timeRange, actions} = this.props;
-    const query = this.getActiveQuery();
-
-    if (!query) {
-      return (
-        <div className="qeditor--empty">
-          <h5>This Graph has no Queries</h5>
-          <br/>
-          <div className="btn btn-primary" role="button" onClick={this.handleAddQuery}>Add a Query</div>
-        </div>
-      );
-    }
-
-    return (
-      <QueryEditor
-        timeRange={timeRange}
-        query={this.getActiveQuery()}
-        actions={actions}
-        onAddQuery={this.handleAddQuery}
-      />
-    );
-  },
-
-  renderQueryTabList() {
-    const {isExpanded, queries} = this.props;
-    if (!isExpanded) {
-      return null;
-    }
-    return (
-      <div className="panel--tabs">
-        {queries.map((q) => {
-          let queryTabText;
-          if (q.rawText) {
-            queryTabText = 'InfluxQL';
-          } else {
-            queryTabText = (q.measurement && q.fields.length !== 0) ? `${q.measurement}.${q.fields[0].field}` : 'Query';
-          }
-          return (
-            <QueryTabItem
-              isActive={this.getActiveQuery().id === q.id}
-              key={q.id}
-              query={q}
-              onSelect={this.handleSetActiveQuery}
-              onDelete={this.handleDeleteQuery}
-              queryTabText={queryTabText}
-            />
-          );
-        })}
-
-        {this.renderAddQuery()}
-      </div>
-    );
-  },
-
-  onChoose(item) {
-    switch (item.text) {
-      case 'Query Builder':
-        this.handleAddQuery();
-        break;
-      case 'InfluxQL':
-        this.handleAddRawQuery();
-        break;
-    }
-  },
-
-  renderAddQuery() {
-    return (
-      <SimpleDropdown onChoose={this.onChoose} items={[{text: 'Query Builder'}, {text: 'InfluxQL'}]} className="panel--tab-new">
-        <span className="icon plus"></span>
-      </SimpleDropdown>
-    );
-  },
-});
-
-export default Panel;
diff --git a/ui/src/data_explorer/components/PanelBuilder.js b/ui/src/data_explorer/components/PanelBuilder.js
deleted file mode 100644
index e5b7890707..0000000000
--- a/ui/src/data_explorer/components/PanelBuilder.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import React, {PropTypes} from 'react';
-import {connect} from 'react-redux';
-import {bindActionCreators} from 'redux';
-import PanelList from './PanelList';
-import * as viewActions from '../actions/view';
-
-const {string, func} = PropTypes;
-const PanelBuilder = React.createClass({
-  propTypes: {
-    width: string,
-    actions: PropTypes.shape({
-      activatePanel: func.isRequired,
-      createPanel: func.isRequired,
-      deleteQuery: func.isRequired,
-      addQuery: func.isRequired,
-      editRawText: func.isRequired,
-      chooseNamespace: func.isRequired,
-      chooseMeasurement: func.isRequired,
-      toggleField: func.isRequired,
-      groupByTime: func.isRequired,
-      applyFuncsToField: func.isRequired,
-      chooseTag: func.isRequired,
-      groupByTag: func.isRequired,
-      toggleTagAcceptance: func.isRequired,
-      deletePanel: func.isRequired,
-    }).isRequired,
-    setActiveQuery: func.isRequired,
-    activePanelID: string,
-    activeQueryID: string,
-  },
-
-  handleCreateExplorer() {
-    this.props.actions.createPanel();
-  },
-
-  render() {
-    const {width, actions, setActiveQuery, activePanelID, activeQueryID} = this.props;
-
-    return (
-      <div className="panel-builder" style={{width}}>
-        <div className="btn btn-block btn-primary" onClick={this.handleCreateExplorer}><span className="icon graphline"></span>&nbsp;&nbsp;Create Graph</div>
-        <PanelList
-          actions={actions}
-          setActiveQuery={setActiveQuery}
-          activePanelID={activePanelID}
-          activeQueryID={activeQueryID}
-        />
-      </div>
-    );
-  },
-});
-
-function mapStateToProps() {
-  return {};
-}
-
-function mapDispatchToProps(dispatch) {
-  return {
-    actions: bindActionCreators(viewActions, dispatch),
-  };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(PanelBuilder);
diff --git a/ui/src/data_explorer/components/PanelList.js b/ui/src/data_explorer/components/PanelList.js
deleted file mode 100644
index c3d365e2d6..0000000000
--- a/ui/src/data_explorer/components/PanelList.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import React, {PropTypes} from 'react';
-import {connect} from 'react-redux';
-import _ from 'lodash';
-
-import Panel from './Panel';
-
-const {func, string, shape} = PropTypes;
-const PanelList = React.createClass({
-  propTypes: {
-    timeRange: shape({
-      upper: string,
-      lower: string,
-    }).isRequired,
-    panels: shape({}).isRequired,
-    queryConfigs: PropTypes.shape({}),
-    actions: shape({
-      activatePanel: func.isRequired,
-      deleteQuery: func.isRequired,
-      addQuery: func.isRequired,
-    }).isRequired,
-    setActiveQuery: func.isRequired,
-    activePanelID: string,
-    activeQueryID: string,
-  },
-
-  handleTogglePanel(panel) {
-    const panelID = panel.id === this.props.activePanelID ? null : panel.id;
-    this.props.actions.activatePanel(panelID);
-
-    // Reset the activeQueryID when toggling Exporations
-    this.props.setActiveQuery(null);
-  },
-
-  render() {
-    const {actions, panels, timeRange, queryConfigs, setActiveQuery, activeQueryID, activePanelID} = this.props;
-
-    return (
-      <div>
-        {Object.keys(panels).map((panelID) => {
-          const panel = panels[panelID];
-          const queries = panel.queryIds.map((configId) => queryConfigs[configId]);
-          const deleteQueryFromPanel = _.partial(actions.deleteQuery, panelID);
-          const addQueryToPanel = _.partial(actions.addQuery, panelID);
-          const allActions = Object.assign({}, actions, {
-            addQuery: addQueryToPanel,
-            deleteQuery: deleteQueryFromPanel,
-          });
-
-          return (
-            <Panel
-              key={panelID}
-              panel={panel}
-              queries={queries}
-              timeRange={timeRange}
-              onTogglePanel={this.handleTogglePanel}
-              setActiveQuery={setActiveQuery}
-              isExpanded={panelID === activePanelID}
-              actions={allActions}
-              activeQueryID={activeQueryID}
-            />
-          );
-        })}
-      </div>
-    );
-  },
-});
-
-function mapStateToProps(state) {
-  return {
-    timeRange: state.timeRange,
-    panels: state.panels,
-    queryConfigs: state.queryConfigs,
-  };
-}
-
-export default connect(mapStateToProps)(PanelList);
diff --git a/ui/src/data_explorer/components/QueryBuilder.js b/ui/src/data_explorer/components/QueryBuilder.js
new file mode 100644
index 0000000000..97b29958ac
--- /dev/null
+++ b/ui/src/data_explorer/components/QueryBuilder.js
@@ -0,0 +1,160 @@
+import React, {PropTypes} from 'react';
+import {bindActionCreators} from 'redux';
+import {connect} from 'react-redux';
+
+import QueryEditor from './QueryEditor';
+import QueryTabItem from './QueryTabItem';
+import SimpleDropdown from 'src/shared/components/SimpleDropdown';
+
+import * as viewActions from '../actions/view';
+const {
+  arrayOf,
+  func,
+  shape,
+  string,
+} = PropTypes;
+
+const QueryBuilder = React.createClass({
+  propTypes: {
+    queries: arrayOf(shape({})).isRequired,
+    timeRange: shape({
+      upper: string,
+      lower: string,
+    }).isRequired,
+    actions: shape({
+      chooseNamespace: func.isRequired,
+      chooseMeasurement: func.isRequired,
+      chooseTag: func.isRequired,
+      groupByTag: func.isRequired,
+      addQuery: func.isRequired,
+      deleteQuery: func.isRequired,
+      toggleField: func.isRequired,
+      groupByTime: func.isRequired,
+      toggleTagAcceptance: func.isRequired,
+      applyFuncsToField: func.isRequired,
+    }).isRequired,
+    height: string,
+    top: string,
+    setActiveQuery: func.isRequired,
+    activeQueryID: string,
+  },
+
+  handleSetActiveQuery(query) {
+    this.props.setActiveQuery(query.id);
+  },
+
+  handleAddQuery() {
+    this.props.actions.addQuery();
+  },
+
+  handleAddRawQuery() {
+    this.props.actions.addQuery({rawText: `SELECT "fields" from "db"."rp"."measurement"`});
+  },
+
+  handleDeleteQuery(query) {
+    this.props.actions.deleteQuery(query.id);
+  },
+
+  getActiveQuery() {
+    const {queries, activeQueryID} = this.props;
+    const activeQuery = queries.find((query) => query.id === activeQueryID);
+    const defaultQuery = queries[0];
+
+    return activeQuery || defaultQuery;
+  },
+
+  render() {
+    const {height, top} = this.props;
+    return (
+      <div className="query-builder" style={{height, top}}>
+        {this.renderQueryTabList()}
+        {this.renderQueryEditor()}
+      </div>
+    );
+  },
+
+  renderQueryEditor() {
+    const {timeRange, actions} = this.props;
+    const query = this.getActiveQuery();
+
+    if (!query) {
+      return (
+        <div className="qeditor--empty">
+          <h5>This Graph has no Queries</h5>
+          <br/>
+          <div className="btn btn-primary" role="button" onClick={this.handleAddQuery}>Add a Query</div>
+        </div>
+      );
+    }
+
+    return (
+      <QueryEditor
+        timeRange={timeRange}
+        query={this.getActiveQuery()}
+        actions={actions}
+        onAddQuery={this.handleAddQuery}
+      />
+    );
+  },
+
+  renderQueryTabList() {
+    const {queries} = this.props;
+    return (
+      <div className="query-builder--tabs">
+        <div className="query-builder--tabs-heading">
+          <h1>Queries</h1>
+          {this.renderAddQuery()}
+        </div>
+        {queries.map((q, i) => {
+          let queryTabText;
+          if (q.rawText) {
+            queryTabText = 'InfluxQL';
+          } else {
+            queryTabText = (q.measurement && q.fields.length !== 0) ? `${q.measurement}.${q.fields[0].field}` : 'Query';
+          }
+          return (
+            <QueryTabItem
+              isActive={this.getActiveQuery().id === q.id}
+              key={q.id + i}
+              query={q}
+              onSelect={this.handleSetActiveQuery}
+              onDelete={this.handleDeleteQuery}
+              queryTabText={queryTabText}
+            />
+          );
+        })}
+      </div>
+    );
+  },
+
+  onChoose(item) {
+    switch (item.text) {
+      case 'Query Builder':
+        this.handleAddQuery();
+        break;
+      case 'InfluxQL':
+        this.handleAddRawQuery();
+        break;
+    }
+  },
+
+  renderAddQuery() {
+    return (
+      <SimpleDropdown onChoose={this.onChoose} items={[{text: 'Query Builder'}, {text: 'InfluxQL'}]} className="panel--tab-new">
+        <span className="icon plus"></span>
+      </SimpleDropdown>
+    );
+  },
+});
+
+function mapStateToProps() {
+  return {};
+}
+
+function mapDispatchToProps(dispatch) {
+  return {
+    actions: bindActionCreators(viewActions, dispatch),
+  };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(QueryBuilder);
diff --git a/ui/src/data_explorer/components/QueryEditor.js b/ui/src/data_explorer/components/QueryEditor.js
index d3bcf4d7e6..1d8046c51b 100644
--- a/ui/src/data_explorer/components/QueryEditor.js
+++ b/ui/src/data_explorer/components/QueryEditor.js
@@ -1,6 +1,4 @@
 import React, {PropTypes} from 'react';
-import classNames from 'classnames';
-import _ from 'lodash';
 import selectStatement from '../utils/influxql/select';
 
 import DatabaseList from './DatabaseList';
@@ -9,12 +7,11 @@ import FieldList from './FieldList';
 import TagList from './TagList';
 import RawQueryEditor from './RawQueryEditor';
 
-const DB_TAB = 'databases';
-const MEASUREMENTS_TAB = 'measurments';
-const FIELDS_TAB = 'fields';
-const TAGS_TAB = 'tags';
-
-const {string, shape, func} = PropTypes;
+const {
+  string,
+  shape,
+  func,
+} = PropTypes;
 const QueryEditor = React.createClass({
   propTypes: {
     query: shape({
@@ -38,29 +35,17 @@ const QueryEditor = React.createClass({
 
   getInitialState() {
     return {
-      activeTab: DB_TAB,
       database: null,
       measurement: null,
     };
   },
 
-  componentWillReceiveProps(nextProps) {
-    const changingQueries = this.props.query.id !== nextProps.query.id;
-    if (changingQueries) {
-      this.setState({activeTab: DB_TAB});
-    }
-  },
-
   handleChooseNamespace(namespace) {
     this.props.actions.chooseNamespace(this.props.query.id, namespace);
-
-    this.setState({activeTab: MEASUREMENTS_TAB});
   },
 
   handleChooseMeasurement(measurement) {
     this.props.actions.chooseMeasurement(this.props.query.id, measurement);
-
-    this.setState({activeTab: FIELDS_TAB});
   },
 
   handleToggleField(field) {
@@ -91,15 +76,13 @@ const QueryEditor = React.createClass({
     this.props.actions.editRawText(this.props.query.id, text);
   },
 
-  handleClickTab(tab) {
-    this.setState({activeTab: tab});
-  },
-
   render() {
     return (
-      <div className="panel--tab-contents">
-        {this.renderQuery()}
-        {this.renderLists()}
+      <div className="query-builder--tab-contents">
+        <div>
+          {this.renderQuery()}
+          {this.renderLists()}
+        </div>
       </div>
     );
   },
@@ -110,7 +93,7 @@ const QueryEditor = React.createClass({
 
     if (!query.rawText) {
       return (
-        <div className="qeditor--query-preview">
+        <div className="query-builder--query-preview">
           <pre><code>{statement}</code></pre>
         </div>
       );
@@ -120,60 +103,32 @@ const QueryEditor = React.createClass({
   },
 
   renderLists() {
-    const {activeTab} = this.state;
-    return (
-      <div>
-        <div className="qeditor--tabs">
-          <div className="qeditor--tabs-heading">Schema Explorer</div>
-          <div onClick={_.wrap(DB_TAB, this.handleClickTab)} className={classNames("qeditor--tab", {active: activeTab === DB_TAB})}>Databases</div>
-          <div onClick={_.wrap(MEASUREMENTS_TAB, this.handleClickTab)} className={classNames("qeditor--tab", {active: activeTab === MEASUREMENTS_TAB})}>Measurements</div>
-          <div onClick={_.wrap(FIELDS_TAB, this.handleClickTab)} className={classNames("qeditor--tab", {active: activeTab === FIELDS_TAB})}>Fields</div>
-          <div onClick={_.wrap(TAGS_TAB, this.handleClickTab)} className={classNames("qeditor--tab", {active: activeTab === TAGS_TAB})}>Tags</div>
-        </div>
-        {this.renderList()}
-      </div>
-    );
-  },
-
-  renderList() {
     const {query} = this.props;
 
-    switch (this.state.activeTab) {
-      case DB_TAB:
-        return (
-          <DatabaseList
-            query={query}
-            onChooseNamespace={this.handleChooseNamespace}
-          />
-        );
-      case MEASUREMENTS_TAB:
-        return (
-          <MeasurementList
-            query={query}
-            onChooseMeasurement={this.handleChooseMeasurement}
-          />
-        );
-      case FIELDS_TAB:
-        return (
-          <FieldList
-            query={query}
-            onToggleField={this.handleToggleField}
-            onGroupByTime={this.handleGroupByTime}
-            applyFuncsToField={this.handleApplyFuncsToField}
-          />
-        );
-      case TAGS_TAB:
-        return (
-          <TagList
-            query={query}
-            onChooseTag={this.handleChooseTag}
-            onGroupByTag={this.handleGroupByTag}
-            onToggleTagAcceptance={this.handleToggleTagAcceptance}
-          />
-        );
-      default:
-        return <ul className="qeditor--list"></ul>;
-    }
+    return (
+      <div className="query-builder--columns">
+        <DatabaseList
+          query={query}
+          onChooseNamespace={this.handleChooseNamespace}
+        />
+        <MeasurementList
+          query={query}
+          onChooseMeasurement={this.handleChooseMeasurement}
+        />
+        <FieldList
+          query={query}
+          onToggleField={this.handleToggleField}
+          onGroupByTime={this.handleGroupByTime}
+          applyFuncsToField={this.handleApplyFuncsToField}
+        />
+        <TagList
+          query={query}
+          onChooseTag={this.handleChooseTag}
+          onGroupByTag={this.handleGroupByTag}
+          onToggleTagAcceptance={this.handleToggleTagAcceptance}
+        />
+      </div>
+    );
   },
 });
 
diff --git a/ui/src/data_explorer/components/QueryTabItem.js b/ui/src/data_explorer/components/QueryTabItem.js
index c3ac85fe34..e8edaad041 100644
--- a/ui/src/data_explorer/components/QueryTabItem.js
+++ b/ui/src/data_explorer/components/QueryTabItem.js
@@ -23,9 +23,9 @@ const QueryTabItem = React.createClass({
 
   render() {
     return (
-      <div className={classNames('panel--tab', {active: this.props.isActive})} onClick={this.handleSelect}>
-        <span className="panel--tab-label">{this.props.queryTabText}</span>
-        <span className="panel--tab-delete" onClick={this.handleDelete}></span>
+      <div className={classNames('query-builder--tab', {active: this.props.isActive})} onClick={this.handleSelect}>
+        <span className="query-builder--tab-label">{this.props.queryTabText}</span>
+        <span className="query-builder--tab-delete" onClick={this.handleDelete}></span>
       </div>
     );
   },
diff --git a/ui/src/data_explorer/components/RenamePanelModal.js b/ui/src/data_explorer/components/RenamePanelModal.js
deleted file mode 100644
index bffa495cca..0000000000
--- a/ui/src/data_explorer/components/RenamePanelModal.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import React, {PropTypes} from 'react';
-
-const RenamePanelModal = React.createClass({
-  propTypes: {
-    onConfirm: PropTypes.func.isRequired,
-    panel: PropTypes.shape({
-      id: PropTypes.string.isRequired,
-    }),
-  },
-
-  getInitialState() {
-    return {error: null};
-  },
-
-  componentDidMount() {
-    this.refs.name.focus();
-  },
-
-  render() {
-    const {panel} = this.props;
-
-    return (
-      <div className="modal fade in" id={`renamePanelModal-${panel.id}`} tabIndex="-1" role="dialog">
-        <div className="modal-dialog">
-          <div className="modal-content">
-            <div className="modal-header">
-              <button type="button" className="close" data-dismiss="modal" aria-label="Close">
-                <span aria-hidden="true">×</span>
-              </button>
-              <h4 className="modal-title">Rename Panel</h4>
-            </div>
-            <div className="modal-body">
-              {this.state.error ?
-                <div className="alert alert-danger" role="alert">{this.state.error}</div>
-                : null}
-              <div className="form-grid padding-top">
-                <div className="form-group col-md-8 col-md-offset-2">
-                  <input ref="name" name="renameExplorer" type="text" placeholder={panel.name} className="form-control input-lg" id="renameExplorer" required={true} />
-                </div>
-              </div>
-            </div>
-            <div className="modal-footer">
-              <button className="btn btn-info" data-dismiss="modal">Cancel</button>
-              <button onClick={this.handleConfirm} className="btn btn-success">Rename</button>
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-
-  handleConfirm() {
-    const name = this.refs.name.value;
-
-    if (name === '') {
-      this.setState({error: "Name can't be blank"});
-      return;
-    }
-
-    $(`#renamePanelModal-${this.props.panel.id}`).modal('hide'); // eslint-disable-line no-undef
-    this.refs.name.value = '';
-    this.setState({error: null});
-    this.props.onConfirm(name);
-  },
-});
-
-export default RenamePanelModal;
diff --git a/ui/src/data_explorer/components/Table.js b/ui/src/data_explorer/components/Table.js
index 12f71084f9..e236cf647a 100644
--- a/ui/src/data_explorer/components/Table.js
+++ b/ui/src/data_explorer/components/Table.js
@@ -33,6 +33,7 @@ const ChronoTable = React.createClass({
       text: string.isRequired,
     }),
     containerWidth: number.isRequired,
+    height: number,
   },
 
   getInitialState() {
@@ -45,6 +46,12 @@ const ChronoTable = React.createClass({
     };
   },
 
+  getDefaultProps() {
+    return {
+      height: 600,
+    };
+  },
+
   fetchCellData(query) {
     this.setState({isLoading: true});
     // second param is db, we want to leave this blank
@@ -81,30 +88,33 @@ const ChronoTable = React.createClass({
 
   // Table data as a list of array.
   render() {
-    const {containerWidth} = this.props;
+    const {containerWidth, height} = this.props;
     const {cellData, columnWidths, isLoading} = this.state;
     const {columns, values} = cellData;
 
-    const ownerHeight = 300;
+    // adjust height to proper value by subtracting the heights of the UI around it
+    // tab height, graph-container vertical padding, graph-heading height, multitable-header height
+    const stylePixelOffset = 136;
+
     const rowHeight = 34;
-    const height = 300;
     const width = 200;
-    const headerHeight = 40;
+    const headerHeight = 30;
     const minWidth = 70;
+    const styleAdjustedHeight = height - stylePixelOffset;
 
     if (!isLoading && !values.length) {
-      return <div>Your query returned no data</div>;
+      return <div className="generic-empty-state">Your query returned no data</div>;
     }
 
     return (
       <Table
         onColumnResizeEndCallback={this.handleColumnResize}
         isColumnResizing={false}
-        ownerHeight={ownerHeight}
         rowHeight={rowHeight}
         rowsCount={values.length}
         width={containerWidth}
-        height={height}
+        ownerHeight={styleAdjustedHeight}
+        height={styleAdjustedHeight}
         headerHeight={headerHeight}>
         {columns.map((columnName, colIndex) => {
           return (
diff --git a/ui/src/data_explorer/components/TagList.js b/ui/src/data_explorer/components/TagList.js
index 6667064174..066b0d00f5 100644
--- a/ui/src/data_explorer/components/TagList.js
+++ b/ui/src/data_explorer/components/TagList.js
@@ -36,14 +36,11 @@ const TagList = React.createClass({
     };
   },
 
-  componentDidMount() {
+  _getTags() {
     const {database, measurement, retentionPolicy} = this.props.query;
     const {source} = this.context;
-    if (!database || !measurement || !retentionPolicy) {
-      return;
-    }
-
     const sourceProxy = source.links.proxy;
+
     showTagKeys({source: sourceProxy, database, retentionPolicy, measurement}).then((resp) => {
       const {errors, tagKeys} = showTagKeysParser(resp.data);
       if (errors.length) {
@@ -61,6 +58,29 @@ const TagList = React.createClass({
     });
   },
 
+  componentDidMount() {
+    const {database, measurement, retentionPolicy} = this.props.query;
+    if (!database || !measurement || !retentionPolicy) {
+      return;
+    }
+
+    this._getTags();
+  },
+
+  componentDidUpdate(prevProps) {
+    const {database, measurement, retentionPolicy} = this.props.query;
+    const {database: prevDB, measurement: prevMeas, retentionPolicy: prevRP} = prevProps.query;
+    if (!database || !measurement || !retentionPolicy) {
+      return;
+    }
+
+    if (database === prevDB && measurement === prevMeas && retentionPolicy === prevRP) {
+      return;
+    }
+
+    this._getTags();
+  },
+
   handleAcceptReject(e) {
     e.stopPropagation();
     this.props.onToggleTagAcceptance();
@@ -70,11 +90,12 @@ const TagList = React.createClass({
     const {query} = this.props;
 
     return (
-      <div>
+      <div className="query-builder--column">
+        <div className="query-builder--column-heading">Tags</div>
         {(!query.database || !query.measurement || !query.retentionPolicy) ? null : <div className="qeditor--list-header">
           <div className="toggle toggle-sm">
-            <div onClick={this.handleAcceptReject} className={cx("toggle-btn", {active: query.areTagsAccepted})}>Accept</div>
-            <div onClick={this.handleAcceptReject} className={cx("toggle-btn", {active: !query.areTagsAccepted})}>Reject</div>
+            <div onClick={this.handleAcceptReject} className={cx("toggle-btn", {active: query.areTagsAccepted})}>=</div>
+            <div onClick={this.handleAcceptReject} className={cx("toggle-btn", {active: !query.areTagsAccepted})}>!=</div>
           </div>
         </div>}
         {this.renderList()}
diff --git a/ui/src/data_explorer/components/TagListItem.js b/ui/src/data_explorer/components/TagListItem.js
index 5970fd6ce3..4d2c3d6aa0 100644
--- a/ui/src/data_explorer/components/TagListItem.js
+++ b/ui/src/data_explorer/components/TagListItem.js
@@ -81,7 +81,10 @@ const TagListItem = React.createClass({
   },
 
   render() {
-    const itemClasses = classNames("qeditor--list-item tag-list__item", {open: this.state.isOpen});
+    const {tagKey, tagValues} = this.props;
+    const {isOpen} = this.state;
+    const itemClasses = classNames("qeditor--list-item tag-list__item", {open: isOpen});
+
     return (
       <div>
         <li className={itemClasses} onClick={this.handleClickKey}>
@@ -89,12 +92,15 @@ const TagListItem = React.createClass({
             <div className="tag-list__caret">
               <div className="icon caret-right"></div>
             </div>
-            {this.props.tagKey}
-            <span className="badge">{this.props.tagValues.length}</span>
+            {tagKey}
+            <span className="badge">{tagValues.length}</span>
+          </div>
+          <div
+            className={classNames('btn btn-info btn-xs tag-list__group-by', {active: this.props.isUsingGroupBy})}
+            onClick={this.handleGroupBy}>Group By {tagKey}
           </div>
-          <div className={classNames('btn btn-info btn-xs tag-list__group-by', {active: this.props.isUsingGroupBy})} onClick={this.handleGroupBy}>Group By</div>
         </li>
-        {this.state.isOpen ? this.renderTagValues() : null}
+        {isOpen ? this.renderTagValues() : null}
       </div>
     );
   },
diff --git a/ui/src/data_explorer/components/Visualization.js b/ui/src/data_explorer/components/Visualization.js
index 027a171c1a..d2f94d99a3 100644
--- a/ui/src/data_explorer/components/Visualization.js
+++ b/ui/src/data_explorer/components/Visualization.js
@@ -6,16 +6,24 @@ import LineGraph from 'shared/components/LineGraph';
 import MultiTable from './MultiTable';
 const RefreshingLineGraph = AutoRefresh(LineGraph);
 
+const {
+  arrayOf,
+  number,
+  shape,
+  string,
+} = PropTypes;
+
 const Visualization = React.createClass({
   propTypes: {
-    timeRange: PropTypes.shape({
-      upper: PropTypes.string,
-      lower: PropTypes.string,
+    timeRange: shape({
+      upper: string,
+      lower: string,
     }).isRequired,
-    queryConfigs: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
-    isActive: PropTypes.bool.isRequired,
-    name: PropTypes.string,
-    activeQueryIndex: PropTypes.number,
+    queryConfigs: arrayOf(shape({})).isRequired,
+    name: string,
+    activeQueryIndex: number,
+    height: string,
+    heightPixels: number,
   },
 
   contextTypes: {
@@ -32,20 +40,12 @@ const Visualization = React.createClass({
     };
   },
 
-  componentDidUpdate() {
-    if (this.props.isActive) {
-      this.panel.scrollIntoView();
-      // scrollIntoView scrolls slightly *too* far, so this adds some top offset.
-      this.panel.parentNode.scrollTop -= 10;
-    }
-  },
-
   handleToggleView() {
     this.setState({isGraphInView: !this.state.isGraphInView});
   },
 
   render() {
-    const {queryConfigs, timeRange, isActive, name, activeQueryIndex} = this.props;
+    const {queryConfigs, timeRange, activeQueryIndex, height, heightPixels} = this.props;
     const {source} = this.context;
     const proxyLink = source.links.proxy;
 
@@ -61,7 +61,7 @@ const Visualization = React.createClass({
     const isInDataExplorer = true;
 
     return (
-      <div ref={(p) => this.panel = p} className={classNames("graph", {active: isActive})}>
+      <div className={classNames("graph", {active: true})} style={{height}}>
         <div className="graph-heading">
           <div className="graph-title">
             {name || "Graph"}
@@ -73,7 +73,7 @@ const Visualization = React.createClass({
             </ul>
           </div>
         </div>
-        <div className="graph-container">
+        <div className={classNames("", {"graph-container": isGraphInView, "table-container": !isGraphInView})}>
           {isGraphInView ? (
             <RefreshingLineGraph
               queries={queries}
@@ -81,7 +81,7 @@ const Visualization = React.createClass({
               activeQueryIndex={activeQueryIndex}
               isInDataExplorer={isInDataExplorer}
               />
-          ) : <MultiTable queries={queries} />}
+          ) : <MultiTable queries={queries} height={heightPixels} />}
         </div>
       </div>
     );
diff --git a/ui/src/data_explorer/components/Visualizations.js b/ui/src/data_explorer/components/Visualizations.js
deleted file mode 100644
index aa577b0d6e..0000000000
--- a/ui/src/data_explorer/components/Visualizations.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import React, {PropTypes} from 'react';
-import {connect} from 'react-redux';
-import Visualization from './Visualization';
-
-const {shape, string} = PropTypes;
-
-const Visualizations = React.createClass({
-  propTypes: {
-    timeRange: shape({
-      upper: string,
-      lower: string,
-    }).isRequired,
-    panels: shape({}).isRequired,
-    queryConfigs: shape({}).isRequired,
-    width: string,
-    activePanelID: string,
-    activeQueryID: string,
-  },
-
-  render() {
-    const {panels, queryConfigs, timeRange, width, activePanelID} = this.props;
-
-    const visualizations = Object.keys(panels).map((panelID) => {
-      const panel = panels[panelID];
-      const queries = panel.queryIds.map((id) => queryConfigs[id]);
-      const isActive = panelID === activePanelID;
-
-      return <Visualization activeQueryIndex={this.getActiveQueryIndex(panelID)} name={panel.name} key={panelID} queryConfigs={queries} timeRange={timeRange} isActive={isActive} />;
-    });
-
-    return (
-      <div className="panels" style={{width}}>
-        {visualizations}
-      </div>
-    );
-  },
-
-  getActiveQueryIndex(panelID) {
-    const {activeQueryID, activePanelID, panels} = this.props;
-    const isPanelActive = panelID === activePanelID;
-
-    if (!isPanelActive) {
-      return -1;
-    }
-
-    if (activeQueryID === null) {
-      return 0;
-    }
-
-    return panels[panelID].queryIds.indexOf(activeQueryID);
-  },
-});
-
-function mapStateToProps(state) {
-  return {
-    panels: state.panels,
-    queryConfigs: state.queryConfigs,
-  };
-}
-
-export default connect(mapStateToProps)(Visualizations);
diff --git a/ui/src/data_explorer/containers/DataExplorer.js b/ui/src/data_explorer/containers/DataExplorer.js
index 2c7d37f4c9..1b56a7efba 100644
--- a/ui/src/data_explorer/containers/DataExplorer.js
+++ b/ui/src/data_explorer/containers/DataExplorer.js
@@ -1,9 +1,9 @@
 import React, {PropTypes} from 'react';
 import {connect} from 'react-redux';
-import PanelBuilder from '../components/PanelBuilder';
-import Visualizations from '../components/Visualizations';
+import QueryBuilder from '../components/QueryBuilder';
+import Visualization from '../components/Visualization';
 import Header from '../containers/Header';
-import ResizeContainer from 'shared/components/ResizeContainer';
+import ResizeContainer from 'src/shared/components/ResizeContainer';
 
 import {
   setTimeRange as setTimeRangeAction,
@@ -23,11 +23,11 @@ const DataExplorer = React.createClass({
         self: string.isRequired,
       }).isRequired,
     }).isRequired,
+    queryConfigs: PropTypes.shape({}),
     timeRange: shape({
       upper: string,
       lower: string,
     }).isRequired,
-    activePanel: string,
     setTimeRange: func.isRequired,
   },
 
@@ -55,7 +55,9 @@ const DataExplorer = React.createClass({
   },
 
   render() {
-    const {timeRange, setTimeRange, activePanel} = this.props;
+    const {timeRange, setTimeRange, queryConfigs} = this.props;
+    const {activeQueryID} = this.state;
+    const queries = Object.keys(queryConfigs).map((q) => queryConfigs[q]);
 
     return (
       <div className="data-explorer">
@@ -64,16 +66,17 @@ const DataExplorer = React.createClass({
           timeRange={timeRange}
         />
         <ResizeContainer>
-          <PanelBuilder
+          <Visualization
             timeRange={timeRange}
-            activePanelID={activePanel}
+            queryConfigs={queries}
             activeQueryID={this.state.activeQueryID}
-            setActiveQuery={this.handleSetActiveQuery}
+            activeQueryIndex={0}
           />
-          <Visualizations
+          <QueryBuilder
+            queries={queries}
             timeRange={timeRange}
-            activePanelID={activePanel}
-            activeQueryID={this.state.activeQueryID}
+            setActiveQuery={this.handleSetActiveQuery}
+            activeQueryID={activeQueryID}
           />
         </ResizeContainer>
       </div>
@@ -82,11 +85,11 @@ const DataExplorer = React.createClass({
 });
 
 function mapStateToProps(state) {
-  const {timeRange, dataExplorerUI} = state;
+  const {timeRange, queryConfigs} = state;
 
   return {
     timeRange,
-    activePanel: dataExplorerUI.activePanel,
+    queryConfigs,
   };
 }
 
diff --git a/ui/src/data_explorer/reducers/dataExplorerUI.js b/ui/src/data_explorer/reducers/dataExplorerUI.js
deleted file mode 100644
index 2140a9eba7..0000000000
--- a/ui/src/data_explorer/reducers/dataExplorerUI.js
+++ /dev/null
@@ -1,11 +0,0 @@
-export default function dataExplorerUI(state = {}, action) {
-  switch (action.type) {
-    case 'ACTIVATE_PANEL':
-    case 'CREATE_PANEL': {
-      const {panelID} = action.payload;
-      return {...state, activePanel: panelID};
-    }
-  }
-
-  return state;
-}
diff --git a/ui/src/data_explorer/reducers/index.js b/ui/src/data_explorer/reducers/index.js
index 4e4483f3bf..4a0171f2a7 100644
--- a/ui/src/data_explorer/reducers/index.js
+++ b/ui/src/data_explorer/reducers/index.js
@@ -1,11 +1,7 @@
 import queryConfigs from './queryConfigs';
-import panels from './panels';
 import timeRange from './timeRange';
-import dataExplorerUI from './dataExplorerUI';
 
 export {
   queryConfigs,
-  panels,
   timeRange,
-  dataExplorerUI,
 };
diff --git a/ui/src/data_explorer/reducers/panels.js b/ui/src/data_explorer/reducers/panels.js
deleted file mode 100644
index e04c585813..0000000000
--- a/ui/src/data_explorer/reducers/panels.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import update from 'react-addons-update';
-
-export default function panels(state = {}, action) {
-  switch (action.type) {
-    case 'CREATE_PANEL': {
-      const {panelID, queryID} = action.payload;
-      return {
-        ...state,
-        [panelID]: {id: panelID, queryIds: [queryID]},
-      };
-    }
-
-    case 'RENAME_PANEL': {
-      const {panelId, name} = action.payload;
-      return update(state, {
-        [panelId]: {
-          name: {$set: name},
-        },
-      });
-    }
-
-    case 'DELETE_PANEL': {
-      const {panelId} = action.payload;
-      return update(state, {$apply: (p) => {
-        const panelsCopy = Object.assign({}, p);
-        delete panelsCopy[panelId];
-        return panelsCopy;
-      }});
-    }
-
-    case 'ADD_QUERY': {
-      const {panelId, queryId} = action.payload;
-      return update(state, {
-        [panelId]: {
-          queryIds: {$push: [queryId]},
-        },
-      });
-    }
-
-    case 'DELETE_QUERY': {
-      const {panelId, queryId} = action.payload;
-      return update(state, {
-        [panelId]: {
-          queryIds: {$set: state[panelId].queryIds.filter((id) => id !== queryId)},
-        },
-      });
-    }
-  }
-
-  return state;
-}
diff --git a/ui/src/data_explorer/reducers/queryConfigs.js b/ui/src/data_explorer/reducers/queryConfigs.js
index 82c14d0ec1..370923e4bc 100644
--- a/ui/src/data_explorer/reducers/queryConfigs.js
+++ b/ui/src/data_explorer/reducers/queryConfigs.js
@@ -46,7 +46,6 @@ export default function queryConfigs(state = {}, action) {
       return nextState;
     }
 
-    case 'CREATE_PANEL':
     case 'ADD_KAPACITOR_QUERY':
     case 'ADD_QUERY': {
       const {queryID, options} = action.payload;
@@ -94,9 +93,9 @@ export default function queryConfigs(state = {}, action) {
     }
 
     case 'DELETE_QUERY': {
-      const {queryId} = action.payload;
+      const {queryID} = action.payload;
       const nextState = update(state, {$apply: (configs) => {
-        delete configs[queryId];
+        delete configs[queryID];
         return configs;
       }});
 
diff --git a/ui/src/localStorage.js b/ui/src/localStorage.js
index 2ab3593653..64c2622d82 100644
--- a/ui/src/localStorage.js
+++ b/ui/src/localStorage.js
@@ -19,13 +19,11 @@ export const loadLocalStorage = () => {
   }
 };
 
-export const saveToLocalStorage = ({panels, queryConfigs, timeRange, dataExplorerUI}) => {
+export const saveToLocalStorage = ({queryConfigs, timeRange}) => {
   try {
     window.localStorage.setItem('state', JSON.stringify({
-      panels,
       queryConfigs,
       timeRange,
-      dataExplorerUI,
     }));
   } catch (err) {
     console.error('Unable to save data explorer: ', JSON.parse(err)); // eslint-disable-line no-console
diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js
index 20bba644cc..ea36c088d5 100644
--- a/ui/src/shared/components/LineGraph.js
+++ b/ui/src/shared/components/LineGraph.js
@@ -79,7 +79,6 @@ export default React.createClass({
       labels,
       connectSeparatedPoints: true,
       labelsKMB: true,
-      height: 300,
       axisLineColor: '#383846',
       gridLineColor: '#383846',
       title,
diff --git a/ui/src/shared/components/ResizeContainer.js b/ui/src/shared/components/ResizeContainer.js
index 223402d582..5b30257bac 100644
--- a/ui/src/shared/components/ResizeContainer.js
+++ b/ui/src/shared/components/ResizeContainer.js
@@ -9,8 +9,8 @@ const ResizeContainer = React.createClass({
 
   getInitialState() {
     return {
-      leftWidth: '34%',
-      rightWidth: '66%',
+      topHeight: '60%',
+      bottomHeight: '40%',
       isDragging: false,
     };
   },
@@ -32,40 +32,43 @@ const ResizeContainer = React.createClass({
       return;
     }
 
-    const appWidth = parseInt(getComputedStyle(this.refs.resizeContainer).width, 10);
-    // handleOffSet moves the resize handle as many pixels as the side bar is taking up.
-    const handleOffSet = window.innerWidth - appWidth;
+    const appHeight = parseInt(getComputedStyle(this.refs.resizeContainer).height, 10);
+    // headingOffset moves the resize handle as many pixels as the page-heading is taking up.
+    const headingOffset = window.innerHeight - appHeight;
     const turnToPercent = 100;
-    const newLeftPanelPercent = Math.ceil(((e.pageX - handleOffSet) / (appWidth)) * turnToPercent);
-    const newRightPanelPercent = (turnToPercent - newLeftPanelPercent);
+    const newTopPanelPercent = Math.ceil(((e.pageY - headingOffset) / (appHeight)) * turnToPercent);
+    const newBottomPanelPercent = (turnToPercent - newTopPanelPercent);
 
     // Don't trigger a resize unless the change in size is greater than minResizePercentage
     const minResizePercentage = 0.5;
-    if (Math.abs(newLeftPanelPercent - parseFloat(this.state.leftWidth)) < minResizePercentage) {
+    if (Math.abs(newTopPanelPercent - parseFloat(this.state.topHeight)) < minResizePercentage) {
       return;
     }
 
     // Don't trigger a resize if the new sizes are too small
-    const minLeftPanelWidth = 371;
-    const minRightPanelWidth = 389;
-    if (((newLeftPanelPercent / turnToPercent) * appWidth) < minLeftPanelWidth || ((newRightPanelPercent / turnToPercent) * appWidth) < minRightPanelWidth) {
+    const minTopPanelHeight = 200;
+    const minBottomPanelHeight = 100;
+    const topHeightPixels = ((newTopPanelPercent / turnToPercent) * appHeight);
+    const bottomHeightPixels = ((newBottomPanelPercent / turnToPercent) * appHeight);
+
+    if (topHeightPixels < minTopPanelHeight || bottomHeightPixels < minBottomPanelHeight) {
       return;
     }
 
-    this.setState({leftWidth: `${(newLeftPanelPercent)}%`, rightWidth: `${(newRightPanelPercent)}%`});
+    this.setState({topHeight: `${(newTopPanelPercent)}%`, bottomHeight: `${(newBottomPanelPercent)}%`, topHeightPixels});
   },
 
   render() {
-    const {leftWidth, rightWidth, isDragging} = this.state;
-    const left = React.cloneElement(this.props.children[0], {width: leftWidth});
-    const right = React.cloneElement(this.props.children[1], {width: rightWidth});
-    const handle = <ResizeHandle isDragging={isDragging} onHandleStartDrag={this.handleStartDrag} />;
+    const {topHeight, bottomHeight, isDragging, topHeightPixels} = this.state;
+    const top = React.cloneElement(this.props.children[0], {height: topHeight, heightPixels: topHeightPixels});
+    const bottom = React.cloneElement(this.props.children[1], {height: bottomHeight, top: topHeight});
+    const handle = <ResizeHandle isDragging={isDragging} onHandleStartDrag={this.handleStartDrag} top={topHeight} />;
 
     return (
       <div className="resize-container page-contents" onMouseLeave={this.handleMouseLeave} onMouseUp={this.handleStopDrag} onMouseMove={this.handleDrag} ref="resizeContainer" >
-        {left}
+        {top}
         {handle}
-        {right}
+        {bottom}
       </div>
     );
   },
diff --git a/ui/src/shared/components/ResizeHandle.js b/ui/src/shared/components/ResizeHandle.js
index e1c0a54ecf..da51e23584 100644
--- a/ui/src/shared/components/ResizeHandle.js
+++ b/ui/src/shared/components/ResizeHandle.js
@@ -1,15 +1,24 @@
 import React from 'react';
 import cx from 'classnames';
 
-const {func, bool} = React.PropTypes;
+const {func, bool, string} = React.PropTypes;
 const ResizeHandle = React.createClass({
   propTypes: {
     onHandleStartDrag: func.isRequired,
     isDragging: bool.isRequired,
+    top: string,
   },
 
   render() {
-    return <div className={cx("resizer__handle", {dragging: this.props.isDragging})} ref="resizer" onMouseDown={this.props.onHandleStartDrag} />;
+    const {isDragging, onHandleStartDrag, top} = this.props;
+
+    return (
+      <div
+        className={cx("resizer__handle", {dragging: isDragging})}
+        onMouseDown={onHandleStartDrag}
+        style={{top}}
+      />
+    );
   },
 });
 
diff --git a/ui/src/style/components/dygraphs.scss b/ui/src/style/components/dygraphs.scss
index 16301b2257..991c3a9e67 100644
--- a/ui/src/style/components/dygraphs.scss
+++ b/ui/src/style/components/dygraphs.scss
@@ -82,21 +82,25 @@
 .dygraph-axis-label {
   color: $g11-sidewalk !important;
   font-weight: 500 !important;
+  user-select: none;
 }
 .dygraph-axis-label-y {
   padding: 0 9px 0 0 !important;
   text-align: left !important;
   left: 0 !important;
+  user-select: none;
 }
 .dygraph-axis-label-y2 {
   padding: 0 0 0 9px !important;
   text-align: right !important;
+  user-select: none;
 }
 .graph-container > div > div > div > div {}
 
 /* Vertical Axis Labels */
 .dygraph-ylabel,
 .dygraph-y2label {
+  user-select: none;
   position: absolute;
   width: 100%;
   text-align: center;
diff --git a/ui/src/style/components/group-by-time-dropdown.scss b/ui/src/style/components/group-by-time-dropdown.scss
index 134be12dc4..12650a7566 100644
--- a/ui/src/style/components/group-by-time-dropdown.scss
+++ b/ui/src/style/components/group-by-time-dropdown.scss
@@ -1,4 +1,4 @@
-.group-by-time-dropdown .dropdown-toggle {
+  .group-by-time-dropdown .dropdown-toggle {
   width: 70px;
 }
 .group-by-time {
@@ -17,6 +17,7 @@
     border-style: solid;
     border-color: $g5-pepper;
     border-width: 2px;
+    background-color: $g3-castle;
   }
   .dropdown-toggle {
     border-radius: 0px 3px 3px 0;
diff --git a/ui/src/style/components/resizer.scss b/ui/src/style/components/resizer.scss
index 245622977c..1822ba1c99 100644
--- a/ui/src/style/components/resizer.scss
+++ b/ui/src/style/components/resizer.scss
@@ -10,12 +10,12 @@ $resizer-color-hover: $g8-storm;
 $resizer-color-active: $c-pool;
 
 .resizer__handle {
-  top: 0;
+  top: 60%;
   left: 0;
-  width: $resizer-click-area;
-  margin-left: -$resizer-click-area/2;
-  margin-right: -$resizer-click-area/2;
-  height: 100%;
+  height: $resizer-click-area;
+  margin-top: -$resizer-click-area/2;
+  margin-bottom: -$resizer-click-area/2;
+  width: 100%;
   z-index: 2;
   user-select: none;
   -webkit-user-select: none;
@@ -31,7 +31,7 @@ $resizer-color-active: $c-pool;
     position: absolute;
     top: 50%;
     left: 50%;
-    transform: translate(-50%,-50%) rotate(90deg);
+    transform: translate(-50%,-50%);
     width: 130px;
     height: $resizer-handle-width;
     line-height: $resizer-handle-width;
@@ -48,18 +48,18 @@ $resizer-color-active: $c-pool;
     content: '';
     display: block;
     position: absolute;
-    top: 0;
-    left: 50%;
-    transform: translateX(-50%);
-    height: 100%;
-    width: $resizer-line-width;
+    top: 50%;
+    left: 0;
+    transform: translateY(-50%);
+    width: 100%;
+    height: $resizer-line-width;
     background-color: $resizer-color;
     box-shadow: 0 0 0 transparent;
     transition:
       background-color 0.19s ease;
   }
   &:hover {
-    cursor: ew-resize;
+    cursor: ns-resize;
 
     &:before {
       background-color: $resizer-color-hover;
@@ -85,4 +85,4 @@ $resizer-color-active: $c-pool;
   display: flex;
   flex-direction: row;
   align-items: stretch;
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/modules/variables.scss b/ui/src/style/modules/variables.scss
index 352528d929..a8ecc3faed 100644
--- a/ui/src/style/modules/variables.scss
+++ b/ui/src/style/modules/variables.scss
@@ -11,4 +11,4 @@ $chronograf-page-header-height: 60px;
 $sidebar-tier1-height:  56px;
 
 // Data Explorer
-$explorer-page-padding: 18px;
+$explorer-page-padding: $page-wrapper-padding;
diff --git a/ui/src/style/pages/data-explorer.scss b/ui/src/style/pages/data-explorer.scss
index 918bb23cba..ae420deee0 100644
--- a/ui/src/style/pages/data-explorer.scss
+++ b/ui/src/style/pages/data-explorer.scss
@@ -15,18 +15,30 @@
 
   .page-header {
     padding-left: $explorer-page-padding;
-    padding-right: ($explorer-page-padding + $scrollbar-width);
+    padding-right: $explorer-page-padding;
   }
   .page-header__container {
     max-width: 100%;
   }
+  .page-contents {
+    overflow: hidden;
+  }
 }
 
+$query-editor-gutter: 16px;
+$query-editor-tab-inactive: $g2-kevlar;
+$query-editor-tab-active: $g3-castle;
+$query-editor-height: 250px;
+$graph-bg-color: $g3-castle;
+$graph-active-color: $g4-onyx;
+$graph-radius: 4px;
+$de-vertical-margin: 16px;
+$dygraphs-legend-offset: 32px;
+$de-graph-heading-height: 44px;
 
 // DE Specific components
+@import 'data-explorer/query-builder';
 @import 'data-explorer/page-header';
-@import 'data-explorer/panel-builder';
-@import 'data-explorer/panel';
 @import 'data-explorer/query-editor';
 @import 'data-explorer/raw-text';
 @import 'data-explorer/tag-list';
diff --git a/ui/src/style/pages/data-explorer/panel-builder.scss b/ui/src/style/pages/data-explorer/panel-builder.scss
deleted file mode 100644
index d71cf7bc7e..0000000000
--- a/ui/src/style/pages/data-explorer/panel-builder.scss
+++ /dev/null
@@ -1,15 +0,0 @@
-.panel-builder {
-  width: 399px;
-  overflow-x: hidden;
-  background: $g1-raven;
-  padding: $explorer-page-padding;
-  @include gradient-v($g2-kevlar,$g0-obsidian);
-
-  &::-webkit-scrollbar { 
-    display: none; 
-  }
-
-  > .btn {
-    margin-bottom: 6px;
-  }
-}
\ No newline at end of file
diff --git a/ui/src/style/pages/data-explorer/panel.scss b/ui/src/style/pages/data-explorer/panel.scss
deleted file mode 100644
index 0e318e4aad..0000000000
--- a/ui/src/style/pages/data-explorer/panel.scss
+++ /dev/null
@@ -1,218 +0,0 @@
-.panels {
-  padding: $explorer-page-padding;
-  overflow: auto;
-  user-select: none;
-  -webkit-touch-callout: none;
-  -webkit-user-select: none;
-  -khtml-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-  width: 100%;
-  @include gradient-v($g2-kevlar,$g0-obsidian);
-  @include custom-scrollbar($g2-kevlar,$c-pool);
-}
-
-.panel {
-  display: block;
-  background-color: $g3-castle;
-  border-radius: $radius;
-  margin-bottom: 6px;
-  transition: background-color 0.25s ease;
-  border: 0;
-
-  &:hover {
-    background-color: $g4-onyx;
-  }
-
-  // For when an panel item is open
-  &.active {
-    background-color: $g4-onyx;
-    
-    .panel--name {
-      color: $g20-white;
-
-      .icon {
-        transform: translateY(-50%) rotate(90deg);
-      }
-    }
-  }
-}
-// panel Header Bar
-.panel--header {
-  align-items: center;
-  text-align: center;
-  display: flex;
-  height: 36px;
-  padding: 0 11px;
-  cursor: pointer;
-  align-items: center;
-  justify-content: space-between;
-  border-radius: $radius;
-}
-.panel--name {
-  color: $g13-mist;
-  font-weight: 600;
-  font-size: 14px;
-  position: relative;
-  padding-left: 16px;
-  transition: color 0.25s ease;
-
-  .icon.caret-right {
-    position: absolute;
-    left: 0;
-    top: 50%;
-    transform: translateY(-50%) rotate(0deg);
-    font-size: 0.75em;
-    transition: transform 0.25s ease;
-  }
-
-  &:hover {
-    color: $g17-whisper;
-  }
-}
-.panel--actions {
-  display: flex;
-  align-items: center;
-}
-.panel--action {
-  width: 24px;
-  height: 24px;
-  border: 0;
-  background-color: transparent;
-  color: $g9-mountain;
-  margin-left: 2px;
-  transition: color 0.25s ease;
-
-  &:hover {
-    cursor: pointer;
-    color: $g18-cloud;
-  }
-}
-
-// Tabs
-.panel--tabs {
-  display: flex;
-  background-color: $g4-onyx;
-  padding: 0 11px;
-}
-.panel--tab {
-  display: flex;
-  align-items: center;
-  color: $g11-sidewalk;
-  background: $g5-pepper;
-  height: 28px;
-  margin-right: 2px;
-  border-radius: $radius $radius 0 0;
-  cursor: pointer;
-  padding: 0 8px 0 8px;
-  transition:
-      color 0.25s ease,
-      background-color 0.25s ease;
-
-  &:hover {
-    color: $g18-cloud;
-    background-color: $g6-smoke;
-  }
-  &.active {
-    background: $g6-smoke;
-    color: $g15-platinum;
-  }
-
-  &-delete {
-    margin: 0 -4px 0 1px;
-    width: 16px;
-    height: 16px;
-    background-color: transparent;
-    display: inline-block;
-    vertical-align: text-top;
-    position: relative;
-
-    &:before,
-    &:after {
-      display: block;
-      content: '';
-      width: 8px;
-      height: 2px;
-      background-color: $g8-storm;
-      transition:
-        background-color 0.25s ease;
-      position: absolute;
-      top: 50%;
-      left: 50%;
-    }
-    &:before {
-      transform: translate(-50%,-50%) rotate(45deg);
-    }
-    &:after {
-      transform: translate(-50%,-50%) rotate(-45deg);
-    }
-
-    &:hover {
-      &:before,
-      &:after {
-        background-color: $c-dreamsicle;
-      }
-    }
-  }
-}
-.panel--tab-new {
-  > .dropdown-toggle {
-    height: 28px !important;
-    border-radius: $radius $radius 0 0;
-
-    > .icon {
-      margin: 0;
-      font-size: 12px;
-      position: relative;
-      top: -1px;
-    }
-  }
-  > .dropdown-menu {
-    width: 108px !important;
-    min-width: 108px !important;
-    max-width: 108px !important;
-  }
-}
-.panel--tab-label {
-  display: inline-block;
-  font-size: 12px;
-  font-weight: 600;
-  white-space: nowrap;
-  overflow: hidden;
-  max-width: 177px;
-  text-overflow: ellipsis;
-}
-
-/*
-  Tab Contents
-  -------------------------------------------
-*/
-.panel--tab-contents {
-  padding: 6px;
-  background-color: $g6-smoke;
-  border-radius: 0 0 $radius $radius;
-}
-
-
-/* Time Range Selector */
-.time-range-dropdown {
-  display: inline-block;
-
-  .dropdown-toggle {
-    width: 160px;
-  }
-}
-
-.panel__header-actions {
-  display: flex;
-
-  * {
-    margin-left: 5px;
-  }
-}
-
-.alert.alert-rawquery {
-  border-color: $g5-pepper;
-  border-color: $g6-smoke;
-  color: $g12-forge;
-}
diff --git a/ui/src/style/pages/data-explorer/query-builder.scss b/ui/src/style/pages/data-explorer/query-builder.scss
new file mode 100644
index 0000000000..185b337d6e
--- /dev/null
+++ b/ui/src/style/pages/data-explorer/query-builder.scss
@@ -0,0 +1,218 @@
+.query-builder {
+  position: absolute;
+  width: calc(100% - #{($explorer-page-padding * 2)});
+  left: $explorer-page-padding;
+  height: 40%;
+  top: 60%;
+  border: 0;
+  display: flex;
+  align-items: stretch;
+  justify-content: space-between;
+}
+
+// Tabs
+.query-builder--tabs {
+  display: flex;
+  width: 250px;
+  margin-top: $de-vertical-margin;
+  height: calc(100% - #{($de-vertical-margin * 2)});
+  flex-direction: column;
+  align-items: stretch;
+  @include gradient-v($g3-castle,$g1-raven);
+  border-radius: $radius 0 0 $radius;
+}
+.query-builder--tabs-heading {
+  height: 60px;
+  padding: 0 9px 0 16px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+
+  h1 {
+    font-size: 17px;
+    font-weight: 400;
+    text-transform: uppercase;
+    color: $g18-cloud;
+    margin: 0;
+  }
+}
+.query-builder--tab {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  color: $g11-sidewalk;
+  background: transparent;
+  height: 30px;
+  cursor: pointer;
+  padding: 0 8px 0 16px;
+  transition:
+      color 0.25s ease,
+      background-color 0.25s ease;
+
+  &:hover {
+    color: $g15-platinum;
+    background-color: $g4-onyx;
+  }
+  &.active {
+    color: $g18-cloud;
+    background: $g5-pepper;
+  }
+
+  &-delete {
+    margin: 0;
+    width: 16px;
+    height: 16px;
+    background-color: transparent;
+    display: inline-block;
+    vertical-align: text-top;
+    position: relative;
+
+    &:before,
+    &:after {
+      display: block;
+      content: '';
+      width: 8px;
+      height: 2px;
+      background-color: $g8-storm;
+      transition:
+        background-color 0.25s ease;
+      position: absolute;
+      top: 50%;
+      left: 50%;
+    }
+    &:before {
+      transform: translate(-50%,-50%) rotate(45deg);
+    }
+    &:after {
+      transform: translate(-50%,-50%) rotate(-45deg);
+    }
+
+    &:hover {
+      &:before,
+      &:after {
+        background-color: $c-dreamsicle;
+      }
+    }
+  }
+}
+.panel--tab-new {
+  > .dropdown-toggle {
+    height: 30px !important;
+    border-radius: $radius;
+    background-color: $c-pool;
+    color: $g20-white !important;
+    padding: 0;
+
+    > .icon {
+      margin: 0;
+      font-size: 12px;
+      position: relative;
+      top: -1px;
+    }
+    &:hover {
+      background-color: $c-laser;
+    }
+  }
+  > .dropdown-menu {
+    width: 108px !important;
+    min-width: 108px !important;
+    max-width: 108px !important;
+  }
+}
+.panel--tab-new.open {
+  > .dropdown-toggle,
+  > .dropdown-toggle:hover {
+    background-color: $c-laser !important;
+    color: $g20-white !important;
+  }
+}
+.query-builder--tab-label {
+  display: inline-block;
+  font-size: 12px;
+  font-weight: 600;
+  white-space: nowrap;
+  overflow: hidden;
+  max-width: 177px;
+  text-overflow: ellipsis;
+}
+
+/*
+  Tab Contents
+  -------------------------------------------
+*/
+$query-builder--column-heading-height: 60px;
+.query-builder--tab-contents {
+  width: 100%;
+  margin-top: $de-vertical-margin;
+  height: calc(100% - #{($de-vertical-margin * 2)});
+  background-color: $g4-onyx;
+  border-radius: 0 $radius $radius 0;
+  overflow: hidden;
+  position: relative;
+}
+.query-builder--tab-contents > div {
+  position: absolute;
+  top: 4px;
+  left: 4px;
+  width: calc(100% - 8px);
+  height: calc(100% - 8px);
+}
+.query-builder--columns {
+  position: absolute;
+  width: 100%;
+  height: calc(100% - 60px);
+  top: 60px;
+}
+.query-builder--column-heading {
+  width: 100%;
+  height: $query-builder--column-heading-height;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  font-weight: 600;
+  color: $g13-mist;
+  padding: 0 9px;
+  line-height: $query-builder--column-heading-height;
+  border-bottom: 2px solid $g5-pepper;
+}
+.query-builder--column {
+  position: absolute;
+  width: 25%;
+  height: 100%;
+  top: 0;
+
+  .qeditor--list {
+    position: absolute;
+    top: $query-builder--column-heading-height;
+    height: calc(100% - #{$query-builder--column-heading-height});
+    width: 100%;
+    left: 0;
+    padding: 0;
+    overflow: auto;
+    overflow-x: hidden;
+    overflow-y: scroll;
+    @include custom-scrollbar($g4-onyx,$c-pool);
+    background-color: $g4-onyx;
+  }
+}
+.query-builder--column:nth-of-type(1) { left: 0; }
+.query-builder--column:nth-of-type(2) { left: 25%; }
+.query-builder--column:nth-of-type(3) { left: 50%; }
+.query-builder--column:nth-of-type(4) { left: 75%; }
+
+/* Time Range Selector */
+.time-range-dropdown {
+  display: inline-block;
+
+  .dropdown-toggle {
+    width: 160px;
+  }
+}
+
+.alert.alert-rawquery {
+  border-color: $g5-pepper;
+  border-color: $g6-smoke;
+  color: $g12-forge;
+}
diff --git a/ui/src/style/pages/data-explorer/query-editor.scss b/ui/src/style/pages/data-explorer/query-editor.scss
index 80172b717a..5891466da0 100644
--- a/ui/src/style/pages/data-explorer/query-editor.scss
+++ b/ui/src/style/pages/data-explorer/query-editor.scss
@@ -5,12 +5,8 @@
   Abbreviated as "qeditor"
 
 */
-$query-editor-gutter: 16px;
-$query-editor-tab-inactive: $g2-kevlar;
-$query-editor-tab-active: $g3-castle;
-$query-editor-height: 250px;
 
-.qeditor--query-preview {
+.query-builder--query-preview {
   position: relative;
 
   pre {
@@ -18,11 +14,10 @@ $query-editor-height: 250px;
     border: 0;
     background-color: $query-editor-tab-inactive;
     color: $c-pool;
-    border-radius: $radius-small $radius-small 0 0;
-    border-bottom: 2px solid $query-editor-tab-active;
+    border-radius: $radius;
     margin-bottom: 0;
     overflow: auto;
-    min-height: 3.25em;
+    height: 56px;
     @include custom-scrollbar($query-editor-tab-inactive, $c-pool);
 
     code {
@@ -90,22 +85,23 @@ $query-editor-height: 250px;
     list-style-type: none;
     margin: 0;
     font-size: 12px;
-    padding: 4px 9px 4px 18px;
+    font-weight: 500;
+    padding: 4px 9px;
     transition:
       color 0.25s ease,
       background-color 0.25s ease;
 
     &:hover {
-      background-color: $g4-onyx;
-      color: $g17-whisper;
+      background-color: $g5-pepper;
+      color: $g15-platinum;
       cursor: pointer;
     }
   }
   &-radio {
     &.active {
       color: $g20-white;
-      background-color: $g4-onyx;
-      font-weight: 600;
+      background-color: $g5-pepper;
+      font-weight: 700;
     }
   }
   &-checkbox {
@@ -169,11 +165,18 @@ $query-editor-height: 250px;
       }
     }
   }
-  &-header {
-    position: relative;
-    background-color: $query-editor-tab-active;
-      padding: 8px 18px 0px 18px;
-  }
+}
+.qeditor--list-header {
+  position: absolute;
+  top: 15px;
+  right: 16px;
+  width: calc(60% - 16px);
+  height: 30px;
+  padding: 0;
+  z-index: 10;
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
 }
 
 // List empty state
@@ -184,8 +187,7 @@ $query-editor-height: 250px;
   width: 100%;
   padding: 18px 0;
   height: $query-editor-height;
-  background-color: $query-editor-tab-active;
-  border-radius: 0 0 $radius $radius;
+  background-color: transparent;
 }
 
 // Hidden dropdowns
@@ -210,7 +212,7 @@ $query-editor-height: 250px;
   height: 30px;
   border-radius: 15px;
   font-size: 13px;
-  padding-left: 38px;
+  padding-left: 28px;
   outline: none;
   color: $g20-white;
   font-weight: 700;
@@ -244,12 +246,12 @@ $query-editor-height: 250px;
   }
   + .icon {
     position: absolute;
-    top: calc(50% + 5px);
-    left: calc(19px * 2);
+    top: 50%;
+    left: 11px;
     transform: translateY(-50%);
     color: $g10-wolf;
     transition: color 0.25s ease;
     font-size: 12px;
     z-index: 2;
   }
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/pages/data-explorer/raw-text.scss b/ui/src/style/pages/data-explorer/raw-text.scss
index 7157001e62..4419924728 100644
--- a/ui/src/style/pages/data-explorer/raw-text.scss
+++ b/ui/src/style/pages/data-explorer/raw-text.scss
@@ -26,12 +26,12 @@ $raw-text-color: $c-comet;
   @include custom-scrollbar($g2-kevlar, $raw-text-color);
   display: block;
   width: 100%;
-  height: 100px;
+  height: 56px;
   background-color: $g2-kevlar;
   border: 2px solid $g2-kevlar;
   color: $raw-text-color;
   padding: (9px - 2px);
-  border-radius: 3px 3px 0 0;
+  border-radius: $radius;
   line-height: 1.5em;
   -webkit-appearance: none;
   -moz-appearance: none;
diff --git a/ui/src/style/pages/data-explorer/tag-list.scss b/ui/src/style/pages/data-explorer/tag-list.scss
index 3dbf18c8e1..1d011cc14b 100644
--- a/ui/src/style/pages/data-explorer/tag-list.scss
+++ b/ui/src/style/pages/data-explorer/tag-list.scss
@@ -1,10 +1,15 @@
 .tag-list {
 
   &__item {
+    height: 30px;
     display: flex;
     align-items: center;
     justify-content: space-between;
 
+    &:hover .tag-list__group-by {
+      display: flex;
+    }
+
     &.open {
       font-weight: 600;
       color: $g20-white;
@@ -63,7 +68,7 @@
       opacity: 0;
       background-color: $c-pool;
       border-radius: 50%;
-      transition: 
+      transition:
         transform 0.25s ease,
         opacity 0.25s ease;
     }
@@ -124,7 +129,7 @@
       color: $g10-wolf;
       font-weight: 500;
     }
-    &:-ms-input-placeholder {  
+    &:-ms-input-placeholder {
       color: $g10-wolf;
       font-weight: 500;
     }
@@ -148,6 +153,7 @@
 }
 
 .tag-list__group-by {
+  display: none;
   background-color: $g5-pepper;
   border-color: $g5-pepper;
   color: $g13-mist !important;
@@ -165,6 +171,7 @@
     border-color: $g6-smoke;
   }
   &.active {
+    display: flex;
     background: $c-pool;
     border-color: $c-pool;
 
@@ -173,4 +180,4 @@
       border-color: $c-laser;
     }
   }
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/pages/data-explorer/visualization.scss b/ui/src/style/pages/data-explorer/visualization.scss
index 8665bf3fb8..a6bb70e953 100644
--- a/ui/src/style/pages/data-explorer/visualization.scss
+++ b/ui/src/style/pages/data-explorer/visualization.scss
@@ -1,24 +1,19 @@
-$graph-bg-color: $g3-castle;
-$graph-active-color: $g4-onyx;
-$graph-radius: 4px;
-
-$dygraphs-legend-offset: 32px;
-
 .graph {
-  position: relative;
-  margin-bottom: 18px;
-
-  &:last-child {
-    margin-bottom: 100%;
-  }
+  position: absolute;
+  width: calc(100% - #{($explorer-page-padding * 2)});
+  left: $explorer-page-padding;
+  top: 0;
+  height: 60%;
 }
 .graph-heading {
+  position: relative;
+  top: $de-vertical-margin;
   background-color: $graph-bg-color;
   border-radius: $graph-radius $graph-radius 0 0;
   display: flex;
   align-items: center;
   justify-content: space-between;
-  height: 44px;
+  height: $de-graph-heading-height;
   padding: 0 16px;
   transition:
     background-color 0.25s ease;
@@ -39,6 +34,41 @@ $dygraphs-legend-offset: 32px;
   display: flex;
   align-items: center;
 }
+.table-container {
+  background-color: $graph-bg-color;
+  border-radius: 0 0 $graph-radius $graph-radius;
+  padding: 8px 16px;
+  position: relative;
+  top: $de-vertical-margin;
+  height: calc(100% - #{$de-graph-heading-height} - #{($de-vertical-margin * 2)});
+
+  & > div {
+    position: absolute;
+    width: calc(100% - #{($de-vertical-margin * 2)});
+    height: calc(100% - #{$de-vertical-margin});
+    top: ($de-vertical-margin/2);
+    left: $de-vertical-margin;;
+  }
+  & > div .multi-table__tabs {
+    position: absolute;
+    height: 30px;
+    width: 100%;
+  }
+  & > div > div:last-child {
+    position: absolute;
+    top: 30px;
+    height: calc(100% - 30px) !important;
+    width: 100%;
+  }
+  .fixedDataTableLayout_main {
+    height: 100% !important;
+  }
+  .generic-empty-state {
+    background-color: $g6-smoke;
+    padding: 50px 0;
+    height: 100%;
+  }
+}
 .graph-container {
   background-color: $graph-bg-color;
   border-radius: 0 0 $graph-radius $graph-radius;
@@ -48,6 +78,30 @@ $dygraphs-legend-offset: 32px;
   transition:
     background-color 0.25s ease;
 }
+.data-explorer .graph-container {
+  top: $de-vertical-margin;
+  height: calc(100% - #{$de-graph-heading-height} - #{($de-vertical-margin * 2)});
+  padding: 0;
+
+  & > div {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+  }
+  & > div > div {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    padding: 8px 16px;
+    // width: calc(100% - #{($de-vertical-margin * 2)});
+    // height: calc(100% - #{$de-vertical-margin});
+    // top: ($de-vertical-margin / 2);
+    // left: $de-vertical-margin;
+  }
+  & > div > div > div:first-child {
+    height: 100% !important;
+  }
+}
 
 
 /* Active State */
@@ -144,4 +198,4 @@ $dygraphs-legend-offset: 32px;
     background-color: $g6-smoke;
     color: $g14-chromium;
   }
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/pages/kapacitor.scss b/ui/src/style/pages/kapacitor.scss
index 27873e039a..3e73641059 100644
--- a/ui/src/style/pages/kapacitor.scss
+++ b/ui/src/style/pages/kapacitor.scss
@@ -219,6 +219,34 @@ div.qeditor.kapacitor-metric-selector {
   .kapacitor-tab-list {
     background-color: $kapacitor-graphic-color;
     border-radius: 0 0 $kap-radius-lg $kap-radius-lg;
+
+    .query-builder--column {
+      position: relative;
+      top: initial;
+      left: initial;
+      width: 100%;
+      height: 190px;
+
+      .qeditor--list-header {
+        width: 50%;
+        top: -34px;
+        right: 0;
+        z-index: 5;
+      }
+      .qeditor--list {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+      }
+      .group-by-time-dropdown {
+        width: 70px;
+      }
+    }
+    .query-builder--column-heading {
+      display: none;
+    }
   }
   .qeditor--list {
     overflow: auto;
diff --git a/ui/src/style/theme/theme-dark.scss b/ui/src/style/theme/theme-dark.scss
index 80fccd25d9..361c833c0a 100644
--- a/ui/src/style/theme/theme-dark.scss
+++ b/ui/src/style/theme/theme-dark.scss
@@ -443,7 +443,7 @@ $toggle-border: 2px;
   .toggle-btn {
     height: ($toggle-height-sm - ($toggle-border * 2));
     line-height: ($toggle-height-sm - ($toggle-border * 2));
-    padding: 0 $toggle-padding-sm;
+    padding: 0 16px;
     font-size: $toggle-font-sm;
     font-weight: 600;
   }