...

Source file src/gonum.org/v1/plot/align.go

Documentation: gonum.org/v1/plot

     1  // Copyright ©2017 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package plot
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  
    11  	"gonum.org/v1/plot/vg"
    12  	"gonum.org/v1/plot/vg/draw"
    13  )
    14  
    15  // Align returns a two-dimensional row-major array of Canvases which will
    16  // produce tiled plots with DataCanvases that are evenly sized and spaced.
    17  // The arguments to the function are a two-dimensional row-major array
    18  // of plots, a tile configuration, and the canvas to which the tiled
    19  // plots are to be drawn.
    20  func Align(plots [][]*Plot, t draw.Tiles, dc draw.Canvas) [][]draw.Canvas {
    21  	o := make([][]draw.Canvas, len(plots))
    22  
    23  	if len(plots) != t.Rows {
    24  		panic(fmt.Errorf("plot: plots rows (%d) != tiles rows (%d)", len(plots), t.Rows))
    25  	}
    26  
    27  	// Create the initial tiles.
    28  	for j := 0; j < t.Rows; j++ {
    29  		if len(plots[j]) != t.Cols {
    30  			panic(fmt.Errorf("plot: plots row %d columns (%d) != tiles columns (%d)", j, len(plots[j]), t.Rows))
    31  		}
    32  
    33  		o[j] = make([]draw.Canvas, len(plots[j]))
    34  		for i := 0; i < t.Cols; i++ {
    35  			o[j][i] = t.At(dc, i, j)
    36  		}
    37  	}
    38  
    39  	type posNeg struct {
    40  		p, n float64
    41  	}
    42  	xSpacing := make([]posNeg, t.Cols)
    43  	ySpacing := make([]posNeg, t.Rows)
    44  
    45  	// Calculate the maximum spacing between data canvases
    46  	// for each row and column.
    47  	for j, row := range plots {
    48  		for i, p := range row {
    49  			if p == nil {
    50  				continue
    51  			}
    52  			c := o[j][i]
    53  			dataC := p.DataCanvas(o[j][i])
    54  			xSpacing[i].n = math.Max(float64(dataC.Min.X-c.Min.X), xSpacing[i].n)
    55  			xSpacing[i].p = math.Max(float64(c.Max.X-dataC.Max.X), xSpacing[i].p)
    56  			ySpacing[j].n = math.Max(float64(dataC.Min.Y-c.Min.Y), ySpacing[j].n)
    57  			ySpacing[j].p = math.Max(float64(c.Max.Y-dataC.Max.Y), ySpacing[j].p)
    58  		}
    59  	}
    60  
    61  	// Calculate the total row and column spacing.
    62  	var xTotalSpace float64
    63  	for _, s := range xSpacing {
    64  		xTotalSpace += s.n + s.p
    65  	}
    66  	xTotalSpace += float64(t.PadX)*float64(len(xSpacing)-1) + float64(t.PadLeft+t.PadRight)
    67  	var yTotalSpace float64
    68  	for _, s := range ySpacing {
    69  		yTotalSpace += s.n + s.p
    70  	}
    71  	yTotalSpace += float64(t.PadY)*float64(len(ySpacing)-1) + float64(t.PadTop+t.PadBottom)
    72  
    73  	avgWidth := vg.Length((float64(dc.Max.X-dc.Min.X) - xTotalSpace) / float64(t.Cols))
    74  	avgHeight := vg.Length((float64(dc.Max.Y-dc.Min.Y) - yTotalSpace) / float64(t.Rows))
    75  
    76  	moveVertical := make([]vg.Length, t.Cols)
    77  	for j := t.Rows - 1; j >= 0; j-- {
    78  		row := plots[j]
    79  		var moveHorizontal vg.Length
    80  		for i, p := range row {
    81  			c := o[j][i]
    82  
    83  			if p != nil {
    84  				dataC := p.DataCanvas(c)
    85  				// Adjust the horizontal and vertical spacing between
    86  				// canvases to match the maximum for each column and row,
    87  				// respectively.
    88  				c = draw.Crop(c,
    89  					vg.Length(xSpacing[i].n)-(dataC.Min.X-c.Min.X),
    90  					c.Max.X-dataC.Max.X-vg.Length(xSpacing[i].p),
    91  					vg.Length(ySpacing[j].n)-(dataC.Min.Y-c.Min.Y),
    92  					c.Max.Y-dataC.Max.Y-vg.Length(ySpacing[j].p),
    93  				)
    94  			}
    95  
    96  			var width, height vg.Length
    97  			if p == nil {
    98  				width = c.Max.X - c.Min.X - vg.Length(xSpacing[i].p+xSpacing[i].n)
    99  				height = c.Max.Y - c.Min.Y - vg.Length(ySpacing[j].p+ySpacing[j].n)
   100  			} else {
   101  				dataC := p.DataCanvas(c)
   102  				width = dataC.Max.X - dataC.Min.X
   103  				height = dataC.Max.Y - dataC.Min.Y
   104  			}
   105  
   106  			// Adjust the canvas so that the height and width of the
   107  			// DataCanvas is the same for all plots.
   108  			o[j][i] = draw.Crop(c,
   109  				moveHorizontal,
   110  				moveHorizontal+avgWidth-width,
   111  				moveVertical[i],
   112  				moveVertical[i]+avgHeight-height,
   113  			)
   114  			moveHorizontal += avgWidth - width
   115  			moveVertical[i] += avgHeight - height
   116  		}
   117  	}
   118  	return o
   119  }
   120  

View as plain text