diff --git a/.gitignore b/.gitignore
index 3e4b6e1..8f4388f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,4 +16,5 @@
 # Other
 .vscode
 .DS_Store
-coverage.html
\ No newline at end of file
+coverage.html
+.idea
diff --git a/examples/logarithmic_axes/main.go b/examples/logarithmic_axes/main.go
new file mode 100644
index 0000000..9f329c8
--- /dev/null
+++ b/examples/logarithmic_axes/main.go
@@ -0,0 +1,41 @@
+package main
+
+//go:generate go run main.go
+
+import (
+	"os"
+
+	"github.com/wcharczuk/go-chart"
+)
+
+func main() {
+
+	/*
+	   In this example we set the primary YAxis to have logarithmic range.
+	*/
+
+	graph := chart.Chart{
+		Background: chart.Style{
+			Padding: chart.Box{
+				Top:  20,
+				Left: 20,
+			},
+		},
+		Series: []chart.Series{
+			chart.ContinuousSeries{
+				Name:    "A test series",
+				XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
+				YValues: []float64{1, 10, 100, 1000, 10000},
+			},
+		},
+		YAxis: chart.YAxis{
+			Style:     chart.Shown(),
+			NameStyle: chart.Shown(),
+			Range: &chart.LogarithmicRange{},
+		},
+	}
+
+	f, _ := os.Create("output.png")
+	defer f.Close()
+	graph.Render(chart.PNG, f)
+}
diff --git a/examples/logarithmic_axes/output.png b/examples/logarithmic_axes/output.png
new file mode 100644
index 0000000..4462b8d
Binary files /dev/null and b/examples/logarithmic_axes/output.png differ
diff --git a/logarithmic_range.go b/logarithmic_range.go
new file mode 100644
index 0000000..5b183b3
--- /dev/null
+++ b/logarithmic_range.go
@@ -0,0 +1,94 @@
+package chart
+
+import (
+	"fmt"
+	"math"
+)
+
+// LogarithmicRange represents a boundary for a set of numbers.
+type LogarithmicRange struct {
+	Min        float64
+	Max        float64
+	Domain     int
+	Descending bool
+}
+
+// IsDescending returns if the range is descending.
+func (r LogarithmicRange) IsDescending() bool {
+	return r.Descending
+}
+
+// IsZero returns if the LogarithmicRange has been set or not.
+func (r LogarithmicRange) IsZero() bool {
+	return (r.Min == 0 || math.IsNaN(r.Min)) &&
+		(r.Max == 0 || math.IsNaN(r.Max)) &&
+		r.Domain == 0
+}
+
+// GetMin gets the min value for the continuous range.
+func (r LogarithmicRange) GetMin() float64 {
+	return r.Min
+}
+
+// SetMin sets the min value for the continuous range.
+func (r *LogarithmicRange) SetMin(min float64) {
+	r.Min = min
+}
+
+// GetMax returns the max value for the continuous range.
+func (r LogarithmicRange) GetMax() float64 {
+	return r.Max
+}
+
+// SetMax sets the max value for the continuous range.
+func (r *LogarithmicRange) SetMax(max float64) {
+	r.Max = max
+}
+
+// GetDelta returns the difference between the min and max value.
+func (r LogarithmicRange) GetDelta() float64 {
+	return r.Max - r.Min
+}
+
+// GetDomain returns the range domain.
+func (r LogarithmicRange) GetDomain() int {
+	return r.Domain
+}
+
+// SetDomain sets the range domain.
+func (r *LogarithmicRange) SetDomain(domain int) {
+	r.Domain = domain
+}
+
+// String returns a simple string for the LogarithmicRange.
+func (r LogarithmicRange) String() string {
+	return fmt.Sprintf("LogarithmicRange [%.2f,%.2f] => %d", r.Min, r.Max, r.Domain)
+}
+
+// Translate maps a given value into the LogarithmicRange space. Modified version from ContinuousRange.
+func (r LogarithmicRange) Translate(value float64) int {
+	if value < 1 {
+		return 0
+	}
+	normalized := math.Max(value-r.Min, 1)
+	ratio := math.Log10(normalized) / math.Log10(r.GetDelta())
+
+	if r.IsDescending() {
+		return r.Domain - int(math.Ceil(ratio*float64(r.Domain)))
+	}
+
+	return int(math.Ceil(ratio * float64(r.Domain)))
+}
+
+// GetTicks calculates the needed ticks for the axis, in log scale. Only supports Y values > 0.
+func (r LogarithmicRange) GetTicks(render Renderer, defaults Style, vf ValueFormatter) []Tick {
+	var ticks []Tick
+	exponentStart := int64(math.Max(0, math.Floor(math.Log10(r.Min))))   // one below min
+	exponentEnd := int64(math.Max(0, math.Ceil(math.Log10(r.Max))))      // one above max
+	for exp:=exponentStart; exp<=exponentEnd; exp++ {
+		tickVal := math.Pow(10, float64(exp))
+		ticks = append(ticks, Tick{Value: tickVal, Label: vf(tickVal)})
+	}
+
+	return ticks
+}
diff --git a/logarithmic_range_test.go b/logarithmic_range_test.go
new file mode 100644
index 0000000..110f761
--- /dev/null
+++ b/logarithmic_range_test.go
@@ -0,0 +1,46 @@
+package chart
+
+import (
+	"testing"
+
+	"github.com/blend/go-sdk/assert"
+)
+
+func TestLogRangeTranslate(t *testing.T) {
+   	assert := assert.New(t)
+	values := []float64{1, 10, 100, 1000, 10000, 100000, 1000000}
+	r := LogarithmicRange{Domain: 1000}
+	r.Min, r.Max = MinMax(values...)
+
+	assert.Equal(0, r.Translate(0))       // goes to bottom
+	assert.Equal(0, r.Translate(1))       // goes to bottom
+	assert.Equal(160, r.Translate(10))    // roughly 1/6th of max
+	assert.Equal(500, r.Translate(1000))  // roughly 1/2 of max (1.0e6 / 1.0e3)
+	assert.Equal(1000, r.Translate(1000000)) // max value
+}
+
+func TestGetTicks(t *testing.T) {
+	assert := assert.New(t)
+	values := []float64{35, 512, 1525122}
+	r := LogarithmicRange{Domain: 1000}
+	r.Min, r.Max = MinMax(values...)
+
+	ticks := r.GetTicks(nil, Style{}, FloatValueFormatter)
+	assert.Equal(7, len(ticks))
+	assert.Equal(10, ticks[0].Value)
+	assert.Equal(100, ticks[1].Value)
+	assert.Equal(10000000, ticks[6].Value)
+}
+
+func TestGetTicksFromHigh(t *testing.T) {
+	assert := assert.New(t)
+	values := []float64{1412, 352144, 1525122} // min tick should be 1000
+	r := LogarithmicRange{}
+	r.Min, r.Max = MinMax(values...)
+
+	ticks := r.GetTicks(nil, Style{}, FloatValueFormatter)
+	assert.Equal(5, len(ticks))
+	assert.Equal(float64(1000), ticks[0].Value)
+	assert.Equal(float64(10000), ticks[1].Value)
+	assert.Equal(float64(10000000), ticks[4].Value)
+}
diff --git a/value_formatter.go b/value_formatter.go
index 468f3bd..1a2002a 100644
--- a/value_formatter.go
+++ b/value_formatter.go
@@ -103,3 +103,8 @@ func KValueFormatter(k float64, vf ValueFormatter) ValueFormatter {
 		return fmt.Sprintf("%0.0fσ %s", k, vf(v))
 	}
 }
+
+// FloatValueFormatter is a ValueFormatter for float64, exponential notation, e.g. 1.52e+08.
+func ExponentialValueFormatter(v interface{}) string {
+	return FloatValueFormatterWithFormat(v, "%.2e")
+}
diff --git a/value_formatter_test.go b/value_formatter_test.go
index 623a399..ae2d1c3 100644
--- a/value_formatter_test.go
+++ b/value_formatter_test.go
@@ -56,3 +56,10 @@ func TestFloatValueFormatterWithFormat(t *testing.T) {
 	assert.Equal("123.456", sv)
 	assert.Equal("123.000", FloatValueFormatterWithFormat(123, "%.3f"))
 }
+
+func TestExponentialValueFormatter(t *testing.T) {
+	assert := assert.New(t)
+	assert.Equal("1.23e+02", ExponentialValueFormatter(123.456))
+	assert.Equal("1.24e+07", ExponentialValueFormatter(12421243.424))
+	assert.Equal("4.50e-01", ExponentialValueFormatter(0.45))
+}