chart.go 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. // Copyright 2016 - 2023 The excelize Authors. All rights reserved. Use of
  2. // this source code is governed by a BSD-style license that can be found in
  3. // the LICENSE file.
  4. //
  5. // Package excelize providing a set of functions that allow you to write to and
  6. // read from XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and
  7. // writing spreadsheet documents generated by Microsoft Excel™ 2007 and later.
  8. // Supports complex components by high compatibility, and provided streaming
  9. // API for generating or reading data from a worksheet with huge amounts of
  10. // data. This library needs Go version 1.16 or later.
  11. package excelize
  12. import (
  13. "encoding/xml"
  14. "fmt"
  15. "strconv"
  16. "strings"
  17. )
  18. // ChartType is the type of supported chart types.
  19. type ChartType byte
  20. // This section defines the currently supported chart types enumeration.
  21. const (
  22. Area ChartType = iota
  23. AreaStacked
  24. AreaPercentStacked
  25. Area3D
  26. Area3DStacked
  27. Area3DPercentStacked
  28. Bar
  29. BarStacked
  30. BarPercentStacked
  31. Bar3DClustered
  32. Bar3DStacked
  33. Bar3DPercentStacked
  34. Bar3DConeClustered
  35. Bar3DConeStacked
  36. Bar3DConePercentStacked
  37. Bar3DPyramidClustered
  38. Bar3DPyramidStacked
  39. Bar3DPyramidPercentStacked
  40. Bar3DCylinderClustered
  41. Bar3DCylinderStacked
  42. Bar3DCylinderPercentStacked
  43. Col
  44. ColStacked
  45. ColPercentStacked
  46. Col3D
  47. Col3DClustered
  48. Col3DStacked
  49. Col3DPercentStacked
  50. Col3DCone
  51. Col3DConeClustered
  52. Col3DConeStacked
  53. Col3DConePercentStacked
  54. Col3DPyramid
  55. Col3DPyramidClustered
  56. Col3DPyramidStacked
  57. Col3DPyramidPercentStacked
  58. Col3DCylinder
  59. Col3DCylinderClustered
  60. Col3DCylinderStacked
  61. Col3DCylinderPercentStacked
  62. Doughnut
  63. Line
  64. Line3D
  65. Pie
  66. Pie3D
  67. PieOfPie
  68. BarOfPie
  69. Radar
  70. Scatter
  71. Surface3D
  72. WireframeSurface3D
  73. Contour
  74. WireframeContour
  75. Bubble
  76. Bubble3D
  77. )
  78. // This section defines the default value of chart properties.
  79. var (
  80. chartView3DRotX = map[ChartType]int{
  81. Area: 0,
  82. AreaStacked: 0,
  83. AreaPercentStacked: 0,
  84. Area3D: 15,
  85. Area3DStacked: 15,
  86. Area3DPercentStacked: 15,
  87. Bar: 0,
  88. BarStacked: 0,
  89. BarPercentStacked: 0,
  90. Bar3DClustered: 15,
  91. Bar3DStacked: 15,
  92. Bar3DPercentStacked: 15,
  93. Bar3DConeClustered: 15,
  94. Bar3DConeStacked: 15,
  95. Bar3DConePercentStacked: 15,
  96. Bar3DPyramidClustered: 15,
  97. Bar3DPyramidStacked: 15,
  98. Bar3DPyramidPercentStacked: 15,
  99. Bar3DCylinderClustered: 15,
  100. Bar3DCylinderStacked: 15,
  101. Bar3DCylinderPercentStacked: 15,
  102. Col: 0,
  103. ColStacked: 0,
  104. ColPercentStacked: 0,
  105. Col3D: 15,
  106. Col3DClustered: 15,
  107. Col3DStacked: 15,
  108. Col3DPercentStacked: 15,
  109. Col3DCone: 15,
  110. Col3DConeClustered: 15,
  111. Col3DConeStacked: 15,
  112. Col3DConePercentStacked: 15,
  113. Col3DPyramid: 15,
  114. Col3DPyramidClustered: 15,
  115. Col3DPyramidStacked: 15,
  116. Col3DPyramidPercentStacked: 15,
  117. Col3DCylinder: 15,
  118. Col3DCylinderClustered: 15,
  119. Col3DCylinderStacked: 15,
  120. Col3DCylinderPercentStacked: 15,
  121. Doughnut: 0,
  122. Line: 0,
  123. Line3D: 20,
  124. Pie: 0,
  125. Pie3D: 30,
  126. PieOfPie: 0,
  127. BarOfPie: 0,
  128. Radar: 0,
  129. Scatter: 0,
  130. Surface3D: 15,
  131. WireframeSurface3D: 15,
  132. Contour: 90,
  133. WireframeContour: 90,
  134. }
  135. chartView3DRotY = map[ChartType]int{
  136. Area: 0,
  137. AreaStacked: 0,
  138. AreaPercentStacked: 0,
  139. Area3D: 20,
  140. Area3DStacked: 20,
  141. Area3DPercentStacked: 20,
  142. Bar: 0,
  143. BarStacked: 0,
  144. BarPercentStacked: 0,
  145. Bar3DClustered: 20,
  146. Bar3DStacked: 20,
  147. Bar3DPercentStacked: 20,
  148. Bar3DConeClustered: 20,
  149. Bar3DConeStacked: 20,
  150. Bar3DConePercentStacked: 20,
  151. Bar3DPyramidClustered: 20,
  152. Bar3DPyramidStacked: 20,
  153. Bar3DPyramidPercentStacked: 20,
  154. Bar3DCylinderClustered: 20,
  155. Bar3DCylinderStacked: 20,
  156. Bar3DCylinderPercentStacked: 20,
  157. Col: 0,
  158. ColStacked: 0,
  159. ColPercentStacked: 0,
  160. Col3D: 20,
  161. Col3DClustered: 20,
  162. Col3DStacked: 20,
  163. Col3DPercentStacked: 20,
  164. Col3DCone: 20,
  165. Col3DConeClustered: 20,
  166. Col3DConeStacked: 20,
  167. Col3DConePercentStacked: 20,
  168. Col3DPyramid: 20,
  169. Col3DPyramidClustered: 20,
  170. Col3DPyramidStacked: 20,
  171. Col3DPyramidPercentStacked: 20,
  172. Col3DCylinder: 20,
  173. Col3DCylinderClustered: 20,
  174. Col3DCylinderStacked: 20,
  175. Col3DCylinderPercentStacked: 20,
  176. Doughnut: 0,
  177. Line: 0,
  178. Line3D: 15,
  179. Pie: 0,
  180. Pie3D: 0,
  181. PieOfPie: 0,
  182. BarOfPie: 0,
  183. Radar: 0,
  184. Scatter: 0,
  185. Surface3D: 20,
  186. WireframeSurface3D: 20,
  187. Contour: 0,
  188. WireframeContour: 0,
  189. }
  190. plotAreaChartOverlap = map[ChartType]int{
  191. BarStacked: 100,
  192. BarPercentStacked: 100,
  193. ColStacked: 100,
  194. ColPercentStacked: 100,
  195. }
  196. chartView3DPerspective = map[ChartType]int{
  197. Line3D: 30,
  198. Contour: 0,
  199. WireframeContour: 0,
  200. }
  201. chartView3DRAngAx = map[ChartType]int{
  202. Area: 0,
  203. AreaStacked: 0,
  204. AreaPercentStacked: 0,
  205. Area3D: 1,
  206. Area3DStacked: 1,
  207. Area3DPercentStacked: 1,
  208. Bar: 0,
  209. BarStacked: 0,
  210. BarPercentStacked: 0,
  211. Bar3DClustered: 1,
  212. Bar3DStacked: 1,
  213. Bar3DPercentStacked: 1,
  214. Bar3DConeClustered: 1,
  215. Bar3DConeStacked: 1,
  216. Bar3DConePercentStacked: 1,
  217. Bar3DPyramidClustered: 1,
  218. Bar3DPyramidStacked: 1,
  219. Bar3DPyramidPercentStacked: 1,
  220. Bar3DCylinderClustered: 1,
  221. Bar3DCylinderStacked: 1,
  222. Bar3DCylinderPercentStacked: 1,
  223. Col: 0,
  224. ColStacked: 0,
  225. ColPercentStacked: 0,
  226. Col3D: 1,
  227. Col3DClustered: 1,
  228. Col3DStacked: 1,
  229. Col3DPercentStacked: 1,
  230. Col3DCone: 1,
  231. Col3DConeClustered: 1,
  232. Col3DConeStacked: 1,
  233. Col3DConePercentStacked: 1,
  234. Col3DPyramid: 1,
  235. Col3DPyramidClustered: 1,
  236. Col3DPyramidStacked: 1,
  237. Col3DPyramidPercentStacked: 1,
  238. Col3DCylinder: 1,
  239. Col3DCylinderClustered: 1,
  240. Col3DCylinderStacked: 1,
  241. Col3DCylinderPercentStacked: 1,
  242. Doughnut: 0,
  243. Line: 0,
  244. Line3D: 0,
  245. Pie: 0,
  246. Pie3D: 0,
  247. PieOfPie: 0,
  248. BarOfPie: 0,
  249. Radar: 0,
  250. Scatter: 0,
  251. Surface3D: 0,
  252. WireframeSurface3D: 0,
  253. Contour: 0,
  254. Bubble: 0,
  255. Bubble3D: 0,
  256. }
  257. chartLegendPosition = map[string]string{
  258. "bottom": "b",
  259. "left": "l",
  260. "right": "r",
  261. "top": "t",
  262. "top_right": "tr",
  263. }
  264. chartValAxNumFmtFormatCode = map[ChartType]string{
  265. Area: "General",
  266. AreaStacked: "General",
  267. AreaPercentStacked: "0%",
  268. Area3D: "General",
  269. Area3DStacked: "General",
  270. Area3DPercentStacked: "0%",
  271. Bar: "General",
  272. BarStacked: "General",
  273. BarPercentStacked: "0%",
  274. Bar3DClustered: "General",
  275. Bar3DStacked: "General",
  276. Bar3DPercentStacked: "0%",
  277. Bar3DConeClustered: "General",
  278. Bar3DConeStacked: "General",
  279. Bar3DConePercentStacked: "0%",
  280. Bar3DPyramidClustered: "General",
  281. Bar3DPyramidStacked: "General",
  282. Bar3DPyramidPercentStacked: "0%",
  283. Bar3DCylinderClustered: "General",
  284. Bar3DCylinderStacked: "General",
  285. Bar3DCylinderPercentStacked: "0%",
  286. Col: "General",
  287. ColStacked: "General",
  288. ColPercentStacked: "0%",
  289. Col3D: "General",
  290. Col3DClustered: "General",
  291. Col3DStacked: "General",
  292. Col3DPercentStacked: "0%",
  293. Col3DCone: "General",
  294. Col3DConeClustered: "General",
  295. Col3DConeStacked: "General",
  296. Col3DConePercentStacked: "0%",
  297. Col3DPyramid: "General",
  298. Col3DPyramidClustered: "General",
  299. Col3DPyramidStacked: "General",
  300. Col3DPyramidPercentStacked: "0%",
  301. Col3DCylinder: "General",
  302. Col3DCylinderClustered: "General",
  303. Col3DCylinderStacked: "General",
  304. Col3DCylinderPercentStacked: "0%",
  305. Doughnut: "General",
  306. Line: "General",
  307. Line3D: "General",
  308. Pie: "General",
  309. Pie3D: "General",
  310. PieOfPie: "General",
  311. BarOfPie: "General",
  312. Radar: "General",
  313. Scatter: "General",
  314. Surface3D: "General",
  315. WireframeSurface3D: "General",
  316. Contour: "General",
  317. WireframeContour: "General",
  318. Bubble: "General",
  319. Bubble3D: "General",
  320. }
  321. chartValAxCrossBetween = map[ChartType]string{
  322. Area: "midCat",
  323. AreaStacked: "midCat",
  324. AreaPercentStacked: "midCat",
  325. Area3D: "midCat",
  326. Area3DStacked: "midCat",
  327. Area3DPercentStacked: "midCat",
  328. Bar: "between",
  329. BarStacked: "between",
  330. BarPercentStacked: "between",
  331. Bar3DClustered: "between",
  332. Bar3DStacked: "between",
  333. Bar3DPercentStacked: "between",
  334. Bar3DConeClustered: "between",
  335. Bar3DConeStacked: "between",
  336. Bar3DConePercentStacked: "between",
  337. Bar3DPyramidClustered: "between",
  338. Bar3DPyramidStacked: "between",
  339. Bar3DPyramidPercentStacked: "between",
  340. Bar3DCylinderClustered: "between",
  341. Bar3DCylinderStacked: "between",
  342. Bar3DCylinderPercentStacked: "between",
  343. Col: "between",
  344. ColStacked: "between",
  345. ColPercentStacked: "between",
  346. Col3D: "between",
  347. Col3DClustered: "between",
  348. Col3DStacked: "between",
  349. Col3DPercentStacked: "between",
  350. Col3DCone: "between",
  351. Col3DConeClustered: "between",
  352. Col3DConeStacked: "between",
  353. Col3DConePercentStacked: "between",
  354. Col3DPyramid: "between",
  355. Col3DPyramidClustered: "between",
  356. Col3DPyramidStacked: "between",
  357. Col3DPyramidPercentStacked: "between",
  358. Col3DCylinder: "between",
  359. Col3DCylinderClustered: "between",
  360. Col3DCylinderStacked: "between",
  361. Col3DCylinderPercentStacked: "between",
  362. Doughnut: "between",
  363. Line: "between",
  364. Line3D: "between",
  365. Pie: "between",
  366. Pie3D: "between",
  367. PieOfPie: "between",
  368. BarOfPie: "between",
  369. Radar: "between",
  370. Scatter: "between",
  371. Surface3D: "midCat",
  372. WireframeSurface3D: "midCat",
  373. Contour: "midCat",
  374. WireframeContour: "midCat",
  375. Bubble: "midCat",
  376. Bubble3D: "midCat",
  377. }
  378. plotAreaChartGrouping = map[ChartType]string{
  379. Area: "standard",
  380. AreaStacked: "stacked",
  381. AreaPercentStacked: "percentStacked",
  382. Area3D: "standard",
  383. Area3DStacked: "stacked",
  384. Area3DPercentStacked: "percentStacked",
  385. Bar: "clustered",
  386. BarStacked: "stacked",
  387. BarPercentStacked: "percentStacked",
  388. Bar3DClustered: "clustered",
  389. Bar3DStacked: "stacked",
  390. Bar3DPercentStacked: "percentStacked",
  391. Bar3DConeClustered: "clustered",
  392. Bar3DConeStacked: "stacked",
  393. Bar3DConePercentStacked: "percentStacked",
  394. Bar3DPyramidClustered: "clustered",
  395. Bar3DPyramidStacked: "stacked",
  396. Bar3DPyramidPercentStacked: "percentStacked",
  397. Bar3DCylinderClustered: "clustered",
  398. Bar3DCylinderStacked: "stacked",
  399. Bar3DCylinderPercentStacked: "percentStacked",
  400. Col: "clustered",
  401. ColStacked: "stacked",
  402. ColPercentStacked: "percentStacked",
  403. Col3D: "standard",
  404. Col3DClustered: "clustered",
  405. Col3DStacked: "stacked",
  406. Col3DPercentStacked: "percentStacked",
  407. Col3DCone: "standard",
  408. Col3DConeClustered: "clustered",
  409. Col3DConeStacked: "stacked",
  410. Col3DConePercentStacked: "percentStacked",
  411. Col3DPyramid: "standard",
  412. Col3DPyramidClustered: "clustered",
  413. Col3DPyramidStacked: "stacked",
  414. Col3DPyramidPercentStacked: "percentStacked",
  415. Col3DCylinder: "standard",
  416. Col3DCylinderClustered: "clustered",
  417. Col3DCylinderStacked: "stacked",
  418. Col3DCylinderPercentStacked: "percentStacked",
  419. Line: "standard",
  420. Line3D: "standard",
  421. }
  422. plotAreaChartBarDir = map[ChartType]string{
  423. Bar: "bar",
  424. BarStacked: "bar",
  425. BarPercentStacked: "bar",
  426. Bar3DClustered: "bar",
  427. Bar3DStacked: "bar",
  428. Bar3DPercentStacked: "bar",
  429. Bar3DConeClustered: "bar",
  430. Bar3DConeStacked: "bar",
  431. Bar3DConePercentStacked: "bar",
  432. Bar3DPyramidClustered: "bar",
  433. Bar3DPyramidStacked: "bar",
  434. Bar3DPyramidPercentStacked: "bar",
  435. Bar3DCylinderClustered: "bar",
  436. Bar3DCylinderStacked: "bar",
  437. Bar3DCylinderPercentStacked: "bar",
  438. Col: "col",
  439. ColStacked: "col",
  440. ColPercentStacked: "col",
  441. Col3D: "col",
  442. Col3DClustered: "col",
  443. Col3DStacked: "col",
  444. Col3DPercentStacked: "col",
  445. Col3DCone: "col",
  446. Col3DConeStacked: "col",
  447. Col3DConeClustered: "col",
  448. Col3DConePercentStacked: "col",
  449. Col3DPyramid: "col",
  450. Col3DPyramidClustered: "col",
  451. Col3DPyramidStacked: "col",
  452. Col3DPyramidPercentStacked: "col",
  453. Col3DCylinder: "col",
  454. Col3DCylinderClustered: "col",
  455. Col3DCylinderStacked: "col",
  456. Col3DCylinderPercentStacked: "col",
  457. Line: "standard",
  458. Line3D: "standard",
  459. }
  460. orientation = map[bool]string{
  461. true: "maxMin",
  462. false: "minMax",
  463. }
  464. catAxPos = map[bool]string{
  465. true: "t",
  466. false: "b",
  467. }
  468. valAxPos = map[bool]string{
  469. true: "r",
  470. false: "l",
  471. }
  472. valTickLblPos = map[ChartType]string{
  473. Contour: "none",
  474. WireframeContour: "none",
  475. }
  476. )
  477. // parseChartOptions provides a function to parse the format settings of the
  478. // chart with default value.
  479. func parseChartOptions(opts *Chart) (*Chart, error) {
  480. if opts == nil {
  481. return nil, ErrParameterInvalid
  482. }
  483. if opts.Dimension.Width == 0 {
  484. opts.Dimension.Width = defaultChartDimensionWidth
  485. }
  486. if opts.Dimension.Height == 0 {
  487. opts.Dimension.Height = defaultChartDimensionHeight
  488. }
  489. if opts.Format.PrintObject == nil {
  490. opts.Format.PrintObject = boolPtr(true)
  491. }
  492. if opts.Format.Locked == nil {
  493. opts.Format.Locked = boolPtr(false)
  494. }
  495. if opts.Format.ScaleX == 0 {
  496. opts.Format.ScaleX = defaultPictureScale
  497. }
  498. if opts.Format.ScaleY == 0 {
  499. opts.Format.ScaleY = defaultPictureScale
  500. }
  501. if opts.Legend.Position == "" {
  502. opts.Legend.Position = defaultChartLegendPosition
  503. }
  504. if opts.Title.Name == "" {
  505. opts.Title.Name = " "
  506. }
  507. if opts.VaryColors == nil {
  508. opts.VaryColors = boolPtr(true)
  509. }
  510. if opts.ShowBlanksAs == "" {
  511. opts.ShowBlanksAs = defaultChartShowBlanksAs
  512. }
  513. return opts, nil
  514. }
  515. // AddChart provides the method to add chart in a sheet by given chart format
  516. // set (such as offset, scale, aspect ratio setting and print settings) and
  517. // properties set. For example, create 3D clustered column chart with data
  518. // Sheet1!$E$1:$L$15:
  519. //
  520. // package main
  521. //
  522. // import (
  523. // "fmt"
  524. //
  525. // "github.com/xuri/excelize/v2"
  526. // )
  527. //
  528. // func main() {
  529. // f := excelize.NewFile()
  530. // defer func() {
  531. // if err := f.Close(); err != nil {
  532. // fmt.Println(err)
  533. // }
  534. // }()
  535. // for idx, row := range [][]interface{}{
  536. // {nil, "Apple", "Orange", "Pear"}, {"Small", 2, 3, 3},
  537. // {"Normal", 5, 2, 4}, {"Large", 6, 7, 8},
  538. // } {
  539. // cell, err := excelize.CoordinatesToCellName(1, idx+1)
  540. // if err != nil {
  541. // fmt.Println(err)
  542. // return
  543. // }
  544. // f.SetSheetRow("Sheet1", cell, &row)
  545. // }
  546. // if err := f.AddChart("Sheet1", "E1", &excelize.Chart{
  547. // Type: excelize.Col3DClustered,
  548. // Series: []excelize.ChartSeries{
  549. // {
  550. // Name: "Sheet1!$A$2",
  551. // Categories: "Sheet1!$B$1:$D$1",
  552. // Values: "Sheet1!$B$2:$D$2",
  553. // },
  554. // {
  555. // Name: "Sheet1!$A$3",
  556. // Categories: "Sheet1!$B$1:$D$1",
  557. // Values: "Sheet1!$B$3:$D$3",
  558. // },
  559. // {
  560. // Name: "Sheet1!$A$4",
  561. // Categories: "Sheet1!$B$1:$D$1",
  562. // Values: "Sheet1!$B$4:$D$4",
  563. // },
  564. // },
  565. // Title: excelize.ChartTitle{
  566. // Name: "Fruit 3D Clustered Column Chart",
  567. // },
  568. // Legend: excelize.ChartLegend{
  569. // ShowLegendKey: false,
  570. // },
  571. // PlotArea: excelize.ChartPlotArea{
  572. // ShowBubbleSize: true,
  573. // ShowCatName: false,
  574. // ShowLeaderLines: false,
  575. // ShowPercent: true,
  576. // ShowSerName: true,
  577. // ShowVal: true,
  578. // },
  579. // }); err != nil {
  580. // fmt.Println(err)
  581. // return
  582. // }
  583. // // Save spreadsheet by the given path.
  584. // if err := f.SaveAs("Book1.xlsx"); err != nil {
  585. // fmt.Println(err)
  586. // }
  587. // }
  588. //
  589. // The following shows the type of chart supported by excelize:
  590. //
  591. // ID | Enumeration | Chart
  592. // ----+-----------------------------+------------------------------
  593. // 0 | Area | 2D area chart
  594. // 1 | AreaStacked | 2D stacked area chart
  595. // 2 | AreaPercentStacked | 2D 100% stacked area chart
  596. // 3 | Area3D | 3D area chart
  597. // 4 | Area3DStacked | 3D stacked area chart
  598. // 5 | Area3DPercentStacked | 3D 100% stacked area chart
  599. // 6 | Bar | 2D clustered bar chart
  600. // 7 | BarStacked | 2D stacked bar chart
  601. // 8 | BarPercentStacked | 2D 100% stacked bar chart
  602. // 9 | Bar3DClustered | 3D clustered bar chart
  603. // 10 | Bar3DStacked | 3D stacked bar chart
  604. // 11 | Bar3DPercentStacked | 3D 100% stacked bar chart
  605. // 12 | Bar3DConeClustered | 3D cone clustered bar chart
  606. // 13 | Bar3DConeStacked | 3D cone stacked bar chart
  607. // 14 | Bar3DConePercentStacked | 3D cone percent bar chart
  608. // 15 | Bar3DPyramidClustered | 3D pyramid clustered bar chart
  609. // 16 | Bar3DPyramidStacked | 3D pyramid stacked bar chart
  610. // 17 | Bar3DPyramidPercentStacked | 3D pyramid percent stacked bar chart
  611. // 18 | Bar3DCylinderClustered | 3D cylinder clustered bar chart
  612. // 19 | Bar3DCylinderStacked | 3D cylinder stacked bar chart
  613. // 20 | Bar3DCylinderPercentStacked | 3D cylinder percent stacked bar chart
  614. // 21 | Col | 2D clustered column chart
  615. // 22 | ColStacked | 2D stacked column chart
  616. // 23 | ColPercentStacked | 2D 100% stacked column chart
  617. // 24 | Col3DClustered | 3D clustered column chart
  618. // 25 | Col3D | 3D column chart
  619. // 26 | Col3DStacked | 3D stacked column chart
  620. // 27 | Col3DPercentStacked | 3D 100% stacked column chart
  621. // 28 | Col3DCone | 3D cone column chart
  622. // 29 | Col3DConeClustered | 3D cone clustered column chart
  623. // 30 | Col3DConeStacked | 3D cone stacked column chart
  624. // 31 | Col3DConePercentStacked | 3D cone percent stacked column chart
  625. // 32 | Col3DPyramid | 3D pyramid column chart
  626. // 33 | Col3DPyramidClustered | 3D pyramid clustered column chart
  627. // 34 | Col3DPyramidStacked | 3D pyramid stacked column chart
  628. // 35 | Col3DPyramidPercentStacked | 3D pyramid percent stacked column chart
  629. // 36 | Col3DCylinder | 3D cylinder column chart
  630. // 37 | Col3DCylinderClustered | 3D cylinder clustered column chart
  631. // 38 | Col3DCylinderStacked | 3D cylinder stacked column chart
  632. // 39 | Col3DCylinderPercentStacked | 3D cylinder percent stacked column chart
  633. // 40 | Doughnut | doughnut chart
  634. // 41 | Line | line chart
  635. // 42 | Line3D | 3D line chart
  636. // 43 | Pie | pie chart
  637. // 44 | Pie3D | 3D pie chart
  638. // 45 | PieOfPie | pie of pie chart
  639. // 46 | BarOfPie | bar of pie chart
  640. // 47 | Radar | radar chart
  641. // 48 | Scatter | scatter chart
  642. // 49 | Surface3D | 3D surface chart
  643. // 50 | WireframeSurface3D | 3D wireframe surface chart
  644. // 51 | Contour | contour chart
  645. // 52 | WireframeContour | wireframe contour chart
  646. // 53 | Bubble | bubble chart
  647. // 54 | Bubble3D | 3D bubble chart
  648. //
  649. // In Excel a chart series is a collection of information that defines which
  650. // data is plotted such as values, axis labels and formatting.
  651. //
  652. // The series options that can be set are:
  653. //
  654. // Name
  655. // Categories
  656. // Sizes
  657. // Values
  658. // Fill
  659. // Line
  660. // Marker
  661. //
  662. // Name: Set the name for the series. The name is displayed in the chart legend
  663. // and in the formula bar. The 'Name' property is optional and if it isn't
  664. // supplied it will default to Series 1..n. The name can also be a formula such
  665. // as Sheet1!$A$1
  666. //
  667. // Categories: This sets the chart category labels. The category is more or less
  668. // the same as the X axis. In most chart types the 'Categories' property is
  669. // optional and the chart will just assume a sequential series from 1..n.
  670. //
  671. // Sizes: This sets the bubble size in a data series.
  672. //
  673. // Values: This is the most important property of a series and is the only
  674. // mandatory option for every chart object. This option links the chart with
  675. // the worksheet data that it displays.
  676. //
  677. // Fill: This set the format for the data series fill.
  678. //
  679. // Line: This sets the line format of the line chart. The 'Line' property is
  680. // optional and if it isn't supplied it will default style. The options that
  681. // can be set are width and color. The range of width is 0.25pt - 999pt. If the
  682. // value of width is outside the range, the default width of the line is 2pt.
  683. //
  684. // Marker: This sets the marker of the line chart and scatter chart. The range
  685. // of optional field 'Size' is 2-72 (default value is 5). The enumeration value
  686. // of optional field 'Symbol' are (default value is 'auto'):
  687. //
  688. // circle
  689. // dash
  690. // diamond
  691. // dot
  692. // none
  693. // picture
  694. // plus
  695. // square
  696. // star
  697. // triangle
  698. // x
  699. // auto
  700. //
  701. // Set properties of the chart legend. The options that can be set are:
  702. //
  703. // Position
  704. // ShowLegendKey
  705. //
  706. // Position: Set the position of the chart legend. The default legend position
  707. // is bottom. The available positions are:
  708. //
  709. // none
  710. // top
  711. // bottom
  712. // left
  713. // right
  714. // top_right
  715. //
  716. // ShowLegendKey: Set the legend keys shall be shown in data labels. The default
  717. // value is false.
  718. //
  719. // Set properties of the chart title. The properties that can be set are:
  720. //
  721. // Title
  722. //
  723. // Name: Set the name (title) for the chart. The name is displayed above the
  724. // chart. The name can also be a formula such as Sheet1!$A$1 or a list with a
  725. // sheet name. The name property is optional. The default is to have no chart
  726. // title.
  727. //
  728. // Specifies how blank cells are plotted on the chart by 'ShowBlanksAs'. The
  729. // default value is gap. The options that can be set are:
  730. //
  731. // gap
  732. // span
  733. // zero
  734. //
  735. // gap: Specifies that blank values shall be left as a gap.
  736. //
  737. // span: Specifies that blank values shall be spanned with a line.
  738. //
  739. // zero: Specifies that blank values shall be treated as zero.
  740. //
  741. // Specifies that each data marker in the series has a different color by
  742. // 'VaryColors'. The default value is true.
  743. //
  744. // Set chart offset, scale, aspect ratio setting and print settings by format,
  745. // same as function 'AddPicture'.
  746. //
  747. // Set the position of the chart plot area by PlotArea. The properties that can
  748. // be set are:
  749. //
  750. // SecondPlotValues
  751. // ShowBubbleSize
  752. // ShowCatName
  753. // ShowLeaderLines
  754. // ShowPercent
  755. // ShowSerName
  756. // ShowVal
  757. //
  758. // SecondPlotValues: Specifies the values in second plot for the 'pieOfPie' and
  759. // 'barOfPie' chart.
  760. //
  761. // ShowBubbleSize: Specifies the bubble size shall be shown in a data label. The
  762. // 'ShowBubbleSize' property is optional. The default value is false.
  763. //
  764. // ShowCatName: Specifies that the category name shall be shown in the data
  765. // label. The 'ShowCatName' property is optional. The default value is true.
  766. //
  767. // ShowLeaderLines: Specifies leader lines shall be shown for data labels. The
  768. // 'ShowLeaderLines' property is optional. The default value is false.
  769. //
  770. // ShowPercent: Specifies that the percentage shall be shown in a data label.
  771. // The 'ShowPercent' property is optional. The default value is false.
  772. //
  773. // ShowSerName: Specifies that the series name shall be shown in a data label.
  774. // The 'ShowSerName' property is optional. The default value is false.
  775. //
  776. // ShowVal: Specifies that the value shall be shown in a data label.
  777. // The 'ShowVal' property is optional. The default value is false.
  778. //
  779. // Set the primary horizontal and vertical axis options by 'XAxis' and 'YAxis'.
  780. // The properties of 'XAxis' that can be set are:
  781. //
  782. // None
  783. // MajorGridLines
  784. // MinorGridLines
  785. // TickLabelSkip
  786. // ReverseOrder
  787. // Maximum
  788. // Minimum
  789. // Font
  790. //
  791. // The properties of 'YAxis' that can be set are:
  792. //
  793. // None
  794. // MajorGridLines
  795. // MinorGridLines
  796. // MajorUnit
  797. // ReverseOrder
  798. // Maximum
  799. // Minimum
  800. // Font
  801. //
  802. // None: Disable axes.
  803. //
  804. // MajorGridLines: Specifies major grid lines.
  805. //
  806. // MinorGridLines: Specifies minor grid lines.
  807. //
  808. // MajorUnit: Specifies the distance between major ticks. Shall contain a
  809. // positive floating-point number. The MajorUnit property is optional. The
  810. // default value is auto.
  811. //
  812. // TickLabelSkip: Specifies how many tick labels to skip between label that is
  813. // drawn. The 'TickLabelSkip' property is optional. The default value is auto.
  814. //
  815. // ReverseOrder: Specifies that the categories or values on reverse order
  816. // (orientation of the chart). The ReverseOrder property is optional. The
  817. // default value is false.
  818. //
  819. // Maximum: Specifies that the fixed maximum, 0 is auto. The 'Maximum' property
  820. // is optional. The default value is auto.
  821. //
  822. // Minimum: Specifies that the fixed minimum, 0 is auto. The 'Minimum' property
  823. // is optional. The default value is auto.
  824. //
  825. // Font: Specifies that the font of the horizontal and vertical axis. The
  826. // properties of font that can be set are:
  827. //
  828. // Bold
  829. // Italic
  830. // Underline
  831. // Family
  832. // Size
  833. // Strike
  834. // Color
  835. // VertAlign
  836. //
  837. // Set chart size by 'Dimension' property. The 'Dimension' property is optional.
  838. // The default width is 480, and height is 290.
  839. //
  840. // combo: Specifies the create a chart that combines two or more chart types in
  841. // a single chart. For example, create a clustered column - line chart with
  842. // data Sheet1!$E$1:$L$15:
  843. //
  844. // package main
  845. //
  846. // import (
  847. // "fmt"
  848. //
  849. // "github.com/xuri/excelize/v2"
  850. // )
  851. //
  852. // func main() {
  853. // f := excelize.NewFile()
  854. // defer func() {
  855. // if err := f.Close(); err != nil {
  856. // fmt.Println(err)
  857. // }
  858. // }()
  859. // for idx, row := range [][]interface{}{
  860. // {nil, "Apple", "Orange", "Pear"}, {"Small", 2, 3, 3},
  861. // {"Normal", 5, 2, 4}, {"Large", 6, 7, 8},
  862. // } {
  863. // cell, err := excelize.CoordinatesToCellName(1, idx+1)
  864. // if err != nil {
  865. // fmt.Println(err)
  866. // return
  867. // }
  868. // f.SetSheetRow("Sheet1", cell, &row)
  869. // }
  870. // enable, disable := true, false
  871. // if err := f.AddChart("Sheet1", "E1", &excelize.Chart{
  872. // Type: "col",
  873. // Series: []excelize.ChartSeries{
  874. // {
  875. // Name: "Sheet1!$A$2",
  876. // Categories: "Sheet1!$B$1:$D$1",
  877. // Values: "Sheet1!$B$2:$D$2",
  878. // },
  879. // },
  880. // Format: excelize.GraphicOptions{
  881. // ScaleX: 1,
  882. // ScaleY: 1,
  883. // OffsetX: 15,
  884. // OffsetY: 10,
  885. // PrintObject: &enable,
  886. // LockAspectRatio: false,
  887. // Locked: &disable,
  888. // },
  889. // Title: excelize.ChartTitle{
  890. // Name: "Clustered Column - Line Chart",
  891. // },
  892. // Legend: excelize.ChartLegend{
  893. // Position: "left",
  894. // ShowLegendKey: false,
  895. // },
  896. // PlotArea: excelize.ChartPlotArea{
  897. // ShowCatName: false,
  898. // ShowLeaderLines: false,
  899. // ShowPercent: true,
  900. // ShowSerName: true,
  901. // ShowVal: true,
  902. // },
  903. // }, &excelize.Chart{
  904. // Type: "line",
  905. // Series: []excelize.ChartSeries{
  906. // {
  907. // Name: "Sheet1!$A$4",
  908. // Categories: "Sheet1!$B$1:$D$1",
  909. // Values: "Sheet1!$B$4:$D$4",
  910. // Marker: excelize.ChartMarker{
  911. // Symbol: "none", Size: 10,
  912. // },
  913. // },
  914. // },
  915. // Format: excelize.GraphicOptions{
  916. // ScaleX: 1,
  917. // ScaleY: 1,
  918. // OffsetX: 15,
  919. // OffsetY: 10,
  920. // PrintObject: &enable,
  921. // LockAspectRatio: false,
  922. // Locked: &disable,
  923. // },
  924. // Legend: excelize.ChartLegend{
  925. // Position: "right",
  926. // ShowLegendKey: false,
  927. // },
  928. // PlotArea: excelize.ChartPlotArea{
  929. // ShowCatName: false,
  930. // ShowLeaderLines: false,
  931. // ShowPercent: true,
  932. // ShowSerName: true,
  933. // ShowVal: true,
  934. // },
  935. // }); err != nil {
  936. // fmt.Println(err)
  937. // return
  938. // }
  939. // // Save spreadsheet by the given path.
  940. // if err := f.SaveAs("Book1.xlsx"); err != nil {
  941. // fmt.Println(err)
  942. // }
  943. // }
  944. func (f *File) AddChart(sheet, cell string, chart *Chart, combo ...*Chart) error {
  945. // Read worksheet data
  946. ws, err := f.workSheetReader(sheet)
  947. if err != nil {
  948. return err
  949. }
  950. opts, comboCharts, err := f.getChartOptions(chart, combo)
  951. if err != nil {
  952. return err
  953. }
  954. // Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder.
  955. drawingID := f.countDrawings() + 1
  956. chartID := f.countCharts() + 1
  957. drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
  958. drawingID, drawingXML = f.prepareDrawing(ws, drawingID, sheet, drawingXML)
  959. drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
  960. drawingRID := f.addRels(drawingRels, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
  961. err = f.addDrawingChart(sheet, drawingXML, cell, int(opts.Dimension.Width), int(opts.Dimension.Height), drawingRID, &opts.Format)
  962. if err != nil {
  963. return err
  964. }
  965. f.addChart(opts, comboCharts)
  966. if err = f.addContentTypePart(chartID, "chart"); err != nil {
  967. return err
  968. }
  969. _ = f.addContentTypePart(drawingID, "drawings")
  970. f.addSheetNameSpace(sheet, SourceRelationship)
  971. return err
  972. }
  973. // AddChartSheet provides the method to create a chartsheet by given chart
  974. // format set (such as offset, scale, aspect ratio setting and print settings)
  975. // and properties set. In Excel a chartsheet is a worksheet that only contains
  976. // a chart.
  977. func (f *File) AddChartSheet(sheet string, chart *Chart, combo ...*Chart) error {
  978. // Check if the worksheet already exists
  979. idx, err := f.GetSheetIndex(sheet)
  980. if err != nil {
  981. return err
  982. }
  983. if idx != -1 {
  984. return ErrExistsSheet
  985. }
  986. opts, comboCharts, err := f.getChartOptions(chart, combo)
  987. if err != nil {
  988. return err
  989. }
  990. cs := xlsxChartsheet{
  991. SheetViews: &xlsxChartsheetViews{
  992. SheetView: []*xlsxChartsheetView{{ZoomScaleAttr: 100, ZoomToFitAttr: true}},
  993. },
  994. }
  995. f.SheetCount++
  996. wb, _ := f.workbookReader()
  997. sheetID := 0
  998. for _, v := range wb.Sheets.Sheet {
  999. if v.SheetID > sheetID {
  1000. sheetID = v.SheetID
  1001. }
  1002. }
  1003. sheetID++
  1004. path := "xl/chartsheets/sheet" + strconv.Itoa(sheetID) + ".xml"
  1005. f.sheetMap[sheet] = path
  1006. f.Sheet.Store(path, nil)
  1007. drawingID := f.countDrawings() + 1
  1008. chartID := f.countCharts() + 1
  1009. drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
  1010. f.prepareChartSheetDrawing(&cs, drawingID, sheet)
  1011. drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
  1012. drawingRID := f.addRels(drawingRels, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
  1013. if err = f.addSheetDrawingChart(drawingXML, drawingRID, &opts.Format); err != nil {
  1014. return err
  1015. }
  1016. f.addChart(opts, comboCharts)
  1017. if err = f.addContentTypePart(chartID, "chart"); err != nil {
  1018. return err
  1019. }
  1020. _ = f.addContentTypePart(sheetID, "chartsheet")
  1021. _ = f.addContentTypePart(drawingID, "drawings")
  1022. // Update workbook.xml.rels
  1023. rID := f.addRels(f.getWorkbookRelsPath(), SourceRelationshipChartsheet, fmt.Sprintf("/xl/chartsheets/sheet%d.xml", sheetID), "")
  1024. // Update workbook.xml
  1025. f.setWorkbook(sheet, sheetID, rID)
  1026. chartsheet, _ := xml.Marshal(cs)
  1027. f.addSheetNameSpace(sheet, NameSpaceSpreadSheet)
  1028. f.saveFileList(path, replaceRelationshipsBytes(f.replaceNameSpaceBytes(path, chartsheet)))
  1029. return err
  1030. }
  1031. // getChartOptions provides a function to check format set of the chart and
  1032. // create chart format.
  1033. func (f *File) getChartOptions(opts *Chart, combo []*Chart) (*Chart, []*Chart, error) {
  1034. var comboCharts []*Chart
  1035. options, err := parseChartOptions(opts)
  1036. if err != nil {
  1037. return options, comboCharts, err
  1038. }
  1039. for _, comboFormat := range combo {
  1040. comboChart, err := parseChartOptions(comboFormat)
  1041. if err != nil {
  1042. return options, comboCharts, err
  1043. }
  1044. if _, ok := chartValAxNumFmtFormatCode[comboChart.Type]; !ok {
  1045. return options, comboCharts, newUnsupportedChartType(comboChart.Type)
  1046. }
  1047. comboCharts = append(comboCharts, comboChart)
  1048. }
  1049. if _, ok := chartValAxNumFmtFormatCode[options.Type]; !ok {
  1050. return options, comboCharts, newUnsupportedChartType(options.Type)
  1051. }
  1052. return options, comboCharts, err
  1053. }
  1054. // DeleteChart provides a function to delete chart in spreadsheet by given
  1055. // worksheet name and cell reference.
  1056. func (f *File) DeleteChart(sheet, cell string) error {
  1057. col, row, err := CellNameToCoordinates(cell)
  1058. if err != nil {
  1059. return err
  1060. }
  1061. col--
  1062. row--
  1063. ws, err := f.workSheetReader(sheet)
  1064. if err != nil {
  1065. return err
  1066. }
  1067. if ws.Drawing == nil {
  1068. return err
  1069. }
  1070. drawingXML := strings.ReplaceAll(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl")
  1071. return f.deleteDrawing(col, row, drawingXML, "Chart")
  1072. }
  1073. // countCharts provides a function to get chart files count storage in the
  1074. // folder xl/charts.
  1075. func (f *File) countCharts() int {
  1076. count := 0
  1077. f.Pkg.Range(func(k, v interface{}) bool {
  1078. if strings.Contains(k.(string), "xl/charts/chart") {
  1079. count++
  1080. }
  1081. return true
  1082. })
  1083. return count
  1084. }
  1085. // ptToEMUs provides a function to convert pt to EMUs, 1 pt = 12700 EMUs. The
  1086. // range of pt is 0.25pt - 999pt. If the value of pt is outside the range, the
  1087. // default EMUs will be returned.
  1088. func (f *File) ptToEMUs(pt float64) int {
  1089. if 0.25 > pt || pt > 999 {
  1090. return 25400
  1091. }
  1092. return int(12700 * pt)
  1093. }