<commit_before>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gg

import (
	"fmt"
	"io"
	"math"
	"reflect"
	"strings"

	"github.com/aclements/go-gg/generic"
	"github.com/aclements/go-gg/table"
	"github.com/ajstarks/svgo"
)

// fontSize is the font size in pixels.
//
// TODO: Theme.
const fontSize float64 = 12

// facetLabelHeight is the height of facet labels, as a multiple of
// the font height.
//
// TODO: Should this be a multiple of fontSize, em height, leading?
// Currently it's leading.
//
// TODO: Theme.
const facetLabelHeight = 1.3

const xTickSep = 5 // TODO: Theme.

const yTickSep = 5 // TODO: Theme.

// plotMargins returns the top, right, bottom, and left margins for a
// plot of the given width and height.
//
// By default, this adds a 5% margin based on the smaller of width and
// height. This ensures that (with automatic scales), the extremes of
// the data and its tick labels don't appear right at the edge of the
// plot area.
//
// TODO: Theme.
var plotMargins = func(w, h float64) (t, r, b, l float64) {
	margin := 0.05 * math.Min(w, h)
	return margin, margin, margin, margin
}

func (p *Plot) WriteSVG(w io.Writer, width, height int) error {
	// TODO: Legend, title.

	// TODO: Check if the same scaler is used for multiple
	// aesthetics with conflicting rangers. Alternatively, if we
	// just computed the scaled data eagerly here, it wouldn't
	// matter if the same Scaler was used for multiple things
	// because we would just change its Ranger between scaling
	// different data. We could still optimize for get/get1 by
	// specifying whether we care about all of the values or just
	// the first when fetching the scaledData (arguably this
	// should also affect scale training, so this is necessary
	// anyway).

	// TODO: Rather than finding these scales here and giving them
	// Ratners, we could use special "Width"/"Height" Rangers and
	// assign them much earlier (e.g., when they are Used). We
	// could then either find all of the scales that have those
	// Rangers and configure them at this point, or we could pass
	// the renderEnv in when ranging.

	// TODO: Default ranges for other things like color.

	// TODO: Expose the layout so a package user can put together
	// multiple Plots.

	// TODO: Let the user alternatively specify the width and
	// height of the subplots, rather than the whole plot.

	// TODO: Automatic aspect ratio by averaging slopes.

	// Find all of the subplots and subdivide the marks.
	//
	// TODO: If a mark was done in a parent subplot, broadcast it
	// to all child leafs of that subplot.
	subplots := make(map[*subplot]*eltSubplot)
	plotElts := []plotElt{}
	for _, mark := range p.marks {
		// TODO: This is wrong. If there are non-subplot
		// groups, it'll add the same mark multiple times to
		// the plotElt.
		for _, gid := range mark.groups {
			subplot := subplotOf(gid)
			elt := subplots[subplot]
			if elt == nil {
				elt = newEltSubplot(subplot)
				plotElts = append(plotElts, elt)
				subplots[subplot] = elt
			}
			elt.marks = append(elt.marks, mark)
		}
	}
	// Subdivide the scales.
	for sk := range p.scaleSet {
		subplot := subplotOf(sk.gid)
		elt := subplots[subplot]
		if elt == nil {
			continue<commit_msg>gg: TODO<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gg

import (
	"fmt"
	"io"
	"math"
	"reflect"
	"strings"

	"github.com/aclements/go-gg/generic"
	"github.com/aclements/go-gg/table"
	"github.com/ajstarks/svgo"
)

// fontSize is the font size in pixels.
//
// TODO: Theme.
const fontSize float64 = 12

// facetLabelHeight is the height of facet labels, as a multiple of
// the font height.
//
// TODO: Should this be a multiple of fontSize, em height, leading?
// Currently it's leading.
//
// TODO: Theme.
const facetLabelHeight = 1.3

const xTickSep = 5 // TODO: Theme.

const yTickSep = 5 // TODO: Theme.

// plotMargins returns the top, right, bottom, and left margins for a
// plot of the given width and height.
//
// By default, this adds a 5% margin based on the smaller of width and
// height. This ensures that (with automatic scales), the extremes of
// the data and its tick labels don't appear right at the edge of the
// plot area.
//
// TODO: Theme.
var plotMargins = func(w, h float64) (t, r, b, l float64) {
	margin := 0.05 * math.Min(w, h)
	return margin, margin, margin, margin
}

func (p *Plot) WriteSVG(w io.Writer, width, height int) error {
	// TODO: Legend, title.

	// TODO: Check if the same scaler is used for multiple
	// aesthetics with conflicting rangers. Alternatively, if we
	// just computed the scaled data eagerly here, it wouldn't
	// matter if the same Scaler was used for multiple things
	// because we would just change its Ranger between scaling
	// different data. We could still optimize for get/get1 by
	// specifying whether we care about all of the values or just
	// the first when fetching the scaledData (arguably this
	// should also affect scale training, so this is necessary
	// anyway).

	// TODO: Rather than finding these scales here and giving them
	// Ratners, we could use special "Width"/"Height" Rangers and
	// assign them much earlier (e.g., when they are Used). We
	// could then either find all of the scales that have those
	// Rangers and configure them at this point, or we could pass
	// the renderEnv in when ranging.

	// TODO: Default ranges for other things like color.

	// TODO: Expose the layout so a package user can put together
	// multiple Plots.

	// TODO: Let the user alternatively specify the width and
	// height of the subplots, rather than the whole plot.

	// TODO: Automatic aspect ratio by averaging slopes.

	// TODO: Custom tick breaks.

	// Find all of the subplots and subdivide the marks.
	//
	// TODO: If a mark was done in a parent subplot, broadcast it
	// to all child leafs of that subplot.
	subplots := make(map[*subplot]*eltSubplot)
	plotElts := []plotElt{}
	for _, mark := range p.marks {
		// TODO: This is wrong. If there are non-subplot
		// groups, it'll add the same mark multiple times to
		// the plotElt.
		for _, gid := range mark.groups {
			subplot := subplotOf(gid)
			elt := subplots[subplot]
			if elt == nil {
				elt = newEltSubplot(subplot)
				plotElts = append(plotElts, elt)
				subplots[subplot] = elt
			}
			elt.marks = append(elt.marks, mark)
		}
	}
	// Subdivide the scales.
	for sk := range p.scaleSet {
		subplot := subplotOf(sk.gid)
		elt := subplots[subplot]
		if elt == nil {
			continue
{'fraction_non_alphanumeric': 0.10059790732436473, 'fraction_numerical': 0.006278026905829596, 'mean_word_length': 3.030722891566265, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1487992', 'n_tokens_mistral': 2209, 'n_tokens_neox': 2027, 'n_words': 926}