                          length         500
                          clamp?         false}}]
 
+  (if-not (and (number? d-min) (number? d-max)
+               (not= d-min d-max))
+    ;;Return empty shape
+    {:extent 0 :min d-min :max d-max :ticks []}
+    
+    ;;Calculate ticks
+    (let [best-score (atom -2)
+          label (atom {})]
 
-  (let [best-score (atom -2)
-        label (atom {})]
+        (iter {for q in Q}
 
-    (iter {for q in Q}
+              (iter {for j from 1}
+                    {for ms = (max-simplicity q j)}
+                    {return-if (< (w [ms 1 1 1]) @best-score)}
 
-          (iter {for j from 1}
-                {for ms = (max-simplicity q j)}
-                {return-if (< (w [ms 1 1 1]) @best-score)}
+                    (iter {for k from 2}
+                          {for md = (max-density (/ k length) target-density)}
+                          {return-if (< (w [ms 1 md 1]) @best-score)}
 
-                (iter {for k from 2}
-                      {for md = (max-density (/ k length) target-density)}
-                      {return-if (< (w [ms 1 md 1]) @best-score)}
+                          (let [delta ;;power of ten by which to multiply the step size
+                                (/ (- d-max d-min)
+                                   (* (inc k) j k))]
+                              (iter {for z from (ceil (log10 delta))}
+                                    {for l-step = (* q j (expt 10 z))}
+                                    {for mc = (max-coverage d-min d-max (* (dec k) l-step))}
+                                    {return-if (< (w [ms mc md 1]) @best-score)}
 
-                      (let [delta ;;power of ten by which to multiply the step size
-                            (/ (- d-max d-min)
-                               (* (inc k) j k))]
-                        (iter {for z from (ceil (log10 delta))}
-                              {for l-step = (* q j (expt 10 z))}
-                              {for mc = (max-coverage d-min d-max (* (dec k) l-step))}
-                              {return-if (< (w [ms mc md 1]) @best-score)}
+                                    (iter {for start
+                                           from (- (floor (/ d-max l-step))
+                                                   (dec k))
+                                           to (/ d-min l-step)
+                                           by (/ 1 j)}
+                                          {for l-min = (* start l-step)}
+                                          {for l-max = (+ l-min (* (dec k) l-step))}
+                                          {for s = (simplicity q j (label-range-contains-zero? l-min l-max l-step))}
+                                          {for c = (coverage d-min d-max l-min l-max)}
+                                          {for d = (density (/ k length) target-density)}
+                                          {for score = (w [s c d 1])}
+                                          {return-if (< score @best-score)}
 
-                              (iter {for start
-                                     from (- (floor (/ d-max l-step))
-                                             (dec k))
-                                     to (/ d-min l-step)
-                                     by (/ 1 j)}
-                                    {for l-min = (* start l-step)}
-                                    {for l-max = (+ l-min (* (dec k) l-step))}
-                                    {for s = (simplicity q j (label-range-contains-zero? l-min l-max l-step))}
-                                    {for c = (coverage d-min d-max l-min l-max)}
-                                    {for d = (density (/ k length) target-density)}
-                                    {for score = (w [s c d 1])}
-                                    {return-if (< score @best-score)}
+                                          ;;(println "inner loop")
+                                          ;;todo, optimize legibility
 
-                                    ;;(println "inner loop")
-                                    ;;todo, optimize legibility
-
-                                    (reset! best-score score)
-                                    (reset! label {:min l-min
-                                                   :max l-max
-                                                   :step l-step})))))))
-    (let [l @label
-          extent [(if clamp? d-min (min (:min l) d-min))
-                 (if clamp? d-max (max (:max l) d-max))]]
-      {:extent extent
-       :min (first extent) :max (second extent)
-       :ticks (filter #(within? % extent)
-                      (irange (:min l) (:max l) (:step l)))})))
+                                          (reset! best-score score)
+                                          (reset! label {:min l-min
+                                                         :max l-max
+                                                         :step l-step})))))))
+      (let [l @label
+            extent [(if clamp? d-min (min (:min l) d-min))
+                    (if clamp? d-max (max (:max l) d-max))]]
+          {:extent extent
+           :min (first extent) :max (second extent)
+           :ticks (filter #(within? % extent)
+                          (irange (:min l) (:max l) (:step l)))}))))
 
 (comment
   (search [0.0 5000.0]

  "Balance the relative merits of different metrics"
  [[simplicity coverage density legibility]]
  (let [w [0.2 0.25 0.5 0.05]]
    (+ (* simplicity (w 0))
       (* coverage (w 1))
       (* density (w 2))
       (* legibility (w 3)))))




  "Objective function modeling niceness of step sizes and whether a range includes zero"
  [q j label-range-contains-zero]
  (let [v (if label-range-contains-zero 1 0)]
      (if (<= (count Q) 1)
        (+ (- 1 j) v)
        (+ (- 1 (/ (index-of q Q) (dec (count Q))) j)
           v))))

(defn max-simplicity [q j] (simplicity q j true))

