diff --git a/packages/jaeger-ui/src/components/DeepDependencies/traces.tsx b/packages/jaeger-ui/src/components/DeepDependencies/traces.tsx
new file mode 100644
index 0000000000..d9a01ede6e
--- /dev/null
+++ b/packages/jaeger-ui/src/components/DeepDependencies/traces.tsx
@@ -0,0 +1,154 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import React, { Component } from 'react';
+import { History as RouterHistory, Location } from 'history';
+import _get from 'lodash/get';
+import { connect } from 'react-redux';
+import { getUrlState } from './url';
+import { getUrl } from '../SearchTracePage/url';
+
+import Graph from './Graph';
+import { extractUiFindFromState, TExtractUiFindFromStateReturn } from '../common/UiFindInput';
+import { EDirection, TDdgModel, TDdgModelParams, TDdgSparseUrlState } from '../../model/ddg/types';
+import TGraph, { makeGraph } from '../../model/ddg/Graph';
+import { encodeDistance } from '../../model/ddg/visibility-codec';
+import { ReduxState } from '../../types';
+
+import './index.css';
+import transformDdgData from '../../model/ddg/transformDdgData';
+import transformTracesToPaths from '../../model/ddg/transformTracesToPaths';
+import HopsSelector from './Header/HopsSelector';
+
+type TDispatchProps = {
+  fetchDeepDependencyGraph: (query: TDdgModelParams) => void;
+  fetchServices: () => void;
+  fetchServiceOperations: (service: string) => void;
+  transformTracesToDDG: (trace: any) => void;
+};
+
+type TReduxProps = TExtractUiFindFromStateReturn & {
+  graph: TGraph | undefined;
+  services?: string[] | null;
+  urlState: TDdgSparseUrlState;
+  trace: any;
+  model: TDdgModel | undefined;
+};
+
+type TOwnProps = {
+  history: RouterHistory;
+  location: Location;
+};
+
+type TProps = TDispatchProps & TReduxProps & TOwnProps;
+
+// export for tests
+export class SearchResultsDDG extends Component<TProps> {
+  // shouldComponentUpdate is necessary as we don't want the plexus graph to re-render due to a uxStatus change
+  shouldComponentUpdate(nextProps: TProps) {
+    const updateCauses = [
+      'uiFind',
+      'trace',
+      'services',
+      'urlState.service',
+      'urlState.operation',
+      'urlState.start',
+      'urlState.end',
+      'urlState.visEncoding',
+    ];
+    return updateCauses.some(cause => _get(nextProps, cause) !== _get(this.props, cause));
+  }
+
+  setDistance = (distance: number, direction: EDirection) => {
+    const { visEncoding } = this.props.urlState;
+    const { model } = this.props;
+    if (model) {
+      this.updateUrlState({
+        visEncoding: encodeDistance({
+          ddgModel: model,
+          direction,
+          distance,
+          prevVisEncoding: visEncoding,
+        }),
+      });
+    }
+  };
+
+  updateUrlState = (newValues: Partial<TDdgSparseUrlState>) => {
+    const { uiFind, urlState, history } = this.props;
+    history.push(getUrl({ uiFind, ...urlState, ...newValues }));
+  };
+
+  render() {
+    const { graph, uiFind, urlState, model } = this.props;
+    const { visEncoding } = urlState;
+    const uiFindMatches = graph && graph.getVisibleUiFindMatches(uiFind, visEncoding);
+
+    let content = (
+      <div>
+        <h1>Unknown graphState:</h1>
+        <p>${JSON.stringify(graph)}</p>
+      </div>
+    );
+    if (graph && model) {
+      const { edges, vertices } = graph.getVisible(visEncoding);
+      const distanceToPathElems = model.distanceToPathElems;
+      content = (
+        <div>
+          <HopsSelector
+            distanceToPathElems={distanceToPathElems}
+            handleClick={this.setDistance}
+            visEncoding={visEncoding}
+          />
+          <div className="Ddg--graphWrapper">
+            <Graph
+              edges={edges}
+              getVisiblePathElems={(key: string) => graph.getVisiblePathElems(key, visEncoding)}
+              uiFindMatches={uiFindMatches}
+              vertices={vertices}
+            />
+          </div>
+        </div>
+      );
+    }
+    return content;
+  }
+}
+
+// export for tests
+export function mapStateToProps(state: ReduxState, ownProps: TOwnProps): TReduxProps {
+  const { trace } = state;
+  const urlState = getUrlState(ownProps.location.search);
+  const { density, operation, service, showOp } = urlState;
+  let graph: TGraph | undefined;
+  let model: TDdgModel | undefined;
+
+  if (service) {
+    const paths = transformTracesToPaths(trace.traces, service, operation);
+    model = transformDdgData(paths, { service, operation });
+    graph = makeGraph(model, showOp, density);
+  } else {
+    graph = undefined;
+  }
+
+  return {
+    model,
+    trace,
+    graph,
+    urlState,
+    ...extractUiFindFromState(state),
+  };
+}
+
+export default connect(mapStateToProps)(SearchResultsDDG);
diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/AltViewOptions.tsx b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/AltViewOptions.tsx
new file mode 100644
index 0000000000..db74d0b722
--- /dev/null
+++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/AltViewOptions.tsx
@@ -0,0 +1,30 @@
+// Copyright (c) 2018 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import * as React from 'react';
+import { Button } from 'antd';
+
+type Props = {
+  traceResultsView: boolean;
+  onTraceGraphViewClicked: () => void;
+};
+
+export default function AltViewOptions(props: Props) {
+  const { onTraceGraphViewClicked, traceResultsView } = props;
+  return (
+    <Button className="ub-mr2" htmlType="button" onClick={onTraceGraphViewClicked}>
+      {traceResultsView ? 'Deep dependency graph' : 'Trace Results'}
+    </Button>
+  );
+}
diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js
index 82c6d343cd..aa00bff697 100644
--- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js
+++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js
@@ -17,13 +17,15 @@
 import * as React from 'react';
 import { Select } from 'antd';
 import { Link } from 'react-router-dom';
