NewSankey creates a new Sankey diagram with the specified flows and stocks.
(flows ...Flow)
| 131 | // NewSankey creates a new Sankey diagram with the specified |
| 132 | // flows and stocks. |
| 133 | func NewSankey(flows ...Flow) (*Sankey, error) { |
| 134 | var s Sankey |
| 135 | |
| 136 | s.stocks = make(map[int]map[string]*stock) |
| 137 | |
| 138 | s.flows = flows |
| 139 | for i, f := range flows { |
| 140 | // Here we make sure the stock categories are in the proper order. |
| 141 | if f.SourceCategory >= f.ReceptorCategory { |
| 142 | return nil, fmt.Errorf("plotter: Flow %d SourceCategory (%d) >= ReceptorCategory (%d)", i, f.SourceCategory, f.ReceptorCategory) |
| 143 | } |
| 144 | if f.Value < 0 { |
| 145 | return nil, fmt.Errorf("plotter: Flow %d value (%g) < 0", i, f.Value) |
| 146 | } |
| 147 | |
| 148 | // Here we initialize the stock holders. |
| 149 | if _, ok := s.stocks[f.SourceCategory]; !ok { |
| 150 | s.stocks[f.SourceCategory] = make(map[string]*stock) |
| 151 | } |
| 152 | if _, ok := s.stocks[f.ReceptorCategory]; !ok { |
| 153 | s.stocks[f.ReceptorCategory] = make(map[string]*stock) |
| 154 | } |
| 155 | |
| 156 | // Here we figure out the plotting order of the stocks. |
| 157 | if _, ok := s.stocks[f.SourceCategory][f.SourceLabel]; !ok { |
| 158 | s.stocks[f.SourceCategory][f.SourceLabel] = &stock{ |
| 159 | order: len(s.stocks[f.SourceCategory]), |
| 160 | label: f.SourceLabel, |
| 161 | category: f.SourceCategory, |
| 162 | } |
| 163 | } |
| 164 | if _, ok := s.stocks[f.ReceptorCategory][f.ReceptorLabel]; !ok { |
| 165 | s.stocks[f.ReceptorCategory][f.ReceptorLabel] = &stock{ |
| 166 | order: len(s.stocks[f.ReceptorCategory]), |
| 167 | label: f.ReceptorLabel, |
| 168 | category: f.ReceptorCategory, |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | // Here we add the current value to the total value of the stocks |
| 173 | s.stocks[f.SourceCategory][f.SourceLabel].sourceValue += f.Value |
| 174 | s.stocks[f.ReceptorCategory][f.ReceptorLabel].receptorValue += f.Value |
| 175 | } |
| 176 | |
| 177 | s.LineStyle = DefaultLineStyle |
| 178 | |
| 179 | s.TextStyle = text.Style{ |
| 180 | Font: font.From(DefaultFont, DefaultFontSize), |
| 181 | Rotation: math.Pi / 2, |
| 182 | XAlign: draw.XCenter, |
| 183 | YAlign: draw.YCenter, |
| 184 | Handler: plot.DefaultTextHandler, |
| 185 | } |
| 186 | s.StockBarWidth = s.TextStyle.FontExtents().Height * 1.15 |
| 187 | |
| 188 | s.FlowStyle = func(_ string) (color.Color, draw.LineStyle) { |
| 189 | return s.Color, s.LineStyle |
| 190 | } |