go-hep.org/x/hep@v0.38.1/hplot/figure.go (about)

     1  // Copyright ©2020 The go-hep 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 hplot
     6  
     7  import (
     8  	"go-hep.org/x/hep/hplot/htex"
     9  	"gonum.org/v1/plot"
    10  	"gonum.org/v1/plot/vg"
    11  	"gonum.org/v1/plot/vg/draw"
    12  	"gonum.org/v1/plot/vg/vgimg"
    13  )
    14  
    15  // Figure creates a new figure from a plot and options.
    16  // Figure returns a value implementing the Drawer interface.
    17  func Figure(p Drawer, opts ...FigOption) *Fig {
    18  	fig := &Fig{
    19  		Plot:  p,
    20  		Latex: htex.NoopHandler{},
    21  		DPI:   float64(vgimg.DefaultDPI),
    22  	}
    23  	for _, opt := range opts {
    24  		opt(fig)
    25  	}
    26  	return fig
    27  }
    28  
    29  // FigOption allows to customize the creation of figures.
    30  type FigOption func(fig *Fig)
    31  
    32  // Border specifies the borders' sizes, the space between the
    33  // end of the plot image (PDF, PNG, ...) and the actual plot.
    34  type Border struct {
    35  	Left   vg.Length
    36  	Right  vg.Length
    37  	Bottom vg.Length
    38  	Top    vg.Length
    39  }
    40  
    41  // WithBorder allows to specify the borders' sizes, the space between the
    42  // end of the plot image (PDF, PNG, ...) and the actual plot.
    43  func WithBorder(b Border) FigOption {
    44  	return func(fig *Fig) {
    45  		fig.Border = b
    46  	}
    47  }
    48  
    49  // WithLatexHandler allows to enable the automatic generation of PDFs from .tex files.
    50  // To enable the automatic generation of PDFs, use DefaultHandler:
    51  //
    52  //	WithLatexHandler(htex.DefaultHandler)
    53  func WithLatexHandler(h htex.Handler) FigOption {
    54  	return func(fig *Fig) {
    55  		fig.Latex = h
    56  	}
    57  }
    58  
    59  // WithDPI allows to modify the default DPI of a plot.
    60  func WithDPI(dpi float64) FigOption {
    61  	return func(fig *Fig) {
    62  		fig.DPI = dpi
    63  	}
    64  }
    65  
    66  // WithLegend enables the display of a legend on the righthand-side of a plot.
    67  func WithLegend(l Legend) FigOption {
    68  	return func(fig *Fig) {
    69  		leg := l
    70  		fig.Legend = &leg
    71  	}
    72  }
    73  
    74  // Fig is a figure, holding a plot and figure-level customizations.
    75  type Fig struct {
    76  	// Plot is a gonum/plot.Plot like value.
    77  	Plot Drawer
    78  
    79  	// Legend displays a legend on the righthand-side of the plot.
    80  	Legend *Legend
    81  
    82  	// Border specifies the borders' sizes, the space between the
    83  	// end of the plot image (PDF, PNG, ...) and the actual plot.
    84  	Border Border
    85  
    86  	// Latex handles the generation of PDFs from .tex files.
    87  	// The default is to use htex.NoopHandler (a no-op).
    88  	// To enable the automatic generation of PDFs, use DefaultHandler:
    89  	//  p := hplot.Wrap(plt)
    90  	//  p.Latex = htex.DefaultHandler
    91  	Latex htex.Handler
    92  
    93  	// DPI is the dot-per-inch for PNG,JPEG,... plots.
    94  	DPI float64
    95  }
    96  
    97  func (fig *Fig) Draw(dc draw.Canvas) {
    98  	vgtexBorder(dc)
    99  
   100  	dc = draw.Crop(dc,
   101  		fig.Border.Left, -fig.Border.Right,
   102  		fig.Border.Bottom, -fig.Border.Top,
   103  	)
   104  
   105  	if fig.Legend != nil {
   106  		var (
   107  			r      = fig.Legend.Rectangle(dc)
   108  			width  = r.Max.X - r.Min.X
   109  			height vg.Length
   110  		)
   111  		// adjust the legend down a little.
   112  		switch p := fig.Plot.(type) {
   113  		case *plot.Plot:
   114  			height = p.Title.TextStyle.FontExtents().Height
   115  		case *Plot:
   116  			height = p.Title.TextStyle.FontExtents().Height
   117  		}
   118  		fig.Legend.YOffs = -height
   119  
   120  		fig.Legend.Draw(dc)
   121  
   122  		// carve up space for the legend.
   123  		dc = draw.Crop(dc, 0, -width-vg.Millimeter, 0, 0)
   124  	}
   125  
   126  	fig.Plot.Draw(dc)
   127  }
   128  
   129  var (
   130  	_ Drawer = (*Fig)(nil)
   131  )