-import { Field, reduxForm, formValueSelector } from 'redux-form';
+import { Field, formValueSelector, reduxForm } from 'redux-form';
+import { History as RouterHistory, Location } from 'history';
 
 import DiffSelection from './DiffSelection';
 import * as markers from './index.markers';
 import ResultItem from './ResultItem';
 import ScatterPlot from './ScatterPlot';
 import { getUrl } from '../url';
+
 import LoadingIndicator from '../../common/LoadingIndicator';
 import NewWindowIcon from '../../common/NewWindowIcon';
 import { getLocation } from '../../TracePage/url';
@@ -36,6 +38,8 @@ import type { FetchedTrace } from '../../../types';
 import type { SearchQuery } from '../../../types/search';
 
 import './index.css';
+import AltViewOptions from './AltViewOptions';
+import SearchResultsDGG from '../../DeepDependencies/traces';
 
 type SearchResultsProps = {
   cohortAddTrace: string => void,
@@ -50,6 +54,12 @@ type SearchResultsProps = {
   showStandaloneLink: boolean,
   skipMessage?: boolean,
   traces: TraceSummary[],
+  history: RouterHistory,
+  location: Location,
+};
+
+type StateProps = {
+  traceResultsView: boolean,
 };
 
 const Option = Select.Option;
@@ -81,11 +91,16 @@ const SelectSort = reduxForm({
 
 export const sortFormSelector = formValueSelector('traceResultsSort');
 
-export default class SearchResults extends React.PureComponent<SearchResultsProps> {
+export default class SearchResults extends React.Component<SearchResultsProps, StateProps> {
   props: SearchResultsProps;
 
   static defaultProps = { skipMessage: false, queryOfResults: undefined };
 
+  constructor(props) {
+    super(props);
+    this.state = { traceResultsView: true };
+  }
+
   toggleComparison = (traceID: string, remove: boolean) => {
     const { cohortAddTrace, cohortRemoveTrace } = this.props;
     if (remove) {
@@ -95,6 +110,13 @@ export default class SearchResults extends React.PureComponent<SearchResultsProp
     }
   };
 
+  onTraceGraphViewClicked = () => {
+    const { traceResultsView } = this.state;
+    this.setState({
+      traceResultsView: !traceResultsView,
+    });
+  };
+
   render() {
     const {
       diffCohort,
@@ -107,7 +129,12 @@ export default class SearchResults extends React.PureComponent<SearchResultsProp
       showStandaloneLink,
       skipMessage,
       traces,
+      history,
+      location,
     } = this.props;
+
+    const { traceResultsView } = this.state;
+
     const diffSelection = !disableComparisons && (
       <DiffSelection toggleComparison={this.toggleComparison} traces={diffCohort} />
     );
@@ -158,6 +185,10 @@ export default class SearchResults extends React.PureComponent<SearchResultsProp
                 {traces.length} Trace{traces.length > 1 && 's'}
               </h2>
               <SelectSort />
+              <AltViewOptions
+                traceResultsView={traceResultsView}
+                onTraceGraphViewClicked={this.onTraceGraphViewClicked}
+              />
               {showStandaloneLink && (
                 <Link
                   className="u-tx-inherit ub-nowrap ub-ml3"
@@ -172,21 +203,24 @@ export default class SearchResults extends React.PureComponent<SearchResultsProp
           </div>
         </div>
         <div>
-          {diffSelection}
-          <ul className="ub-list-reset">
-            {traces.map(trace => (
-              <li className="ub-my3" key={trace.traceID}>
-                <ResultItem
-                  durationPercent={getPercentageOfDuration(trace.duration, maxTraceDuration)}
-                  isInDiffCohort={cohortIds.has(trace.traceID)}
-                  linkTo={getLocation(trace.traceID, { fromSearch: searchUrl })}
-                  toggleComparison={this.toggleComparison}
-                  trace={trace}
-                  disableComparision={disableComparisons}
-                />
-              </li>
-            ))}
-          </ul>
+          {!traceResultsView && <SearchResultsDGG location={location} history={history} />}
+          {traceResultsView && diffSelection}
+          {traceResultsView && (
+            <ul className="ub-list-reset">
+              {traces.map(trace => (
+                <li className="ub-my3" key={trace.traceID}>
+                  <ResultItem
+                    durationPercent={getPercentageOfDuration(trace.duration, maxTraceDuration)}
+                    isInDiffCohort={cohortIds.has(trace.traceID)}
+                    linkTo={getLocation(trace.traceID, { fromSearch: searchUrl })}
+                    toggleComparison={this.toggleComparison}
+                    trace={trace}
+                    disableComparision={disableComparisons}
+                  />
+                </li>
+              ))}
+            </ul>
+          )}
         </div>
       </div>
     );
diff --git a/packages/jaeger-ui/src/components/SearchTracePage/index.js b/packages/jaeger-ui/src/components/SearchTracePage/index.js
index cd4426736a..79a976c81a 100644
--- a/packages/jaeger-ui/src/components/SearchTracePage/index.js
+++ b/packages/jaeger-ui/src/components/SearchTracePage/index.js
@@ -90,10 +90,13 @@ export class SearchTracePageImpl extends Component {
       traceResults,
       queryOfResults,
       loadJsonTraces,
+      location,
+      history,
     } = this.props;
     const hasTraceResults = traceResults && traceResults.length > 0;
     const showErrors = errors && !loadingTraces;
     const showLogo = isHomepage && !hasTraceResults && !loadingTraces && !errors;
+
     return (
       <div>
         <Row>
@@ -134,6 +137,8 @@ export class SearchTracePageImpl extends Component {
                 showStandaloneLink={Boolean(embedded)}
                 skipMessage={isHomepage}
                 traces={traceResults}
+                location={location}
+                history={history}
               />
             )}
             {showLogo && (
@@ -191,6 +196,8 @@ SearchTracePageImpl.propTypes = {
     })
   ),
   loadJsonTraces: PropTypes.func,
+  // eslint-disable-next-line react/forbid-prop-types
+  location: PropTypes.any,
 };
 
 const stateTraceXformer = memoizeOne(stateTrace => {
@@ -248,9 +255,11 @@ export function mapStateToProps(state) {
   if (serviceError) {
     errors.push(serviceError);
   }
+  const location = router.location;
   const sortBy = sortFormSelector(state, 'sortBy');
   const traceResults = sortedTracesXformer(traces, sortBy);
   return {
+    location,
     queryOfResults,
     diffCohort,
     embedded,
diff --git a/packages/jaeger-ui/src/components/SearchTracePage/index.test.js b/packages/jaeger-ui/src/components/SearchTracePage/index.test.js
index 65ca7277bd..c1e89d1588 100644
--- a/packages/jaeger-ui/src/components/SearchTracePage/index.test.js
+++ b/packages/jaeger-ui/src/components/SearchTracePage/index.test.js
@@ -155,9 +155,14 @@ describe('mapStateToProps()', () => {
       services: stateServices,
     };
 
-    const { maxTraceDuration, traceResults, diffCohort, numberOfTraceResults, ...rest } = mapStateToProps(
-      state
-    );
+    const {
+      maxTraceDuration,
+      traceResults,
+      diffCohort,
+      numberOfTraceResults,
+      location,
+      ...rest
+    } = mapStateToProps(state);
     expect(traceResults).toHaveLength(stateTrace.search.results.length);
     expect(traceResults[0].traceID).toBe(trace.traceID);
     expect(maxTraceDuration).toBe(trace.duration);
diff --git a/packages/jaeger-ui/src/model/ddg/transformTracesToPaths.tsx b/packages/jaeger-ui/src/model/ddg/transformTracesToPaths.tsx
new file mode 100644
index 0000000000..29dbe3fbb7
--- /dev/null
+++ b/packages/jaeger-ui/src/model/ddg/transformTracesToPaths.tsx
@@ -0,0 +1,117 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { TDdgPayloadEntry, TDdgPayloadPath, TDdgPayload } from './types';
+import { Span, Trace } from '../../types/trace';
+import { FetchedTrace } from '../../types';
+
+type Node = {
+  value?: Span;
+  children: Node[];
+};
+
+const hasFocal = (path: TDdgPayloadEntry[], focalService: string, focalOperation: string | undefined) => {
+  for (let i = 0; i < path.length; ++i) {
+    if (
+      focalService === path[i].service &&
+      (focalOperation === undefined || focalOperation === path[i].operation)
+    ) {
+      return true;
+    }
+  }
+  return false;
+};
+
+function convertSpan(span: Span, trace: Trace) {
+  const serviceName = trace.processes[span.processID].serviceName;
+  const operationName = span.operationName;
+  return { service: serviceName, operation: operationName };
+}
+
+function findPathToRoot(
+  node: Node,
+  root: Node,
+  nodes: Map<String, Node>,
+  trace: Trace,
+  focalService: string,
+  focalOperation: string | undefined
+): TDdgPayloadPath | null {
+  const path: TDdgPayloadEntry[] = [];
+  let actual: Node | undefined = node;
+  while (
+    actual &&
+    actual.value &&
+    actual.value.references !== undefined &&
+    Array.isArray(actual.value.references) &&
+    actual.value.references.length
+  ) {
+    path.push(convertSpan(actual.value, trace));
+    actual = nodes.get(actual.value.references[0].spanID);
+  }
+  if (actual && actual.value) {
+    path.push(convertSpan(actual.value, trace));
+  }
+  if (hasFocal(path, focalService, focalOperation) === true) {
+    return { path: path.reverse(), trace_id: trace.traceID };
+  }
+  return null;
+}
+
+const processTrace = (
+  trace: Trace,
+  focalService: string,
+  focalOperation: string | undefined
+): TDdgPayload => {
+  const root: Node = { children: [] };
+  const nodes: Map<String, Node> = new Map<String, Node>(
+    trace.spans.map(span => [span.spanID, { children: [], value: span }])
+  );
+  nodes.forEach(node => {
+    const span = node.value;
+    if (span && Array.isArray(span.references) && span.references.length) {
+      const reference = span.references[0];
+      const parent = nodes.get(reference.spanID);
+      if (parent) {
+        parent.children.push(node);
+      }
+    } else {
+      root.children.push(node);
+    }
+  });
+  // Process leaves
+  const tracePaths: TDdgPayload = [];
+  nodes.forEach(node => {
+    if (node.children.length === 0) {
+      const path = findPathToRoot(node, root, nodes, trace, focalService, focalOperation);
+      if (path) {
+        tracePaths.push(path);
+      }
+    }
+  });
+  return tracePaths;
+};
+
+export default function(
+  traces: Record<string, FetchedTrace>,
+  focalService: string,
+  focalOperation: string | undefined
+) {
+  let paths: TDdgPayload = [];
+  Object.values(traces).forEach(trace => {
+    if (trace && trace.data) {
+      paths = paths.concat(processTrace(trace.data, focalService, focalOperation));
+    }
+  });
+  return paths;
+}
diff --git a/packages/jaeger-ui/src/model/ddg/types.tsx b/packages/jaeger-ui/src/model/ddg/types.tsx
index e5f504145a..b228657650 100644
--- a/packages/jaeger-ui/src/model/ddg/types.tsx
+++ b/packages/jaeger-ui/src/model/ddg/types.tsx
@@ -25,10 +25,12 @@ export type TDdgPayloadEntry = {
   service: string;
 };
 
-export type TDdgPayload = {
+export type TDdgPayloadPath = {
   path: TDdgPayloadEntry[];
   trace_id: string; // eslint-disable-line camelcase
-}[];
+};
+
+export type TDdgPayload = TDdgPayloadPath[];
 
 export type TDdgService = {
   name: string;